Completed
Push — master ( 50e176...8c9387 )
by Joschi
03:11
created

AbstractObject::setLicense()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 3
c 1
b 0
f 1
nc 1
nop 1
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 9.4285
1
<?php
2
3
/**
4
 * apparat-object
5
 *
6
 * @category    Apparat
7
 * @package     Apparat\Object
8
 * @subpackage  Apparat\Object\Domain
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\Object;
38
39
use Apparat\Kernel\Ports\Kernel;
40
use Apparat\Object\Domain\Model\Path\RepositoryPath;
41
use Apparat\Object\Domain\Model\Path\RepositoryPathInterface;
42
use Apparat\Object\Domain\Model\Properties\AbstractDomainProperties;
43
use Apparat\Object\Domain\Model\Properties\GenericPropertiesInterface;
44
use Apparat\Object\Domain\Model\Properties\InvalidArgumentException as PropertyInvalidArgumentException;
45
use Apparat\Object\Domain\Model\Properties\MetaProperties;
46
use Apparat\Object\Domain\Model\Properties\ProcessingInstructions;
47
use Apparat\Object\Domain\Model\Properties\Relations;
48
use Apparat\Object\Domain\Model\Properties\SystemProperties;
49
use Apparat\Object\Domain\Repository\Service;
50
51
/**
52
 * Abstract object
53
 *
54
 * @package Apparat\Object
55
 * @subpackage Apparat\Object\Domain
56
 */
