GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

AbstractCmisObject   F
last analyzed

Complexity

Total Complexity 90

Size/Duplication

Total Lines 846
Duplicated Lines 1.3 %

Coupling/Cohesion

Components 1
Dependencies 23

Test Coverage

Coverage 4.36%

Importance

Changes 0
Metric Value
wmc 90
lcom 1
cbo 23
dl 11
loc 846
ccs 12
cts 275
cp 0.0436
rs 1.754
c 0
b 0
f 0

48 Methods

Rating   Name   Duplication   Size   Complexity  
A initialize() 0 26 3
B initializeObjectData() 11 45 8
A initializeObjectDataProperties() 0 24 4
A initializeObjectDataPolicies() 0 11 3
A getMissingBaseProperties() 0 18 4
A getSession() 0 4 1
A getRepositoryId() 0 4 1
A getObjectType() 0 4 1
A getObjectFactory() 0 4 1
A getBinding() 0 4 1
A getCreationContext() 0 4 1
A getPropertyQueryName() 0 9 2
A delete() 0 4 1
B updateProperties() 0 44 5
A rename() 0 14 2
A getType() 0 4 1
A getBaseType() 0 9 2
A getBaseTypeId() 0 9 2
A getChangeToken() 0 4 1
A getCreatedBy() 0 4 1
A getCreationDate() 0 4 1
A getId() 0 4 1
A getLastModificationDate() 0 4 1
A getLastModifiedBy() 0 4 1
A getName() 0 4 1
A getDescription() 0 4 1
A getProperties() 0 4 1
A getProperty() 0 8 2
A getPropertyValue() 0 9 3
A getSecondaryTypes() 0 4 1
A findObjectType() 0 19 6
A getAllowableActions() 0 4 1
A hasAllowableAction() 0 9 3
A getRenditions() 0 4 1
A applyAcl() 0 8 1
A addAcl() 0 4 1
A removeAcl() 0 4 1
A setAcl() 0 8 1
A getAcl() 0 4 1
B getPermissionsForPrincipal() 0 22 6
A applyPolicies() 0 4 1
A getPolicies() 0 4 1
A removePolicy() 0 4 1
A getRelationships() 0 4 1
A getExtensions() 0 8 2
A getRefreshTimestamp() 0 4 1
A refresh() 0 23 1
A refreshIfOld() 0 6 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like AbstractCmisObject often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractCmisObject, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Dkd\PhpCmis\DataObjects;
3
4
/*
5
 * This file is part of php-cmis-client.
6
 *
7
 * (c) Sascha Egerer <[email protected]>
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
use Dkd\PhpCmis\Bindings\CmisBindingInterface;
14
use Dkd\PhpCmis\CmisObject\CmisObjectInterface;
15
use Dkd\PhpCmis\Data\AceInterface;
16
use Dkd\PhpCmis\Data\AclInterface;
17
use Dkd\PhpCmis\Data\AllowableActionsInterface;
18
use Dkd\PhpCmis\Data\CmisExtensionElementInterface;
19
use Dkd\PhpCmis\Data\ObjectDataInterface;
20
use Dkd\PhpCmis\Data\ObjectIdInterface;
21
use Dkd\PhpCmis\Data\ObjectTypeInterface;
22
use Dkd\PhpCmis\Data\PolicyIdListInterface;
23
use Dkd\PhpCmis\Data\PolicyInterface;
24
use Dkd\PhpCmis\Data\PropertiesInterface;
25
use Dkd\PhpCmis\Data\PropertyInterface;
26
use Dkd\PhpCmis\Data\RelationshipInterface;
27
use Dkd\PhpCmis\Data\RenditionInterface;
28
use Dkd\PhpCmis\Data\SecondaryTypeInterface;
29
use Dkd\PhpCmis\Definitions\PropertyDefinitionInterface;
30
use Dkd\PhpCmis\Enum\AclPropagation;
31
use Dkd\PhpCmis\Enum\Action;
32
use Dkd\PhpCmis\Enum\BaseTypeId;
33
use Dkd\PhpCmis\Enum\ExtensionLevel;
34
use Dkd\PhpCmis\Enum\Updatability;
35
use Dkd\PhpCmis\Exception\CmisInvalidArgumentException;
36
use Dkd\PhpCmis\Exception\CmisObjectNotFoundException;
37
use Dkd\PhpCmis\Exception\IllegalStateException;
38
use Dkd\PhpCmis\ObjectFactoryInterface;
39
use Dkd\PhpCmis\OperationContextInterface;
40
use Dkd\PhpCmis\PropertyIds;
41
use Dkd\PhpCmis\SessionInterface;
42
43
/**
44
 * Class AbstractCmisObject
45
 */
