Completed
Push — master ( 51b910...e719dd )
by Joschi
03:23
created

SystemProperties::__construct()   F

Complexity

Conditions 16
Paths 512

Size

Total Lines 64
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 39
CRAP Score 16.0296

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 39
cts 41
cp 0.9512
crap 16.0296
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 25
        }
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 25
        }
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 25
        }
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 25
        }
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 25
        }
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 20
        }
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 25
        }
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 26
        );
228
229
        // Test if all mandatory properties are set
230 26
        if (!($this->uid instanceof Id)
231 26
            || !($this->type instanceof Type)
232 25
            || !($this->revision instanceof Revision)
233 25
            || !($this->created instanceof \DateTimeImmutable)
234 25
            || !($this->modified instanceof \DateTimeImmutable)
235 25
            || !strlen($this->language)
236 26
        ) {
237 1
            throw new InvalidArgumentException(
238 1
                'Invalid system properties',
239
                InvalidArgumentException::INVALID_SYSTEM_PROPERTIES
240 1
            );
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 object publication state
286
     *
287
     * @return boolean Object is published
288
     */
289
    public function isPublished()
290
    {
291
        return ($this->published instanceof \DateTimeImmutable);
292
    }
293
294
    /**
295
     * Return the object deletion state
296
     *
297
     * @return boolean Object is deleted
298
     */
299
    public function isDeleted()
300
    {
301
        return ($this->deleted instanceof \DateTimeImmutable);
302
    }
303
304
    /**
305
     * Return the creation date & time of this revision
306
     *
307
     * @return \DateTimeImmutable Creation date & time
308
     */
309 1
    public function getCreated()
310
    {
311 1
        return $this->created;
312
    }
313
314
    /**
315
     * Return the modification date & time of this revision
316
     *
317
     * @return \DateTimeImmutable Modification date & time
318
     */
319 1
    public function getModified()
320
    {
321 1
        return $this->modified;
322
    }
323
324
    /**
325
     * Return the publication date & time of this revision
326
     *
327
     * @return \DateTimeImmutable|null Publication date & time
328
     */
329 1
    public function getPublished()
330
    {
331 1
        return $this->published;
332
    }
333
334
    /**
335
     * Return the deletion date & time of this revision
336
     *
337
     * @return \DateTimeImmutable|null Deletion date & time
338
     */
339 1
    public function getDeleted()
340
    {
341 1
        return $this->deleted;
342
    }
343
344
    /**
345
     * Return the object language
346
     *
347
     * @return string
348
     */
349 1
    public function getLanguage()
350
    {
351 1
        return $this->language;
352
    }
353
354
    /**
355
     * Return the latitude
356
     *
357
     * @return float Latitude
358
     */
359 1
    public function getLatitude()
360
    {
361 1
        return $this->location->getLatitude();
362
    }
363
364
    /**
365
     * Set the latitude
366
     *
367
     * @param float $latitude Latitude
368
     * @return SystemProperties Self reference
369
     */
370 1
    public function setLatitude($latitude)
371
    {
372 1
        return $this->mutatePropertiesProperty(
373 1
            self::PROPERTY_LOCATION,
374 1
            $this->location->setLatitude($latitude)
375 1
        );
376
    }
377
378
    /**
379
     * Return the longitude
380
     *
381
     * @return float Longitude
382
     */
383 1
    public function getLongitude()
384
    {
385 1
        return $this->location->getLongitude();
386
    }
387
388
    /**
389
     * Set the longitude
390
     *
391
     * @param float $longitude Longitude
392
     * @return SystemProperties Self reference
393
     */
394 1
    public function setLongitude($longitude)
395
    {
396 1
        return $this->mutatePropertiesProperty(
397 1
            self::PROPERTY_LOCATION,
398 1
            $this->location->setLongitude($longitude)
399 1
        );
400
    }
401
402
    /**
403
     * Return the elevation
404
     *
405
     * @return float Elevation
406
     */
407 1
    public function getElevation()
408
    {
409 1
        return $this->location->getElevation();
410
    }
411
412
    /**
413
     * Set the elevation
414
     *
415
     * @param float $elevation
416
     * @return SystemProperties Self reference
417
     */
418 1
    public function setElevation($elevation)
419
    {
420 1
        return $this->mutatePropertiesProperty(
421 1
            self::PROPERTY_LOCATION,
422 1
            $this->location->setElevation($elevation)
423 1
        );
424
    }
425
426
    /**
427
     * Derive draft system properties
428
     *
429
     * @param Revision $draftRevision Draft revision
430
     * @return SystemProperties Draft system properties
431
     */
432 4
    public function createDraft(Revision $draftRevision)
433
    {
434 4
        $now = time();
435 4
        return new static(
436
            [
437 4
                self::PROPERTY_ID => $this->uid->getId(),
438 4
                self::PROPERTY_TYPE => $this->type->getType(),
439 4
                self::PROPERTY_REVISION => $draftRevision->getRevision(),
440 4
                self::PROPERTY_CREATED => $now,
441 4
                self::PROPERTY_MODIFIED => $now,
442 4
                self::PROPERTY_LANGUAGE => $this->language,
443 4
            ],
444 4
            $this->object
445 4
        );
446
    }
447
448
    /**
449
     * Indicate that the object got published
450
     *
451
     * @return SystemProperties System properties
452
     * @throws RuntimeException If the object is already published
453
     */
454 2
    public function publish()
455
    {
456
        // If the object is already published
457 2
        if ($this->published instanceof \DateTimeImmutable) {
458 1
            throw new RuntimeException(
459 1
                'Cannot republish object previously published at '.$this->published->format('c'),
460
                RuntimeException::CANNOT_REPUBLISH_OBJECT
461 1
            );
462
        }
463
464 2
        $systemProperties = clone $this;
465 2
        $systemProperties->published = new \DateTimeImmutable();
466 2
        return $systemProperties;
467
    }
468
469
    /**
470
     * Update the object's modification timestamp
471
     *
472
     * @return SystemProperties System properties
473
     */
474 7
    public function touch()
475
    {
476 7
        $systemProperties = clone $this;
477 7
        $systemProperties->modified = new \DateTimeImmutable();
478 7
        return $systemProperties;
479
    }
480
481
    /**
482
     * Set the object's deletion timestamp
483
     *
484
     * @return SystemProperties System properties
485
     */
486
    public function delete()
487
    {
488
        $systemProperties = clone $this;
489
        $systemProperties->deleted = new \DateTimeImmutable();
490
        return $systemProperties;
491
    }
492
493
    /**
494
     * Unset the object's deletion timestamp
495
     *
496
     * @return SystemProperties System properties
497
     */
498
    public function undelete()
499
    {
500
        $systemProperties = clone $this;
501
        $systemProperties->deleted = null;
502
        return $systemProperties;
503
    }
504
505
    /**
506
     * Return the property values as array
507
     *
508
     * @return array Property values
509
     */
510 5
    public function toArray()
511
    {
512 5
        return array_filter([
513 5
            self::PROPERTY_ID => $this->uid->getId(),
514 5
            self::PROPERTY_TYPE => $this->type->getType(),
515 5
            self::PROPERTY_REVISION => $this->revision->getRevision(),
516 5
            self::PROPERTY_CREATED => $this->created->format('c'),
517 5
            self::PROPERTY_MODIFIED => $this->modified->format('c'),
518 5
            self::PROPERTY_PUBLISHED => ($this->published instanceof \DateTimeImmutable) ?
519 5
                $this->published->format('c') : null,
520 5
            self::PROPERTY_DELETED => ($this->deleted instanceof \DateTimeImmutable) ?
521 5
                $this->deleted->format('c') : null,
522 5
            self::PROPERTY_LOCATION => $this->location->toArray(),
523 5
        ]);
524
    }
525
}
526