GoogleMapsViewHelperっぽいのを書いてみた
前日のポストで造ってみよう的なやつをさくっと書いてみました。
バグあったらすみません。。。
以下ソース
ViewHelperっぽいの
[CC lang="php"]
<?php
require_once("Zend/Exception.php") ;
require_once("Zend/Db.php") ;
require_once("Zend/Registry.php") ;
require_once("Zend/Http/Client.php");
require_once("Zend/View/Helper/Abstract.php") ;
require_once("Nully/View/Helper/Google/Maps/MapModel.php") ;
class Nully_View_Helper_Google_Maps_Map extends Zend_View_Helper_Abstract {
/**
**/
const API_URL = "http://www.google.com/jsapi" ;
/**
* geo coding url
* @var string
**/
const GEOCODE_URI = "http://maps.google.com/maps/geo" ;
/**
* @var string
*/
protected $_api_key ;
/**
* display target block elements id
* @var string
**/
protected $_id = "gmap" ;
/**
* google maps cache dir
* @var string
**/
protected $_cache_dir ;
/**
* cache name
**/
protected $_cache_name = "cache.dat" ;
/**
* cache life time
* @var int
**/
protected $_cache_life_time = 21600 ; // 60 * 60 * 6 ( 1/4 hour )
/**
* constructor
* set the Zend_Config registerd google maps API KEY.
* @access public
**/
public function __construct() {
if(Zend_Registry::isRegistered("google_config")) {
$gConfig = Zend_Registry::get("google_config") ;
if(isset($gConfig->map->apikey)) {
$this->_api_key = $gConfig->map->apikey ;
}
}
$database = array() ;
if(Zend_Registry::isRegistered("database")) {
$database = Zend_Registry::get("database");
}
$this->_cache_dir = dirname(__FILE__). "/cache/" ;
try {
$db = Zend_Db::factory($database) ;
$db->getConnection()->exec("SET NAMES utf8;") ;
$this->_geo = new Nully_View_Helper_Google_Maps_MapModel($db) ;
}
catch(Exception $e) {
throw new Exception("Database connection faild.") ;
}
}
/**
* display google maps script tag.
* @access public
* @param str|array registerd address data.
* @param array parameter is so many...
* @return str|bool generated google maps script tag, or false.
**/
public function map($addresses, $params = array()) {
if(empty($addresses)) {
return false ;
}
$this->_setParams($params) ;
if($this->_hasCache()) {
$data = $this->_loadCache() ;
}
else {
$data = $this->_getGeos($addresses) ;
$this->_saveCache($data) ;
}
$param = $this->_getScriptParams() ;
echo $this->_displayScript($data, $param) ;
}
/**
* set parametars
* @access priavate
**/
private function _setParams($param) {
foreach($param as $func => $val) {
$func = "_set".$func ;
if(method_exists(&$this, $func)) {
$this->{$func}($val) ;
}
}
}
/**
* display javascript tag.
* @access private
* @param array data array.
* @param array data parameter array.
**/
private function _displayScript($data, $param) {
$json = $this->_toJson($data) ;
$jsapi = $this->_getApiUrl() ;
$script = <<< SCRIPT_END
<script type="text/javascript" src="{$jsapi}"></script>
<script type="text/javascript">
google.load("maps", 2, 'initialize') ;
var addr = {$json} ;
function initialize() {
var map = new GMap2(document.getElementById("{$param['id']}")) ;
map.setCenter(new GLatLng(addr[0]["lat"], addr[0]["lon"]), 10) ;
for(var i = 0; i < addr.length; i ++) {
var point = new GLatLng(addr[i]["lat"], addr[i]["lon"]);
map.addOverlay(new GMarker(point));
}
}
window.onload = function() { initialize() ; } ;
window.onunload = function() { GUnload() ; } ;
</script>
SCRIPT_END;
return $script ;
}
/**
* thrown data is json?
* @acess private
* @param string|array
* @return boolean is json not encoded return false.
**/
private function _isJson($addr) {
if(is_array($addr) || !is_string($addr)) {
return false ;
}
if(preg_match("/促{.*促}/", $addr)) {
return true ;
}
return false ;
}
/**
* has cache?
* @access private
* @return bool
**/
private function _hasCache() {
$file = $this->_cache_dir. $this->_cache_name ;
if(!file_exists($file)) {
unset($file) ;
return false ;
}
// checking for life time.
if($this->_compareLifeTime($file)) {
unset($file);
return true ;
}
unset($file) ;
return false ;
}
/**
* compare life time.
* @access private
* @return boolean
**/
private function _compareLifeTime($file) {
$modified = filemtime($file) ;
$now = time() ;
if*1 {
return false ;
}
$put_data = $this->_toJson($data) ;
$file = $this->_cache_dir. $this->_cache_name ;
$fp = fopen($file, "w") ;
flock($fp, LOCK_SH) ;
fputs($fp, $put_data. PHP_EOL) ;
flock($fp, LOCK_UN) ;
fclose($fp) ;
return true ;
}
/**
* load cache data
* if not has cache data, return empty array.
* @access private
* @return array caceh data.
**/
private function _loadCache() {
$file = $this->_cache_dir. $this->_cache_name ;
$data = file($file) ;
if(empty($data)) {
return array() ;
}
return json_decode($data[0]) ;
}
/**
* get geometries.
* @access private
* @param array address data array
**/
private function _getGeos($addr) {
if(empty($addr)) {
return false ;
}
$geos = array() ;
foreach($addr as $key => $address) {
$geos[$key] = $this->_findGeos($address) ;
}
return $geos ;
}
/**
* find for database geometry data.
* @access private
* @param string find address name.
* @return array cache data or request google geo API data.
**/
private function _findGeos($address) {
$select = $this->_geo
->select()
->where("address = ?", $address) ;
$stmt = $select->query() ;
$row = $stmt->fetchAll() ;
if(!empty($row)) {
return $row[0] ;
}
else {
return $this->_requestGeocode($address) ;
}
}
/**
* request geo code.
* result is csv data.
* @access priavte
* @param array
* response data is address, lat, lon.
**/
private function _requestGeocode($addr) {
if(empty($addr)) {
return array() ;
}
$cli = new Zend_Http_Client() ;
$cli->setUri(self::GEOCODE_URI) ;
$cli->setParameterGet(array(
"q" => $address,
"key" => $this->_api_key,
"output" => "csv"
)) ;
$response = $cli->request() ;
if($response->getStatus() === 200) {
$csv = $response->getBody();
if($csv) {
list($sts, $accure, $lat, $lon) = split(",", $csv) ;
if*2 {
return json_encode(array());
}
return json_encode($data) ;
}
/**
* get google jsapi url
* @access private
* @return string jsapi url
**/
private function _getApiUrl() {
if(!isset($this->_api_key)) {
return false ;
}
return self::API_URL. "?key=".$this->_api_key ;
}
/**
* set map box id
* @access private
* @param string
* @return this
**/
private function _setId($id) {
if(!is_string($id)) {
$id = (string)$id ;
}
$this->_id = $id ;
return $this ;
}
/**
* set cache path
* @access private
* @param string
* @return this
**/
private function _setCachePath($path) {
if(!is_string($path)) {
$path = (string)$path ;
}
$this->_cache_path = $path ;
return $this ;
}
/**
* set cache name
* @access private
* @param string
* @return this
**/
private function _setCacheName($name) {
if(!is_string($name)) {
$name = (string)$name ;
}
$this->_cache_name = $name ;
return $this ;
}
/**
* set cache life time.
* @access private
* @param string
* @return this
**/
private function _setCacheLifeTime($time) {
if(!is_numeric($time)) {
$time = (int)$time ;
}
$this->_cache_life_time = $time ;
return $this ;
}
/**
* get script paramaters
* @access private
* @return array
**/
private function _getScriptParams() {
return array(
"id" => $this->_id
) ;
}
}
?>
[/CC]
付随するModel
[CC lang="php"]
<?php
require_once("Zend/Db/Table/Abstract.php") ;
class Nully_View_Helper_Google_Maps_MapModel extends Zend_Db_Table_Abstract {
/**
* geocode table name
*/
protected $_name = "geocodes" ;
/**
* primary key
**/
protected $_primary = "address" ;
}
?>
[/CC]
Modelは変にいろいろmethodたてるのがめんどくさかったのでDbTableを継承させて造りました。
テーブルは以下のクエリを発行で。
[CC lang="sql"]
CREATE TABLE geocodes (
`address` VARCHAR(255) NOT NULL DEFAULT '',
`lat` FLOAR DEFAULT NULL,
`lon` FLOAR DEFAULT NULL,
PRIMARY KEY (address)
);
[/CC]
後はControllerでaddPrefixPathでパスとクラスPrefixを指定して、Viewで$this->map($this->addresses, $this->map_param) で呼ぶとGoogleMapsが表示されます。
$map_paramで有効なパラメタはid、cachepath、cachename、cachelifetimeです。
それぞれkey => valの形で渡します。
まだまだ足りない機能(nocssとか)いろいろ有るけど、まぁまだ実装しなくていいかなぁと。
あとそろそろGit使いたい。
*1:$now - $modified) < $this->_cache_life_time) {
return true ;
}
return false ;
}
/**
* save cache data.
* @access private
* @param array geo data array.
**/
private function _saveCache($data) {
if(empty($data
$this->_addDbGeo($addr, $lat, $lon) ;
return array(
"address" => $addr,
"lat" => $lat,
"lon" => $lon
) ;
}
else {
$this->_addDbGeo($addr, 0, 0) ;
return array(
"address" => $addr,
"lat" => 0,
"lon" => 0
) ;
}
}
else {
// not have a csv data...
return false ;
}
}
else {
// http status error.
return false ;
}
}
/**
* add geometry to database.
* @access private
* @param string
* @param floor
* @param floor
**/
private function _addDbGeo($address, $lat, $lon) {
$geos = array(
"address" => $address,
"lat" => $lat,
"lon" => $lon
) ;
$res = $this->_geo->insert($geos) ;
}
/**
* to json encode.
* @access private
* @param array to json data array.
* @return string to json data.
**/
private function _toJson($data) {
if(!is_array($data