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\Author\AuthorInterface; |
41
|
|
|
use Apparat\Object\Domain\Model\Path\RepositoryPath; |
42
|
|
|
use Apparat\Object\Domain\Model\Path\RepositoryPathInterface; |
43
|
|
|
use Apparat\Object\Domain\Model\Properties\AbstractDomainProperties; |
44
|
|
|
use Apparat\Object\Domain\Model\Properties\GenericPropertiesInterface; |
45
|
|
|
use Apparat\Object\Domain\Model\Properties\InvalidArgumentException as PropertyInvalidArgumentException; |
46
|
|
|
use Apparat\Object\Domain\Model\Properties\MetaProperties; |
47
|
|
|
use Apparat\Object\Domain\Model\Properties\ProcessingInstructions; |
48
|
|
|
use Apparat\Object\Domain\Model\Properties\Relations; |
49
|
|
|
use Apparat\Object\Domain\Model\Properties\SystemProperties; |
50
|
|
|
use Apparat\Object\Domain\Repository\Service; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Abstract object |
54
|
|
|
* |
55
|
|
|
* @package Apparat\Object |
56
|
|
|
* @subpackage Apparat\Object\Domain |
57
|
|
|
*/ |
58
|
|
|
abstract class AbstractObject implements ObjectInterface |
59
|
|
|
{ |
60
|
|
|
/** |
61
|
|
|
* Clean state |
62
|
|
|
* |
63
|
|
|
* @var int |
64
|
|
|
*/ |
65
|
|
|
const STATE_CLEAN = 0; |
66
|
|
|
/** |
67
|
|
|
* Dirty state |
68
|
|
|
* |
69
|
|
|
* @var int |
70
|
|
|
*/ |
71
|
|
|
const STATE_DIRTY = 1; |
72
|
|
|
/** |
73
|
|
|
* Mutated state |
74
|
|
|
* |
75
|
|
|
* @var int |
76
|
|
|
*/ |
77
|
|
|
const STATE_MUTATED = 2; |
78
|
|
|
/** |
79
|
|
|
* System properties |
80
|
|
|
* |
81
|
|
|
* @var SystemProperties |
82
|
|
|
*/ |
83
|
|
|
protected $systemProperties; |
84
|
|
|
/** |
85
|
|
|
* Meta properties |
86
|
|
|
* |
87
|
|
|
* @var MetaProperties |
88
|
|
|
*/ |
89
|
|
|
protected $metaProperties; |
90
|
|
|
/** |
91
|
|
|
* Domain properties |
92
|
|
|
* |
93
|
|
|
* @var AbstractDomainProperties |
94
|
|
|
*/ |
95
|
|
|
protected $domainProperties; |
96
|
|
|
/** |
97
|
|
|
* Object payload |
98
|
|
|
* |
99
|
|
|
* @var string |
100
|
|
|
*/ |
101
|
|
|
protected $payload; |
102
|
|
|
/** |
103
|
|
|
* Repository path |
104
|
|
|
* |
105
|
|
|
* @var RepositoryPathInterface |
106
|
|
|
*/ |
107
|
|
|
protected $path; |
108
|
|
|
/** |
109
|
|
|
* Domain property collection class |
110
|
|
|
* |
111
|
|
|
* @var string |
112
|
|
|
*/ |
113
|
|
|
protected $domainPropertyCClass = AbstractDomainProperties::class; |
114
|
|
|
/** |
115
|
|
|
* Object relations |
116
|
|
|
* |
117
|
|
|
* @var Relations |
118
|
|
|
*/ |
119
|
|
|
protected $relations; |
120
|
|
|
/** |
121
|
|
|
* Processing instructions |
122
|
|
|
* |
123
|
|
|
* @var ProcessingInstructions |
124
|
|
|
*/ |
125
|
|
|
protected $processingInstructions; |
126
|
|
|
/** |
127
|
|
|
* Latest revision index |
128
|
|
|
* |
129
|
|
|
* @var Revision |
130
|
|
|
*/ |
131
|
|
|
protected $latestRevision; |
132
|
|
|
/** |
133
|
|
|
* Object state |
134
|
|
|
* |
135
|
|
|
* @var int |
136
|
|
|
*/ |
137
|
|
|
protected $state = self::STATE_CLEAN; |
138
|
|
|
/** |
139
|
|
|
* Property collection states |
140
|
|
|
* |
141
|
|
|
* @var array |
142
|
|
|
*/ |
143
|
|
|
protected $collectionStates = []; |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* Object constructor |
147
|
|
|
* |
148
|
|
|
* @param string $payload Object payload |
149
|
|
|
* @param array $propertyData Property data |
150
|
|
|
* @param RepositoryPathInterface $path Object repository path |
151
|
|
|
*/ |
152
|
21 |
|
public function __construct($payload = '', array $propertyData = [], RepositoryPathInterface $path = null) |
153
|
|
|
{ |
154
|
|
|
// If the domain property collection class is invalid |
155
|
21 |
|
if (!$this->domainPropertyCClass |
156
|
21 |
|
|| !class_exists($this->domainPropertyCClass) |
157
|
21 |
|
|| !(new \ReflectionClass($this->domainPropertyCClass))->isSubclassOf(AbstractDomainProperties::class) |
158
|
21 |
|
) { |
159
|
1 |
|
throw new PropertyInvalidArgumentException( |
160
|
1 |
|
sprintf( |
161
|
1 |
|
'Invalid domain property collection class "%s"', |
162
|
1 |
|
$this->domainPropertyCClass |
163
|
1 |
|
), |
164
|
|
|
PropertyInvalidArgumentException::INVALID_DOMAIN_PROPERTY_COLLECTION_CLASS |
165
|
1 |
|
); |
166
|
|
|
} |
167
|
|
|
|
168
|
20 |
|
$this->path = $path; |
169
|
|
|
|
170
|
|
|
// Load the current revision data |
171
|
20 |
|
$this->loadRevisionData($payload, $propertyData); |
172
|
|
|
|
173
|
|
|
// Save the latest revision index |
174
|
18 |
|
$this->latestRevision = $this->getRevision(); |
175
|
18 |
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* Load object revision data |
179
|
|
|
* |
180
|
|
|
* @param string $payload Object payload |
181
|
|
|
* @param array $propertyData Property data |
182
|
|
|
*/ |
183
|
20 |
|
protected function loadRevisionData($payload = '', array $propertyData = []) |
184
|
|
|
{ |
185
|
20 |
|
$this->payload = $payload; |
186
|
|
|
|
187
|
|
|
// Instantiate the system properties |
188
|
20 |
|
$systemPropertyData = (empty($propertyData[SystemProperties::COLLECTION]) || |
189
|
20 |
|
!is_array( |
190
|
20 |
|
$propertyData[SystemProperties::COLLECTION] |
191
|
20 |
|
)) ? [] : $propertyData[SystemProperties::COLLECTION]; |
192
|
20 |
|
$this->systemProperties = Kernel::create(SystemProperties::class, [$systemPropertyData, $this]); |
193
|
|
|
|
194
|
|
|
// Instantiate the meta properties |
195
|
19 |
|
$metaPropertyData = (empty($propertyData[MetaProperties::COLLECTION]) || |
196
|
18 |
|
!is_array( |
197
|
18 |
|
$propertyData[MetaProperties::COLLECTION] |
198
|
19 |
|
)) ? [] : $propertyData[MetaProperties::COLLECTION]; |
199
|
|
|
/** @var MetaProperties $metaPropertyCollection */ |
200
|
19 |
|
$metaPropertyCollection = Kernel::create(MetaProperties::class, [$metaPropertyData, $this]); |
201
|
18 |
|
$this->setMetaProperties($metaPropertyCollection, true); |
202
|
|
|
|
203
|
|
|
// Instantiate the domain properties |
204
|
18 |
|
$domainPropertyData = (empty($propertyData[AbstractDomainProperties::COLLECTION]) || |
205
|
17 |
|
!is_array( |
206
|
17 |
|
$propertyData[AbstractDomainProperties::COLLECTION] |
207
|
18 |
|
)) ? [] : $propertyData[AbstractDomainProperties::COLLECTION]; |
208
|
|
|
/** @var AbstractDomainProperties $domainPropertyCollection */ |
209
|
18 |
|
$domainPropertyCollection = Kernel::create($this->domainPropertyCClass, [$domainPropertyData, $this]); |
210
|
18 |
|
$this->setDomainProperties($domainPropertyCollection, true); |
211
|
|
|
|
212
|
|
|
// Instantiate the processing instructions |
213
|
18 |
|
$procInstData = (empty($propertyData[ProcessingInstructions::COLLECTION]) || |
214
|
14 |
|
!is_array( |
215
|
14 |
|
$propertyData[ProcessingInstructions::COLLECTION] |
216
|
18 |
|
)) ? [] : $propertyData[ProcessingInstructions::COLLECTION]; |
217
|
|
|
/** @var ProcessingInstructions $procInstCollection */ |
218
|
18 |
|
$procInstCollection = Kernel::create(ProcessingInstructions::class, [$procInstData, $this]); |
219
|
18 |
|
$this->setProcessingInstructions($procInstCollection, true); |
220
|
|
|
|
221
|
|
|
// Instantiate the object relations |
222
|
18 |
|
$relationData = (empty($propertyData[Relations::COLLECTION]) || |
223
|
14 |
|
!is_array( |
224
|
14 |
|
$propertyData[Relations::COLLECTION] |
225
|
18 |
|
)) ? [] : $propertyData[Relations::COLLECTION]; |
226
|
|
|
/** @var Relations $relationCollection */ |
227
|
18 |
|
$relationCollection = Kernel::create(Relations::class, [$relationData, $this]); |
228
|
18 |
|
$this->setRelations($relationCollection, true); |
229
|
|
|
|
230
|
|
|
// Reset the object state to clean |
231
|
18 |
|
$this->state = self::STATE_CLEAN; |
232
|
18 |
|
} |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* Set the meta properties collection |
236
|
|
|
* |
237
|
|
|
* @param MetaProperties $metaProperties Meta property collection |
238
|
|
|
* @param bool $overwrite Overwrite the existing collection (if present) |
239
|
|
|
*/ |
240
|
18 |
|
protected function setMetaProperties(MetaProperties $metaProperties, $overwrite = false) |
241
|
|
|
{ |
242
|
18 |
|
$this->metaProperties = $metaProperties; |
243
|
18 |
|
$metaPropertiesState = spl_object_hash($this->metaProperties); |
244
|
|
|
|
245
|
|
|
// If the meta property collection state has changed |
246
|
|
|
if (!$overwrite |
247
|
18 |
|
&& !empty($this->collectionStates[MetaProperties::COLLECTION]) |
248
|
18 |
|
&& ($metaPropertiesState !== $this->collectionStates[MetaProperties::COLLECTION]) |
249
|
18 |
|
) { |
250
|
|
|
// Flag this object as mutated |
251
|
1 |
|
$this->setMutatedState(); |
252
|
1 |
|
} |
253
|
|
|
|
254
|
18 |
|
$this->collectionStates[MetaProperties::COLLECTION] = $metaPropertiesState; |
255
|
18 |
|
} |
256
|
|
|
|
257
|
|
|
/** |
258
|
|
|
* Set the object state to mutated |
259
|
|
|
*/ |
260
|
2 |
|
protected function setMutatedState() |
261
|
|
|
{ |
262
|
|
|
// If this object is not in mutated state yet |
263
|
2 |
|
if (!($this->state & self::STATE_MUTATED) && !$this->isDraft()) { |
264
|
|
|
// TODO: Send signal |
265
|
|
|
|
266
|
|
|
// Increment the latest revision number |
267
|
2 |
|
$this->latestRevision = $this->latestRevision->increment(); |
268
|
|
|
|
269
|
|
|
// Create draft system properties |
270
|
2 |
|
$this->systemProperties = $this->systemProperties->createDraft($this->latestRevision); |
271
|
|
|
|
272
|
|
|
// Set the draft flag on the repository path |
273
|
2 |
|
$this->path = $this->path->setDraft(true); |
274
|
|
|
|
275
|
|
|
// If this is not already a draft ... |
276
|
|
|
// Recreate the system properties |
277
|
|
|
// Copy the object ID |
278
|
|
|
// Copy the object type |
279
|
|
|
// Set the revision number to latest revision + 1 |
280
|
|
|
// Set the creation date to now |
281
|
|
|
// Set no publication date |
282
|
|
|
// Set the draft flag on the repository path |
283
|
|
|
// Increase the latest revision by 1 |
284
|
|
|
|
285
|
|
|
// Else if this is a draft |
286
|
|
|
// No action needed |
287
|
2 |
|
} |
288
|
|
|
|
289
|
|
|
// Enable the mutated (and dirty) state |
290
|
2 |
|
$this->state |= (self::STATE_DIRTY | self::STATE_MUTATED); |
291
|
2 |
|
} |
292
|
|
|
|
293
|
|
|
/** |
294
|
|
|
* Return the object draft mode |
295
|
|
|
* |
296
|
|
|
* @return boolean Object draft mode |
297
|
|
|
*/ |
298
|
3 |
|
public function isDraft() |
299
|
|
|
{ |
300
|
3 |
|
return $this->systemProperties->isDraft(); |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* Set the domain properties collection |
305
|
|
|
* |
306
|
|
|
* @param GenericPropertiesInterface $domainProperties Domain property collection |
307
|
|
|
* @param bool $overwrite Overwrite the existing collection (if present) |
308
|
|
|
*/ |
309
|
18 |
|
protected function setDomainProperties(GenericPropertiesInterface $domainProperties, $overwrite = false) |
310
|
|
|
{ |
311
|
18 |
|
$this->domainProperties = $domainProperties; |
|
|
|
|
312
|
18 |
|
$domainPropertiesState = spl_object_hash($this->domainProperties); |
313
|
|
|
|
314
|
|
|
// If the domain property collection state has changed |
315
|
|
|
if (!$overwrite |
316
|
18 |
|
&& !empty($this->collectionStates[AbstractDomainProperties::COLLECTION]) |
317
|
18 |
|
&& ($domainPropertiesState !== $this->collectionStates[AbstractDomainProperties::COLLECTION]) |
318
|
18 |
|
) { |
319
|
|
|
// Flag this object as mutated |
320
|
1 |
|
$this->setMutatedState(); |
321
|
1 |
|
} |
322
|
|
|
|
323
|
18 |
|
$this->collectionStates[AbstractDomainProperties::COLLECTION] = $domainPropertiesState; |
324
|
18 |
|
} |
325
|
|
|
|
326
|
|
|
/** |
327
|
|
|
* Set the processing instruction collection |
328
|
|
|
* |
329
|
|
|
* @param GenericPropertiesInterface $processingInstructions Processing instruction collection |
330
|
|
|
* @param bool $overwrite Overwrite the existing collection (if present) |
331
|
|
|
*/ |
332
|
18 |
|
protected function setProcessingInstructions(GenericPropertiesInterface $processingInstructions, $overwrite = false) |
333
|
|
|
{ |
334
|
18 |
|
$this->processingInstructions = $processingInstructions; |
|
|
|
|
335
|
18 |
|
$processingInstructionsState = spl_object_hash($this->processingInstructions); |
336
|
|
|
|
337
|
|
|
// If the domain property collection state has changed |
338
|
|
|
if (!$overwrite |
339
|
18 |
|
&& !empty($this->collectionStates[ProcessingInstructions::COLLECTION]) |
340
|
18 |
|
&& ($processingInstructionsState !== $this->collectionStates[ProcessingInstructions::COLLECTION]) |
341
|
18 |
|
) { |
342
|
|
|
// Flag this object as dirty |
343
|
1 |
|
$this->setDirtyState(); |
344
|
1 |
|
} |
345
|
|
|
|
346
|
18 |
|
$this->collectionStates[ProcessingInstructions::COLLECTION] = $processingInstructionsState; |
347
|
18 |
|
} |
348
|
|
|
|
349
|
|
|
/** |
350
|
|
|
* Set the object state to dirty |
351
|
|
|
*/ |
352
|
1 |
|
protected function setDirtyState() |
353
|
|
|
{ |
354
|
|
|
// If this object is not in dirty state yet |
355
|
1 |
|
if (!($this->state & self::STATE_DIRTY)) { |
356
|
|
|
// TODO: Send signal |
357
|
1 |
|
} |
358
|
|
|
|
359
|
|
|
// Enable the dirty state |
360
|
1 |
|
$this->state |= self::STATE_DIRTY; |
361
|
1 |
|
} |
362
|
|
|
|
363
|
|
|
/** |
364
|
|
|
* Set the relations collection |
365
|
|
|
* |
366
|
|
|
* @param Relations $relations Relations collection |
367
|
|
|
* @param bool $overwrite Overwrite the existing collection (if present) |
368
|
|
|
*/ |
369
|
18 |
|
protected function setRelations(Relations $relations, $overwrite = false) |
370
|
|
|
{ |
371
|
18 |
|
$this->relations = $relations; |
372
|
18 |
|
$relationsState = spl_object_hash($this->relations); |
373
|
|
|
|
374
|
|
|
// If the domain property collection state has changed |
375
|
|
|
if (!$overwrite |
376
|
18 |
|
&& !empty($this->collectionStates[Relations::COLLECTION]) |
377
|
18 |
|
&& ($relationsState !== $this->collectionStates[Relations::COLLECTION]) |
378
|
18 |
|
) { |
379
|
|
|
// Flag this object as dirty |
380
|
|
|
$this->setDirtyState(); |
381
|
|
|
} |
382
|
|
|
|
383
|
18 |
|
$this->collectionStates[Relations::COLLECTION] = $relationsState; |
384
|
18 |
|
} |
385
|
|
|
|
386
|
|
|
/** |
387
|
|
|
* Return the object revision |
388
|
|
|
* |
389
|
|
|
* @return Revision Object revision |
390
|
|
|
*/ |
391
|
18 |
|
public function getRevision() |
392
|
|
|
{ |
393
|
18 |
|
return $this->systemProperties->getRevision(); |
394
|
|
|
} |
395
|
|
|
|
396
|
|
|
/** |
397
|
|
|
* Return whether the object is in mutated state |
398
|
|
|
* |
399
|
|
|
* @return boolean Mutated state |
400
|
|
|
*/ |
401
|
3 |
|
public function isMutated() |
402
|
|
|
{ |
403
|
3 |
|
return !!($this->state & self::STATE_MUTATED); |
404
|
|
|
} |
405
|
|
|
|
406
|
|
|
/** |
407
|
|
|
* Use a specific object revision |
408
|
|
|
* |
409
|
|
|
* @param Revision $revision Revision to be used |
410
|
|
|
* @return ObjectInterface Object |
411
|
|
|
* @throws OutOfBoundsException If the requested revision is invalid |
412
|
|
|
*/ |
413
|
17 |
|
public function useRevision(Revision $revision) |
414
|
|
|
{ |
415
|
17 |
|
$isCurrentRevision = false; |
416
|
|
|
|
417
|
|
|
// If the requested revision is invalid |
418
|
17 |
|
if (!$revision->isCurrent() && |
419
|
|
|
(($revision->getRevision() < 1) || ($revision->getRevision() > $this->latestRevision->getRevision())) |
420
|
17 |
|
) { |
421
|
|
|
throw new OutOfBoundsException(sprintf('Invalid object revision "%s"', $revision->getRevision()), |
422
|
|
|
OutOfBoundsException::INVALID_OBJECT_REVISION); |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
// If the current revision got requested |
426
|
17 |
|
if ($revision->isCurrent()) { |
427
|
17 |
|
$isCurrentRevision = true; |
428
|
17 |
|
$revision = $this->latestRevision; |
429
|
17 |
|
} |
430
|
|
|
|
431
|
|
|
// If the requested revision is not already used |
432
|
17 |
|
if ($revision != $this->getRevision()) { |
433
|
|
|
/** @var ManagerInterface $objectManager */ |
434
|
|
|
$objectManager = Kernel::create(Service::class)->getObjectManager(); |
435
|
|
|
|
436
|
|
|
// Load the requested object revision resource |
437
|
|
|
/** @var Revision $newRevision */ |
438
|
|
|
$newRevision = $isCurrentRevision ? Kernel::create(Revision::class, [Revision::CURRENT]) : |
439
|
|
|
$revision; |
440
|
|
|
/** @var RepositoryPath $newRevisionPath */ |
441
|
|
|
$newRevisionPath = $this->path->setRevision($newRevision); |
442
|
|
|
$revisionResource = $objectManager->loadObject($newRevisionPath); |
443
|
|
|
|
444
|
|
|
// Load the revision resource data |
445
|
|
|
$this->loadRevisionData($revisionResource->getPayload(), $revisionResource->getPropertyData()); |
446
|
|
|
|
447
|
|
|
// Set the current revision path |
448
|
|
|
$this->path = $newRevisionPath; |
449
|
|
|
} |
450
|
|
|
|
451
|
17 |
|
return $this; |
452
|
|
|
} |
453
|
|
|
|
454
|
|
|
/** |
455
|
|
|
* Return the object ID |
456
|
|
|
* |
457
|
|
|
* @return Id Object ID |
458
|
|
|
*/ |
459
|
5 |
|
public function getId() |
460
|
|
|
{ |
461
|
5 |
|
return $this->systemProperties->getId(); |
462
|
|
|
} |
463
|
|
|
|
464
|
|
|
/** |
465
|
|
|
* Return the object type |
466
|
|
|
* |
467
|
|
|
* @return Type Object type |
468
|
|
|
*/ |
469
|
1 |
|
public function getType() |
470
|
|
|
{ |
471
|
1 |
|
return $this->systemProperties->getType(); |
472
|
|
|
} |
473
|
|
|
|
474
|
|
|
/** |
475
|
|
|
* Return the creation date & time |
476
|
|
|
* |
477
|
|
|
* @return \DateTimeImmutable Creation date & time |
478
|
|
|
*/ |
479
|
1 |
|
public function getCreated() |
480
|
|
|
{ |
481
|
1 |
|
return $this->systemProperties->getCreated(); |
482
|
|
|
} |
483
|
|
|
|
484
|
|
|
/** |
485
|
|
|
* Return the publication date & time |
486
|
|
|
* |
487
|
|
|
* @return \DateTimeImmutable Publication date & time |
488
|
|
|
*/ |
489
|
1 |
|
public function getPublished() |
490
|
|
|
{ |
491
|
1 |
|
return $this->systemProperties->getPublished(); |
492
|
|
|
} |
493
|
|
|
|
494
|
|
|
/** |
495
|
|
|
* Return the object hash |
496
|
|
|
* |
497
|
|
|
* @return string Object hash |
498
|
|
|
*/ |
499
|
1 |
|
public function getHash() |
500
|
|
|
{ |
501
|
1 |
|
return $this->systemProperties->getHash(); |
502
|
|
|
} |
503
|
|
|
|
504
|
|
|
/** |
505
|
|
|
* Return the object description |
506
|
|
|
* |
507
|
|
|
* @return string Object description |
508
|
|
|
*/ |
509
|
2 |
|
public function getDescription() |
510
|
|
|
{ |
511
|
2 |
|
return $this->metaProperties->getDescription(); |
512
|
|
|
} |
513
|
|
|
|
514
|
|
|
/** |
515
|
|
|
* Set the description |
516
|
|
|
* |
517
|
|
|
* @param string $description Description |
518
|
|
|
* @return ObjectInterface Self reference |
519
|
|
|
*/ |
520
|
1 |
|
public function setDescription($description) |
521
|
|
|
{ |
522
|
1 |
|
$this->setMetaProperties($this->metaProperties->setDescription($description)); |
523
|
1 |
|
return $this; |
524
|
|
|
} |
525
|
|
|
|
526
|
|
|
/** |
527
|
|
|
* Return the object abstract |
528
|
|
|
* |
529
|
|
|
* @return string Object abstract |
530
|
|
|
*/ |
531
|
2 |
|
public function getAbstract() |
532
|
|
|
{ |
533
|
2 |
|
return $this->metaProperties->getAbstract(); |
534
|
|
|
} |
535
|
|
|
|
536
|
|
|
/** |
537
|
|
|
* Set the abstract |
538
|
|
|
* |
539
|
|
|
* @param string $abstract Abstract |
540
|
|
|
* @return ObjectInterface Self reference |
541
|
|
|
*/ |
542
|
1 |
|
public function setAbstract($abstract) |
543
|
|
|
{ |
544
|
1 |
|
$this->setMetaProperties($this->metaProperties->setAbstract($abstract)); |
545
|
1 |
|
return $this; |
546
|
|
|
} |
547
|
|
|
|
548
|
|
|
/** |
549
|
|
|
* Return all object keywords |
550
|
|
|
* |
551
|
|
|
* @return array Object keywords |
552
|
|
|
*/ |
553
|
2 |
|
public function getKeywords() |
554
|
|
|
{ |
555
|
2 |
|
return $this->metaProperties->getKeywords(); |
556
|
|
|
} |
557
|
|
|
|
558
|
|
|
/** |
559
|
|
|
* Set the keywords |
560
|
|
|
* |
561
|
|
|
* @param array $keywords Keywords |
562
|
|
|
* @return ObjectInterface Self reference |
563
|
|
|
*/ |
564
|
1 |
|
public function setKeywords(array $keywords) |
565
|
|
|
{ |
566
|
1 |
|
$this->setMetaProperties($this->metaProperties->setKeywords($keywords)); |
567
|
1 |
|
return $this; |
568
|
|
|
} |
569
|
|
|
|
570
|
|
|
/** |
571
|
|
|
* Return all object categories |
572
|
|
|
* |
573
|
|
|
* @return array Object categories |
574
|
|
|
*/ |
575
|
2 |
|
public function getCategories() |
576
|
|
|
{ |
577
|
2 |
|
return $this->metaProperties->getCategories(); |
578
|
|
|
} |
579
|
|
|
|
580
|
|
|
/** |
581
|
|
|
* Set the categories |
582
|
|
|
* |
583
|
|
|
* @param array $categories Categories |
584
|
|
|
* @return ObjectInterface Self reference |
585
|
|
|
*/ |
586
|
1 |
|
public function setCategories(array $categories) |
587
|
|
|
{ |
588
|
1 |
|
$this->setMetaProperties($this->metaProperties->setCategories($categories)); |
589
|
1 |
|
return $this; |
590
|
|
|
} |
591
|
|
|
|
592
|
|
|
/** |
593
|
|
|
* Return all object authors |
594
|
|
|
* |
595
|
|
|
* @return AuthorInterface[] Authors |
596
|
|
|
*/ |
597
|
2 |
|
public function getAuthors() |
598
|
|
|
{ |
599
|
2 |
|
return $this->metaProperties->getAuthors(); |
600
|
|
|
} |
601
|
|
|
|
602
|
|
|
/** |
603
|
|
|
* Add an object author |
604
|
|
|
* |
605
|
|
|
* @param AuthorInterface $author Author |
606
|
|
|
* @return ObjectInterface Self reference |
607
|
|
|
*/ |
608
|
1 |
|
public function addAuthor(AuthorInterface $author) |
609
|
|
|
{ |
610
|
1 |
|
$authors = $this->metaProperties->getAuthors(); |
611
|
1 |
|
$authors[] = $author; |
612
|
1 |
|
$this->metaProperties->setAuthors($authors); |
613
|
1 |
|
return $this; |
614
|
|
|
} |
615
|
|
|
|
616
|
|
|
/** |
617
|
|
|
* Return the object repository path |
618
|
|
|
* |
619
|
|
|
* @return RepositoryPathInterface Object repository path |
620
|
|
|
*/ |
621
|
18 |
|
public function getRepositoryPath() |
622
|
|
|
{ |
623
|
18 |
|
return $this->path; |
624
|
|
|
} |
625
|
|
|
|
626
|
|
|
/** |
627
|
|
|
* Return the object property data |
628
|
|
|
* |
629
|
|
|
* @return array Object property data |
630
|
|
|
*/ |
631
|
5 |
|
public function getPropertyData() |
632
|
|
|
{ |
633
|
5 |
|
$propertyData = array_filter([ |
634
|
5 |
|
SystemProperties::COLLECTION => $this->systemProperties->toArray(), |
635
|
5 |
|
MetaProperties::COLLECTION => $this->metaProperties->toArray(), |
636
|
5 |
|
AbstractDomainProperties::COLLECTION => $this->domainProperties->toArray(), |
637
|
5 |
|
ProcessingInstructions::COLLECTION => $this->processingInstructions->toArray(), |
638
|
5 |
|
Relations::COLLECTION => $this->relations->toArray(), |
639
|
5 |
|
], function (array $collection) { |
640
|
5 |
|
return (boolean)count($collection); |
641
|
5 |
|
}); |
642
|
|
|
|
643
|
5 |
|
return $propertyData; |
644
|
|
|
} |
645
|
|
|
|
646
|
|
|
/** |
647
|
|
|
* Return the object payload |
648
|
|
|
* |
649
|
|
|
* @return string Object payload |
650
|
|
|
*/ |
651
|
2 |
|
public function getPayload() |
652
|
|
|
{ |
653
|
2 |
|
return $this->payload; |
654
|
|
|
} |
655
|
|
|
|
656
|
|
|
/** |
657
|
|
|
* Set the payload |
658
|
|
|
* |
659
|
|
|
* @param string $payload Payload |
660
|
|
|
* @return ObjectInterface Self reference |
661
|
|
|
*/ |
662
|
|
|
public function setPayload($payload) |
663
|
|
|
{ |
664
|
|
|
// If the payload is changed |
665
|
|
|
if ($payload !== $this->payload) { |
666
|
|
|
$this->setMutatedState(); |
667
|
|
|
} |
668
|
|
|
|
669
|
|
|
$this->payload = $payload; |
670
|
|
|
return $this; |
671
|
|
|
} |
672
|
|
|
|
673
|
|
|
/** |
674
|
|
|
* Return the absolute object URL |
675
|
|
|
* |
676
|
|
|
* @return string |
677
|
|
|
*/ |
678
|
4 |
|
public function getAbsoluteUrl() |
679
|
|
|
{ |
680
|
4 |
|
return getenv('APPARAT_BASE_URL').ltrim($this->path->getRepository()->getUrl(), '/').strval($this->path); |
681
|
|
|
} |
682
|
|
|
|
683
|
|
|
/** |
684
|
|
|
* Get a domain property value |
685
|
|
|
* |
686
|
|
|
* Multi-level properties might be traversed by property name paths separated with colons (":"). |
687
|
|
|
* |
688
|
|
|
* @param string $property Property name |
689
|
|
|
* @return mixed Property value |
690
|
|
|
*/ |
691
|
2 |
|
public function getDomainProperty($property) |
692
|
|
|
{ |
693
|
2 |
|
return $this->domainProperties->getProperty($property); |
694
|
|
|
} |
695
|
|
|
|
696
|
|
|
/** |
697
|
|
|
* Set a domain property value |
698
|
|
|
* |
699
|
|
|
* @param string $property Property name |
700
|
|
|
* @param mixed $value Property value |
701
|
|
|
* @return ObjectInterface Self reference |
702
|
|
|
*/ |
703
|
1 |
|
public function setDomainProperty($property, $value) |
704
|
|
|
{ |
705
|
1 |
|
$this->setDomainProperties($this->domainProperties->setProperty($property, $value)); |
706
|
1 |
|
return $this; |
707
|
|
|
} |
708
|
|
|
|
709
|
|
|
/** |
710
|
|
|
* Get a processing instruction |
711
|
|
|
* |
712
|
|
|
* @param string $procInst Processing instruction name |
713
|
|
|
* @return mixed Processing instruction |
714
|
|
|
*/ |
715
|
|
|
public function getProcessingInstruction($procInst) |
716
|
|
|
{ |
717
|
|
|
return $this->processingInstructions->getProperty($procInst); |
718
|
|
|
} |
719
|
|
|
|
720
|
|
|
/** |
721
|
|
|
* Set a processing instruction |
722
|
|
|
* |
723
|
|
|
* @param string $procInst Processing instruction name |
724
|
|
|
* @param mixed $value Processing instruction |
725
|
|
|
* @return ObjectInterface Self reference |
726
|
|
|
*/ |
727
|
1 |
|
public function setProcessingInstruction($procInst, $value) |
728
|
|
|
{ |
729
|
1 |
|
$this->setProcessingInstructions($this->processingInstructions->setProperty($procInst, $value)); |
730
|
1 |
|
return $this; |
731
|
|
|
} |
732
|
|
|
|
733
|
|
|
/** |
734
|
|
|
* Persist the current object revision |
735
|
|
|
* |
736
|
|
|
* @return ObjectInterface Object |
737
|
|
|
*/ |
738
|
|
|
public function persist() |
739
|
|
|
{ |
740
|
|
|
// If this is not the latest revision |
741
|
|
|
if ($this->getRevision() != $this->latestRevision) { |
742
|
|
|
throw new RuntimeException( |
743
|
|
|
sprintf( |
744
|
|
|
'Cannot persist revision %s/%s', |
745
|
|
|
$this->getRevision()->getRevision(), |
746
|
|
|
$this->latestRevision->getRevision() |
747
|
|
|
), |
748
|
|
|
RuntimeException::CANNOT_PERSIST_EARLIER_REVISION |
749
|
|
|
); |
750
|
|
|
} |
751
|
|
|
|
752
|
|
|
// If this object is in dirty state |
753
|
|
|
if ($this->isDirty()) { |
754
|
|
|
$this->path->getRepository()->updateObject($this); |
755
|
|
|
$this->state = self::STATE_CLEAN; |
756
|
|
|
} |
757
|
|
|
|
758
|
|
|
return $this; |
759
|
|
|
} |
760
|
|
|
|
761
|
|
|
/** |
762
|
|
|
* Return whether the object is in dirty state |
763
|
|
|
* |
764
|
|
|
* @return boolean Dirty state |
765
|
|
|
*/ |
766
|
3 |
|
public function isDirty() |
767
|
|
|
{ |
768
|
3 |
|
return !!($this->state & self::STATE_DIRTY); |
769
|
|
|
} |
770
|
|
|
} |
771
|
|
|
|
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.