Use SpatialTrait, Point, Polygon and LineString in Laravel (Zone Service)

Created At: 2023-02-13 01:06:14 Updated At: 2023-05-19 03:24:36

Here we will see how to work with geometry and coordinates using SpatialTrait, Point, Polygon and LineString in Laravel. We will also see how response to API call, that comes from front end and process the data and save the database.

There are packages for it, and just install the package using composer.

composer require grimzy/laravel-mysql-spatial:^4.0

After getting the package you need to publish it, in general it should be auto published. If not add this in config/app.php

'providers' => [
  /*
   * Package Service Providers...
   */
  Grimzy\LaravelMysqlSpatial\SpatialServiceProvider::class,
],

Then you are ready to use spatial coordinates and all the other classes.

Complete code

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Grimzy\LaravelMysqlSpatial\Eloquent\SpatialTrait;
use Grimzy\LaravelMysqlSpatial\Types\Point;
use Grimzy\LaravelMysqlSpatial\Types\Polygon;
use Grimzy\LaravelMysqlSpatial\Types\LineString;

class Zone extends Model
{
    use HasFactory;
    use SpatialTrait;

    protected $spatialFields = [
        'coordinates'
    ];


    public function orders()
    {
        return $this->hasManyThrough(Order::class);
    }

    public function deliverymen()
    {
        return $this->hasMany(DeliveryMan::class);
    }

    public function scopeActive($query)
    {
        return $query->where('status', '=', 1);
    }

    public function getCoordinatesAttribute($value)
    {
        if($value){

        $data_str = "";
        foreach($value as $coord)
        {
            foreach ($coord as $val){
                $data_str = $data_str."({$val->getlat()},{$val->getlng()}),";
            }
        }
        return substr($data_str,0,-1);
        }
        return $value;
    }

    public function setCoordinatesAttribute($value)
    {

        $lastcord = [];
        $polygon= [];
        foreach(explode('),(',trim($value,'()')) as $index=>$single_array){
            if($index == 0)
            {
                $lastcord = explode(',',$single_array);
            }
            $coords = explode(',',$single_array);
            $polygon[] = new Point($coords[0], $coords[1]);
        }
        $polygon[] = new Point($lastcord[0], $lastcord[1]);
        $coordinates = new Polygon([new LineString($polygon)]);
        $this->attributes['coordinates'] = $coordinates;

    }
}

API Call

If you have an api call from front end that send latitude and longitude, You may grab the value in request object. then first pass them to Point() class and then pass an object of the Point() to Contains() method of zone model.

The code looks like this 

   public function get_zone(Request $request)
    {
          $validator = Validator::make($request->all(), [
            'lat' => 'required',
            'lng' => 'required',
        ]);

        if ($validator->errors()->count()>0) {
            return response()->json(['errors' => Helpers::error_processor($validator)], 403);
        }
        $point = new Point($request->lat,$request->lng);
        

        $zones = Zone::contains('coordinates', $point)->first();
        if(empty($zones)){
            return response()->json(['code'=>-1,'message'=>'error']);
        }
        return response()->json(['code'=>0,'message'=>'success','data'=>$zones->id]);
      
     
    }

Comment

  • M
    Musa

    2024-02-15 02:12:30

    Selamun Aleykum Ahmad, Thansk for useful information

Add Reviews