http://www.phing.info/

Source Code Coverage

Designed for use with PHPUnit, Xdebug and Phing.

Methods: 23 LOC: 508 Statements: 114
Legend: executednot executeddead code
Source file Statements Methods Total coverage
OpenStreetMap.php 100.0% 91.3% 98.5%
   
1
<?php
2
/**
3
 * Provide a method of interfacing with OpenStreetMap servers.
4
 *
5
 * PHP Version 5
6
 *
7
 * @category Services
8
 * @package  Services_OpenStreetMap
9
 * @author   Ken Guest <kguest@php.net>
10
 * @license  BSD http://www.opensource.org/licenses/bsd-license.php
11
 * @version  Release: @package_version@
12
 * @link     http://pear.php.net/package/Services_OpenStreetMap
13
 * @link     http://wiki.openstreetmap.org/wiki/Api06
14
 */
15
16
require_once 'HTTP/Request2.php';
17
spl_autoload_register(array('Services_OpenStreetMap', 'autoload'));
18
19
/**
20
 * Services_OpenStreetMap - interface with OpenStreetMap
21
 *
22
 * @category  Services
23
 * @package   Services_OpenStreetMap
24
 * @author    Ken Guest <kguest@php.net>
25
 * @copyright 2010 Ken Guest
26
 * @license   BSD http://www.opensource.org/licenses/bsd-license.php
27
 * @version   Release: 0.0.1
28
 * @link      http://pear.php.net/package/Services_OpenStreetMap
29
 */
