Coder Social home page Coder Social logo

laravel-geographical's Introduction

Laravel Geographical

Easily add longitude and latitude columns to your records and use inherited functionality for calculating distances.

First either update your database or add this to a migration for each model:

$table->double('longitude');
$table->double('latitude');

Finally, edit you model to use the Geographical Trait, as the example below:

<?php

namespace App\Models;

use Malhal\Geographical\Geographical;
use Illuminate\Database\Eloquent\Model;

class ModelExample extends Model
{
    use Geographical;

1. Distance

Find the distance to all the entries in your table from a particular location.

$query = ModelExample::distance($latitude, $longitude);
$asc = $query->orderBy('distance', 'ASC')->get();

2. Geofence

Find all the entries in your table inside a circular geo-fence.

$query = ModelExample::geofence($latitude, $longitude, $inner_radius, $outer_radius);
$all = $query->get();

Use $inner_radius= 0 & $outer_radius = any number in miles that you desire.

Units

The default unit of distance is miles. You can change it to kilometers by putting this in your model

protected static $kilometers = true;

Notes

  1. The method returns a Eloquent\Builder object so that you can add optional conditions if you want.
  2. If you require to select only a certain columns, it can be achieved by using select().
    ModelExample::select('id', 'name')->distance($latitude, $longitude);
    (select() should precede the distance()/geofence())
  3. You can use distance as an aggregate column in the result. (Aggregate columns cannot be used in WHERE, use HAVING to execute any condition.)
  4. If you use different column names for latitude and longitude, mention them in the Model.php
    const LATITUDE  = 'lat';
    const LONGITUDE = 'lng';

Options

  1. You may pass an array of options as the third parameter of the distance method, these options will allow you to set a new table name or column names at runtime.

    $query = Model::distance($latitude, $longitude, $options);
  2. There are three fields you set with the options parameter at runtime: table, latitude_column, and longitude_column:

    $options = [
       'table' => 'coordinates',
       'latitude_column' => 'lat',
       'longitude_column' => 'lon'
    ]
    
    Model::select('id', 'name')->distance($latitude, $longitude, $options);
  3. The table field will allow you to set the table from which the the coordinates will be selected at runtime, allowing you to join the coordinates to your model from another table.

    Model::join('locations', function($join){ 
               $join->on('model.id', '=', 'locations.model_id');
           })
           ->select('id', 'name')
           ->distance($latitude, $longitude, ['table' => 'locations']);
  4. The latitude_column and longitude_column fields can be used to set the column names for a joined table, or to override the default column names (including those set on your model) at runtime. If you don't set the column name fields at runtime when using a joined table then column names set on your model, or the defaults of 'latitude' and 'longitude' will be used. Setting const LATITUDE = 'lat' or const LONGITUDE = 'lng' on a joined model will have no effect.

Installation

PHP 5.6.4+ and Laravel 5+ are required.

To get the latest version of Laravel Geographical, simply require the project using Composer:

$ composer require malhal/laravel-geographical

laravel-geographical's People

Contributors

amorphia avatar ashnehete avatar flaviosilveira avatar grayda avatar icaroscherma avatar izshreyansh avatar jcs224 avatar malhal avatar xitude avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-geographical's Issues

Laravel 7 support

Laravel 7 support? I believe it is only needed to change the composer.json to enable the installation.

Geofence returns long numbers

Hello!
When I call scope geofence I get long numbers of coordinates and distances.
For example:
The database contains the coordinates:
latitude 57.161948
longitude 50.316044

In response, I get
latitude 57.16194800000000242334863287396728992462158203125
longitude 50.31604399999999799319994053803384304046630859375
distance 1.580186425277957606994050365756265819072723388671875

How can I reduce the returned numbers to 6 decimal places, how are they stored in the database?

Can´t paginate while using fence

When i try to paginate using scopeFence i get this error:

(2/2) QueryException
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'distance' in 'having clause' (SQL: select count(*) as aggregate from spots inner join favorites on spots.id = favorites.spot_id where favorites.user_id = 1 having distance BETWEEN 0 AND 150)

does not install on laravel 5.4

$ composer require malhal/laravel-geographical
Using version ^1.0 for malhal/laravel-geographical
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

Problem 1
- Installation request for malhal/laravel-geographical ^1.0 -> satisfiable by malhal/laravel-geographical[1.0.0].
- malhal/laravel-geographical 1.0.0 requires laravel/framework 5.3.* -> satisfiable by laravel/framework[5.3.x-dev, v5.3.0, v5.3.0-RC1, v5.3.1, v5.3.10, v5.3.11, v5.3.12, v5.3.13, v5.3.14, v5.3.15, v5.3.16, v5.3.17, v5.3.18, v5.3.19, v5.3.2, v5.3.20, v5.3.21, v5.3.22, v5.3.23, v5.3.24, v5.3.25, v5.3.26, v5.3.27, v5.3.28, v5.3.29, v5.3.3, v5.3.30, v5.3.31, v5.3.4, v5.3.5, v5.3.6, v5.3.7, v5.3.8, v5.3.9] but these conflict with your requirements or minimum-stability.

Installation failed, reverting ./composer.json to its original content.

Short Video for demo

Hi Malhal,
I saw your package and its very helpful, however i would like you to if possible record a short video to demonstrate how it all works to calculate and display the distance of every user from a common location.
Thanks alot.

can't get it working in Laravel 5.6

I've just followed all readme steps but when I try to run migrations, it returns:

PHP Fatal error:  Trait 'Malhal\Geographical' not found in /var/www/app/Place.php on line 13

