Completed
Push — master ( e562e6...7da42d )
by Joschi
03:38
created

SystemProperties::__construct()   F

Complexity

Conditions 16
Paths 512

Size

Total Lines 64
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 16.0086

Importance

Changes 20
Bugs 0 Features 5
Metric Value
cc 16
eloc 30
c 20
b 0
f 5
nc 512
nop 2
dl 0
loc 64
ccs 30
cts 31
cp 0.9677
crap 16.0086
rs 3.8272

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * apparat-object
5
 *
6
 * @category    Apparat
7
 * @package     Apparat\Object
8
 * @subpackage  Apparat\Object\Application
9
 * @author      Joschi Kuphal <[email protected]> / @jkphl
10
 * @copyright   Copyright © 2016 Joschi Kuphal <[email protected]> / @jkphl
11
 * @license     http://opensource.org/licenses/MIT The MIT License (MIT)
12
 */
13
14
/***********************************************************************************
15
 *  The MIT License (MIT)
16
 *
17
 *  Copyright © 2016 Joschi Kuphal <[email protected]> / @jkphl
18
 *
19
 *  Permission is hereby granted, free of charge, to any person obtaining a copy of
20
 *  this software and associated documentation files (the "Software"), to deal in
21
 *  the Software without restriction, including without limitation the rights to
22
 *  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
23
 *  the Software, and to permit persons to whom the Software is furnished to do so,
24
 *  subject to the following conditions:
25
 *
26
 *  The above copyright notice and this permission notice shall be included in all
27
 *  copies or substantial portions of the Software.
28
 *
29
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
31
 *  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
32
 *  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
33
 *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34
 *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
 ***********************************************************************************/
36
37
namespace Apparat\Object\Domain\Model\Properties;
38
39
use Apparat\Kernel\Tests\Kernel;
40
use Apparat\Object\Domain\Model\Object\Id;
41
use Apparat\Object\Domain\Model\Object\ObjectInterface;
42
use Apparat\Object\Domain\Model\Object\Revision;
43
use Apparat\Object\Domain\Model\Object\RuntimeException;
44
use Apparat\Object\Domain\Model\Object\Type;
45
46
/**
47
 * Object system properties collection
48
 *
49
 * In general, the system properties are used as read-only collection, with one exception: Draft objects don't have the
50
 * `published` property set, so there's a {@link publish()} method for advancing an object's state.
51
 *
52
 * @package Apparat\Object
53
 * @subpackage Apparat\Object\Application
54
 */
