Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating to CakePHP 2.0 #4

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 100 additions & 17 deletions models/behaviors/geocodable.php → Model/Behavior/Geocodable.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<?php
App::import('Core', array('HttpSocket', 'Security'));

App::uses('HttpSocket', 'Network/Http');
App::uses('Security', 'Utility');
App::uses('ModelBehavior', 'Model');
App::uses('AppModel', 'Model');

class GeocodableBehavior extends ModelBehavior {
/**
Expand Down Expand Up @@ -55,6 +59,13 @@ class GeocodableBehavior extends ModelBehavior {
'longitude' => 2
)
),
'google-json' => array(
'url' => 'http://maps.google.com/maps/geo?q=${address}&output=json&key=${key}',
'format' => '${address1} ${address2}, ${city}, ${zip} ${state}, ${country}',
'pattern' => false,
'matches' => array(),
'parser' => '_google_json_parser',
),
'yahoo' => array(
'url' => 'http://api.local.yahoo.com/MapsService/V1/geocode?appid=${key}&location=${address}',
'format' => '${address1} ${address2}, ${city}, ${zip} ${state}, ${country}',
Expand Down Expand Up @@ -168,17 +179,26 @@ public function beforeSave($model) {
!empty($latitudeField) && !empty($longitudeField) &&
!isset($model->data[$model->alias][$latitudeField]) && !isset($model->data[$model->alias][$longitudeField])
) {

// If data['address'] is set, but data['address1'] is not, assume data['address'] is the street address, not the full address
if (!empty($model->data[$model->alias]['address']) && empty($model->data[$model->alias]['address1'])) {
$model->data[$model->alias]['address1'] = $model->data[$model->alias]['address'];
unset($model->data[$model->alias]['address']);
}

$data = $model->data[$model->alias];
if (!empty($settings['models'])) {
$data = $this->_data($settings['models'], $data);
}
$geocode = $this->geocode($model, $data, false);
if (!empty($geocode)) {
$address = array();
list($address[$latitudeField], $address[$longitudeField]) = $geocode;
$address[$latitudeField] = $geocode['latitude'];
$address[$longitudeField] = $geocode['longitude'];
if (!empty($settings['fields']['address'])) {
$address[$settings['fields']['address']] = $this->_address($settings, $data);
}
$address = $this->_standardize($settings, $address, $geocode);

$model->data[$model->alias] = array_merge(
$model->data[$model->alias],
Expand All @@ -198,7 +218,7 @@ public function beforeSave($model) {
* @param object $model
* @param mixed $address Array with address info (address, city, etc.) or full address as string
* @param bool $save Set to true to save result in model, false otherwise
* @return mixed Array (latitude, longitude), or false if error
* @return mixed Array (latitude, longitude, (array)address), or false if error
*/
public function geocode($model, $address, $save = true) {
$settings = $this->settings[$model->alias];
Expand Down Expand Up @@ -245,8 +265,8 @@ public function geocode($model, $address, $save = true) {
));
if (!empty($coordinates)) {
$coordinates = array(
$coordinates[$model->alias][$settings['fields']['latitude']],
$coordinates[$model->alias][$settings['fields']['longitude']],
'latitude' => $coordinates[$model->alias][$settings['fields']['latitude']],
'longitude' => $coordinates[$model->alias][$settings['fields']['longitude']],
);
}
}
Expand All @@ -261,14 +281,14 @@ public function geocode($model, $address, $save = true) {
}

if (!empty($coordinates)) {
foreach($coordinates as $i => $coordinate) {
$coordinates[$i] = floatval($coordinate);
}
$coordinates['latitude'] = floatval($coordinates['latitude']);
$coordinates['longitude'] = floatval($coordinates['longitude']);
}