46
abstract class AbstractCmisObject implements CmisObjectInterface
47
{
48
    /**
49
     * @var SessionInterface
50
     */
51
    protected $session;
52
53
    /**
54
     * @var ObjectTypeInterface
55
     */
56
    protected $objectType;
57
58
    /**
59
     * @var null|SecondaryTypeInterface[]
60
     */
61
    protected $secondaryTypes;
62
63
    /**
64
     * @var PropertyInterface[]
65
     */
66
    protected $properties = [];
67
68
    /**
69
     * @var AllowableActionsInterface|null
70
     */
71
    protected $allowableActions;
72
73
    /**
74
     * @var RenditionInterface[]
75
     */
76
    protected $renditions = [];
77
78
    /**
79
     * @var AclInterface|null
80
     */
81
    protected $acl;
82
83
    /**
84
     * @var PolicyInterface[]
85
     */
86
    protected $policies = [];
87
88
    /**
89
     * @var RelationshipInterface[]
90
     */
91
    protected $relationships = [];
92
93
    /**
94
     * A list that contains a list of <code>CmisExtensionElementInterface</code> identified by
95
     * <code>ExtensionLevel</code>. The key is the string representation of <code>ExtensionLevel</code> and the value
96
     * the array of <code>CmisExtensionElementInterface</code>
97
     *
98
     * @see ExtensionLevel
99
     * @see CmisExtensionElementInterface
100
     * @var array[]
101
     */
102
    protected $extensions = [];
103
104
    /**
105
     * @var OperationContextInterface
106
     */
107
    protected $creationContext;
108
109
    /**
110
     * @var integer
111
     */
112
    protected $refreshTimestamp = 0;
113
114
    /**
115
     * Initialize the CMIS Object
116
     *
117
     * @param SessionInterface $session
118
     * @param ObjectTypeInterface $objectType
119
     * @param OperationContextInterface $context
120
     * @param ObjectDataInterface|null $objectData
121
     */
122
    public function initialize(
123
        SessionInterface $session,
124
        ObjectTypeInterface $objectType,
125
        OperationContextInterface $context,
126
        ObjectDataInterface $objectData = null
127
    ) {
128
        if (count($this->getMissingBaseProperties($objectType->getPropertyDefinitions())) !== 0) {
129
            throw new CmisInvalidArgumentException(
130
                sprintf(
131
                    'Object type must have at least the base property definitions! '
132
                    . 'These property definitions are missing: %s',
133
                    implode(', ', PropertyIds::getBasePropertyKeys())
134
                )
135
            );
136
        };
137
138
        $this->session = $session;
139
        $this->objectType = $objectType;
140
        $this->secondaryTypes = null;
141
        $this->creationContext = clone $context;
142
        $this->refreshTimestamp = (integer) round(microtime(true) * 1000);
143
144
        if ($objectData !== null) {
145
            $this->initializeObjectData($objectData);
146
        }
147
    }
148
149
    /**
150
     * Handle initialization for objectData
151
     *
152
     * @param ObjectDataInterface $objectData
153
     */
154
    private function initializeObjectData(ObjectDataInterface $objectData)
155
    {
156
        // handle properties
157
        if ($objectData->getProperties() !== null) {
158
            $this->initializeObjectDataProperties($objectData->getProperties());
159
        }
160
161
        // handle allowable actions
162 View Code Duplication
        if ($objectData->getAllowableActions() !== null) {
163
            $this->allowableActions = $objectData->getAllowableActions();
164
            $this->extensions[(string) ExtensionLevel::cast(
165
                ExtensionLevel::ALLOWABLE_ACTIONS
166
            )] = $objectData->getAllowableActions()->getExtensions();
167
        }
168
169
        // handle renditions
170
        foreach ($objectData->getRenditions() as $rendition) {
171
            $this->renditions[] = $this->getObjectFactory()->convertRendition($this->getId(), $rendition);
172
        }
173
174
        // handle ACL
175 View Code Duplication
        if ($objectData->getAcl() !== null) {
176
            $this->acl = $objectData->getAcl();
177
            $this->extensions[(string) ExtensionLevel::cast(ExtensionLevel::ACL)] = $objectData->getAcl(
178
            )->getExtensions();
179
        }
180
181
        // handle policies
182
        if ($objectData->getPolicyIds() !== null) {
183
            $this->initializeObjectDataPolicies($objectData->getPolicyIds());
184
        }
185
186
        // handle relationships
187
        foreach ($objectData->getRelationships() as $relationshipData) {
188
            $relationship = $this->getObjectFactory()->convertObject(
189
                $relationshipData,
190
                $this->getCreationContext()
191
            );
192
            if ($relationship instanceof RelationshipInterface) {
193
                $this->relationships[] = $relationship;
194
            }
195
        }
196
197
        $this->extensions[(string) ExtensionLevel::OBJECT] = $objectData->getExtensions();
198
    }
199
200
    /**
201
     * Handle initialization of properties from the object data
202
     *
203
     * @param PropertiesInterface $properties
204
     */
205
    private function initializeObjectDataProperties(PropertiesInterface $properties)
206
    {
207
        // get secondary types
208
        $propertyList = $properties->getProperties();
209
        if (isset($propertyList[PropertyIds::SECONDARY_OBJECT_TYPE_IDS])) {
210
            $this->secondaryTypes = [];
211
            foreach ($propertyList[PropertyIds::SECONDARY_OBJECT_TYPE_IDS]->getValues() as $secondaryTypeId) {
212
                $type = $this->getSession()->getTypeDefinition($secondaryTypeId);
213
                if ($type instanceof SecondaryTypeInterface) {
214
                    $this->secondaryTypes[] = $type;
215
                }
216
            }
217
        }
218
219
        $this->properties = $this->getObjectFactory()->convertPropertiesDataToPropertyList(
220
            $this->getObjectType(),
221
            (array) $this->getSecondaryTypes(),
222
            $properties
223
        );
224
225
        $this->extensions[(string) ExtensionLevel::cast(
226
            ExtensionLevel::PROPERTIES
227
        )] = $properties->getExtensions();
228
    }
229
230
    /**
231
     * Handle initialization of policies from the object data
232
     *
233
     * @param PolicyIdListInterface $policies
234
     */
235
    private function initializeObjectDataPolicies(PolicyIdListInterface $policies)
236
    {
237
        foreach ($policies->getPolicyIds() as $policyId) {
238
            $policy = $this->getSession()->getObject($this->getSession()->createObjectId($policyId));
239
            if ($policy instanceof PolicyInterface) {
240
                $this->policies[] = $policy;
241
            }
242
        }
243
244
        $this->extensions[(string) ExtensionLevel::POLICIES] = $policies->getExtensions();
245
    }
246
247
248
    /**
249
     * Returns a list of missing property keys
250
     *
251 4
     * @param PropertyDefinitionInterface[]|null $properties
252
     * @return array
253 4
     */
254
    protected function getMissingBaseProperties(array $properties = null)
255 4
    {
256 1
        $basePropertyKeys = PropertyIds::getBasePropertyKeys();
257
258
        if ($properties === null) {
259 3
            return $basePropertyKeys;
260 2
        }
261 2
262 2
        foreach ($properties as $property) {
263 2
            $propertyId = $property->getId();
264 2
            $basePropertyKey = array_search($propertyId, $basePropertyKeys);
265 3
            if ($basePropertyKey !== false) {
266
                unset($basePropertyKeys[$basePropertyKey]);
267 3
            }
268
        }
269
270
        return $basePropertyKeys;
271
    }
272
273
    /**
274
     * Returns the session object
275
     *
276
     * @return SessionInterface
277
     */
278
    protected function getSession()
279
    {
280
        return $this->session;
281
    }
282
283
    /**
284
     * Returns the repository id
285
     *
286
     * @return string
287
     */
288
    protected function getRepositoryId()
289
    {
290
        return $this->getSession()->getRepositoryInfo()->getId();
291
    }
292
293
    /**
294
     * Returns the object type
295
     *
296
     * @return ObjectTypeInterface
297
     */
298
    protected function getObjectType()
299
    {
300
        return $this->objectType;
301
    }
302
303
    /**
304
     * Returns the object factory.
305
     *
306
     * @return ObjectFactoryInterface
307
     */
308
    protected function getObjectFactory()
309
    {
310
        return $this->getSession()->getObjectFactory();
311
    }
312
313
    /**
314
     * Get the binding object
315
     *
316
     * @return CmisBindingInterface
317
     */
318
    protected function getBinding()
319
    {
320
        return $this->getSession()->getBinding();
321
    }
322
323
    /**
324
     * Returns the OperationContext that was used to create this object.
325
     *
326
     * @return OperationContextInterface
327
     */
328
    protected function getCreationContext()
329
    {
330
        return $this->creationContext;
331
    }
332
333
    /**
334
     * Returns the query name of a property.
335
     *
336
     * @param string $propertyId
337
     * @return null|string
338
     */
339
    protected function getPropertyQueryName($propertyId)
340
    {
341
        $propertyDefinition = $this->getObjectType()->getPropertyDefinition($propertyId);
342
        if ($propertyDefinition === null) {
343
            return null;
344
        }
345
346
        return $propertyDefinition->getQueryName();
347
    }
348
349
    /**
350
     * Delete this object
351
     *
352
     * @param boolean $allVersions indicates if all versions of the object should be deleted
353
     */
354
    public function delete($allVersions = true)
355
    {
356
        $this->getSession()->delete($this, $allVersions);
357
    }
358
359
    /**
360
     * Updates the provided properties. If the repository created a new object, for example a new version,
361
     * the object ID of the new object is returned. Otherwise the object ID of the current object is returned.
362
     *
363
     * @param mixed[] $properties the properties to update
364
     * @param boolean $refresh <code>true</code> if this object should be refresh after the update,
365
     *      <code>false</code> if not
366
     * @return CmisObjectInterface|null the object ID of the updated object - can return <code>null</code> in case
367
     *      of a repository failure
368
     */
369
    public function updateProperties(array $properties, $refresh = true)
370
    {
371
        if (empty($properties)) {
372
            throw new CmisInvalidArgumentException('Properties must not be empty!');
373
        }
374
375
        $objectId = $this->getId();
376
        $changeToken = $this->getChangeToken();
377
378
        $updatability = [];
379
        $updatability[] = Updatability::cast(Updatability::READWRITE);
380
        if ((boolean) $this->getPropertyValue(PropertyIds::IS_VERSION_SERIES_CHECKED_OUT) === true) {
381
            $updatability[] = Updatability::cast(Updatability::WHENCHECKEDOUT);
382
        }
383
384
        $newObjectId = $objectId;
385
        $this->getBinding()->getObjectService()->updateProperties(
386
            $this->getRepositoryId(),
387
            $newObjectId,
388
            $this->getObjectFactory()->convertProperties(
389
                $properties,
390
                $this->getObjectType(),
391
                (array) $this->getSecondaryTypes(),
392
                $updatability
393
            ),
394
            $changeToken
395
        );
396
397
        // remove the object from the cache, it has been changed
398
        $this->getSession()->removeObjectFromCache($this->getSession()->createObjectId($objectId));
399
400
        if ($refresh === true) {
401
            $this->refresh();
402
        }
403
404
        if ($newObjectId === null) {
405
            return null;
406
        }
407
408
        return $this->getSession()->getObject(
409
            $this->getSession()->createObjectId($newObjectId),
410
            $this->getCreationContext()
411
        );
412
    }
413
414
    /**
415
     * Renames this object (changes the value of cmis:name).
416
     * If the repository created a new object, for example a new version, the object id of the
417
     * new object is returned. Otherwise the object id of the current object is returned.
418
     *
419
     * @param string $newName the new name, not <code>null</code> or empty
420
     * @param boolean $refresh <code>true</code> if this object should be refresh after the update,
421
     *     <code>false</code> if not
422
     * @return CmisObjectInterface|null the object ID of the updated object - can return <code>null</code> in case of
423
     *     a repository failure
424
     */
425
    public function rename($newName, $refresh = true)
426
    {
427
        if (empty($newName)) {
428
            throw new CmisInvalidArgumentException('New name must not be empty!');
429
        }
430
431
        $properties = [
432
            PropertyIds::NAME => $newName,
433
        ];
434
435
        $object = $this->updateProperties($properties, $refresh);
436
437
        return $object;
438
    }
439
440
    /**
441
     * Returns the type of this CMIS object (object type identified by <code>cmis:objectTypeId</code>).
442
     *
443
     * @return ObjectTypeInterface the type of the object or <code>null</code> if the property
444
     *         <code>cmis:objectTypeId</code> hasn't been requested or hasn't been provided by the repository
445
     */
446
    public function getType()
447
    {
448
        return $this->getObjectType();
449
    }
450
451
    /**
452
     * Returns the base type of this CMIS object (object type identified by cmis:baseTypeId).
453
     *
454
     * @return ObjectTypeInterface the base type of the object or <code>null</code> if the property cmis:baseTypeId
455
     *         hasn't been requested or hasn't been provided by the repository
456
     */
457
    public function getBaseType()
458
    {
459
        $baseType = $this->getBaseTypeId();
460
        if ($baseType === null) {
461
            return null;
462
        }
463
464
        return $this->getSession()->getTypeDefinition((string) $baseType);
465
    }
466
467
    /**
468
     * Returns the base type of this CMIS object (object type identified by cmis:baseTypeId).
469
     *
470
     * @return BaseTypeId|null the base type of the object or <code>null</code> if the property
471
     *         cmis:baseTypeId hasn't been requested or hasn't been provided by the repository
472
     */
473
    public function getBaseTypeId()
474
    {
475
        $baseTypeProperty = $this->getProperty(PropertyIds::BASE_TYPE_ID);
476
        if ($baseTypeProperty === null) {
477
            return null;
478
        }
479
480
        return BaseTypeId::cast($baseTypeProperty->getFirstValue());
481
    }
482
483
    /**
484
     * Returns the change token (CMIS property cmis:changeToken).
485
     *
486
     * @return string the change token of the object or <code>null</code> if the property hasn't been requested or
487
     *         hasn't been provided or isn't supported by the repository
488
     */
489
    public function getChangeToken()
490
    {
491
        return $this->getPropertyValue(PropertyIds::CHANGE_TOKEN);
492
    }
493
494
    /**
495
     * Returns the user who created this CMIS object (CMIS property cmis:createdBy).
496
     *
497
     * @return string the creator of the object or <code>null</code> if the property hasn't been requested or hasn't
498
     *         been provided by the repository
499
     */
500
    public function getCreatedBy()
501
    {
502
        return $this->getPropertyValue(PropertyIds::CREATED_BY);
503
    }
504
505
    /**
506
     * Returns the timestamp when this CMIS object has been created (CMIS property cmis:creationDate).
507
     *
508
     * @return \DateTime|null the creation time of the object or <code>null</code> if the property hasn't been
509
     *         requested or hasn't been provided by the repository
510
     */
511
    public function getCreationDate()
512
    {
513
        return $this->getPropertyValue(PropertyIds::CREATION_DATE);
514
    }
515
516
    /**
517
     * Returns the object ID
518
     *
519
     * @return string
520
     */
521
    public function getId()
522
    {
523
        return $this->getPropertyValue(PropertyIds::OBJECT_ID);
524
    }
525
526
    /**
527
     * Returns the timestamp when this CMIS object has been modified (CMIS property cmis:lastModificationDate).
528
     *
529
     * @return \DateTime|null the last modification date of the object or <code>null</code> if the property hasn't been
530
     *         requested or hasn't been provided by the repository
531
     */
532
    public function getLastModificationDate()
533
    {
534
        return $this->getPropertyValue(PropertyIds::LAST_MODIFICATION_DATE);
535
    }
536
537
    /**
538
     * Returns the user who modified this CMIS object (CMIS property cmis:lastModifiedBy).
539
     *
540
     * @return string|null the last modifier of the object or <code>null</code> if the property hasn't
541
     *         been requested or hasn't been provided by the repository
542
     */
543
    public function getLastModifiedBy()
544
    {
545
        return $this->getPropertyValue(PropertyIds::LAST_MODIFIED_BY);
546
    }
547
548
    /**
549
     * Returns the name of this CMIS object (CMIS property cmis:name).
550
     *
551
     * @return string|null the name of the object or <code>null</code> if the property hasn't been requested
552
     *         or hasn't been provided by the repository
553
     */
554
    public function getName()
555
    {
556
        return $this->getPropertyValue(PropertyIds::NAME);
557
    }
558
559
    /**
560
     * Returns the description of this CMIS object (CMIS property cmis:description).
561
     *
562
     * @return string|null the description of the object or <code>null</code> if the property hasn't been requested,
563
     *         hasn't been provided by the repository, or the property value isn't set
564
     */
565
    public function getDescription()
566
    {
567
        return $this->getPropertyValue(PropertyIds::DESCRIPTION);
568
    }
569
570
    /**
571
     * Returns a list of all available CMIS properties.
572
     *
573
     * @return PropertyInterface[] all available CMIS properties
574
     */
575
    public function getProperties()
576
    {
577
        return $this->properties;
578
    }
579
580
    /**
581
     * Returns a property.
582
     *
583
     * @param string $id the ID of the property
584
     * @return PropertyInterface|null the property or <code>null</code> if the property hasn't been requested or
585
     *         hasn't been provided by the repository
586
     */
587
    public function getProperty($id)
588
    {
589
        if (!isset($this->properties[$id])) {
590
            return null;
591
        }
592
593
        return $this->properties[$id];
594
    }
595
596
    /**
597
     * Returns the value of a property.
598
     *
599
     * @param string $id the ID of the property
600
     * @return mixed the property value or <code>null</code> if the property hasn't been requested,
601
     *         hasn't been provided by the repository, or the property value isn't set
602
     */
603
    public function getPropertyValue($id)
604
    {
605
        $property = $this->getProperty($id);
606
        if ($property === null) {
607
            return null;
608
        }
609
610
        return $property->isMultiValued() ? $property->getValues() : $property->getFirstValue();
611
    }
612
613
    /**
614
     * Returns the secondary types of this CMIS object (object types identified by cmis:secondaryObjectTypeIds).
615
     *
616
     * @return SecondaryTypeInterface[]|null the secondary types of the object or <code>null</code> if the property
617
     *         cmis:secondaryObjectTypeIds hasn't been requested or hasn't been provided by the repository
618
     */
619
    public function getSecondaryTypes()
620
    {
621
        return $this->secondaryTypes;
622
    }
623
624
    /**
625
     * Returns a list of primary and secondary object types that define the given property.
626
     *
627
     * @param string $id the ID of the property
628
     * @return ObjectTypeInterface[]|null a list of object types that define the given property or <code>null</code>
629
     *         if the property could not be found in the object types that are attached to this object
630
     */
631
    public function findObjectType($id)
632
    {
633
        $result = [];
634
635
        if ($this->getObjectType()->getPropertyDefinition($id) !== null) {
636
            $result[] = $this->getObjectType();
637
        }
638
639
        $secondaryTypes = $this->getSecondaryTypes();
640
        if ($secondaryTypes !== null) {
641
            foreach ($secondaryTypes as $secondaryType) {
642
                if ($secondaryType->getPropertyDefinition($id) !== null) {
643
                    $result[] = $secondaryType;
644
                }
645
            }
646
        }
647
648
        return empty($result) ? null : $result;
649
    }
650
651
    /**
652
     * Returns the allowable actions if they have been fetched for this object.
653
     *
654
     * @return AllowableActionsInterface|null
655
     */
656
    public function getAllowableActions()
657
    {
658
        return $this->allowableActions;
659
    }
660
661
    /**
662
     * Checks if the given action is an allowed action for the object
663
     *
664
     * @param Action $action
665
     * @return boolean
666
     */
667
    public function hasAllowableAction(Action $action)
668
    {
669
        $currentAllowableActions = $this->getAllowableActions();
670
        if ($currentAllowableActions === null || count($currentAllowableActions->getAllowableActions()) === 0) {
671
            throw new IllegalStateException('Allowable Actions are not available!');
672
        }
673
674
        return in_array($action, $currentAllowableActions->getAllowableActions(), false);
675
    }
676
677
    /**
678
     * Returns the renditions if they have been fetched for this object.
679
     *
680
     * @return RenditionInterface[]
681
     */
682
    public function getRenditions()
683
    {
684
        return $this->renditions;
685
    }
686
687
    /**
688
     * Adds and removes ACEs to the object and refreshes this object afterwards.
689
     *
690
     * @param AceInterface[] $addAces
691
     * @param AceInterface[] $removeAces
692
     * @param AclPropagation $aclPropagation
693
     * @return AclInterface the new ACL of this object
694
     */
695
    public function applyAcl(array $addAces, array $removeAces, AclPropagation $aclPropagation)
696
    {
697
        $result = $this->getSession()->applyAcl($this, $addAces, $removeAces, $aclPropagation);
698
699
        $this->refresh();
700
701
        return $result;
702
    }
703
704
    /**
705
     * Adds ACEs to the object and refreshes this object afterwards.
706
     *
707
     * @param AceInterface[] $addAces
708
     * @param AclPropagation $aclPropagation
709
     * @return AclInterface the new ACL of this object
710
     */
711
    public function addAcl(array $addAces, AclPropagation $aclPropagation)
712
    {
713
        return $this->applyAcl($addAces, [], $aclPropagation);
714
    }
715
716
    /**
717
     * Removes ACEs to the object and refreshes this object afterwards.
718
     *
719
     * @param array $removeAces
720
     * @param AclPropagation $aclPropagation
721
     * @return AclInterface the new ACL of this object
722
     */
723
    public function removeAcl(array $removeAces, AclPropagation $aclPropagation)
724
    {
725
        return $this->applyAcl([], $removeAces, $aclPropagation);
726
    }
727
728
    /**
729
     * Removes the direct ACE of this object, sets the provided ACEs to the object and refreshes this object afterwards.
730
     *
731
     * @param AceInterface[] $aces
732
     * @return AclInterface
733
     */
734
    public function setAcl(array $aces)
735
    {
736
        $result = $this->getSession()->setAcl($this, $aces);
737
738
        $this->refresh();
739
740
        return $result;
741
    }
742
743
    /**
744
     * Returns the ACL if it has been fetched for this object.
745
     *
746
     * @return AclInterface|null
747
     */
748
    public function getAcl()
749
    {
750
        return $this->acl;
751
    }
752
753
    /**
754
     * Returns all permissions for the given principal from the ACL.
755
     *
756
     * @param string $principalId the principal ID
757
     * @return string[] the set of permissions for this user, or an empty set if principal is not in the ACL
758
     * @throws IllegalStateException if the ACL hasn't been fetched or provided by the repository
759
     */
760
    public function getPermissionsForPrincipal($principalId)
761
    {
762
        if (empty($principalId)) {
763
            throw new IllegalStateException('Principal ID must be set!');
764
        }
765
766
        $currentAcl = $this->getAcl();
767
768
        if ($currentAcl === null) {
769
            throw new IllegalStateException('ACLs are not available');
770
        }
771
772
        $result = [];
773
774
        foreach ($currentAcl->getAces() as $ace) {
775
            if ($principalId === $ace->getPrincipalId() && count($ace->getPermissions()) > 0) {
776
                $result = array_merge($result, $ace->getPermissions());
777
            }
778
        }
779
780
        return $result;
781
    }
782
783
    /**
784
     * Applies the provided policies and refreshes this object afterwards.
785
     *
786
     * @param ObjectIdInterface[] $policyIds
787
     */
788
    public function applyPolicies(array $policyIds)
789
    {
790
        $this->getSession()->applyPolicies($this, $policyIds);
791
    }
792
793
    /**
794
     * Returns the applied policies if they have been fetched for this object.
795
     *
796
     * @return PolicyInterface[]
797
     */
798
    public function getPolicies()
799
    {
800
        $this->policies;
801
    }
802
803
    /**
804
     * Removes the provided policies and refreshes this object afterwards.
805
     *
806
     * @param ObjectIdInterface[] $policyIds
807
     */
808
    public function removePolicy(array $policyIds)
809
    {
810
        $this->getSession()->removePolicy($this, $policyIds);
811
    }
812
813
    /**
814
     * Returns the relationships if they have been fetched for this object.
815
     *
816
     * @return RelationshipInterface[]
817
     */
818
    public function getRelationships()
819
    {
820
        return $this->relationships;
821
    }
822
823
    /**
824
     * Returns the extensions for the given level.
825
     *
826
     * @param ExtensionLevel $level the level
827
     * @return array[]|null A list of <code>CmisExtensionElementInterface</code> at the requested level or
828
     *      <code>null</code> if there are no extensions for the requested level
829
     * @see CmisExtensionElementInterface
830
     */
831
    public function getExtensions(ExtensionLevel $level)
832
    {
833
        if (!isset($this->extensions[(string) $level])) {
834
            return null;
835
        }
836
837
        return $this->extensions[(string) $level];
838
    }
839
840
    /**
841
     * Returns the timestamp of the last refresh.
842
     *
843
     * @return integer returns the Java-style milliseconds UNIX timestamp of last refresh
844
     */
845
    public function getRefreshTimestamp()
846
    {
847
        return $this->refreshTimestamp;
848
    }
849
850
    /**
851
     * Reloads this object from the repository.
852
     *
853
     * @throws CmisObjectNotFoundException - if the object doesn't exist anymore in the repository
854
     */
855
    public function refresh()
856
    {
857
        $operationContext = $this->getCreationContext();
858
859
        $objectData = $this->getSession()->getBinding()->getObjectService()->getObject(
860
            $this->getRepositoryId(),
861
            $this->getId(),
862
            $operationContext->getQueryFilterString(),
863
            $operationContext->isIncludeAllowableActions(),
864
            $operationContext->getIncludeRelationships(),
865
            $operationContext->getRenditionFilterString(),
866
            $operationContext->isIncludePolicies(),
867
            $operationContext->isIncludeAcls(),
868
            null
869
        );
870
871
        $this->initialize(
872
            $this->getSession(),
873
            $this->getSession()->getTypeDefinition($this->getObjectType()->getId()),
874
            $this->creationContext,
875
            $objectData
876
        );
877
    }
878
879
    /**
880
     * Reloads the data from the repository if the last refresh did not occur within durationInMillis.
881
     *
882
     * @param integer $durationInMillis
883
     * @throws CmisObjectNotFoundException - if the object doesn't exist anymore in the repository
884
     */
885
    public function refreshIfOld($durationInMillis = 0)
886
    {
887
        if ($this->getRefreshTimestamp() < ((round(microtime(true) * 1000)) - (integer) $durationInMillis)) {
888
            $this->refresh();
889
        }
890
    }
891
}
892