55
class SystemProperties extends AbstractProperties
56
{
57
    /**
58
     * Collection name
59
     *
60
     * @var string
61
     */
62
    const COLLECTION = 'system';
63
    /**
64
     * ID property
65
     *
66
     * @var string
67
     */
68
    const PROPERTY_ID = 'id';
69
    /**
70
     * Type property
71
     *
72
     * @var string
73
     */
74
    const PROPERTY_TYPE = 'type';
75
    /**
76
     * Revision property
77
     *
78
     * @var string
79
     */
80
    const PROPERTY_REVISION = 'revision';
81
    /**
82
     * Created property
83
     *
84
     * @var string
85
     */
86
    const PROPERTY_CREATED = 'created';
87
    /**
88
     * Modified property
89
     *
90
     * @var string
91
     */
92
    const PROPERTY_MODIFIED = 'modified';
93
    /**
94
     * Published property
95
     *
96
     * @var string
97
     */
98
    const PROPERTY_PUBLISHED = 'published';
99
    /**
100
     * Deleted property
101
     *
102
     * @var string
103
     */
104
    const PROPERTY_DELETED = 'deleted';
105
    /**
106
     * Language property
107
     *
108
     * @var string
109
     */
110
    const PROPERTY_LANGUAGE = 'language';
111
    /**
112
     * Location property
113
     *
114
     * @var string
115
     */
116
    const PROPERTY_LOCATION = 'location';
117
    /**
118
     * Object ID (constant throughout revisions)
119
     *
120
     * @var Id
121
     */
122
    protected $uid = null;
123
    /**
124
     * Object type (constant throughout revisions)
125
     *
126
     * @var Type
127
     */
128
    protected $type = null;
129
    /**
130
     * Object revision
131
     *
132
     * @var Revision
133
     */
134
    protected $revision = null;
135
    /**
136
     * Creation date of this revision
137
     *
138
     * @var \DateTimeImmutable
139
     */
140
    protected $created = null;
141
    /**
142
     * Modification date of this revision
143
     *
144
     * @var \DateTimeImmutable
145
     */
146
    protected $modified = null;
147
    /**
148
     * Publication date of this revision
149
     *
150
     * @var \DateTimeImmutable
151
     */
152
    protected $published = null;
153
    /**
154
     * Deletion date of this revision
155
     *
156
     * @var \DateTimeImmutable
157
     */
158
    protected $deleted = null;
159
    /**
160
     * Location
161
     *
162
     * @var LocationProperties
163
     */
164
    protected $location = null;
165
    /**
166
     * Language (BCP 47 compliant)
167
     *
168
     * @var string
169
     * @see https://tools.ietf.org/html/bcp47
170
     */
171
    protected $language = null;
172
173
    /**
174
     * System properties constructor
175
     *
176
     * @param array $data Property data
177
     * @param ObjectInterface $object Owner object
178
     */
179 27
    public function __construct(array $data, ObjectInterface $object)
180
    {
181 27
        parent::__construct($data, $object);
182
183
        // Initialize the object ID
184 27
        if (array_key_exists(self::PROPERTY_ID, $data)) {
185 25
            $this->uid = Id::unserialize($data[self::PROPERTY_ID]);
186
        }
187
188
        // Initialize the object type
189 27
        if (array_key_exists(self::PROPERTY_TYPE, $data)) {
190 26
            $this->type = Type::unserialize($data[self::PROPERTY_TYPE]);
191
        }
192
193
        // Initialize the object revision
194 26
        if (array_key_exists(self::PROPERTY_REVISION, $data)) {
195 25
            $this->revision = Revision::unserialize($data[self::PROPERTY_REVISION]);
196
        }
197
198
        // Initialize the object creation date
199 26
        if (array_key_exists(self::PROPERTY_CREATED, $data)) {
200 25
            $this->created = new \DateTimeImmutable('@'.$data[self::PROPERTY_CREATED]);
201
        }
202
203
        // Initialize the object modification date
204 26
        if (array_key_exists(self::PROPERTY_MODIFIED, $data)) {
205 25
            $this->modified = new \DateTimeImmutable('@'.$data[self::PROPERTY_MODIFIED]);
206
        }
207
208
        // Initialize the object publication date
209 26
        if (array_key_exists(self::PROPERTY_PUBLISHED, $data)) {
210 20
            $this->published = new \DateTimeImmutable('@'.$data[self::PROPERTY_PUBLISHED]);
211
        }
212
213
        // Initialize the object deletion date
214 26
        if (array_key_exists(self::PROPERTY_DELETED, $data)) {
215
            $this->deleted = new \DateTimeImmutable('@'.$data[self::PROPERTY_DELETED]);
216
        }
217
218
        // Initialize the object language
219 26
        if (array_key_exists(self::PROPERTY_LANGUAGE, $data)) {
220 25
            $this->language = trim($data[self::PROPERTY_LANGUAGE]);
221
        }
222
223
        // Initialize the location
224 26
        $this->location = Kernel::create(
225 26
            LocationProperties::class,
226 26
            [empty($data[self::PROPERTY_LOCATION]) ? [] : $data[self::PROPERTY_LOCATION], $this->object]
227
        );
228
229
        // Test if all mandatory properties are set
230 26
        if (!($this->uid instanceof Id)
231 25
            || !($this->type instanceof Type)
232 25
            || !($this->revision instanceof Revision)
233 25
            || !($this->created instanceof \DateTimeImmutable)
234 25
            || !($this->modified instanceof \DateTimeImmutable)
235 26
            || !strlen($this->language)
236
        ) {
237 1
            throw new InvalidArgumentException(
238 1
                'Invalid system properties',
239 1
                InvalidArgumentException::INVALID_SYSTEM_PROPERTIES
240
            );
241
        }
242 25
    }
243
244
    /**
245
     * Return the object ID
246
     *
247
     * @return Id Object ID
248
     */
249 5
    public function getId()
250
    {
251 5
        return $this->uid;
252
    }
253
254
    /**
255
     * Return the object type
256
     *
257
     * @return Type Object type
258
     */
259 1
    public function getType()
260
    {
261 1
        return $this->type;
262
    }
263
264
    /**
265
     * Return the object revision
266
     *
267
     * @return Revision Object revision
268
     */
269 24
    public function getRevision()
270
    {
271 24
        return $this->revision;
272
    }
273
274
    /**
275
     * Return the object draft mode
276
     *
277
     * @return boolean Object draft mode
278
     */
279 5
    public function isDraft()
280
    {
281 5
        return !($this->published instanceof \DateTimeImmutable);
282
    }
283
284
    /**
285
     * Return the creation date & time of this revision
286
     *
287
     * @return \DateTimeImmutable Creation date & time
288
     */
289 1
    public function getCreated()
290
    {
291 1
        return $this->created;
292
    }
293
294
    /**
295
     * Return the modification date & time of this revision
296
     *
297
     * @return \DateTimeImmutable Modification date & time
298
     */
299 1
    public function getModified()
300
    {
301 1
        return $this->modified;
302
    }
303
304
    /**
305
     * Return the publication date & time of this revision
306
     *
307
     * @return \DateTimeImmutable|null Publication date & time
308
     */
309 1
    public function getPublished()
310
    {
311 1
        return $this->published;
312
    }
313
314
    /**
315
     * Return the deletion date & time of this revision
316
     *
317
     * @return \DateTimeImmutable|null Deletion date & time
318
     */
319 1
    public function getDeleted()
320
    {
321 1
        return $this->deleted;
322
    }
323
324
    /**
325
     * Return the object language
326
     *
327
     * @return string
328
     */
329 1
    public function getLanguage()
330
    {
331 1
        return $this->language;
332
    }
333
334
    /**
335
     * Return the latitude
336
     *
337
     * @return float Latitude
338
     */
339 1
    public function getLatitude()
340
    {
341 1
        return $this->location->getLatitude();
342
    }
343
344
    /**
345
     * Set the latitude
346
     *
347
     * @param float $latitude Latitude
348
     * @return SystemProperties Self reference
349
     */
350 1
    public function setLatitude($latitude)
351
    {
352 1
        return $this->mutatePropertiesProperty(
353 1
            self::PROPERTY_LOCATION,
354 1
            $this->location->setLatitude($latitude)
355
        );
356
    }
357
358
    /**
359
     * Return the longitude
360
     *
361
     * @return float Longitude
362
     */
363 1
    public function getLongitude()
364
    {
365 1
        return $this->location->getLongitude();
366
    }
367
368
    /**
369
     * Set the longitude
370
     *
371
     * @param float $longitude Longitude
372
     * @return SystemProperties Self reference
373
     */
374 1
    public function setLongitude($longitude)
375
    {
376 1
        return $this->mutatePropertiesProperty(
377 1
            self::PROPERTY_LOCATION,
378 1
            $this->location->setLongitude($longitude)
379
        );
380
    }
381
382
    /**
383
     * Return the elevation
384
     *
385
     * @return float Elevation
386
     */
387 1
    public function getElevation()
388
    {
389 1
        return $this->location->getElevation();
390
    }
391
392
    /**
393
     * Set the elevation
394
     *
395
     * @param float $elevation
396
     * @return SystemProperties Self reference
397
     */
398 1
    public function setElevation($elevation)
399
    {
400 1
        return $this->mutatePropertiesProperty(
401 1
            self::PROPERTY_LOCATION,
402 1
            $this->location->setElevation($elevation)
403
        );
404
    }
405
406
    /**
407
     * Derive draft system properties
408
     *
409
     * @param Revision $draftRevision Draft revision
410
     * @return SystemProperties Draft system properties
411
     */
412 4
    public function createDraft(Revision $draftRevision)
413
    {
414 4
        $now = time();
415 4
        return new static(
416
            [
417 4
                self::PROPERTY_ID => $this->uid->getId(),
418 4
                self::PROPERTY_TYPE => $this->type->getType(),
419 4
                self::PROPERTY_REVISION => $draftRevision->getRevision(),
420 4
                self::PROPERTY_CREATED => $now,
421 4
                self::PROPERTY_MODIFIED => $now,
422 4
                self::PROPERTY_LANGUAGE => $this->language,
423
            ],
424 4
            $this->object
425
        );
426
    }
427
428
    /**
429
     * Indicate that the object got published
430
     *
431
     * @return SystemProperties System properties
432
     * @throws RuntimeException If the object is already published
433
     */
434 2
    public function publish()
435
    {
436
        // If the object is already published
437 2
        if ($this->published instanceof \DateTimeImmutable) {
438 1
            throw new RuntimeException(
439 1
                'Cannot republish object previously published at '.$this->published->format('c'),
440 1
                RuntimeException::CANNOT_REPUBLISH_OBJECT
441
            );
442
        }
443
444 2
        $systemProperties = clone $this;
445 2
        $systemProperties->published = new \DateTimeImmutable();
446 2
        return $systemProperties;
447
    }
448
449
    /**
450
     * Update the object's modification timestamp
451
     *
452
     * @return SystemProperties System properties
453
     */
454 7
    public function touch()
455
    {
456 7
        $systemProperties = clone $this;
457 7
        $systemProperties->modified = new \DateTimeImmutable();
458 7
        return $systemProperties;
459
    }
460
461
    /**
462
     * Return the property values as array
463
     *
464
     * @return array Property values
465
     */
466 5
    public function toArray()
467
    {
468 5
        return array_filter([
469 5
            self::PROPERTY_ID => $this->uid->getId(),
470 5
            self::PROPERTY_TYPE => $this->type->getType(),
471 5
            self::PROPERTY_REVISION => $this->revision->getRevision(),
472 5
            self::PROPERTY_CREATED => $this->created->format('c'),
473 5
            self::PROPERTY_MODIFIED => $this->modified->format('c'),
474 5
            self::PROPERTY_PUBLISHED => ($this->published instanceof \DateTimeImmutable) ?
475 5
                $this->published->format('c') : null,
476 5
            self::PROPERTY_DELETED => ($this->deleted instanceof \DateTimeImmutable) ?
477
                $this->deleted->format('c') : null,
478 5
            self::PROPERTY_LOCATION => $this->location->toArray(),
479
        ]);
480
    }
481
}
482