http://www.phing.info/

Source Code Coverage

Designed for use with PHPUnit, Xdebug and Phing.

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


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