Location: PHPKode > projects > Porte > porte-0.2.2/src/plugins/Gis.php
<?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'));

?>
Return current item: Porte