CakePHP2でMySQLのGeometry型を扱う

CakePHPでGeometry型を用いた
位置情報に基づいた検索を行う方法です

大事なこと

最初に言っておきます

CakePHPはGeometry型を用いた取得
には標準では、対応してません

なので取得保存にはちょっと
手順を踏まないといけないです

その前に

詳しくGeometry型について知りたい人は
以下から確認してください
[http://dev.mysql.com/doc/refman/5.6/ja/gis-class-geometry.html](MySQL :: MySQL 5.6 リファレンスマニュアル :: 11.5.2.2 Geometry クラス)

やってみた

データベース

まずデータベースとテーブルを用意しましょう
SQLはこんな感じです

CREATE DATABASE hoge;

USE hoge;

CREATE TABLE IF NOT EXISTS `geometries` (
    `id` int(11) NOT NULL,
    `hoge_id` int(11) NOT NULL,
    `latlng` geometry NOT NULL,
    `created` datetime NOT NULL,
    `modified` datetime NOT NULL
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

モデル

次にモデルを用意

ここで保存した際にGeometry型に変換されるように
beforeSaveの所に記述する

virtualFieldも用意しておきましょう
そうするとあとで楽なので

<?php class Geometry extends AppModel {

    function beforeSave() {
        $lat = $this->data['Geometry']['lat'];
        $lng = $this->data['Geometry']['lng'];

        $latlng = $this->query("SELECT GeomFromText('POINT($lng $lat)') as latlng");
        $this->data['Geometry']['latlng'] =     $latlng[0][0]['latlng'];

        return true;
    }

    var $virtualFields = array(
        'latitude' => X(latlag),
        'longitude' => Y(latlng)
    );

}

コントローラー

次にコントローラーでデータを取り出す方法
最初にも書いたとおりいつも通りのCakeの書き方じゃ取り出せ無いです。

でも基本は同じなのでいつもどおり書けばOKです

<?php class Geometries extends AppController {
    public function get_geo() {
        $geo = $this->Geometory->find(
            'all',
            array(
                'fields' => array(
                   // ここを変える
                ),
                'order' => array(
                    'let' => 'ASC'
                ),
            )
        );
    }
}

気をつけて欲しいのがfieldsのところに条件を与えることです
検索条件だからconditionsのところに条件を与えるとハマります

与えられた位置情報から近い順に情報を取得する場合は
こんなかんじに書きます

 GLength(GeomFromText(CONCAT('LineString(".経度." ".緯度.",', X(latlng), ' ', Y(latlng),')'))) AS let

ここの部分を変えれば2点間の距離を求めたり4点の位置に含まれる情報を取得することが出来ます

コメントを残す