30
class Services_OpenStreetMap
31
{
32
    /**
33
     * Default config settings
34
     *
35
     * @var Services_OpenStreetMap_Config
36
     * @see Services_OpenStreetMap::getConfig
37
     * @see Services_OpenStreetMap::setConfig
38
     */
39
    protected $config = null;
40
41
    /**
42
     * [Retrieved] XML
43
     * @var string
44
     * @internal
45
     */
46
    protected $xml = null;
47
48
    protected $transport = null;
49
50
    /**
51
     * autoloader
52
     *
53
     * @param string $class Name of class
54
     *
55
     * @return boolean
56
     */
57
    public static function autoload($class)
58
    {
59 12
        $dir  = dirname(dirname(__FILE__));
60 12
        $file = $dir . '/' . str_replace('_', '/', $class) . '.php';
61 12
        if (file_exists($file)) {
62 12
            return include_once $file;
63 12
        }
64
        return false;
65
    }
66
67
    /**
68
     * constructor; which optionally sets config details.
69
     *
70
     * @param array $configuration Defaults to empty array if none provided
71
     *
72
     * @return Services_OpenStreetMap
73
     */
74
    public function __construct($configuration = array())
75
    {
76 102
        $config = new Services_OpenStreetMap_Config();
77 102
        $this->setConfig($config);
78
79 102
        $transport = new Services_OpenStreetMap_Transport_HTTP();
80 102
        $transport->setConfig($config);
81
82 102
        $this->setTransport($transport);
83 102
        $config->setTransport($transport);
84 102
        $config->setValue($configuration);
85
86 98
        $version = $config->getValue('api_version');
87
88 98
        $api = "Services_OpenStreetMap_API_V" . str_replace('.', '', $version);
89 98
        $this->api = new $api;
90 98
        $this->api->setTransport($transport);
91 98
        $this->api->setConfig($config);
92
    }
93
94
    /**
95
     * Convert a 'bbox' ordered set of coordinates to ordering required for get
96
     * method.
97
     *
98
     * <code>
99
     * $osm = new Services_OpenStreetMap();
100
     * $osm->get($osm->bboxToMinMax($minLat, $minLon, $maxLat, $maxLon));
101
     * file_put_contents("area_covered.osm", $osm->getXML());
102
     * </code>
103
     *
104
     * @param mixed $minLat min Latitude
105
     * @param mixed $minLon min Longitude
106
     * @param mixed $maxLat max Latitude
107
     * @param mixed $maxLon max Longitude
108
     *
109
     * @return array
110
     */
111
    public function bboxToMinMax($minLat, $minLon, $maxLat, $maxLon)
112
    {
113 1
        return array($minLon, $minLat, $maxLon, $maxLat);
114
    }
115
116
    /**
117
     * Get XML describing area prescribed by the given co-ordinates.
118
     *
119
     * <code>
120
     * $osm = new Services_OpenStreetMap();
121
     * $osm->get(-8.3564758, 52.821022799999994, -7.7330017, 53.0428644);
122
     * file_put_contents("area_covered.osm", $osm->getXML());
123
     * </code>
124
     *
125
     * @param string $minLon min Longitude (leftmost point)
126
     * @param string $minLat min Latitude (bottom point)
127
     * @param string $maxLon max Longitude (rightmost point)
128
     * @param string $maxLat max Latitude (top point)
129
     *
130
     * @return void
131
     */
132
133
    public function get($minLon, $minLat, $maxLon, $maxLat)
134
    {
135 3
        $config = $this->getConfig();
136 3
        $url = $config->getValue('server')
137
            . 'api/'
138 3
            . $config->getValue('api_version')
139 3
            . "/map?bbox=$minLat,$minLon,$maxLat,$maxLon";
140 3
        $response = $this->getTransport()->getResponse($url);
141 3
        $this->xml = $response->getBody();
142 3
        return $this->xml;
143
    }
144
145
    /**
146
     * Get co-ordinates of some named place
147
     *
148
     * <code>
149
     * $coords = $osm->getCoordsOfPlace('Limerick, Ireland');
150
     * </code>
151
     *
152
     * @param string $place name
153
     *
154
     * @return array Associated array of lat/lon values.
155
     * @throws Services_OpenStreetMap_Exception If the place can not be found.
156
     */
157
    public function getCoordsOfPlace($place)
158
    {
159 4
        $places = $this->getPlace($place);
160 4
        if (empty($places)) {
161 2
            throw new Services_OpenStreetMap_Exception(
162
                'Could not get coords for ' . $place
163 2
            );
164 2
        }
165 2
        $attrs = $places[0]->attributes();
166 2
        $lat = (string) $attrs['lat'];
167 2
        $lon = (string) $attrs['lon'];
168 2
        return compact('lat', 'lon');
169
    }
170
171
    /**
172
     * Return a structured result set for $place
173
     *
174
     * @param string $place Location to search for details of
175
     *
176
     * @return void
177
     */
178
    public function getPlace($place)
179
    {
180 4
        $nominatim = new Services_OpenStreetMap_Nominatim(
181 4
            $this->getTransport()
182 4
        );
183 4
        return $nominatim->search($place, 1);
184
    }
185
186
    /**
187
     * Given the results of a call to func_get_args return an array of unique
188
     * valid IDs specified in those results (either 1 per argument or each
189
     * argument containing an array of IDs).
190
     *
191
     * @param mixed $args results of call to func_get_args
192
     *
193
     * @return array
194
     *
195
     */
196
    public static function getIDs($args)
197
    {
198 11
        $IDs = array();
199 11
        foreach ($args as $arg) {
200 11
            if (is_array($arg)) {
201 7
                $IDs = array_merge($arg, $IDs);
202 11
            } elseif (is_numeric($arg)) {
203 4
                $IDs[] = $arg;
204 4
            }
205 11
        }
206 11
        return array_unique($IDs);
207
    }
208
209
    /**
210
     * Load XML from [cache] file.
211
     *
212
     * @param string $file filename
213
     *
214
     * @return void
215
     */
216
    public function loadXml($file)
217
    {
218 1
        $this->xml = file_get_contents($file);
219
    }
220
221
    /**
222
     * return XML.
223
     *
224
     * @return string
225
     */
226
    public function getXml()
227
    {
228 2
        return $this->xml;
229
    }
230
231
232
    /**
233
     * search based on given criteria.
234
     *
235
     * returns an array of objects such as Services_OpenStreetMap_Node etc.
236
     *
237
     * <code>
238
     *  $osm = new Services_OpenStreetMap();
239
     *
240
     *  $osm->loadXML("./osm.osm");
241
     *  $results = $osm->search(array("amenity" => "pharmacy"));
242
     *  echo "List of Pharmacies\n";
243
     *  echo "==================\n\n";
244
     *
245
     *  foreach ($results as $result) {
246
     *      $name = $result->getTag('name');
247
     *      $addrStreet = $result->getTag('addr:street');
248
     *      $addrCity = $result->getTag('addr:city');
249
     *      $addrCountry = $result->getTag('addr:country');
250
     *      $addrHouseName = $result->getTag('addr:housename');
251
     *      $addrHouseNumber = $result->getTag('addr:housenumber');
252
     *      $openingHours = $result->getTag('opening_hours');
253
     *      $phone = $result->getTag('phone');
254
     *
255
     *      $line1 = ($addrHouseNumber) ? $addrHouseNumber : $addrHouseName;
256
     *      if ($line1 != null) {
257
     *          $line1 .= ', ';
258
     *      }
259
     *      echo  "$name\n{$line1}{$addrStreet}\n$phone\n$openingHours\n\n";
260
     *  }
261
     * </code>
262
     *
263
     * @param array $criteria what to search for
264
     *
265
     * @return array
266
     */
267
    public function search(array $criteria)
268
    {
269 3
        $results = array();
270
271 3
        $xml = simplexml_load_string($this->xml);
272 3
        if ($xml === false) {
273 3
            return array();
274 3
        }
275 2
        foreach ($criteria as $key => $value) {
276 2
            foreach ($xml->xpath('//way') as $node) {
277 2
                $results = array_merge(
278 2
                    $results,
279 2
                    $this->_searchNode($node, $key, $value, 'way')
280 2
                );
281 2
            }
282 2
            foreach ($xml->xpath('//node') as $node) {
283 2
                $results = array_merge(
284 2
                    $results,
285 2
                    $this->_searchNode($node, $key, $value, 'node')
286 2
                );
287 2
            }
288 2
        }
289 2
        return $results;
290
    }
291
292
    /**
293
     * Search node for a specific key/value pair, allowing for value to be
294
     * included in a semicolon delimited list.
295
     *
296
     * @param SimpleXMLElement $node  Node to search
297
     * @param string           $key   Key to search for (Eg 'amenity')
298
     * @param string           $value Value to search for (Eg 'pharmacy')
299
     * @param string           $type  Type of object to return.
300
     *
301
     * @return array
302
     */
303
    private function _searchNode(SimpleXMLElement $node, $key, $value, $type)
304
    {
305 2
        $class =  'Services_OpenStreetMap_' . ucfirst(strtolower($type));
306 2
        $results = array();
307 2
        foreach ($node->tag as $tag) {
308 2
            if ($tag['k'] == $key) {
309 2
                if ($tag['v'] == $value) {
310 2
                    $obj = new $class();
311 2
                    $obj->setTransport($this->getTransport());
312 2
                    $obj->setConfig($this->getConfig());
313 2
                    $obj->setXml(simplexml_load_string($node->saveXML()));
314 2
                    $results[] = $obj;
315 2
                } elseif (strpos($tag['v'], ';')) {
316 2
                    $array = explode(';', $tag['v']);
317 2
                    if (in_array($value, $array)) {
318 1
                        $obj = new $class();
319 1
                        $obj->setTransport($this->getTransport());
320 1
                        $obj->setConfig($this->getConfig());
321 1
                        $obj->setXml(simplexml_load_string($node->saveXML()));
322 1
                        $results[] = $obj;
323 1
                    }
324 2
                }
325 2
            }
326 2
        }
327 2
        return $results;
328
    }
329
330
    /**
331
     * Return the number of seconds that must elapse before a connection is
332
     * considered to have timed-out.
333
     *
334
     * @return int
335
     */
336
    public function getTimeout()
337
    {
338 1
        return $this->getConfig()->getTimeout();
339
    }
340
341
    /**
342
     * minVersion - min API version supported by connected server.
343
     *
344
     * <code>
345
     * $config = array('user' => 'fred@example.net', 'password' => 'wilma4eva');
346
     * $osm = new Services_OpenStreetMap($config);
347
     * $min = $osm->getMinVersion();
348
     * </code>
349
     *
350
     * @return float
351
     */
352
    public function getMinVersion()
353
    {
354 1
        return $this->getConfig()->getMinVersion();
355
    }
356
357
    /**
358
     * maxVersion - max API version supported by connected server.
359
     *
360
     * <code>
361
     * $config = array('user' => 'fred@example.net', 'password' => 'wilma4eva');
362
     * $osm = new Services_OpenStreetMap($config);
363
     * $max = $osm->getMaxVersion();
364
     * </code>
365
     *
366
     * @return float
367
     */
368
    public function getMaxVersion()
369
    {
370 1
        return $this->getConfig()->getMaxVersion();
371
    }
372
373
    /**
374
     * Max size of area that can be downloaded in one request.
375
     *
376
     * <code>
377
     * $osm = new Services_OpenStreetMap();
378
     * $area_allowed = $osm->getMaxArea();
379
     * </code>
380
     *
381
     * @return float
382
     */
383
    public function getMaxArea()
384
    {
385 1
        return $this->getConfig()->getMaxArea();
386
    }
387
388
    /**
389
     * Maximum number of tracepoints per page.
390
     *
391
     * <code>
392
     * $osm = new Services_OpenStreetMap();
393
     * $tracepoints = $osm->getTracepointsPerPage();
394
     * </code>
395
     *
396
     * @return float
397
     */
398
    public function getTracepointsPerPage()
399
    {
400 1
        return $this->getConfig()->getTracepointsPerPage();
401
    }
402
403
    /**
404
     * Maximum number of nodes per way.
405
     *
406
     * Anymore than that and the way must be split.
407
     *
408
     * <code>
409
     * $osm = new Services_OpenStreetMap();
410
     * $max = $osm->getMaxNodes();
411
     * </code>
412
     *
413
     * @return float
414
     */
415
    public function getMaxNodes()
416
    {
417 1
        return $this->getConfig()->getMaxNodes();
418
    }
419
420
    /**
421
     * Number of elements allowed per changeset
422
     *
423
     * <code>
424
     * $osm = new Services_OpenStreetMap();
425
     * $max = $osm->getMaxElements();
426
     * </code>
427
     *
428
     * @return float
429
     */
430
    public function getMaxElements()
431
    {
432 1
        return $this->getConfig()->getMaxElements();
433
    }
434
435
    /**
436
     * Set Config object
437
     *
438
     * @param Services_OpenStreetMap_Config $config Config settings.
439
     *
440
     * @return Services_OpenStreetMap_API_V06
441
     */
442
    public function setConfig(Services_OpenStreetMap_Config $config)
443
    {
444 102
        $this->config = $config;
445 102
        return $this;
446
    }
447
448
    /**
449
     * Get current Config object
450
     *
451
     * @return Services_OpenStreetMap_Config
452
     */
453
    public function getConfig()
454
    {
455 23
        return $this->config;
456
    }
457
458
    /**
459
     * Get current Transport object.
460
     *
461
     * @return Services_OpenStreetMap_Transport
462
     */
463
    public function getTransport()
464
    {
465 17
        return $this->transport;
466
    }
467
468
    /**
469
     * set Transport object.
470
     *
471
     * @param Services_OpenStreetMap_Transport $transport transport object
472
     *
473
     * @return Services_OpenStreetMap
474
     */
475
    public function setTransport($transport)
476
    {
477 102
        $this->transport = $transport;
478 102
        return $this;
479
    }
480
481
    /**
482
     * __call
483
     *
484
     * If possible, call the appropriate method of the API instance.
485
     *
486
     * @param string $name      Name of missing method to call.
487
     * @param array  $arguments Arguments to be used when calling method.
488
     *
489
     * @return void
490
     * @throws Services_OpenStreetMap_Exception If the method is not supported
491
     *                                          by the API instance.
492
     */
493
    public function __call($name, $arguments)
494
    {
495 56
        if (method_exists($this->api, $name)) {
496 56
            return call_user_func_array(array($this->api, $name), $arguments);
497 56
        } else {
498
            throw new Services_OpenStreetMap_Exception(
499
                sprintf(
500
                    'Method %s does not exist.',
501
                    $name
502
                )
503
            );
504
        }
505
    }
506
}
507
// vim:set et ts=4 sw=4:
508
?>


Report generated at 2012-10-02T18:40:35+01:00