<?php
/**
* Copyright (c) 2008, SARL Adaltas. All rights reserved.
* Code licensed under the BSD License:
* http://porte.adaltas.com/en/developer/license.html
*/
/**
* PorteGis
*
* Add gis support and related methods.
*
* @package Porte
* @subpackage plugin
* @author David Worms info(at)adaltas.com
* @copyright 2008 Adaltas
*/
class PorteGis{
public static function _modelPropertyBefore(PorteModels $models,$type,$property){
$config = $models->{$type}['properties'][$property];
if(isset($config['type'])&&$config['type']=='point'){
$models->{$type}['to_array']['exclude'][] = $property;
if(!array_key_exists('x',$config)||!array_key_exists('y',$config)){
throw new PorteException('Property of type "point" should contain extra "x" and "y" properties');
}
if(empty($config['field'])){
$config['field'] = PorteUtils::underscore($property);
}
if(empty($config['select'])){
$config['select'] = 'AsText(`address_point`)';
}
if(!array_key_exists('default',$config)){
$config['default'] = null;
}
//$model->properties->set($property,$config);
//if(!in_array($property,$model->properties)) $model->properties[] = $property;
PorteModel::addMethod($models,$type,'set'.PorteUtils::camelize($property),$property,array('PorteGis','set'));
PorteModel::addMethod($models,$type,'get'.PorteUtils::camelize($property),$property,array('PorteGis','get'));
PorteModel::addMethod($models,$type,'get'.PorteUtils::camelize($property).'Distance',$property,array('PorteGis','getDistance'));
PorteModel::addMethod($models,$type,'get'.PorteUtils::camelize($property).'Nearest',$property,array('PorteGis','getNearest'));
$models->{$type}['properties'][$property] = $config;
return true;
}
}
public static function getDistance($property,$record,$x=null,$y=null){
$model = $record->porte->models->{$record->type};
//$config = $config['properties'][$property];
if(is_null($x)||is_null($y)||!is_numeric($x)||!is_numeric($y)){
throw new PorteException('Incorrect arguments: expect 2 arguments (x and y coordinnate)');
}
$x = $record->porte->quote($x);
$y = $record->porte->quote($y);
$query = 'SELECT GLength(LineStringFromWKB(LineString(AsBinary(`'.$property.'`), AsBinary(GeomFromText(\'POINT('.$x.' '.$y.')\')) ))) AS distance FROM `'.$model['database'].'`.`'.$model['table'].'` WHERE `'.$model['primary_key'].'` = \''.$record->getIdentifier().'\';';
return (float) $record->porte->query($query)->fetchColumn();
}
public static function getNearest($property,$record,$arg1=null,$arg2=null,$arg3=null){
$model = $record->porte->models->{$record->type};
//$config = $model['properties'][$property];
if($arg1&&$arg2&&is_numeric($arg1)&&is_numeric($arg2)){
$radius = $record->porte->quote($arg1);
$distance = 'GLength(LineStringFromWKB(LineString(AsBinary(GeomFromText(\'POINT('.$arg1.' '.$arg2.')\')), AsBinary(`f`.`'.$property.'`) )))';
$options = array(
'select'=>'f.*',
'from'=>'`'.$model['database'].'`.`'.$model['table'].'` as f',
'where'=>' 1 ',
'order_by'=>$distance,
);
if(is_array($arg3)){
$optionsArg = $arg3;
if(isset($optionsArg['where'])){
$options['where'] .= ' AND '.$optionsArg['where'];
}
if(isset($optionsArg['limit'])){
$options['limit'] = $optionsArg['limit'];
}
}
return $record->table->find($options);
}else if($arg1&&is_numeric($arg1)){
$radius = $record->porte->quote($arg1);
$distance = 'GLength(LineStringFromWKB(LineString(AsBinary(`l`.`'.$property.'`), AsBinary(`f`.`'.$property.'`) )))';
$options = array(
'select'=>'f.*',
'from'=>'`'.$model['database'].'`.'.$model['table'].' as l, `'.$model['database'].'`.`'.$model['table'].'` as f',
'where'=>'`l`.`'.$model['primary_key'].'` = \''.$record->getIdentifier().'\' AND '.$distance.' < \''.$radius.'\' ',
'order_by'=>$distance,
);
if(is_array($arg2)){
$optionsArg = $arg1;
if(isset($optionsArg['where'])){
$options['where'] .= ' AND '.$optionsArg['where'];
}
}
return $record->table->find($options);
}
throw new PorteException('Incorrect arguments: expect 1 or 2 arguments (radius as numeric or point coordinates)');
}
/*
public static function get($property,$record){
$config = $record->model->properties->$property;
if(array_key_exists($property,$record->attributes)){
return $record->attributes[$property];
}else if(array_key_exists('default',$config)){
return $config['default'];
}
throw new PorteException('Invalid method call "get{GisProperty} (property: "'.$property.'")');
}
*/
public static function get($property,$record){
$config = $record->porte->models->{$record->type}['properties'][$property];
if(array_key_exists($property,$record->attributes)){
return (bool) $record->attributes[$property];
}else if(!$record->isNew()&&empty($config['transient'])){
$record->load($record->getIdentifier(),array('force'=>true));
return $record->attributes[$property];
}else if(array_key_exists('default',$config)){
return $config['default'];
}
throw new PorteException('Invalid method call "get{GisProperty} (property: "'.$property.'")');
}
public static function set($property,$record,$x=null,$y=null){
if(is_null($x)||is_null($y)){
throw new PorteException('Incorrect arguments: expect 2 arguments (x and y coordinnate)');
}
if(is_numeric($x)&&is_numeric($y)){
$config = $record->porte->models->{$record->type}['properties'][$property];
$xField = $config['x'];
$yField = $config['y'];
$record->attributes[$xField] = $x;
$record->attributes[$yField] = $y;
}else{
}
return $record;
}
}
PorteEvents::connect('model_property_before',array('PorteGis','_modelPropertyBefore'));
?>