if ($save && !empty($coordinates) && !empty($data)) {
$data[$model->alias][$settings['fields']['latitude']] = $coordinates[0];
$data[$model->alias][$settings['fields']['longitude']] = $coordinates[1];
$data[$model->alias][$settings['fields']['latitude']] = $coordinates['latitude'];
$data[$model->alias][$settings['fields']['longitude']] = $coordinates['longitude'];
$data[$model->alias] = $this->_standardize($settings, $data[$model->alias], $coordinates);

if (!empty($data[$model->alias][$settings['fields']['state']])) {
$model->create();
Expand Down Expand Up @@ -309,6 +329,7 @@ public function near($model, $type, $origin, $distance = null, $unit = 'k', $que
$point = $origin;
} else {
$point = $this->geocode($model, $origin);
$point = array( $point['latitude'], $point['longitude'] );
}

if (empty($point)) {
Expand Down Expand Up @@ -357,6 +378,7 @@ public function distance($model, $origin, $destination, $unit = 'k') {
$$var = $data;
} else {
$$var = $this->geocode($model, $data);
$$var = array( $$var['latitude'], $$var['longitude'] );
}
}

Expand Down Expand Up @@ -473,18 +495,52 @@ protected function _fetchCoordinates($settings, $address) {
$url = str_replace(array_keys($vars), $vars, $service['url']);
$result = $this->socket->get($url);

if (empty($result) || !preg_match($service['pattern'], $result, $matches)) {
return false;
if (empty($result)) return false;
if (!empty($service['parser'])) {
$parser = $service['parser'];
$coordinates = $this->$parser($result);
}
else if (!empty($service['pattern'])) {
if (!preg_match($service['pattern'], $result, $matches)) {
return false;
}

$coordinates = array(
$matches[$service['matches']['latitude']],
$matches[$service['matches']['longitude']]
);
$coordinates = array(
'latitude' => $matches[$service['matches']['latitude']],
'longitude' => $matches[$service['matches']['longitude']]
);
}

return $coordinates;
}

/**
* Extract the useful data from the full Google JSON response
*
* @param string $json JSON string from Google Maps API
* @return array Lat/lon, street, city, state, zip, country
*/
protected function _google_json_parser($json) {
$data = json_decode($json);

$place = array();
if (@$data->Status->code == 200) {
$placemark =& $data->Placemark[0];
$locality = $placemark->AddressDetails->Country->AdministrativeArea->SubAdministrativeArea->Locality;
$place = array(
'latitude' => $placemark->Point->coordinates[0],
'longitude' => $placemark->Point->coordinates[1],
'address' => $placemark->address,
'address1' => $locality->Thoroughfare->ThoroughfareName,
'city' => $locality->LocalityName,
'state' => $placemark->AddressDetails->Country->AdministrativeArea->AdministrativeAreaName,
'zip' => $locality->PostalCode->PostalCodeNumber,
'country' => $placemark->AddressDetails->Country->CountryNameCode,
);
}
return $place;
}

/**
* Build full address from given address
*
Expand All @@ -495,6 +551,13 @@ protected function _fetchCoordinates($settings, $address) {
protected function _address($settings, $address) {
if (is_array($address)) {
$elements = array();

// If data['address'] is set, but data['address1'] is not, assume data['address'] is the street address, not the full address
if (!empty($address['address']) && empty($address['address1'])) {
$address['address1'] = $address['address'];
unset($address['address']);
}

foreach($settings['addressFields'] as $type => $fields) {
$fields = array_merge(array($type => $type), (array) $fields);
$elements['${' . $type . '}'] = str_replace(',', ' ', trim(current(array_intersect_key($address, array_flip($fields)))));
Expand All @@ -515,12 +578,32 @@ protected function _address($settings, $address) {
foreach($replacements as $pattern => $replacement) {
$address = preg_replace($pattern, $replacement, $address);
}
$address = preg_replace('/,\s*$/', '', $address);

// Clean up any leading or trailing commas
$address = preg_replace('/(,\s*)*$/', '', $address);
$address = preg_replace('/^(\s*,)*/', '', $address);
$address = trim($address);
}

return $address;
}

/**
* Standardize address fields in model using fields from geocoded results
* @param array $settings Settings
* @param array $data Model data
* @param array $geocode Geocoded data
* @return array $data Standardized model data
*/
protected function _standardize($settings, $data, $geocode) {
foreach (array_keys($this->default['addressFields']) as $field) {
if (!empty($geocode[$field])) {
$data[$settings['fields'][$field]] = $geocode[$field];
}
}
return $data;
}

/**
* Adds missing address information based on specified settings.
* E.g: 'city' => array('model' => 'City', 'referenceField' => 'city_id', 'field' => 'name')
Expand Down
2 changes: 1 addition & 1 deletion models/geo_address.php → Model/GeoAddress.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class GeoAddress extends AppModel {
* @return array Array of records
*/
public function find($conditions = null, $fields = array(), $order = null, $recursive = null) {
$findMethods = array_merge($this->_findMethods, array('near'=>true));
$findMethods = array_merge($this->findMethods, array('near'=>true));
$findType = (is_string($conditions) && $conditions != 'count' && array_key_exists($conditions, $findMethods) ? $conditions : null);
if (empty($findType) && is_string($conditions) && $conditions == 'count' && !empty($fields['type']) && array_key_exists($fields['type'], $findMethods)) {
$findType = $fields['type'];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
App::import('Behavior', 'Geocode.Geocodable');
App::import('Model', 'Geocode.GeoAddress');
App::import('Controller', 'Controller');
App::uses('GeocodableBehavior', 'Geocode.Model/Behavior');
App::uses('GeoAddress', 'Geocode.Model');
App::uses('Controller', 'Controller');

class TestGeocodableBehavior extends GeocodableBehavior {
public function run($method) {
Expand Down Expand Up @@ -46,7 +46,7 @@ class TestExtendedAddress extends GeoAddress {

class GeocodableBehaviorTest extends CakeTestCase {
public $fixtures = array(
'plugin.geocode.geo_address', 'plugin.geocode.address', 'plugin.geocode.city', 'plugin.geocode.state', 'plugin.geocode.country'
'plugin.geocode.geoAddress', 'plugin.geocode.address', 'plugin.geocode.city', 'plugin.geocode.state', 'plugin.geocode.country'

);

Expand Down Expand Up @@ -259,8 +259,8 @@ public function testDistance() {
$this->assertEqual($result, $expected);

if (!$this->skipIf(empty($this->Geocodable->settings[$this->Address->alias]['key']), 'No service API Key provided for test')) {
$result = round($this->Address->distance($origin, '3700 Rocinante Blvd, Tampa, FL', 'm'), 1);
$expected = 3.4;
$result = round($this->Address->distance($origin, '502 Warren Road, Tampa, FL', 'm'), 1);
$expected = 3.1;
$this->assertEqual($result, $expected);
}
}
Expand Down Expand Up @@ -484,7 +484,8 @@ public function testFind() {
public function testPaginate() {
$Controller = new Controller();
$Controller->uses = array('TestAddress');
$Controller->params['url'] = array();
$Controller->request = new CakeRequest();
$Controller->request->params['named'] = array();
$Controller->constructClasses();

$Controller->paginate = array('TestAddress' => array(
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.