2017.9.11
Livvon#4【ジオコーディング#1-Google Maps Geocoding API-】
ジオコーディングとは。
―各種情報に対して、関連する地理座標(典型的には緯度・経度)を付加すること、およびこれに関する技術やソフトウェアをいう。付加された地理座標のことをジオコードと称する。
出典:ジオコーディング - wikipedia
まぁ要するに
住所をLATLNGに変換したいってわけですね。
地図上から選択させて直接入力させるのが一番ラクなのですが、そんなめんどくさいことユーザーにさせるシステムはさすがに雲古なのできちんと作ります。
まぁこんなの別に僕が実装しなくても人にやらせたいところなんですけど、プログラムに於いて人の手を借りるというのは必須条件ではないので、最悪のシナリオを想定して自分でできる範囲はやっておきます。
もちろん、一から実装とか不可能に近いのですが、この世には便利なライブラリがあるのでそれを使い、なんとかして住所を緯度経度に変換したいと思います。
ちなみにこのジオコーディング、グローバル化とか言っておきながら国外対応はしないつもりです。
流石に僕のスキルじゃ厳しい気がします。
Q.じゃあどうすんの?お手軽ホームステイっていうコンセプト守れなくない?
A.知らん。やってくれる人を探す。()
とりあえず国内だけなんとか実装すれば、雰囲気だけは掴めるっしょ。うん。
と、思っていたんですが・・・・・・そういえばと思って調べてみたら
Googleがジオコーディング用のAPI出してるんですよね。
住所のジオコーディングなんてそう頻繁にする操作ではないので、課金してでも取り入れる価値はあるかなと思います。
というのも、Googleお手製ですから世界中の住所に対応しているはずです。その辺のフリーのライブラリとは信頼感が違いますからね。
あと、未検証なのですが、わりとあいまいな記述をしても、検索エンジン経由でいい感じに結果を拾ってくれそうなので、住所の全角/半角縛りバリデーションが要らなくなる・・・・・・?
ということで、当面の目標として
Google Maps Geocoding APIを使っていきたいという方針に定まることになります。
あともう一つ、やらなくてはいけない作業としては
ジオコーディング結果をバリデーションに使用するというところですね。
ジオコーディングに失敗する=不正な住所情報、ということで個別にエラーを返すことになります。まぁこの辺の実装は、ジオコーディングさえうまくいけばなんとかなると思います。
そうですね、今日はこのGoogleのAPIに接続するところまでいきますかね。
そういえばPHPでどうやって実装したらいいのかよくわからないので
テキトーな参考ページを見つつ考えてみましょうね。
まぁダメならjavascriptで書けばいいのですが、なるべく安定なPHPでなんとかしたいところ。
ざっと見たところ、住所のデータをGoogleのAPIに投げ、jsonが返ってくるのでそれをごにょごにょする、って感じですね。
その辺をいい感じにやってくれる関数を実装すればよきって感じですね。さすがに直打ちは頭悪すぎるのでオブジェクトにしましょう。
このページが参考になりそうですね。
ファサード化するのはめんどいので、普通のクラスとして作りましょう。
まず、日本語が絡むとバグりそうなので、海外の住所ぶっ込んでテストしてみましょう。
んじゃテキトーにクラスつくりましょ。関数はとりあえず丸コピしますかね。
まぁ・・・・・・プログラム三大あるあるがあれば必ず入っているであろう
サンプルが動かない問題に3時間ほど溶かされましたが、無事に
なんかわからんけど解決したので、ソースコードを並べてみることにします。
<?php
namespace App\Classes;
class Geocoding{
function geocode($address){
// url encode the address
$address = urlencode($address);
// google map geocode api url
$url = "http://maps.google.com/maps/api/geocode/json?address={$address}";
// get the json response
$resp_json = file_get_contents($url);
// decode the json
$resp = json_decode($resp_json, true);
// response status will be 'OK', if able to geocode given address
if($resp['status']=='OK'){
// get the important data
$lati = $resp['results'][0]['geometry']['location']['lat'];
$longi = $resp['results'][0]['geometry']['location']['lng'];
$formatted_address = $resp['results'][0]['formatted_address'];
// verify if data is complete
if($lati && $longi && $formatted_address){
// put the data in the array
$data_arr = array();
array_push(
$data_arr,
$lati,
$longi,
$formatted_address
);
return $data_arr;
}else{
return false;
}
}else{
return false;
}
}
public function __construct()
{
}
}
見て分かる通り、ジオコーディングクラスです。ほぼ丸コピです。
住所情報を
geocode()に渡すと検索してデータをかき集めてくれます。
namespaceの設定は忘れないようにしましょうね。(このくだらない抜けで10分ぐらいロスした)
use App\Classes\Geocoding;
public function geotest() {
$geocoding = new Geocoding();
$geodata = $geocoding->geocode("新宿三丁目駅");
return view('Test.geotest')->with('geodata',$geodata);
}
コントローラーにはこんな関数を用意します。先程のGeocodingクラスを忘れずにuseしましょうね。
とりあえず今回は新宿三丁目駅という単語をばっさり入れてみます。これで動いて詳細な住所を取ってきてくれるみたいなので。
@php
if($geodata){
$latitude = $geodata[0];
$longitude = $geodata[1];
$formatted_address = $geodata[2];
}
@endphp
<!doctype html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<script type="text/javascript" src="http://maps.google.com/maps/api/js?key=(ここにAPIキーを入れる)"></script>
<script type="text/javascript">
function initialize() {
var latlng = new google.maps.LatLng({{$latitude}},{{$longitude}});
var myOptions = {
zoom: 15,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var myLatlng = new google.maps.LatLng({{$latitude}},{{$longitude}});
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title:"Hello"
});
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas" style="width:320px; height:320px"></div>
</body>
</html>
最適化もクソもないコードですが、これで動きます。APIキーは各自で取得しましょ。無制限なキーだとローカルでも動きます。
先程紹介したとこのコードだと表示すらしてくれなかったのでめちゃくちゃ格闘した結果、全然違うサイトのコードを引っ張ってくるのに至りました。
つまり何がよくなかったのかが分かりません。
あとはこれをいい感じに弄ればお目当てのものが手に入りそうなので、その辺は明日に持ち越しです。つかれた、、、、、、、、、、、
ちなみに、実機だとこんな画面になります。はい。