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から見れば、緯度経度情報が配列で扱えるようになる。
もっとうまいやり方があるのかもしれないが、とりあえずはこれで動くといえば動く。