Skip to content

Commit

Permalink
Cache table with data.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark Scherer committed May 6, 2016
1 parent 8a5e2e2 commit 2dbc64c
Show file tree
Hide file tree
Showing 25 changed files with 160 additions and 39 deletions.
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -25,6 +25,9 @@ Also new:
- MYSQL support
- PostgreSQL support

And also:
- GeocodedAddresses Table class for caching of API requests to prevent rate limits and speed up lookups

## Installation & Docs

- [Documentation](docs/README.md)
Expand Down
21 changes: 14 additions & 7 deletions config/bootstrap.php
@@ -1,11 +1,18 @@
<?php

use Cake\Core\Configure;
use Cake\Database\Type;
use Cake\Log\Log;

Log::config('geo', [
'className' => 'Cake\Log\Engine\FileLog',
'path' => LOGS,
'levels' => ['debug'],
'scopes' => ['geocode'],
'file' => 'geocode',
]);
$className = Configure::read('Log.defaultClassName') ?: 'Cake\Log\Engine\FileLog';
if (!Log::config('geo')) {
Log::config('geo', [
'className' => $className,
'path' => LOGS,
'levels' => ['debug'],
'scopes' => ['geocode'],
'file' => 'geocode',
]);
}

Type::map('object', 'Geo\Database\Type\ObjectType');
68 changes: 68 additions & 0 deletions src/Database/Type/ObjectType.php
@@ -0,0 +1,68 @@
<?php
namespace Geo\Database\Type;

use Cake\Database\Driver;
use Cake\Database\Type;
use PDO;

/**
* This can serialize and unserialize objects.
*/
class ObjectType extends Type {

/**
* @param string|null $value
* @param \Cake\Database\Driver $driver
*
* @return object|null
*/
public function toPHP($value, Driver $driver) {
if ($value === null) {
return $value;
}
return unserialize($value);
}

/**
* @param object|string|null $value
*
* @return object|null
*/
public function marshal($value) {
if ($value === null) {
return $value;
}
if (is_object($value)) {
return $value;
}
dd($value);

This comment has been minimized.

Copy link
@Spriz

Spriz Jan 14, 2017

@dereuromark it seems a bit agressive to have a dd() here :D

This comment has been minimized.

Copy link
@dereuromark

dereuromark Jan 14, 2017

Owner

Isn't this long gong since a follow commit removed this left over again? :)

This comment has been minimized.

This comment has been minimized.

Copy link
@dereuromark

dereuromark Jan 14, 2017

Owner

Oh geeze

This comment has been minimized.

Copy link
@Spriz

Spriz Jan 14, 2017

😅

This comment has been minimized.

Copy link
@dereuromark

dereuromark Jan 14, 2017

Owner

New release done. Thx!

return unserialize($value);
}

/**
* @param object|null $value
* @param \Cake\Database\Driver $driver
*
* @return string|null
*/
public function toDatabase($value, Driver $driver) {
if ($value === null) {
return $value;
}
return serialize($value);
}

/**
* @param mixed|null $value
* @param \Cake\Database\Driver $driver
*
* @return int
*/
public function toStatement($value, Driver $driver) {
if ($value === null) {
return PDO::PARAM_NULL;
}
return PDO::PARAM_STR;
}

}
64 changes: 50 additions & 14 deletions src/Model/Behavior/GeocoderBehavior.php
Expand Up @@ -11,11 +11,13 @@
use Cake\ORM\Entity;
use Cake\ORM\Query;
use Cake\ORM\Table;
use Cake\ORM\TableRegistry;
use Geocoder\Formatter\StringFormatter;
use Geo\Exception\InconclusiveException;
use Geo\Exception\NotAccurateEnoughException;
use Geo\Geocoder\Calculator;
use Geo\Geocoder\Geocoder;
use RuntimeException;

