reza-id / yii2-geopoint
Yii2 ActiveRecord supporting MySQL spatial pint data
Installs: 2 064
Dependents: 0
Suggesters: 0
Security: 0
Stars: 5
Watchers: 1
Forks: 3
Open Issues: 1
Type:yii2-extension
pkg:composer/reza-id/yii2-geopoint
Requires
- yiisoft/yii2: *
This package is not auto-updated.
Last update: 2025-12-21 02:44:58 UTC
README
ActiveRecord inspired by yii2-spatial but made simpler only to use specific spatial datatype: POINT.
Transform the internal MySQL format to simple coordinate text after finding, and vice versa before storing.
Yii2-geopoint can also be used to find the model or models which are nearest to a given location.
Notice that this extension can be used with MySQL >= 5.6.1, MariaDB >= 5.3.3, and PostgreSQL >= 9.1.
Installation
Install Yii2-geopoint with Composer. Either add the following to the require section of your composer.json file:
"reza-id/yii2-geopoint": "*"
Or run:
$ php composer.phar require reza-id/yii2-geopoint "*"
You can manually install Yii2-geopoint by downloading the source in ZIP-format.
Usage
Create spatial indexed table using migration:
$this->createTable('{{%place}}', [
'id' => $this->primaryKey(),
'name' => $this->string(125)->notNull(),
'location' => 'POINT NOT NULL',
], $tableOptions);
if ($this->db->driverName === 'mysql') {
$this->execute('CREATE SPATIAL INDEX `idx-place-location` ON '.'{{%place}}(location);');
} elseif ($this->db->driverName === 'pgsql') {
$this->execute('CREATE INDEX "idx-place-location" ON '.'{{%place}} USING GIST(location);');
}
Use a rezaid\geopoint\ActiveRecord as base class for your models, like so:
<?php
namespace app\models;
use rezaid\geopoint\ActiveRecord;
class MyModel extends ActiveRecord
{
// ...
}
Notice: if you override find() in a rezaid\geopoint\ActiveRecord-derived class, be sure to return a rezaid\geopoint\ActiveQuery and not an 'ordinary' yii\db\ActiveQuery.
ActiveQuery method
nearest()
public function nearest($from, $attribute, $radius, $unit)
Change the query so that it finds the model(s) nearest to the point given by $from.
$from-string: location in the form<lng>,<lat>(twofloats).$attribute-stringattribute name ofPointin the model.$radius-numbersearch radius in kilometers or miles. Default100.$unit-stringunit valuekmfor kilometers ormilfor miles. Defaultkm.
Example usages:
$here = '4.9,52.3'; // longitude and latitude of my place
$nearestModel = <model>::find()->nearest($here, <attributeName>, 200, 'mil')->one(); // search radius is 200 miles
$fiveNearestModels = <model>::find()->nearest($here, <attributeName>)->limit(5)->all(); // search radius is 100 km (default)
$dataProvider = new ActiveDataProvider([ 'query' => <model>::find()->nearest($here, <attributeName>) ]);
ActiveRecord method
getDistance()
Get the distance from given location in the ActiveQuery method nearest(), if you want to display the distance in RESTful API, add this as new field in your model:
<?php
namespace app\models;
use rezaid\geopoint\ActiveRecord;
class MyModel extends ActiveRecord
{
// ...
public function fields()
{
$fields = parent::fields();
$fields['distance'] = function ($model) {
return $model->getDistance();
};
return $fields;
}
// ...
}
Example rest controller:
<?php
namespace app\controllers;
use Yii;
use yii\rest\ActiveController;
class PlaceController extends ActiveController
{
public $modelClass = 'app\models\MyModel';
public function actionSearch()
{
$from = Yii::$app->request->get('from');
$model = new $this->modelClass;
$query = $model->find();
if (!empty($from)) {
$query->nearest($from, 'location', 200);
}
try {
$provider = new \yii\data\ActiveDataProvider([
'query' => $query,
]);
} catch (Exception $ex) {
throw new \yii\web\HttpException(500, 'Internal server error');
}
if ($provider->getCount() <= 0) {
throw new \yii\web\HttpException(404, 'No entries found');
} else {
return $provider;
}
}
}