Browse Source

geocoder cleanup

euromark 13 years ago
parent
commit
fa49aee260
2 changed files with 124 additions and 81 deletions
  1. 47 23
      Model/Behavior/GeocoderBehavior.php
  2. 77 58
      Test/Case/Model/Behavior/GeocoderBehaviorTest.php

+ 47 - 23
Model/Behavior/GeocoderBehavior.php

@@ -110,7 +110,7 @@ class GeocoderBehavior extends ModelBehavior {
 
 		$Model->data[$Model->alias]['geocoder_result'] = array();
 
-		// See if we should request a geocode
+		// See if we should request a geocode //TODO: reverse and return here
 		if ((!$this->settings[$Model->alias]['real'] || ($Model->hasField($this->settings[$Model->alias]['lat']) && $Model->hasField($this->settings[$Model->alias]['lng']))) && ($this->settings[$Model->alias]['overwrite'] || (empty($Model->data[$Model->alias][$this->settings[$Model->alias]['lat']]) || ($Model->data[$Model->alias][$this->settings[$Model->alias]['lat']]==0 && $Model->data[$Model->alias][$this->settings[$Model->alias]['lat']]==0)))) {
 
 			if (!empty($Model->whitelist) && (!in_array($this->settings[$Model->alias]['lat'], $Model->whitelist) || !in_array($this->settings[$Model->alias]['lng'], $Model->whitelist))) {
@@ -187,7 +187,6 @@ class GeocoderBehavior extends ModelBehavior {
 				}
 			}
 
-
 			# correct country id if neccessary
 			/*
 			if (in_array('country_name', $this->settings[$Model->alias]['address'])) {
@@ -209,6 +208,9 @@ class GeocoderBehavior extends ModelBehavior {
 	/**
 	 * Add the distance to this point as a virtual field
 	 *
+	 * @param Model $Model
+	 * @param float $lat
+	 * @param float $lng
 	 * @return void
 	 */
 	public function setDistanceAsVirtualField(Model $Model, $lat, $lng, $modelName = null) {
@@ -216,15 +218,45 @@ class GeocoderBehavior extends ModelBehavior {
 	}
 
 	/**
+	 * return a sql snippet for distance calculation on db level using two lat/lng points
+	 *
+	 * @return string
+	 */
+	public function distance(Model $Model, $lat, $lng, $fieldLat = null, $fieldLng = null, $modelName = null) {
+		if ($fieldLat === null) {
+			$fieldLat = $this->settings[$Model->alias]['lat'];
+		}
+		if ($fieldLng === null) {
+			$fieldLng = $this->settings[$Model->alias]['lng'];
+		}
+		if ($modelName === null) {
+			$modelName = $Model->alias;
+		}
+		return '6371.04 * ACOS( COS( PI()/2 - RADIANS(90 - '.$modelName.'.'.$fieldLat.')) * ' .
+			'COS( PI()/2 - RADIANS(90 - '. $lat .')) * ' .
+			'COS( RADIANS('.$modelName.'.'.$fieldLat.') - RADIANS('. $lng .')) + ' .
+			'SIN( PI()/2 - RADIANS(90 - '.$modelName.'.'.$fieldLng.')) * ' .
+			'SIN( PI()/2 - RADIANS(90 - '. $lat . ')))';
+	}
+
+	/**
+	 * snippet for custom pagination
+	 *
 	 * @return array
 	 */
-	public function distanceConditions(Model $Model, $distance = null, $fieldName = null, $modelName = null) {
+	public function distanceConditions(Model $Model, $distance = null, $fieldName = null,  $fieldLat = null, $fieldLng = null, $modelName = null) {
+		if ($fieldLat === null) {
+			$fieldLat = $this->settings[$Model->alias]['lat'];
+		}
+		if ($fieldLng === null) {
+			$fieldLng = $this->settings[$Model->alias]['lng'];
+		}
 		if ($modelName === null) {
 			$modelName = $Model->alias;
 		}
 		$conditions = array(
-			$modelName . '.lat <> 0',
-			$modelName . '.lng <> 0',
+			$modelName . '.'.$fieldLat.' <> 0',
+			$modelName . '.'.$fieldLng.' <> 0',
 		);
 		$fieldName = !empty($fieldName) ? $fieldName : 'distance';
 		if ($distance !== null) {
@@ -234,6 +266,8 @@ class GeocoderBehavior extends ModelBehavior {
 	}
 
 	/**
+	 * snippet for custom pagination
+	 *
 	 * @return string
 	 */
 	public function distanceField(Model $Model, $lat, $lng, $fieldName = null, $modelName = null) {
@@ -245,25 +279,11 @@ class GeocoderBehavior extends ModelBehavior {
 	}
 
 	/**
+	 * snippet for custom pagination
+	 * still useful?
+	 *
 	 * @return string
 	 */
-	public function distance(Model $Model, $lat, $lng, $fieldLat = null, $fieldLng = null, $modelName = null) {
-		if ($fieldLat === null) {
-			$fieldLat = $this->settings[$Model->alias]['lat'];
-		}
-		if ($fieldLng === null) {
-			$fieldLng = $this->settings[$Model->alias]['lng'];
-		}
-		if ($modelName === null) {
-			$modelName = $Model->alias;
-		}
-		return '6371.04 * ACOS( COS( PI()/2 - RADIANS(90 - '.$modelName.'.'.$fieldLat.')) * ' .
-			'COS( PI()/2 - RADIANS(90 - '. $lat .')) * ' .
-			'COS( RADIANS('.$modelName.'.'.$fieldLat.') - RADIANS('. $lng .')) + ' .
-			'SIN( PI()/2 - RADIANS(90 - '.$modelName.'.'.$fieldLng.')) * ' .
-			'SIN( PI()/2 - RADIANS(90 - '. $lat . ')))';
-	}
-
 	public function distanceByField(Model $Model, $lat, $lng, $byFieldName = null, $fieldName = null, $modelName = null) {
 		if ($modelName === null) {
 			$modelName = $Model->alias;
@@ -278,6 +298,11 @@ class GeocoderBehavior extends ModelBehavior {
 		return $this->distance($Model, $lat, $lng, null, null, $modelName).' '.$byFieldName;
 	}
 
+	/**
+	 * snippet for custom pagination
+	 *
+	 * @return int $count
+	 */
 	public function paginateDistanceCount(Model $Model, $conditions = null, $recursive = -1, $extra = array()) {
 		if (!empty($extra['radius'])) {
 			$conditions[] = $extra['distance'].' < '.$extra['radius'].(!empty($extra['startRadius'])?' AND '.$extra['distance'].' > '.$extra['startRadius']:'').(!empty($extra['endRadius'])?' AND '.$extra['distance'].' < '.$extra['endRadius']:'');
@@ -289,7 +314,6 @@ class GeocoderBehavior extends ModelBehavior {
 		return $Model->paginateCount($conditions, $recursive, $extra);
 	}
 
-
 	/**
 	 * Returns if a latitude is valid or not.
 	 * validation rule for models

+ 77 - 58
Test/Case/Model/Behavior/GeocoderBehaviorTest.php

@@ -2,6 +2,7 @@
 App::uses('GeocoderBehavior', 'Tools.Model/Behavior');
 App::uses('Set', 'Utility');
 App::uses('AppModel', 'Model');
+App::uses('AppController', 'Controller');
 
 class GeocoderBehaviorTest extends CakeTestCase {
 
@@ -9,14 +10,85 @@ class GeocoderBehaviorTest extends CakeTestCase {
 		'core.comment', 'plugin.tools.address'
 	);
 
-
 	public function startTest() {
 		$this->Comment = ClassRegistry::init('Comment');
 
-
 		$this->Comment->Behaviors->attach('Tools.Geocoder', array('real'=>false));
 	}
 
+	public function testDistance() {
+		$res = $this->Comment->distance(12, 14);
+		$expected = '6371.04 * ACOS( COS( PI()/2 - RADIANS(90 - Comment.lat)) * COS( PI()/2 - RADIANS(90 - 12)) * COS( RADIANS(Comment.lat) - RADIANS(14)) + SIN( PI()/2 - RADIANS(90 - Comment.lng)) * SIN( PI()/2 - RADIANS(90 - 12)))';
+		$this->assertEquals($expected, $res);
+
+		$this->Comment->Behaviors->detach('Geocoder');
+		$this->Comment->Behaviors->attach('Tools.Geocoder', array('lat'=>'x', 'lng'=>'y'));
+		$res = $this->Comment->distance(12, 14);
+		$expected = '6371.04 * ACOS( COS( PI()/2 - RADIANS(90 - Comment.x)) * COS( PI()/2 - RADIANS(90 - 12)) * COS( RADIANS(Comment.x) - RADIANS(14)) + SIN( PI()/2 - RADIANS(90 - Comment.y)) * SIN( PI()/2 - RADIANS(90 - 12)))';
+		$this->assertEquals($expected, $res);
+	}
+
+	public function testDistanceField() {
+		$res = $this->Comment->distanceField(12, 14);
+		$expected = '6371.04 * ACOS( COS( PI()/2 - RADIANS(90 - Comment.lat)) * COS( PI()/2 - RADIANS(90 - 12)) * COS( RADIANS(Comment.lat) - RADIANS(14)) + SIN( PI()/2 - RADIANS(90 - Comment.lng)) * SIN( PI()/2 - RADIANS(90 - 12))) AS Comment.distance';
+		$this->assertEquals($expected, $res);
+	}
+
+	public function testSetDistanceAsVirtualField() {
+		$this->Address = ClassRegistry::init('Address');
+		$this->Address->Behaviors->attach('Tools.Geocoder');
+		$this->Address->setDistanceAsVirtualField(13.3, 19.2);
+		$options = array('order' => array('Address.distance' => 'ASC'));
+		$res = $this->Address->find('all', $options);
+		$this->assertTrue($res[0]['Address']['distance'] < $res[1]['Address']['distance']);
+		$this->assertTrue($res[1]['Address']['distance'] < $res[2]['Address']['distance']);
+	}
+
+	public function testPagination() {
+		$this->Controller = new TestController(new CakeRequest(null, false), null);
+		$this->Controller->constructClasses();
+		$this->Controller->Address->Behaviors->attach('Tools.Geocoder');
+		$this->Controller->Address->setDistanceAsVirtualField(13.3, 19.2);
+		$this->Controller->paginate = array(
+			'conditions'=>array('distance <' => 3000),
+			'order' => array('distance' => 'ASC')
+		);
+		$res = $this->Controller->paginate();
+		$this->assertEquals(2, count($res));
+		$this->assertTrue($res[0]['Address']['distance'] < $res[1]['Address']['distance']);
+	}
+
+	public function testValidate() {
+		$is = $this->Comment->validateLatitude(44);
+		$this->assertTrue($is);
+
+		$is = $this->Comment->validateLatitude(110);
+		$this->assertFalse($is);
+
+		$is = $this->Comment->validateLongitude(150);
+		$this->assertTrue($is);
+
+		$is = $this->Comment->validateLongitude(-190);
+		$this->assertFalse($is);
+
+		$this->Comment->validator()->add('lat', 'validateLatitude', array('rule'=>'validateLatitude', 'message'=>'validateLatitudeError'));
+		$this->Comment->validator()->add('lng', 'validateLongitude', array('rule'=>'validateLongitude', 'message'=>'validateLongitudeError'));
+		$data = array(
+			'lat' => 44,
+			'lng' => 190,
+		);
+		$this->Comment->set($data);
+		$res = $this->Comment->validates();
+		$this->assertFalse($res);
+		$expectedErrors = array(
+			'lng' => array(__('validateLongitudeError'))
+		);
+		$this->assertEquals($expectedErrors, $this->Comment->validationErrors);
+	}
+
+	/**
+	 * geocoding tests using the google webservice
+	 */
 	public function testBasic() {
 		echo '<h3>'.__FUNCTION__.'</h3>';
 
@@ -171,66 +243,13 @@ class GeocoderBehaviorTest extends CakeTestCase {
 		$this->assertTrue(!empty($res['Comment']['lat']) && !empty($res['Comment']['lng']));
 	}
 
+}
 
-	public function testDistance() {
-		$res = $this->Comment->distance(12, 14);
-		$expected = '6371.04 * ACOS( COS( PI()/2 - RADIANS(90 - Comment.lat)) * COS( PI()/2 - RADIANS(90 - 12)) * COS( RADIANS(Comment.lat) - RADIANS(14)) + SIN( PI()/2 - RADIANS(90 - Comment.lng)) * SIN( PI()/2 - RADIANS(90 - 12)))';
-		$this->assertEquals($expected, $res);
-
-		$this->Comment->Behaviors->detach('Geocoder');
-		$this->Comment->Behaviors->attach('Tools.Geocoder', array('lat'=>'x', 'lng'=>'y'));
-		$res = $this->Comment->distance(12, 14);
-		$expected = '6371.04 * ACOS( COS( PI()/2 - RADIANS(90 - Comment.x)) * COS( PI()/2 - RADIANS(90 - 12)) * COS( RADIANS(Comment.x) - RADIANS(14)) + SIN( PI()/2 - RADIANS(90 - Comment.y)) * SIN( PI()/2 - RADIANS(90 - 12)))';
-		$this->assertEquals($expected, $res);
-	}
-
-	public function testDistanceField() {
-		$res = $this->Comment->distanceField(12, 14);
-		$expected = '6371.04 * ACOS( COS( PI()/2 - RADIANS(90 - Comment.lat)) * COS( PI()/2 - RADIANS(90 - 12)) * COS( RADIANS(Comment.lat) - RADIANS(14)) + SIN( PI()/2 - RADIANS(90 - Comment.lng)) * SIN( PI()/2 - RADIANS(90 - 12))) AS Comment.distance';
-		$this->assertEquals($expected, $res);
-	}
-
-	public function testSetDistanceAsVirtualField() {
-		$this->Address = ClassRegistry::init('Address');
-		$this->Address->Behaviors->attach('Tools.Geocoder');
-		$this->Address->setDistanceAsVirtualField(13.3, 19.2);
-		$options = array('order' => array('Address.distance' => 'ASC'));
-		$res = $this->Address->find('all', $options);
-		$this->assertTrue($res[0]['Address']['distance'] < $res[1]['Address']['distance']);
-		$this->assertTrue($res[1]['Address']['distance'] < $res[2]['Address']['distance']);
-	}
-
-	public function testValidate() {
-		$is = $this->Comment->validateLatitude(44);
-		$this->assertTrue($is);
-
-		$is = $this->Comment->validateLatitude(110);
-		$this->assertFalse($is);
-
-		$is = $this->Comment->validateLongitude(150);
-		$this->assertTrue($is);
-
-		$is = $this->Comment->validateLongitude(-190);
-		$this->assertFalse($is);
-
-		$this->Comment->validator()->add('lat', 'validateLatitude', array('rule'=>'validateLatitude', 'message'=>'validateLatitudeError'));
-		$this->Comment->validator()->add('lng', 'validateLongitude', array('rule'=>'validateLongitude', 'message'=>'validateLongitudeError'));
-		$data = array(
-			'lat' => 44,
-			'lng' => 190,
-		);
-		$this->Comment->set($data);
-		$res = $this->Comment->validates();
-		$this->assertFalse($res);
-		$expectedErrors = array(
-			'lng' => array(__('validateLongitudeError'))
-		);
-		$this->assertEquals($expectedErrors, $this->Comment->validationErrors);
-	}
 
+class TestController extends AppController {
 
+	public $uses = array('Address');
 
 }
 
 
-