The Scheme website has had low level integration with the Open Domesday project site since September 2011, and it has taken me this long to get round to writing about how it works. Each record we create, ideally should have a National Grid Reference (NGR) attached to it. These NGRs are converted at the point of data entry, via a backend script, to Latitude and Longitude which gives us more flexibility for integrating with 3rd party services (mapping apis, flickr, etc.) These LatLon pairs can also be used to retrieve data easily from Open Domesday, via Anna Powell-Smith’s excellent API. In this instance, I’m interested in just places near to the point of discovery of an object, and this can be seen in the segment of a record displayed below.
The API call that you need to do this is ‘PlacesNear: returns places within a radius (in km) of a given point, or places within a bounding box. Uses WGS84 coordinates.’ This is very simple to call as her examples show you and I just use the following format:
|
1 |
http://domesdaymap.co.uk/api/1.0/placesnear?lat={LAT}&lng={LON}&radius={RADIUS} |
To automate this in my Zend Framework based application, I’ve built some simple PHP library code and some view helpers as detailed below.
The service library classes
These can be seen here: https://github.com/portableant/Beowulf—PAS/tree/master/library/Pas/Service/Domesday
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
<?php class App_Service_Domesday_Place extends Zend_Rest_Client { protected $_params = array(); protected $_uri = 'http://domesdaymap.co.uk'; protected $_responseTypes = array('xml', 'json', 'django'); protected $_responseType = 'json'; protected $_methods = array('place', 'placesnear', 'manor', 'image', 'hundred', 'area', 'county' ); protected $_placeNearParams = array( 'lat', 'lng', 'radius', 's', 'e', 'n', 'w','format'); protected $_apiPath = '/api/1.0/'; public function __construct(){ $this->setUri($this->_uri); $client = self::getHttpClient(); $client->setHeaders('Accept-Charset', 'ISO-8859-1,utf-8'); } public function setParams($params) { foreach ($params as $key => $value) { switch (strtolower($key)) { case 'format': $this->_params['format'] = $this->setResponseType($value); break; default: $this->_params[$key] = $value; break; } } return $this; } public function getParams() { return $this->_params; } public function setResponseType($responseType) { if (!in_array(strtolower($responseType), $this->_responseTypes)) { throw new Pas_Service_Domesday_Exception('Invalid Response Type'); } $this->_responseType = strtolower($responseType); return $this->_responseType; } public function getResponseType() { return $this->_responseType; } public function sendRequest($requestType, $path) { $requestType = ucfirst(strtolower($requestType)); if ($requestType !== 'Post' && $requestType !== 'Get') { throw new Pas_Service_Domesday_Exception('Invalid request type: ' . $requestType); } try { $requestMethod = 'rest' . $requestType; $response = $this->{$requestMethod}($path, $this->getParams()); return $this->formatResponse($response); } catch (Zend_Http_Client_Exception $e) { throw new Pas_Service_Domesday_Exception($e->getMessage()); } } /** Set up the response rendering * * @param string $response */ public function formatResponse(Zend_Http_Response $response) { if ('json' === $this->getResponseType()) { return json_decode($response->getBody()); } else { return new Zend_Rest_Client_Result($response->getBody()); } } /** Retrieve data from the api * * @param string $method * @param array $params */ public function getData($method, array $params = array()) { if(!in_array($method,$this->_methods)){ throw new Pas_Service_Domesday_Exception('That is not a valid method'); } foreach($params as $k => $v) { if(!in_array($k, $this->_placeNearParams)){ unset($params['k']); } } $this->setParams($params); $path = $this->_apiPath . $method; return $this->sendRequest('GET', $path); } } |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php /** The exception for geo based classes * @category Pas * @package Pas_Service_Domesday * @subpackage Exception * @copyright Copyright (c) 2011 Daniel Pett * @license GNU * @author Daniel pett * @version 1 * @since 26 September 2011 */ class Pas_Service_Domesday_Exception extends Zend_Exception { } |
The view helper
This needs rewriting for OO PHP and chained methods and perhaps moving HTML to a view partial instead. As always there are lots of different ways to write the code to get to the end point.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
<?php /** * * @author dpett * @version */ /** * DomesdayNear helper * * @uses viewHelper Pas_View_Helper */ class Pas_View_Helper_DomesdayNear extends Zend_View_Helper_Abstract { protected $_url = 'http://domesdaymap.co.uk/'; protected $_baseurl = 'http://domesdaymap.co.uk/place/'; protected $_domesday; protected $_cache; public function __construct(){ $this->_domesday = new Pas_Service_Domesday_Place(); $this->_cache = Zend_Registry::get('cache'); } /** * */ public function domesdayNear($lat, $lng, $radius) { if(!is_int($radius)){ throw new Exception('Defined radius needs to be an integer'); } $params = array('lat' => $lat, 'lng' => $lng, 'radius' => $radius); $key = md5($lat . $lng . $radius); $response = $this->getPlacesNear($params,$key); return $this->buildHtml($response, $radius); } public function getPlacesNear(array $params, $key ){ if (!($this->_cache->test($key))) { $data = $this->_domesday->getData('placesnear', $params); $this->_cache->save($data); } else { $data = $this->_cache->load($key); } return $data; } public function buildHtml($response, $radius){ if($response){ $html = '<h3>Adjacent Domesday Book places</h3>'; $html .= '<a href="' . $this->_url . '"><img class="dec flow" src="http://domesdaymap.co.uk/media/images/lion1.gif" width="67" height="93"/></a>'; $html .= '<ul>'; foreach($response as $domesday){ $html .= '<li><a href="' . $this->_baseurl . $domesday->grid . '/' . $domesday->vill_slug . '">'. $domesday->vill . '</a></li>'; } $html .= '</ul>'; $html .= '<p>Domesday data within ' . $radius . ' km of discovery point is surfaced via the excellent <a href="http://domesdaymap.co.uk"> Open Domesday</a> website.</p>'; return $html; } } } |
To use this:
|
1 2 3 4 |
<?php //In the view script in which you want this to appear echo $this->domesdayNear($lat, $lng, $radius); ?> |