/**
* A geocoding behavior for CakePHP to easily geocode addresses.
Expand Down Expand Up @@ -56,12 +58,13 @@ class GeocoderBehavior extends Behavior {
'distance' => 'findDistance',
],
'validationError' => null,
'cache' => false // Enable only if you got a GeocodedAddresses table running
];

/**
* @var \Geo\Geocoder\Geocoder
*/
public $_Geocoder;
protected $_Geocoder;

/**
* Initiate behavior for the model using specified settings. Available settings:
Expand Down Expand Up @@ -202,8 +205,13 @@ public function geocode(Entity $entity) {
protected function _geocode($entity, $addressData) {
$entityData['geocoder_result'] = [];

$addresses = $this->_execute($addressData);
if (!$addresses || $addresses->count() < 1) {
$search = implode(' ', $addressData);
if ($search === '') {
return false;
}

$address = $this->_execute($search);
if (!$address) {
if ($this->_config['allowEmpty']) {
return true;
}
Expand All @@ -212,7 +220,6 @@ protected function _geocode($entity, $addressData) {
}
return false;
}
$address = $addresses->first();

if (!$this->_Geocoder->isExpectedType($address)) {
if ($this->_config['allowEmpty']) {
Expand All @@ -223,6 +230,7 @@ protected function _geocode($entity, $addressData) {
}
return false;
}

// Valid lat/lng found
$entityData[$this->_config['lat']] = $address->getLatitude();
$entityData[$this->_config['lng']] = $address->getLongitude();
Expand Down Expand Up @@ -423,25 +431,53 @@ public function validateLongitude($longitude) {
/**
* Uses the Geocode class to query
*
* @param array $addressFields (simple array of address pieces)
* @return \Geocoder\Model\AddressCollection|null
* @param string $address
* @return \Geocoder\Model\Address|null
*/
protected function _execute($addressFields) {
$address = implode(' ', $addressFields);
if (empty($address)) {
return null;
protected function _execute($address) {
$this->_Geocoder = new Geocoder($this->_config);

if ($this->config('cache')) {
$GeocodedAddresses = TableRegistry::get('Geo.GeocodedAddresses');
$result = $GeocodedAddresses->find()->where(['address' => $address])->first();

if ($result) {
return $result->data ?: null;
}
}

$this->_Geocoder = new Geocoder($this->_config);
try {
$addresses = $this->_Geocoder->geocode($address);
} catch (InconclusiveException $e) {
return null;
$addresses = null;
} catch (NotAccurateEnoughException $e) {
return null;
$addresses = null;
}
$result = null;
if ($addresses && $addresses->count() > 0) {
$result = $addresses->first();
}

if ($this->config('cache')) {
$addressEntity = $GeocodedAddresses->newEntity([
'address' => $address
]);
if ($result) {
$formatter = new StringFormatter();
$addressEntity->formatted_address = $formatter->format($result, '%S %n, %z %L');
$addressEntity->lat = $result->getLatitude();
$addressEntity->lng = $result->getLongitude();
$addressEntity->country = $result->getCountry()->getCode();
$addressEntity->data = $result;
}

//dd($GeocodedAddresses->save($addressEntity));
if (!$GeocodedAddresses->save($addressEntity, ['atomic' => false])) {
throw new RuntimeException('Could not store geocoding cache data');
}
}

return $addresses;
return $result;
}

/**
Expand Down
16 changes: 13 additions & 3 deletions src/Model/Table/GeocodedAddressesTable.php
@@ -1,6 +1,7 @@
<?php
namespace Geo\Model\Table;

use Cake\Database\Schema\Table as Schema;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
Expand Down Expand Up @@ -28,10 +29,20 @@ public function initialize(array $config) {
$this->primaryKey('id');
}

/**
* @param \Cake\Database\Schema\Table $schema
*
* @return \Cake\Database\Schema\Table
*/
protected function _initializeSchema(Schema $schema) {
$schema->columnType('data', 'object');
return $schema;
}

/**
* @param string $address
*
* @return bool|\Cake\Datasource\EntityInterface
* @return bool|\Geo\Model\Entity\GeocodedAddress
*/
public function retrieve($address) {
$entity = $this->find()->where(['address' => $address])->first();
Expand All @@ -50,8 +61,7 @@ public function retrieve($address) {

$formatter = new StringFormatter();
$address->formatted_address = $formatter->format($result, '%S %n, %z %L');
//FIXME (Array Type needed)
//$address->data = $address->toArray();
$address->data = $result;
}

return $this->save($address);
Expand Down
2 changes: 1 addition & 1 deletion tests/TestApp/src/Geocoder/Geocoder.php
Expand Up @@ -31,7 +31,7 @@ public function setGeocoderAndResult($geocoder) {
* @return \Geocoder\Model\AddressCollection
*/
public function geocode($address, array $params = []) {
$file = Inflector::slug($address) . '.php';
$file = Inflector::slug($address) . '.txt';

$testFiles = ROOT . DS . 'tests' . DS . 'test_files' . DS . 'Geocoder' . DS;
$testFile = $testFiles . $file;
Expand Down
25 changes: 11 additions & 14 deletions tests/TestApp/src/Model/Behavior/GeocoderBehavior.php
Expand Up @@ -14,18 +14,14 @@ class GeocoderBehavior extends GeoGeocoderBehavior {
/**
* Uses the Geocode class to query
*
* @param array $addressFields (simple array of address pieces)
* @return \Geocoder\Model\AddressCollection|null
* @param string $address
* @return \Geocoder\Model\Address|null
* @throws \Exception
*/
protected function _execute($addressFields) {
$address = implode(' ', $addressFields);
if (empty($address)) {
return [];
}

protected function _execute($address) {
$this->_Geocoder = new Geocoder($this->_config);

$file = Inflector::slug($address) . '.php';
$file = Inflector::slug($address) . '.txt';

$testFiles = ROOT . DS . 'tests' . DS . 'test_files' . DS . 'Behavior' . DS;
$testFile = $testFiles . $file;
Expand All @@ -35,14 +31,15 @@ protected function _execute($addressFields) {
throw new Exception('Should not happen on CI: ' . $testFile);
}

$addresses = parent::_execute($addressFields);
file_put_contents($testFile, serialize($addresses));
$address = parent::_execute($address);
file_put_contents($testFile, serialize($address));
return $address;
}

$addresses = file_get_contents($testFile);
$addresses = unserialize($addresses);
$address = file_get_contents($testFile);
$address = unserialize($address);

return $addresses;
return $address;
}

}
Binary file removed tests/test_files/Behavior/74523-Deutschland.php
Binary file not shown.
Binary file added tests/test_files/Behavior/74523-Deutschland.txt
Binary file not shown.
Binary file removed tests/test_files/Behavior/Berlin-Deutschland.php
Binary file not shown.
Binary file added tests/test_files/Behavior/Berlin-Deutschland.txt
Binary file not shown.
Binary file removed tests/test_files/Behavior/Bibersfeld.php
Binary file not shown.
Binary file added tests/test_files/Behavior/Bibersfeld.txt
Binary file not shown.
Binary file removed tests/test_files/Behavior/Deutschland.php
Binary file not shown.
Binary file added tests/test_files/Behavior/Deutschland.txt
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed tests/test_files/Behavior/Muenchen.php
Binary file not shown.
Binary file added tests/test_files/Behavior/Muenchen.txt
Binary file not shown.
Binary file removed tests/test_files/Behavior/Neustadt.php
Binary file not shown.
Binary file added tests/test_files/Behavior/Neustadt.txt
Binary file not shown.
Binary file removed tests/test_files/Geocoder/129-94-102-121.php
Binary file not shown.
Binary file added tests/test_files/Geocoder/129-94-102-121.txt
Binary file not shown.

0 comments on commit 2dbc64c

Please sign in to comment.