57
abstract class AbstractObject implements ObjectInterface
58
{
59
    /**
60
     * Clean state
61
     *
62
     * @var int
63
     */
64
    const STATE_CLEAN = 0;
65
    /**
66
     * Dirty state
67
     *
68
     * @var int
69
     */
70
    const STATE_DIRTY = 1;
71
    /**
72
     * Mutated state
73
     *
74
     * @var int
75
     */
76
    const STATE_MUTATED = 2;
77
    /**
78
     * Published state
79
     *
80
     * @var int
81
     */
82
    const STATE_PUBLISHED = 4;
83
    /**
84
     * System properties
85
     *
86
     * @var SystemProperties
87
     */
88
    protected $systemProperties;
89
    /**
90
     * Meta properties
91
     *
92
     * @var MetaProperties
93
     */
94
    protected $metaProperties;
95
    /**
96
     * Domain properties
97
     *
98
     * @var AbstractDomainProperties
99
     */
100
    protected $domainProperties;
101
    /**
102
     * Object payload
103
     *
104
     * @var string
105
     */
106
    protected $payload;
107
    /**
108
     * Repository path
109
     *
110
     * @var RepositoryPathInterface
111
     */
112
    protected $path;
113
    /**
114
     * Domain property collection class
115
     *
116
     * @var string
117
     */
118
    protected $domainPropertyCClass = AbstractDomainProperties::class;
119
    /**
120
     * Object relations
121
     *
122
     * @var Relations
123
     */
124
    protected $relations;
125
    /**
126
     * Processing instructions
127
     *
128
     * @var ProcessingInstructions
129
     */
130
    protected $processingInstructions;
131
    /**
132
     * Latest revision index
133
     *
134
     * @var Revision
135
     */
136
    protected $latestRevision;
137
    /**
138
     * Object state
139
     *
140
     * @var int
141
     */
142
    protected $state = self::STATE_CLEAN;
143
    /**
144
     * Property collection states
145
     *
146
     * @var array
147
     */
148
    protected $collectionStates = [];
149
150
    /**
151
     * Object constructor
152
     *
153
     * @param string $payload Object payload
154
     * @param array $propertyData Property data
155
     * @param RepositoryPathInterface $path Object repository path
156
     */
157 20
    public function __construct($payload = '', array $propertyData = [], RepositoryPathInterface $path = null)
158
    {
159
        // If the domain property collection class is invalid
160 20
        if (!$this->domainPropertyCClass
161 20
            || !class_exists($this->domainPropertyCClass)
162 20
            || !(new \ReflectionClass($this->domainPropertyCClass))->isSubclassOf(AbstractDomainProperties::class)
163 20
        ) {
164 1
            throw new PropertyInvalidArgumentException(
165 1
                sprintf(
166 1
                    'Invalid domain property collection class "%s"',
167 1
                    $this->domainPropertyCClass
168 1
                ),
169
                PropertyInvalidArgumentException::INVALID_DOMAIN_PROPERTY_COLLECTION_CLASS
170 1
            );
171
        }
172
173
        // Right after instantiation it's always the current revision
174 19
        $this->path = $path->setRevision(Revision::current());
0 ignored issues
show
Bug introduced by
It seems like $path is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
175
176
        // Load the current revision data
177 19
        $this->loadRevisionData($payload, $propertyData);
178
179
        // Save the latest revision index
180 18
        $this->latestRevision = $this->getRevision();
181 18
    }
182
183
    /**
184
     * Load object revision data
185
     *
186
     * @param string $payload Object payload
187
     * @param array $propertyData Property data
188
     */
189 19
    protected function loadRevisionData($payload = '', array $propertyData = [])
190
    {
191 19
        $this->payload = $payload;
192
193
        // Instantiate the system properties
194 19
        $systemPropertyData = (empty($propertyData[SystemProperties::COLLECTION]) ||
195 19
            !is_array(
196 19
                $propertyData[SystemProperties::COLLECTION]
197 19
            )) ? [] : $propertyData[SystemProperties::COLLECTION];
198 19
        $this->systemProperties = Kernel::create(SystemProperties::class, [$systemPropertyData, $this]);
199
200
        // Instantiate the meta properties
201 18
        $metaPropertyData = (empty($propertyData[MetaProperties::COLLECTION]) ||
202 17
            !is_array(
203 17
                $propertyData[MetaProperties::COLLECTION]
204 18
            )) ? [] : $propertyData[MetaProperties::COLLECTION];
205
        /** @var MetaProperties $metaPropertyCollection */
206 18
        $metaPropertyCollection = Kernel::create(MetaProperties::class, [$metaPropertyData, $this]);
207 18
        $this->setMetaProperties($metaPropertyCollection, true);
208
209
        // Instantiate the domain properties
210 18
        $domainPropertyData = (empty($propertyData[AbstractDomainProperties::COLLECTION]) ||
211 17
            !is_array(
212 17
                $propertyData[AbstractDomainProperties::COLLECTION]
213 18
            )) ? [] : $propertyData[AbstractDomainProperties::COLLECTION];
214
        /** @var AbstractDomainProperties $domainPropertyCollection */
215 18
        $domainPropertyCollection = Kernel::create($this->domainPropertyCClass, [$domainPropertyData, $this]);
216 18
        $this->setDomainProperties($domainPropertyCollection, true);
217
218
        // Instantiate the processing instructions
219 18
        $procInstData = (empty($propertyData[ProcessingInstructions::COLLECTION]) ||
220 14
            !is_array(
221 14
                $propertyData[ProcessingInstructions::COLLECTION]
222 18
            )) ? [] : $propertyData[ProcessingInstructions::COLLECTION];
223
        /** @var ProcessingInstructions $procInstCollection */
224 18
        $procInstCollection = Kernel::create(ProcessingInstructions::class, [$procInstData, $this]);
225 18
        $this->setProcessingInstructions($procInstCollection, true);
226
227
        // Instantiate the object relations
228 18
        $relationData = (empty($propertyData[Relations::COLLECTION]) ||
229 17
            !is_array(
230 17
                $propertyData[Relations::COLLECTION]
231 18
            )) ? [] : $propertyData[Relations::COLLECTION];
232
        /** @var Relations $relationCollection */
233 18
        $relationCollection = Kernel::create(Relations::class, [$relationData, $this]);
234 18
        $this->setRelations($relationCollection, true);
235
236
        // Reset the object state to clean
237 18
        $this->state = self::STATE_CLEAN;
238 18
    }
239
240
    /**
241
     * Set the meta properties collection
242
     *
243
     * @param MetaProperties $metaProperties Meta property collection
244
     * @param bool $overwrite Overwrite the existing collection (if present)
245
     */
246 18
    protected function setMetaProperties(MetaProperties $metaProperties, $overwrite = false)
247
    {
248 18
        $this->metaProperties = $metaProperties;
249 18
        $metaPropertiesState = spl_object_hash($this->metaProperties);
250
251
        // If the meta property collection state has changed
252
        if (!$overwrite
253 18
            && !empty($this->collectionStates[MetaProperties::COLLECTION])
254 18
            && ($metaPropertiesState !== $this->collectionStates[MetaProperties::COLLECTION])
255 18
        ) {
256
            // Flag this object as mutated
257 1
            $this->setMutatedState();
258 1
        }
259
260 18
        $this->collectionStates[MetaProperties::COLLECTION] = $metaPropertiesState;
261 18
    }
262
263
    /**
264
     * Set the object state to mutated
265
     */
266 3
    protected function setMutatedState()
267
    {
268
        // If this object is not in mutated state yet
269 3
        if (!($this->state & self::STATE_MUTATED) && !$this->isDraft()) {
270
            // TODO: Send signal
271 3
            $this->convertToDraft();
272 3
        }
273
274
        // Enable the mutated (and dirty) state
275 3
        $this->state |= (self::STATE_DIRTY | self::STATE_MUTATED);
276 3
    }
277
278
    /**
279
     * Return the object draft mode
280
     *
281
     * @return boolean Object draft mode
282
     */
283 4
    public function isDraft()
284
    {
285 4
        return $this->systemProperties->isDraft() || $this->isPublished();
286
    }
287
288
    /**
289
     * Return whether the object is in published state
290
     *
291
     * @return boolean Published state
292
     */
293 4
    public function isPublished()
294
    {
295 4
        return !!($this->state & self::STATE_PUBLISHED);
296
    }
297
298
    /**
299
     * Convert this object revision into a draft
300
     */
301 3
    protected function convertToDraft()
302
    {
303
        // Increment the latest revision number
304 3
        $this->latestRevision = $this->latestRevision->increment();
305
306
        // Create draft system properties
307 3
        $this->systemProperties = $this->systemProperties->createDraft($this->latestRevision);
308
309
        // Adapt the system properties collection state
310 3
        $this->collectionStates[SystemProperties::COLLECTION] = spl_object_hash($this->systemProperties);
311
312
        // Set the draft flag on the repository path
313 3
        $this->path = $this->path->setDraft(true)->setRevision(Revision::current());
314
315
        // If this is not already a draft ...
316
        // Recreate the system properties
317
        // Copy the object ID
318
        // Copy the object type
319
        // Set the revision number to latest revision + 1
320
        // Set the creation date to now
321
        // Set no publication date
322
        // Set the draft flag on the repository path
323
        // Increase the latest revision by 1
324
325
        // Else if this is a draft
326
        // No action needed
327 3
    }
328
329
    /**
330
     * Set the domain properties collection
331
     *
332
     * @param GenericPropertiesInterface $domainProperties Domain property collection
333
     * @param bool $overwrite Overwrite the existing collection (if present)
334
     */
335 18
    protected function setDomainProperties(GenericPropertiesInterface $domainProperties, $overwrite = false)
336
    {
337 18
        $this->domainProperties = $domainProperties;
0 ignored issues
show
Documentation Bug introduced by
$domainProperties is of type object<Apparat\Object\Do...ricPropertiesInterface>, but the property $domainProperties was declared to be of type object<Apparat\Object\Do...stractDomainProperties>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
338 18
        $domainPropertiesState = spl_object_hash($this->domainProperties);
339
340
        // If the domain property collection state has changed
341
        if (!$overwrite
342 18
            && !empty($this->collectionStates[AbstractDomainProperties::COLLECTION])
343 18
            && ($domainPropertiesState !== $this->collectionStates[AbstractDomainProperties::COLLECTION])
344 18
        ) {
345
            // Flag this object as mutated
346 1
            $this->setMutatedState();
347 1
        }
348
349 18
        $this->collectionStates[AbstractDomainProperties::COLLECTION] = $domainPropertiesState;
350 18
    }
351
352
    /**
353
     * Set the processing instruction collection
354
     *
355
     * @param GenericPropertiesInterface $processingInstructions Processing instruction collection
356
     * @param bool $overwrite Overwrite the existing collection (if present)
357
     */
358 18
    protected function setProcessingInstructions(GenericPropertiesInterface $processingInstructions, $overwrite = false)
359
    {
360 18
        $this->processingInstructions = $processingInstructions;
0 ignored issues
show
Documentation Bug introduced by
$processingInstructions is of type object<Apparat\Object\Do...ricPropertiesInterface>, but the property $processingInstructions was declared to be of type object<Apparat\Object\Do...ProcessingInstructions>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
361 18
        $processingInstructionsState = spl_object_hash($this->processingInstructions);
362
363
        // If the domain property collection state has changed
364
        if (!$overwrite
365 18
            && !empty($this->collectionStates[ProcessingInstructions::COLLECTION])
366 18
            && ($processingInstructionsState !== $this->collectionStates[ProcessingInstructions::COLLECTION])
367 18
        ) {
368
            // Flag this object as dirty
369 1
            $this->setDirtyState();
370 1
        }
371
372 18
        $this->collectionStates[ProcessingInstructions::COLLECTION] = $processingInstructionsState;
373 18
    }
374
375
    /**
376
     * Set the object state to dirty
377
     */
378 1
    protected function setDirtyState()
379
    {
380
        // If this object is not in dirty state yet
381 1
        if (!($this->state & self::STATE_DIRTY)) {
382
            // TODO: Send signal
383 1
        }
384
385
        // Enable the dirty state
386 1
        $this->state |= self::STATE_DIRTY;
387 1
    }
388
389
    /**
390
     * Set the relations collection
391
     *
392
     * @param Relations $relations Relations collection
393
     * @param bool $overwrite Overwrite the existing collection (if present)
394
     */
395 18
    protected function setRelations(Relations $relations, $overwrite = false)
396
    {
397 18
        $this->relations = $relations;
398 18
        $relationsState = spl_object_hash($this->relations);
399
400
        // If the domain property collection state has changed
401
        if (!$overwrite
402 18
            && !empty($this->collectionStates[Relations::COLLECTION])
403 18
            && ($relationsState !== $this->collectionStates[Relations::COLLECTION])
404 18
        ) {
405
            // Flag this object as dirty
406
            $this->setDirtyState();
407
        }
408
409 18
        $this->collectionStates[Relations::COLLECTION] = $relationsState;
410 18
    }
411
412
    /**
413
     * Return the object revision
414
     *
415
     * @return Revision Object revision
416
     */
417 18
    public function getRevision()
418
    {
419 18
        return $this->systemProperties->getRevision();
420
    }
421
422
    /**
423
     * Return whether the object is in mutated state
424
     *
425
     * @return boolean Mutated state
426
     */
427 3
    public function isMutated()
428
    {
429 3
        return !!($this->state & self::STATE_MUTATED);
430
    }
431
432
    /**
433
     * Use a specific object revision
434
     *
435
     * @param Revision $revision Revision to be used
436
     * @return ObjectInterface Object
437
     * @throws OutOfBoundsException If the requested revision is invalid
438
     */
439 17
    public function useRevision(Revision $revision)
440
    {
441 17
        $isCurrentRevision = false;
442
443
        // If the requested revision is invalid
444 17
        if (!$revision->isCurrent() &&
445
            (($revision->getRevision() < 1) || ($revision->getRevision() > $this->latestRevision->getRevision()))
446 17
        ) {
447
            throw new OutOfBoundsException(sprintf('Invalid object revision "%s"', $revision->getRevision()),
448
                OutOfBoundsException::INVALID_OBJECT_REVISION);
449
        }
450
451
        // If the current revision got requested
452 17
        if ($revision->isCurrent()) {
453 17
            $isCurrentRevision = true;
454 17
            $revision = $this->latestRevision;
455 17
        }
456
457
        // If the requested revision is not already used
458 17
        if ($revision != $this->getRevision()) {
459
            /** @var ManagerInterface $objectManager */
460
            $objectManager = Kernel::create(Service::class)->getObjectManager();
461
462
            // Load the requested object revision resource
463
            /** @var Revision $newRevision */
464
            $newRevision = $isCurrentRevision ? Revision::current() : $revision;
465
            /** @var RepositoryPath $newRevisionPath */
466
            $newRevisionPath = $this->path->setRevision($newRevision);
467
            $revisionResource = $objectManager->loadObject($newRevisionPath);
468
469
            // Load the revision resource data
470
            $this->loadRevisionData($revisionResource->getPayload(), $revisionResource->getPropertyData());
471
472
            // Set the current revision path
473
            $this->path = $newRevisionPath;
474
        }
475
476 17
        return $this;
477
    }
478
479
    /**
480
     * Return the object ID
481
     *
482
     * @return Id Object ID
483
     */
484 5
    public function getId()
485
    {
486 5
        return $this->systemProperties->getId();
487
    }
488
489
    /**
490
     * Return the object type
491
     *
492
     * @return Type Object type
493
     */
494 1
    public function getType()
495
    {
496 1
        return $this->systemProperties->getType();
497
    }
498
499
    /**
500
     * Return the creation date & time
501
     *
502
     * @return \DateTimeImmutable Creation date & time
503
     */
504 1
    public function getCreated()
505
    {
506 1
        return $this->systemProperties->getCreated();
507
    }
508
509
    /**
510
     * Return the publication date & time
511
     *
512
     * @return \DateTimeImmutable|null Publication date & time
513
     */
514 1
    public function getPublished()
515
    {
516 1
        return $this->systemProperties->getPublished();
517
    }
518
519
    /**
520
     * Return the object hash
521
     *
522
     * @return string Object hash
523
     */
524 1
    public function getHash()
525
    {
526 1
        return $this->systemProperties->getHash();
527
    }
528
529
    /**
530
     * Return the object title
531
     *
532
     * @return string Object title
533
     */
534 1
    public function getTitle()
535
    {
536 1
        return $this->metaProperties->getTitle();
537
    }
538
539
    /**
540
     * Set the title
541
     *
542
     * @param string $title Title
543
     * @return ObjectInterface Self reference
544
     */
545 1
    public function setTitle($title)
546
    {
547 1
        $this->setMetaProperties($this->metaProperties->setTitle($title));
548 1
        return $this;
549
    }
550
551
    /**
552
     * Return the object slug
553
     *
554
     * @return string Object slug
555
     */
556 1
    public function getSlug()
557
    {
558 1
        return $this->metaProperties->getSlug();
559
    }
560
561
    /**
562
     * Set the slug
563
     *
564
     * @param string $slug Slug
565
     * @return ObjectInterface Self reference
566
     */
567 1
    public function setSlug($slug)
568
    {
569 1
        $this->setMetaProperties($this->metaProperties->setSlug($slug));
570 1
        return $this;
571
    }
572
573
    /**
574
     * Return the object description
575
     *
576
     * @return string Object description
577
     */
578 2
    public function getDescription()
579
    {
580 2
        return $this->metaProperties->getDescription();
581
    }
582
583
    /**
584
     * Set the description
585
     *
586
     * @param string $description Description
587
     * @return ObjectInterface Self reference
588
     */
589 1
    public function setDescription($description)
590
    {
591 1
        $this->setMetaProperties($this->metaProperties->setDescription($description));
592 1
        return $this;
593
    }
594
595
    /**
596
     * Return the object abstract
597
     *
598
     * @return string Object abstract
599
     */
600 2
    public function getAbstract()
601
    {
602 2
        return $this->metaProperties->getAbstract();
603
    }
604
605
    /**
606
     * Set the abstract
607
     *
608
     * @param string $abstract Abstract
609
     * @return ObjectInterface Self reference
610
     */
611 1
    public function setAbstract($abstract)
612
    {
613 1
        $this->setMetaProperties($this->metaProperties->setAbstract($abstract));
614 1
        return $this;
615
    }
616
617
    /**
618
     * Return the license
619
     *
620
     * @return string License
621
     */
622 1
    public function getLicense()
623
    {
624 1
        return $this->metaProperties->getLicense();
625
    }
626
627
    /**
628
     * Set the license
629
     *
630
     * @param string $license License
631
     * @return MetaProperties Self reference
632
     */
633 1
    public function setLicense($license)
634
    {
635 1
        $this->setMetaProperties($this->metaProperties->setLicense($license));
636 1
        return $this;
637
    }
638
639
    /**
640
     * Return the privacy
641
     *
642
     * @return string Privacy
643
     */
644 1
    public function getPrivacy()
645
    {
646 1
        return $this->metaProperties->getPrivacy();
647
    }
648
649
    /**
650
     * Set the privacy
651
     *
652
     * @param string $privacy Privacy
653
     * @return MetaProperties Self reference
654
     */
655 1
    public function setPrivacy($privacy)
656
    {
657 1
        $this->setMetaProperties($this->metaProperties->setPrivacy($privacy));
658 1
        return $this;
659
    }
660
661
    /**
662
     * Return all object keywords
663
     *
664
     * @return array Object keywords
665
     */
666 2
    public function getKeywords()
667
    {
668 2
        return $this->metaProperties->getKeywords();
669
    }
670
671
    /**
672
     * Set the keywords
673
     *
674
     * @param array $keywords Keywords
675
     * @return ObjectInterface Self reference
676
     */
677 1
    public function setKeywords(array $keywords)
678
    {
679 1
        $this->setMetaProperties($this->metaProperties->setKeywords($keywords));
680 1
        return $this;
681
    }
682
683
    /**
684
     * Return all object categories
685
     *
686
     * @return array Object categories
687
     */
688 2
    public function getCategories()
689
    {
690 2
        return $this->metaProperties->getCategories();
691
    }
692
693
    /**
694
     * Set the categories
695
     *
696
     * @param array $categories Categories
697
     * @return ObjectInterface Self reference
698
     */
699 1
    public function setCategories(array $categories)
700
    {
701 1
        $this->setMetaProperties($this->metaProperties->setCategories($categories));
702 1
        return $this;
703
    }
704
705
    /**
706
     * Return the object repository path
707
     *
708
     * @return RepositoryPathInterface Object repository path
709
     */
710 18
    public function getRepositoryPath()
711
    {
712 18
        return $this->path;
713
    }
714
715
    /**
716
     * Return the object property data
717
     *
718
     * @return array Object property data
719
     */
720 5
    public function getPropertyData()
721
    {
722 5
        $propertyData = array_filter([
723 5
            SystemProperties::COLLECTION => $this->systemProperties->toArray(),
724 5
            MetaProperties::COLLECTION => $this->metaProperties->toArray(),
725 5
            AbstractDomainProperties::COLLECTION => $this->domainProperties->toArray(),
726 5
            ProcessingInstructions::COLLECTION => $this->processingInstructions->toArray(),
727 5
            Relations::COLLECTION => $this->relations->toArray(),
728 5
        ], function (array $collection) {
729 5
            return (boolean)count($collection);
730 5
        });
731
732 5
        return $propertyData;
733
    }
734
735
    /**
736
     * Return the object payload
737
     *
738
     * @return string Object payload
739
     */
740 2
    public function getPayload()
741
    {
742 2
        return $this->payload;
743
    }
744
745
    /**
746
     * Set the payload
747
     *
748
     * @param string $payload Payload
749
     * @return ObjectInterface Self reference
750
     */
751 1
    public function setPayload($payload)
752
    {
753
        // If the payload is changed
754 1
        if ($payload !== $this->payload) {
755 1
            $this->setMutatedState();
756 1
        }
757
758 1
        $this->payload = $payload;
759 1
        return $this;
760
    }
761
762
    /**
763
     * Return the absolute object URL
764
     *
765
     * @return string
766
     */
767 4
    public function getAbsoluteUrl()
768
    {
769 4
        return getenv('APPARAT_BASE_URL').ltrim($this->path->getRepository()->getUrl(), '/').strval($this->path);
770
    }
771
772
    /**
773
     * Get a domain property value
774
     *
775
     * Multi-level properties might be traversed by property name paths separated with colons (":").
776
     *
777
     * @param string $property Property name
778
     * @return mixed Property value
779
     */
780 2
    public function getDomainProperty($property)
781
    {
782 2
        return $this->domainProperties->getProperty($property);
783
    }
784
785
    /**
786
     * Set a domain property value
787
     *
788
     * @param string $property Property name
789
     * @param mixed $value Property value
790
     * @return ObjectInterface Self reference
791
     */
792 1
    public function setDomainProperty($property, $value)
793
    {
794 1
        $this->setDomainProperties($this->domainProperties->setProperty($property, $value));
795 1
        return $this;
796
    }
797
798
    /**
799
     * Get a processing instruction
800
     *
801
     * @param string $procInst Processing instruction name
802
     * @return mixed Processing instruction
803
     */
804
    public function getProcessingInstruction($procInst)
805
    {
806
        return $this->processingInstructions->getProperty($procInst);
807
    }
808
809
    /**
810
     * Set a processing instruction
811
     *
812
     * @param string $procInst Processing instruction name
813
     * @param mixed $value Processing instruction
814
     * @return ObjectInterface Self reference
815
     */
816 1
    public function setProcessingInstruction($procInst, $value)
817
    {
818 1
        $this->setProcessingInstructions($this->processingInstructions->setProperty($procInst, $value));
819 1
        return $this;
820
    }
821
822
    /**
823
     * Persist the current object revision
824
     *
825
     * @return ObjectInterface Object
826
     */
827 1
    public function persist()
828
    {
829
        // If this is not the latest revision
830 1
        if ($this->getRevision() != $this->latestRevision) {
831
            throw new RuntimeException(
832
                sprintf(
833
                    'Cannot persist revision %s/%s',
834
                    $this->getRevision()->getRevision(),
835
                    $this->latestRevision->getRevision()
836
                ),
837
                RuntimeException::CANNOT_PERSIST_EARLIER_REVISION
838
            );
839
        }
840
841
        // Update the object repository
842 1
        $this->path->getRepository()->updateObject($this);
843
844
        // Reset state
845 1
        $this->state = self::STATE_CLEAN;
846
847 1
        return $this;
848
    }
849
850
    /**
851
     * Publish the current object revision
852
     *
853
     * @return ObjectInterface Object
854
     */
855 1
    public function publish()
856
    {
857
        // If this is a draft
858 1
        if ($this->isDraft()) {
859
            // TODO: Send signal
860
861
            // Create draft system properties
862 1
            $this->systemProperties = $this->systemProperties->publish();
863
864
            // Adapt the system properties collection state
865 1
            $this->collectionStates[SystemProperties::COLLECTION] = spl_object_hash($this->systemProperties);
866
867
            // Set the draft flag on the repository path
868 1
            $this->path = $this->path->setDraft(false);
869
870
            // Flag this object as dirty
871 1
            $this->setPublishedState();
872 1
        }
873
874 1
        return $this;
875
    }
876
877
    /**
878
     * Set the object state to published
879
     */
880 1
    protected function setPublishedState()
881
    {
882
        // If this object is not in dirty state yet
883 1
        if (!($this->state & self::STATE_PUBLISHED)) {
884
            // TODO: Send signal
885 1
        }
886
887
        // Enable the dirty state
888 1
        $this->state |= (self::STATE_DIRTY | self::STATE_PUBLISHED);
889 1
    }
890
891
    /**
892
     * Return whether the object is in dirty state
893
     *
894
     * @return boolean Dirty state
895
     */
896 3
    public function isDirty()
897
    {
898 3
        return !!($this->state & self::STATE_DIRTY);
899
    }
900
}
901