1 |
|
<?php |
2 |
|
/** |
3 |
|
* Object.php |
4 |
|
* 26-Apr-2011 |
5 |
|
* |
6 |
|
* PHP Version 5 |
7 |
|
* |
8 |
|
* @category Services |
9 |
|
* @package Services_OpenStreetMap |
10 |
|
* @author Ken Guest <kguest@php.net> |
11 |
|
* @license BSD http://www.opensource.org/licenses/bsd-license.php |
12 |
|
* @version Release: @package_version@ |
13 |
|
* @link Object.php |
14 |
|
*/ |
15 |
|
|
16 |
|
/** |
17 |
|
* Services_OpenStreetMap_Object |
18 |
|
* |
19 |
|
* @category Services |
20 |
|
* @package Services_OpenStreetMap |
21 |
|
* @author Ken Guest <kguest@php.net> |
22 |
|
* @license BSD http://www.opensource.org/licenses/bsd-license.php |
23 |
|
* @link Object.php |
24 |
|
*/ |
25 |
|
class Services_OpenStreetMap_Object |
26 |
|
{ |
27 |
|
protected $xml = null; |
28 |
|
|
29 |
|
/** |
30 |
|
* Array of tags in key/value format |
31 |
|
* |
32 |
|
* @var array |
33 |
|
*/ |
34 |
|
protected $tags = array(); |
35 |
|
|
36 |
|
protected $id = null; |
37 |
|
|
38 |
|
protected $transport = null; |
39 |
|
|
40 |
|
protected $config = null; |
41 |
|
|
42 |
|
/** |
43 |
|
* type of object |
44 |
|
* |
45 |
|
* @var string |
46 |
|
*/ |
47 |
|
protected $type = null; |
48 |
|
|
49 |
|
protected $obj = null; |
50 |
|
|
51 |
|
protected $dirty = false; |
52 |
|
|
53 |
|
protected $action = null; |
54 |
|
|
55 |
|
protected $changesetId = null; |
56 |
|
|
57 |
|
/** |
58 |
|
* getXml |
59 |
|
* |
60 |
|
* @return string |
61 |
|
*/ |
62 |
|
public function getXml() |
63 |
|
{ |
64 |
7 |
return $this->xml; |
65 |
|
} |
66 |
|
|
67 |
|
/** |
68 |
|
* If modified, return the osmChangeXML for the object, otherwise the defining |
69 |
|
* XML. |
70 |
|
* |
71 |
|
* @return string |
72 |
|
* @link http://wiki.openstreetmap.org/wiki/OsmChange |
73 |
|
*/ |
74 |
|
public function __toString() |
75 |
|
{ |
76 |
2 |
$changeXML = $this->getOsmChangeXml(); |
77 |
2 |
if (is_null($changeXML)) { |
78 |
1 |
return '' . $this->getXml(); |
79 |
1 |
} else { |
80 |
1 |
return $changeXML; |
81 |
|
} |
82 |
|
} |
83 |
|
|
84 |
|
/** |
85 |
|
* setXml |
86 |
|
* |
87 |
|
* @param SimpleXMLElement $xml OSM XML |
88 |
|
* |
89 |
|
* @return void |
90 |
|
*/ |
91 |
|
public function setXml(SimpleXMLElement $xml) |
92 |
|
{ |
93 |
32 |
$this->xml = $xml->saveXml(); |
94 |
32 |
$obj = $xml->xpath('//' . $this->getType()); |
95 |
32 |
foreach ($obj[0]->children() as $child) { |
96 |
25 |
$key = (string) $child->attributes()->k; |
97 |
25 |
if ($key != '') { |
98 |
24 |
$this->tags[$key] = (string) $child->attributes()->v; |
99 |
24 |
} |
100 |
32 |
} |
101 |
32 |
$this->obj = $obj; |
102 |
32 |
return $this; |
103 |
|
} |
104 |
|
|
105 |
|
/** |
106 |
|
* Store a specified value. |
107 |
|
* |
108 |
|
* @param string $value Most likely an id value, returned from the server. |
109 |
|
* |
110 |
|
* @return void |
111 |
|
*/ |
112 |
|
public function setVal($value) |
113 |
|
{ |
114 |
|
$this->xml = $value; |
115 |
|
return $this; |
116 |
|
} |
117 |
|
|
118 |
|
/** |
119 |
|
* Set the Changeset Id for this object. |
120 |
|
* |
121 |
|
* @param integer $id Changeset Id (numeric) |
122 |
|
* |
123 |
|
* @return Services_OpenStreetMap_Object |
124 |
|
*/ |
125 |
|
public function setChangesetId($id) |
126 |
|
{ |
127 |
6 |
$this->changesetId = $id; |
128 |
6 |
return $this; |
129 |
|
} |
130 |
|
|
131 |
|
/** |
132 |
|
* Generate and return the OsmChange XML required to record the changes |
133 |
|
* made to the object in question. |
134 |
|
* |
135 |
|
* @return string |
136 |
|
* @link http://wiki.openstreetmap.org/wiki/OsmChange |
137 |
|
*/ |
138 |
|
public function getOsmChangeXml() |
139 |
|
{ |
140 |
7 |
$type = $this->getType(); |
141 |
7 |
if ($this->dirty) { |
142 |
2 |
$version = $this->getVersion(); |
143 |
2 |
$version++; |
144 |
2 |
$domd = new DomDocument(); |
145 |
2 |
$domd->loadXml($this->getXml()); |
146 |
2 |
$xpath = new DomXPath($domd); |
147 |
2 |
$nodelist = $xpath->query("//{$type}"); |
148 |
2 |
$nodelist->item(0)->setAttribute('action', $this->action); |
149 |
2 |
$nodelist->item(0)->setAttribute('id', $this->getId()); |
150 |
|
|
151 |
2 |
if (!is_null($this->changesetId)) { |
152 |
1 |
$nodelist->item(0)->setAttribute('changeset', $this->changesetId); |
153 |
1 |
} |
154 |
2 |
$tags = $xpath->query("//{$type}/tag"); |
155 |
|
|
156 |
2 |
$set = array(); |
157 |
2 |
for ($i = 0; $i < $tags->length; $i++) { |
158 |
1 |
$key = $tags->item($i)->getAttribute('k'); |
159 |
1 |
$val = $tags->item($i)->getAttribute('v'); |
160 |
1 |
$set[$key] = $val; |
161 |
1 |
} |
162 |
|
|
163 |
2 |
$diff = array_diff($this->getTags(), $set); |
164 |
|
|
165 |
|
// Remove existing tags |
166 |
2 |
for ($i = 0; $i < $tags->length; $i++) { |
167 |
1 |
$rkey = $tags->item($i)->getAttribute('k'); |
168 |
1 |
if (isset($diff[$rkey])) { |
169 |
1 |
$nodelist->item(0)->removeChild($tags->item($i)); |
170 |
1 |
} |
171 |
1 |
} |
172 |
|
|
173 |
2 |
foreach ($diff as $key=>$value) { |
174 |
2 |
$new = $domd->createElement('tag'); |
175 |
2 |
$new->setAttribute('k', $key); |
176 |
2 |
$new->setAttribute('v', $value); |
177 |
2 |
$nodelist->item(0)->appendChild($new); |
178 |
2 |
} |
179 |
|
|
180 |
2 |
$xml = $domd->saveXml($nodelist->item(0)); |
181 |
2 |
$xml = "<{$this->action}>{$xml}</{$this->action}>"; |
182 |
2 |
return $this->osmChangeXml($xml); |
183 |
|
|
184 |
5 |
} elseif ($this->action == 'delete') { |
185 |
4 |
$xml = null; |
186 |
4 |
$domd = new DomDocument(); |
187 |
4 |
$domd->loadXml($this->getXml()); |
188 |
4 |
$xpath = new DomXPath($domd); |
189 |
4 |
$n = $xpath->query("//{$type}"); |
190 |
4 |
$version = $this->getVersion(); |
191 |
4 |
$version++; |
192 |
4 |
if (!is_null($this->changesetId)) { |
193 |
4 |
$n->item(0)->setAttribute('changeset', $this->changesetId); |
194 |
4 |
} |
195 |
4 |
$n->item(0)->setAttribute('action', 'delete'); |
196 |
4 |
$xml = $domd->saveXml($n->item(0)); |
197 |
4 |
return $this->osmChangeXml("<delete>{$xml}</delete>"); |
198 |
4 |
} |
199 |
|
} |
200 |
|
|
201 |
|
/** |
202 |
|
* Amend changeXML with specific updates as appropriate. |
203 |
|
* |
204 |
|
* @param string $xml OsmChange XML as generated by getOsmChangeXml |
205 |
|
* |
206 |
|
* @return string |
207 |
|
* @see getOsmChangeXml |
208 |
|
* @link http://wiki.openstreetmap.org/wiki/OsmChange |
209 |
|
*/ |
210 |
|
public function osmChangeXml($xml) |
211 |
|
{ |
212 |
5 |
return $xml; |
213 |
|
} |
214 |
|
|
215 |
|
/** |
216 |
|
* Retrieve the id of the object in question. |
217 |
|
* |
218 |
|
* @return integer id of the object |
219 |
|
*/ |
220 |
|
public function getId() |
221 |
|
{ |
222 |
23 |
if (!is_null($this->id)) { |
223 |
9 |
return $this->id; |
224 |
9 |
} |
225 |
|
|
226 |
20 |
$attribs = $this->getAttributes(); |
227 |
20 |
if (!is_null($attribs)) { |
228 |
18 |
return (integer) $attribs->id; |
229 |
18 |
} |
230 |
|
} |
231 |
|
|
232 |
|
/** |
233 |
|
* Set the id value of the object in question. |
234 |
|
* |
235 |
|
* <pre> |
236 |
|
* $obj->setId($id)->... |
237 |
|
* </pre> |
238 |
|
* |
239 |
|
* @param integer $value new id of the object |
240 |
|
* |
241 |
|
* @return Services_OpenStreetMap_Object |
242 |
|
*/ |
243 |
|
public function setId($value) |
244 |
|
{ |
245 |
7 |
$this->id = $value; |
246 |
7 |
return $this; |
247 |
|
} |
248 |
|
|
249 |
|
/** |
250 |
|
* Retrieve the uid of the object in question. |
251 |
|
* |
252 |
|
* @return integer uid of the object |
253 |
|
*/ |
254 |
|
public function getUid() |
255 |
|
{ |
256 |
3 |
$attribs = $this->getAttributes(); |
257 |
3 |
if (!is_null($attribs)) { |
258 |
2 |
return (integer) $attribs->uid; |
259 |
2 |
} |
260 |
|
} |
261 |
|
|
262 |
|
/** |
263 |
|
* Retrieve the user (creator/editor) of the object in question. |
264 |
|
* |
265 |
|
* @return string user of the object |
266 |
|
*/ |
267 |
|
public function getUser() |
268 |
|
{ |
269 |
3 |
$attribs = $this->getAttributes(); |
270 |
3 |
if (!is_null($attribs)) { |
271 |
2 |
return (string) $attribs->user; |
272 |
2 |
} |
273 |
|
} |
274 |
|
|
275 |
|
/** |
276 |
|
* Retrieve the version of the object in question |
277 |
|
* |
278 |
|
* @return string version of the object |
279 |
|
*/ |
280 |
|
public function getVersion() |
281 |
|
{ |
282 |
10 |
$attribs = $this->getAttributes(); |
283 |
10 |
if (!is_null($attribs)) { |
284 |
9 |
return (integer) $attribs->version; |
285 |
9 |
} |
286 |
|
} |
287 |
|
|
288 |
|
/** |
289 |
|
* Return the attributes set for this object in question. |
290 |
|
* |
291 |
|
* @return string getAttributes() |
292 |
|
*/ |
293 |
|
public function getAttributes() |
294 |
|
{ |
295 |
|
|
296 |
30 |
if (is_null($this->obj[0])) { |
297 |
10 |
return null; |
298 |
10 |
} |
299 |
25 |
return $this->obj[0]->attributes(); |
300 |
|
} |
301 |
|
|
302 |
|
/** |
303 |
|
* Return the tags set for this object in question. |
304 |
|
* |
305 |
|
* @return array tags |
306 |
|
*/ |
307 |
|
public function getTags() |
308 |
|
{ |
309 |
20 |
return $this->tags; |
310 |
|
} |
311 |
|
|
312 |
|
|
313 |
|
/** |
314 |
|
* Return value of specified tag as set against this object. |
315 |
|
* If tag isn't set, return null. |
316 |
|
* |
317 |
|
* @param string $key Key value, For example, 'amenity', 'highway' etc |
318 |
|
* |
319 |
|
* @return string |
320 |
|
*/ |
321 |
|
public function getTag($key) |
322 |
|
{ |
323 |
1 |
if (isset($this->tags[$key])) { |
324 |
1 |
return $this->tags[$key]; |
325 |
1 |
} else { |
326 |
|
return null; |
327 |
|
} |
328 |
|
} |
329 |
|
|
330 |
|
/** |
331 |
|
* Return which type of object this is. |
332 |
|
* |
333 |
|
* @return string type |
334 |
|
*/ |
335 |
|
public function getType() |
336 |
|
{ |
337 |
33 |
return $this->type; |
338 |
|
} |
339 |
|
|
340 |
|
/** |
341 |
|
* Get each distinct version of an object. |
342 |
|
* |
343 |
|
* @return Services_OpenStreetMap_Objects |
344 |
|
*/ |
345 |
|
public function history() |
346 |
|
{ |
347 |
2 |
$transport = null; |
348 |
2 |
$type = $this->getType(); |
349 |
2 |
$id = $this->getId(); |
350 |
2 |
$config = $this->getConfig(); |
351 |
2 |
$url = $config->getValue('server') |
352 |
|
. 'api/' |
353 |
2 |
. $config->getValue('api_version') |
354 |
2 |
. "/$type/$id/history"; |
355 |
2 |
$class = 'Services_OpenStreetMap_' . ucfirst($type) . 's'; |
356 |
2 |
$transport = $this->getTransport(); |
357 |
2 |
$response = $transport->getResponse($url); |
358 |
2 |
$obj = new $class(); |
359 |
2 |
$sxe = @simplexml_load_string($response->getBody()); |
360 |
2 |
if ($sxe === false) { |
361 |
|
$obj->setVal(trim($response->getBody())); |
362 |
|
} else { |
363 |
2 |
$obj->setXml($sxe); |
364 |
|
} |
365 |
2 |
return $obj; |
366 |
|
} |
367 |
|
|
368 |
|
/** |
369 |
|
* Get all relations referring to the object in question. |
370 |
|
* |
371 |
|
* @return Services_OpenStreetMap_Relations |
372 |
|
*/ |
373 |
|
public function getRelations() |
374 |
|
{ |
375 |
2 |
$type = $this->getType(); |
376 |
2 |
$id = $this->getId(); |
377 |
2 |
$config = $this->getConfig(); |
378 |
2 |
$url = $config->getValue('server') |
379 |
|
. 'api/' |
380 |
2 |
. $config->getValue('api_version') |
381 |
2 |
. "/$type/$id/relations"; |
382 |
2 |
$response = $this->getTransport()->getResponse($url); |
383 |
2 |
$obj = new Services_OpenStreetMap_Relations(); |
384 |
2 |
$sxe = @simplexml_load_string($response->getBody()); |
385 |
2 |
if ($sxe === false) { |
386 |
|
$obj->setVal(trim($response->getBody())); |
387 |
|
} else { |
388 |
2 |
$obj->setXml($sxe); |
389 |
|
} |
390 |
2 |
return $obj; |
391 |
|
} |
392 |
|
|
393 |
|
/** |
394 |
|
* setTag |
395 |
|
* |
396 |
|
* <pre> |
397 |
|
* $obj->setTag('key', 'value')->setTag(...); |
398 |
|
* </pre> |
399 |
|
* |
400 |
|
* @param mixed $key key |
401 |
|
* @param mixed $value value |
402 |
|
* |
403 |
|
* @return Services_OpenStreetMap_Object |
404 |
|
*/ |
405 |
|
public function setTag($key, $value) |
406 |
|
{ |
407 |
7 |
if (is_null($this->action)) { |
408 |
6 |
if ($this->getId() < 0) { |
409 |
4 |
$this->action = 'create'; |
410 |
4 |
} else { |
411 |
2 |
$this->action = 'modify'; |
412 |
|
} |
413 |
6 |
} |
414 |
7 |
$this->dirty = true; |
415 |
7 |
$this->tags[$key] = $value; |
416 |
7 |
return $this; |
417 |
|
} |
418 |
|
|
419 |
|
/** |
420 |
|
* Set a number of tags at once, using an associative array. |
421 |
|
* |
422 |
|
* <pre> |
423 |
|
* $obj->setTag( |
424 |
|
* array( |
425 |
|
* 'key' => 'value', |
426 |
|
* 'key2', 'value2', |
427 |
|
* ) |
428 |
|
* ); |
429 |
|
* </pre> |
430 |
|
* |
431 |
|
* @param array $tags array of tags. |
432 |
|
* |
433 |
|
* @return Services_OpenStreetMap_Object |
434 |
|
*/ |
435 |
|
public function setTags($tags = array()) |
436 |
|
{ |
437 |
1 |
foreach ($tags as $key => $value) { |
438 |
1 |
$this->setTag($key, $value); |
439 |
1 |
} |
440 |
1 |
return $this; |
441 |
|
} |
442 |
|
|
443 |
|
/** |
444 |
|
* Mark the object as deleted. |
445 |
|
* |
446 |
|
* <pre> |
447 |
|
* $obj->delete(); |
448 |
|
* </pre> |
449 |
|
* |
450 |
|
* @return void |
451 |
|
*/ |
452 |
|
public function delete() |
453 |
|
{ |
454 |
4 |
$this->action = 'delete'; |
455 |
4 |
return $this; |
456 |
|
} |
457 |
|
|
458 |
|
/** |
459 |
|
* Set Config object |
460 |
|
* |
461 |
|
* @param Services_OpenStreetMap_Config $config Config object |
462 |
|
* |
463 |
|
* @return Services_OpenStreetMap_Changeset |
464 |
|
*/ |
465 |
|
public function setConfig(Services_OpenStreetMap_Config $config) |
466 |
|
{ |
467 |
32 |
$this->config = $config; |
468 |
32 |
return $this; |
469 |
|
} |
470 |
|
|
471 |
|
/** |
472 |
|
* Get current Config object |
473 |
|
* |
474 |
|
* @return Services_OpenStreetMap_Config |
475 |
|
*/ |
476 |
|
public function getConfig() |
477 |
|
{ |
478 |
14 |
return $this->config; |
479 |
|
} |
480 |
|
|
481 |
|
/** |
482 |
|
* Set the Transport instance. |
483 |
|
* |
484 |
|
* @param Services_OpenStreetMap_Transport $transport Transport instance. |
485 |
|
* |
486 |
|
* @return Services_OpenStreetMap_Config |
487 |
|
*/ |
488 |
|
public function setTransport($transport) |
489 |
|
{ |
490 |
33 |
$this->transport = $transport; |
491 |
33 |
return $this; |
492 |
|
} |
493 |
|
|
494 |
|
/** |
495 |
|
* Retrieve the current Transport instance. |
496 |
|
* |
497 |
|
* @return Services_OpenStreetMap_Transport. |
498 |
|
*/ |
499 |
|
public function getTransport() |
500 |
|
{ |
501 |
12 |
return $this->transport; |
502 |
|
} |
503 |
|
} |
504 |
|
|
505 |
|
// vim:set et ts=4 sw=4: |
506 |
|
?> |