Posted at

fuelphpでgeometry型を扱う

More than 5 years have passed since last update.

MySQLのviewを使うことで実現してみた。

ここではSpotという、名前と説明と位置情報を持つデータを考えてみる。

scaffoldでは、geometryを指定

php oil g scaffold -f spots title:string description:string location:geometry

できあがったmigrationファイルのup()関数内で

\DBUtil::create_index('spots', 'location', 'sp_index', 'spatial');

\DB::query("create view spots_all_view as select id, title, description, ASTEXT(location) as location, created_at, updated_at from spots")->execute();

自動生成されたSpotの定義内の$_observersに、

'Model_Spot_Observer' => array(

'events' => array('before_save', 'after_load'),
);

を追加。

で、Model_Spot_Observerの実態は

class Model_Spot_Observer extends Orm\Observer

{
public function before_save(Model_Spot $obj)
{
$location = $obj->location;
$obj->set('location', \DB::expr('GeomFromText("POINT('.$location[0].' '.$location[1].')")'));
}

public function after_load(Model_Spot $obj)
{
$location = $obj->location;
preg_match('/POINT\((.+)\s(.+)\)/', $location, $matches);
$obj->location = array($matches[1], $matches[2]);

}
}

before_saveは、値がDBに保存される前処理。ここで、controllerから配列形式で渡した緯度経度情報を基にGeomFromText関数の呼び出し形式の文字列を生成し、locationに設定する。

after_loadはDBから値を読み込んだ時の後処理。MySQLのviewの定義を見るとわかるように、ASTEXT(location) as locationとしているので、DBから読み込んだ値は"POINT(経度 緯度)"という文字列になる。ここままでは非常に扱いにくいのafter_load関数でその値を配列にしてあげる。

これによって、controller、viewから見れば、緯度経度情報が配列で扱えるようになる。

もっとうまいやり方があるのかもしれないが、とりあえずはこれで動くといえば動く。