1 : <?php
2 : /**
3 : * Changeset.php
4 : * 25-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 Changeset.php
14 : */
15 :
16 : /**
17 : * Services_Openstreetmap_Changeset
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 Changeset.php
24 : */
25 : class Services_Openstreetmap_Changeset extends Services_Openstreetmap_Object
26 : {
27 : protected $type = 'changeset';
28 : protected $members = array();
29 : protected $membersIds = array();
30 : protected $open = false;
31 : protected $id = null;
32 :
33 : /**
34 : * __construct
35 : *
36 : * @return Services_Openstreetmap_Changeset
37 : */
38 : public function __construct()
39 : {
40 12 : }
41 :
42 : /**
43 : * begin
44 : *
45 : * @param string $message The changeset log message.
46 : *
47 : * @return void
48 : * @throws Services_Openstreetmap_RuntimeException If either user or
49 : * password are not set.
50 : */
51 : public function begin($message)
52 : {
53 9 : $this->members = array();
54 9 : $this->open = true;
55 9 : $config = $this->getConfig();
56 9 : $userAgent = $config->getValue('User-Agent');
57 : $doc = "<?xml version='1.0' encoding=\"UTF-8\"?>\n" .
58 9 : '<osm version="0.6" generator="' . $userAgent . '">'
59 9 : . "<changeset id='0' open='false'>"
60 9 : . '<tag k="comment" v="' . $message . '"/>'
61 9 : . '<tag k="created_by" v="' . $userAgent . '/0.1"/>'
62 9 : . '</changeset></osm>';
63 9 : $url = $config->getValue('server')
64 : . 'api/'
65 9 : . $config->getValue('api_version')
66 9 : . '/changeset/create';
67 9 : $user = $config->getValue('user');
68 9 : $password = $config->getValue('password');
69 9 : if (is_null($user)) {
70 1 : throw new Services_Openstreetmap_RuntimeException('User must be set');
71 : }
72 8 : if (is_null($password)) {
73 1 : throw new Services_Openstreetmap_RuntimeException('Password must be set');
74 : }
75 7 : $response = $this->getTransport()->getResponse(
76 7 : $url,
77 7 : HTTP_Request2::METHOD_PUT,
78 7 : $user,
79 7 : $password,
80 7 : $doc,
81 7 : null,
82 7 : array(array('Content-type', 'text/xml', true))
83 7 : );
84 7 : $code = $response->getStatus();
85 7 : if (Services_Openstreetmap_Transport::OK == $code) {
86 7 : $trimmed = trim($response->getBody());
87 7 : if (is_numeric($trimmed)) {
88 6 : $this->id = $trimmed;
89 6 : }
90 7 : }
91 7 : }
92 :
93 : /**
94 : * add object to the changeset so changes can be transmitted to the server
95 : *
96 : * @param Services_Openstreetmap_Object $object OSM object
97 : *
98 : * @return void
99 : * @throws Services_Openstreetmap_RuntimeException If an object has already
100 : * been added to the changeset
101 : * or has been added to a
102 : * closed changeset.
103 : */
104 : public function add(Services_Openstreetmap_Object $object)
105 : {
106 7 : if ($this->open === false) {
107 1 : throw new Services_Openstreetmap_RuntimeException(
108 : 'Object added to closed changeset'
109 1 : );
110 : }
111 6 : $object->setChangesetId($this->getId());
112 6 : $objectId = $object->getType() . $object->getId();
113 6 : if (!in_array($objectId, $this->membersIds)) {
114 6 : $this->members[] = $object;
115 6 : $this->membersIds[] = $objectId;
116 6 : } else {
117 1 : throw new Services_Openstreetmap_RuntimeException(
118 : 'Object added to changeset already'
119 1 : );
120 : }
121 6 : }
122 :
123 : /**
124 : * commit
125 : *
126 : * Generate osmChange document and post it to the server, when successful
127 : * close the changeset.
128 : *
129 : * @return void
130 : * @link http://wiki.openstreetmap.org/wiki/OsmChange
131 : */
132 : public function commit()
133 : {
134 6 : if (!$this->open) {
135 1 : throw new Services_Openstreetmap_Exception(
136 : 'Attempt to commit a closed changeset'
137 1 : );
138 : }
139 :
140 : // Generate URL that the osmChange document will be posted to
141 6 : $cId = $this->getId();
142 6 : $config = $this->getConfig()->asArray();
143 6 : $url = $config['server']
144 : . 'api/'
145 6 : . $config['api_version'] .
146 6 : "/changeset/{$cId}/upload";
147 :
148 : // Generate the osmChange document
149 6 : $blocks = null;
150 6 : foreach ($this->members as $member) {
151 5 : $blocks .= $member->getOsmChangeXML() . "\n";
152 6 : }
153 :
154 : $doc = "<osmChange version='0.6' generator='Services_Openstreetmap'>\n"
155 6 : . $blocks . '</osmChange>';
156 :
157 : // Post the osmChange document to the server
158 : try {
159 6 : $response = $this->getTransport()->getResponse(
160 6 : $url,
161 6 : HTTP_Request2::METHOD_POST,
162 6 : $config['user'],
163 6 : $config['password'],
164 6 : $doc,
165 6 : null,
166 6 : array(array('Content-type', 'text/xml', true))
167 6 : );
168 5 : $this->updateObjectIds($response->getBody());
169 6 : } catch (Exception $ex) {
170 1 : $code = $ex->getCode();
171 : }
172 :
173 6 : if (isset($response) && is_object($response)) {
174 5 : $code = $response->getStatus();
175 5 : }
176 6 : if (Services_Openstreetmap_Transport::OK != $code) {
177 1 : throw new Services_Openstreetmap_Exception(
178 1 : 'Error posting changeset',
179 : $code
180 1 : );
181 :
182 : }
183 : // Explicitly close the changeset
184 5 : $url = $config['server']
185 : . 'api/'
186 5 : . $config['api_version']
187 5 : . "/changeset/{$cId}/close";
188 :
189 5 : $code = null;
190 5 : $response = null;
191 : try {
192 5 : $response = $this->getTransport()->getResponse(
193 5 : $url,
194 5 : HTTP_Request2::METHOD_PUT,
195 5 : $config['user'],
196 5 : $config['password'],
197 5 : null,
198 5 : null,
199 5 : array(array('Content-type', 'text/xml', true))
200 5 : );
201 5 : } catch (Exception $ex) {
202 2 : $code = $ex->getCode();
203 : }
204 5 : if (isset($response) && is_object($response)) {
205 3 : $code = $response->getStatus();
206 3 : }
207 5 : if (Services_Openstreetmap_Transport::OK != $code) {
208 2 : throw new Services_Openstreetmap_Exception(
209 2 : 'Error closing changeset',
210 : $code
211 2 : );
212 : }
213 3 : $this->open = false;
214 3 : }
215 :
216 : /**
217 : * getCreatedAt
218 : *
219 : * @return string
220 : */
221 : public function getCreatedAt()
222 : {
223 1 : return (string) $this->getAttributes()->created_at;
224 : }
225 :
226 : /**
227 : * getClosedAt
228 : *
229 : * @return string
230 : */
231 : public function getClosedAt()
232 : {
233 1 : return (string) $this->getAttributes()->closed_at;
234 : }
235 :
236 : /**
237 : * isOpen
238 : *
239 : * @return boolean
240 : */
241 : public function isOpen()
242 : {
243 10 : $attribs = $this->getAttributes();
244 10 : if (!is_null($attribs)) {
245 1 : return $attribs->open == 'true';
246 : } else {
247 9 : return $this->open;
248 : }
249 : }
250 :
251 : /**
252 : * getMinLon
253 : *
254 : * @return float
255 : */
256 : public function getMinLon()
257 : {
258 1 : return (float) $this->getAttributes()->min_lon;
259 : }
260 :
261 : /**
262 : * getMinLat
263 : *
264 : * @return float
265 : */
266 : public function getMinLat()
267 : {
268 1 : return (float) $this->getAttributes()->min_lat;
269 : }
270 :
271 :
272 : /**
273 : * getMaxLon
274 : *
275 : * @return float
276 : */
277 : public function getMaxLon()
278 : {
279 1 : return (float) $this->getAttributes()->max_lon;
280 : }
281 :
282 : /**
283 : * getMaxLat
284 : *
285 : * @return float
286 : */
287 : public function getMaxLat()
288 : {
289 1 : return (float) $this->getAttributes()->max_lat;
290 : }
291 :
292 :
293 : /**
294 : * getId
295 : *
296 : * @return numeric value or null if none set
297 : */
298 : public function getId()
299 : {
300 9 : $p_id = parent::getId();
301 9 : if (is_null($p_id)) {
302 1 : return $this->id;
303 : } else {
304 8 : return $p_id;
305 : }
306 : }
307 :
308 : /**
309 : * Given diffResult xml, update Ids of objects that are members of the
310 : * current changeset.
311 : *
312 : * @param string $body diffResult xml
313 : *
314 : * @return void
315 : */
316 : public function updateObjectIds($body)
317 : {
318 5 : $body = trim($body);
319 5 : $cxml = simplexml_load_string($body);
320 5 : $obj = $cxml->xpath('//diffResult');
321 5 : foreach ($obj[0]->children() as $child) {
322 5 : $old_id = null;
323 5 : $new_id = null;
324 5 : $old_id = (string) $child->attributes()->old_id;
325 5 : $new_id = (string) $child->attributes()->new_id;
326 5 : $this->updateObjectId($child->getName(), $old_id, $new_id);
327 5 : }
328 5 : }
329 :
330 : /**
331 : * Update id of some type of object
332 : *
333 : * @param string $type Object type
334 : * @param integer $old_id Old id
335 : * @param integer $new_id New id
336 : *
337 : * @return void
338 : */
339 : public function updateObjectId($type, $old_id, $new_id)
340 : {
341 5 : if ($old_id == $new_id) {
342 1 : return;
343 : }
344 4 : foreach ($this->members as $member) {
345 4 : if ($member->getType() == $type) {
346 4 : if ($member->getId() == $old_id) {
347 4 : $member->setId($new_id);
348 4 : }
349 4 : }
350 4 : }
351 4 : }
352 : }
353 : // vim:set et ts=4 sw=4:
354 : ?>
|