   Symfony\Component\Debug\Exception\FatalErrorException  : Trait 'Malhal\Geographical' not found

  at /var/www/app/Place.php:13
     9|
    10| class Place extends Model
    11| {
    12|     use SoftDeletes;
  > 13|     use Geographical;
    14|
    15|     protected static $kilometers = true;
    16|     const LATITUDE  = 'pin_lat';

I tried many different ways to load the trait in my model:

use Malhal\Geographical;
use Geographical;
use \Malhal\Geographical;
... etc

Am I doing something wrong?

Support Laravel 6

Hey,

as Laravel 6 has been released, the current composer.json doesn't allow to upgrade to laravel ^6.0.
Do you know if there are any breaking changes in here?

geofence with pgsql error

i install and use it as instructed. I can get the distance method working but when i use geofence it give me error

SQLSTATE[42703]: Undefined column: 7 ERROR: column "distance" does not exist LINE 1: ...PI()) * 60 * $4) as distance from "stores" having distance B... ^ (SQL: select "stores".*, ((ACOS(SIN(16.8095486 * PI() / 180) * SIN(stores.latitude * PI() / 180) + COS(16.8095486 * PI() / 180) * COS(stores.latitude * PI() / 180) * COS((96.1209137 - stores.longitude) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) as distance from "stores" having distance BETWEEN 1 AND 1)

Geofence Return Null even the lng and lat are the same.

Laravel Version: 7.22

$lat = 122.9563;
$lng = 10.684;
$in_radius = 30; // What is the measurement of radius?
$out_radius = 30; // What is the measurement of radius?

Model::geofence($lat,$lng,$in_radius,$out_radius)->get();

When i use the distance the return value is 0.4412770539854747 but when i use the geofence it return null.

No Postgres support

It doesn't work with Postgres. It would be great if it was mentioned or that support would be added in the future.

Returning Empty Array

Hi there,

I am attempting to use the package you created to return results within a particular radius. Per the brief documentation outlined, this is my code:

      $latitude = 45.68616989612867;
      $longitude = -87.59278603624216;
      $inner_radius = 1;
      $outer_radius = 1000000000;

      return FFL::geofence($latitude, $longitude, $inner_radius, $outer_radius)->get();

The result I receive is an empty array. I updated my model to use Geographical and my migration has these two column:

            $table->double('latitude');
            $table->double('longitude');

Any ideas you have would be helpful. Regards.

Call to undefined method App\\Model::geofence()

I follow the steps what you said in read me.

I am not sure about it is a right way I did though. Is there any solution? Can I get examples?
I am using it on Laravel 7 with the column you suggested.
image

Geofence does not work with pagination

Laravel Framework 5.8.14
PHP 7.2.11
10.2.10-MariaDB

 $ads = Ads::geofence($json->lat, $json->lon, 0, $distance);
 $ads = $ads->Paginate(25);

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'distance' in 'having clause' (SQL: select count(*) as aggregate from ads having distance BETWEEN 0 AND 99999999)

Syntax error or access violation: 1463

Laravel Framework 5.8.14
PHP 7.2.11
10.2.10-MariaDB

ERROR:
SQLSTATE[42000]: Syntax error or access violation: 1463 Non-grouping field 'distance' is used in HAVING clause (SQL: select ads.*, ((ACOS(SIN(51.4691877 * PI() / 180) * SIN(ads.latitude * PI() / 180) + COS(51.4691877 * PI() / 180) * COS(ads.latitude * PI() / 180) * COS((6.08554785 - ads.longitude) * PI() / 180)) * 180 / PI()) * 60 * 1.853159616) as distance from adswherecategory_id = 2 having distance BETWEEN 0 AND 10 limit 26 offset 0)

Query select() issue when using distance column

I need only these fields in my query:

$places->select(
    'id',
    'title',
    'subtitle',
    'distance'
);

This is working fine so far, but breaks when I add distance columns

$places->distance($params->latitude, $params->longitude);
$places->orderBy('distance', 'ASC');
$places->having('distance', '<=', $params->distance);

Adding this code it looks like my previous select() is ignored cause it returns all Model fields.

So I tried to put select() after distance and then it returns column error:

Column not found: 1054 Unknown column 'distance' in 'field list'

Am I doing something wrong?

Method Illuminate\Database\Eloquent\Collection::distance does not exist.

Hey there.
Great package you made there, I want to say thank you.

I have an issue when using Eloquent query.
For instance, I only want to use distance() for some ids and not the whole Model.
I use :
$events = Nosevenement::find($ids) -> distance($latitude, $longitude) -> orderBy('distance', 'ASC');
And i get an error : Method Illuminate\Database\Eloquent\Collection::distance does not exist.

I guess we can't combine both for now.
It's a shame because the package is doing wonders so far.

SQLite trig functions

When trying to test geofence using a sqlite db, it will fail because sqlite does not have trig functions. Currently, my workaround is to manually create the trig functions in my setup with

DB::connection()->getPdo()->sqliteCreateFunction("ACOS", "acos", 1);
DB::connection()->getPdo()->sqliteCreateFunction("COS", "cos", 1);
DB::connection()->getPdo()->sqliteCreateFunction("SIN", "sin", 1);
DB::connection()->getPdo()->sqliteCreateFunction("PI", "pi", 0);

I also add this to the trait due to a "missing group by clause" error

public function scopeGeofence($query, $latitude, $longitude, $inner_radius, $outer_radius) {
    $query = $this->scopeDistance($query, $latitude, $longitude);
    
    return $query->groupBy('id')
      ->havingRaw('distance BETWEEN ? AND ?', [
        $inner_radius,
        $outer_radius ?: $this->getDefaultRadius()
      ]);
  }

here is the test that I am running

/** @test */
  public function a_user_can_get_shops_around_a_specific_shop_within_a_radius() {
    $null_island_coordinates = ['latitude' => 0, 'longitude' => 0];
    $north_pole_coordinates = ['latitude' => 90, 'longitude' => 0];
    $shop = create('App\Shop', $null_island_coordinates);
    $shopAround = create('App\Shop', $null_island_coordinates);
    $shopNotAround = create('App\Shop', $north_pole_coordinates);
    $radius = 300;
    $this->get($shop->path() . '/around?radius=' . $radius)
      ->assertSee($shopAround->name)
      ->assertDontSee($shopNotAround->name);
  }

and the endpoint

/**
   * @param $id
   * @return mixed
   */
  public function around($id) {
    $shop = Shop::find($id);
    $radius = $this->fetchQueries('radius');
    return Shop::geofence(
      $shop->latitude,
      $shop->longitude,
      0,
      $radius)
      ->get();
  }

Distance is incorrect?

Using $query = User::geofence($myLatitude, $myLongitude, 0, 1000)->get() results that I am 5.8987221219523E-5 away from myself. Shouldn't it be 0 since I'm passing the exact lat/long it's comparing to?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.