http://www.phing.info/

Source Code Coverage

Designed for use with PHPUnit, Xdebug and Phing.

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


Report generated at 2012-01-31T21:54:36Z