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.

Session   F
last analyzed

Complexity

Total Complexity 102

Size/Duplication

Total Lines 1266
Duplicated Lines 5.13 %

Coupling/Cohesion

Components 2
Dependencies 26

Test Coverage

Coverage 22.91%

Importance

Changes 0
Metric Value
wmc 102
lcom 2
cbo 26
dl 65
loc 1266
ccs 93
cts 406
cp 0.2291
rs 0.8
c 0
b 0
f 0

50 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 46 8
A createObjectFactory() 0 23 4
A createDefaultObjectFactoryInstance() 0 4 1
A createCache() 0 28 4
A createDefaultCacheInstance() 0 4 1
A getCache() 0 4 1
A applyAcl() 0 8 1
A applyPolicies() 0 4 1
A bulkUpdateProperties() 0 8 1
A clear() 0 4 1
A createDocument() 0 36 4
B createDocumentFromSource() 0 49 6
A createFolder() 23 23 2
A createItem() 23 23 2
A createObjectId() 0 4 1
A createOperationContext() 0 30 3
A createPolicy() 0 9 1
A createQueryStatement() 0 15 3
A createRelationship() 0 24 3
A createType() 10 10 2
A delete() 0 9 1
A deleteType() 9 9 2
A getAcl() 0 4 1
A getBinding() 0 4 1
A getCheckedOutDocs() 0 4 1
A getCmisBindingHelper() 0 4 1
A getContentChanges() 0 21 2
A getContentStream() 0 10 1
A getDefaultContext() 0 4 1
A getLatestChangeLogToken() 0 4 1
A getLatestDocumentVersion() 0 7 1
A getLocale() 0 4 1
A getObject() 0 33 4
A getObjectByPath() 0 29 4
A getObjectFactory() 0 4 1
A getRelationships() 0 22 2
A getRepositoryInfo() 0 4 1
A getRepositoryId() 0 4 1
A getRootFolder() 0 15 3
A getTypeChildren() 0 10 1
A getTypeDefinition() 0 10 1
A getTypeDescendants() 0 9 1
A query() 0 35 5
B queryObjects() 0 60 8
A removeObjectFromCache() 0 4 1
A removePolicy() 0 4 1
A setAcl() 0 4 1
A setDefaultContext() 0 4 1
A updateType() 0 4 1
A convertTypeDefinition() 0 5 1

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 Session 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 Session, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Dkd\PhpCmis;
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\Bindings\CmisBindingsHelper;
15
use Dkd\PhpCmis\CmisObject\CmisObjectInterface;
16
use Dkd\PhpCmis\Data\AceInterface;
17
use Dkd\PhpCmis\Data\AclInterface;
18
use Dkd\PhpCmis\Data\BulkUpdateObjectIdAndChangeTokenInterface;
19
use Dkd\PhpCmis\Data\DocumentInterface;
20
use Dkd\PhpCmis\Data\FolderInterface;
21
use Dkd\PhpCmis\Data\ObjectDataInterface;
22
use Dkd\PhpCmis\Data\ObjectIdInterface;
23
use Dkd\PhpCmis\Data\ObjectTypeInterface;
24
use Dkd\PhpCmis\Data\PolicyInterface;
25
use Dkd\PhpCmis\Data\RelationshipInterface;
26
use Dkd\PhpCmis\Data\RepositoryInfoInterface;
27
use Dkd\PhpCmis\DataObjects\ObjectId;
28
use Dkd\PhpCmis\Definitions\TypeDefinitionContainerInterface;
29
use Dkd\PhpCmis\Definitions\TypeDefinitionInterface;
30
use Dkd\PhpCmis\Definitions\TypeDefinitionListInterface;
31
use Dkd\PhpCmis\Enum\AclPropagation;
32
use Dkd\PhpCmis\Enum\BaseTypeId;
33
use Dkd\PhpCmis\Enum\CmisVersion;
34
use Dkd\PhpCmis\Enum\IncludeRelationships;
35
use Dkd\PhpCmis\Enum\RelationshipDirection;
36
use Dkd\PhpCmis\Enum\Updatability;
37
use Dkd\PhpCmis\Enum\VersioningState;
38
use Dkd\PhpCmis\Exception\CmisInvalidArgumentException;
39
use Dkd\PhpCmis\Exception\CmisNotSupportedException;
40
use Dkd\PhpCmis\Exception\CmisObjectNotFoundException;
41
use Dkd\PhpCmis\Exception\CmisRuntimeException;
42
use Dkd\PhpCmis\Exception\IllegalStateException;
43
use Doctrine\Common\Cache\ArrayCache;
44
use Doctrine\Common\Cache\Cache;
45
use Doctrine\Common\Cache\CacheProvider;
46
use GuzzleHttp\Stream\StreamInterface;
47
48
/**
49
 * Class Session
50
 */
51
class Session implements SessionInterface
52
{
53
    /**
54
     * @var CmisBindingInterface
55
     */
56
    protected $binding;
57
58
    /**
59
     * @var Cache
60
     */
61
    protected $cache;
62
63
    /**
64
     * @var OperationContextInterface
65
     */
66
    private $defaultContext;
67
68
    /**
69
     * @var CmisBindingsHelper
70
     */
71
    protected $cmisBindingHelper;
72
73
    /**
74
     * @var ObjectFactoryInterface
75
     */
76
    private $objectFactory;
77
78
    /**
79
     * @var RepositoryInfoInterface
80
     */
81
    protected $repositoryInfo;
82
83
    /**
84
     * @var array
85
     */
86
    protected $parameters = [];
87
88
    /**
89
     * @var Cache
90
     */
91
    protected $typeDefinitionCache;
92
93
    /**
94
     * @var Cache
95
     */
96
    protected $objectTypeCache;
97
98
    /**
99
     * @var Updatability[]
100
     */
101
    protected static $createUpdatability = [];
102
103
    /**
104
     * @var Updatability[]
105
     */
106
    protected static $createAndCheckoutUpdatability = [];
107
108
    /**
109
     * @param array $parameters
110
     * @param ObjectFactoryInterface|null $objectFactory
111
     * @param Cache|null $cache
112
     * @param Cache|null $typeDefinitionCache
113
     * @param Cache|null $objectTypeCache
114
     * @param CmisBindingsHelper|null $cmisBindingHelper
115
     * @throws CmisInvalidArgumentException
116
     * @throws IllegalStateException
117
     */
118
    public function __construct(
119
        array $parameters,
120 11
        ObjectFactoryInterface $objectFactory = null,
121
        Cache $cache = null,
122
        Cache $typeDefinitionCache = null,
123
        Cache $objectTypeCache = null,
124
        CmisBindingsHelper $cmisBindingHelper = null
125
    ) {
126
        if (empty($parameters)) {
127
            throw new CmisInvalidArgumentException('No parameters provided!', 1408115280);
128 11
        }
129 1
130
        $this->parameters = $parameters;
131
        $this->objectFactory = $objectFactory === null ? $this->createObjectFactory() : $objectFactory;
132 10
        $this->cache = $cache === null ? $this->createCache() : $cache;
133 10
        $this->typeDefinitionCache = $typeDefinitionCache === null ? $this->createCache() : $typeDefinitionCache;
134 9
        $this->objectTypeCache = $objectTypeCache === null ? $this->createCache() : $objectTypeCache;
135 8
        $this->cmisBindingHelper = $cmisBindingHelper === null ? new CmisBindingsHelper() : $cmisBindingHelper;
136 8
137 8
        $this->defaultContext = new OperationContext();
138
        $this->defaultContext->setCacheEnabled(true);
139 8
140 8
        $this->binding = $this->getCmisBindingHelper()->createBinding(
141
            $this->parameters,
142 8
            $this->typeDefinitionCache
143 8
        );
144 8
145 8
        if (!isset($this->parameters[SessionParameter::REPOSITORY_ID])) {
146
            throw new IllegalStateException('Repository ID is not set!');
147 8
        }
148
149
        $this->repositoryInfo = $this->getBinding()->getRepositoryService()->getRepositoryInfo(
150
            $this->parameters[SessionParameter::REPOSITORY_ID]
151 8
        );
152 8
153 8
        self::$createUpdatability = [
154
            Updatability::cast(Updatability::ONCREATE),
155 8
            Updatability::cast(Updatability::READWRITE)
156 8
        ];
157 8
158 8
        self::$createAndCheckoutUpdatability = [
159
            Updatability::cast(Updatability::ONCREATE),
160 8
            Updatability::cast(Updatability::READWRITE),
161 8
            Updatability::cast(Updatability::WHENCHECKEDOUT)
162 8
        ];
163 8
    }
164 8
165 8
    /**
166
     * Create an object factory based on the SessionParameter::OBJECT_FACTORY_CLASS. If not set it returns an instance
167
     * of ObjectFactory.
168
     *
169
     * @return ObjectFactoryInterface
170
     * @throws \RuntimeException
171
     */
172
    protected function createObjectFactory()
173
    {
174 9
        try {
175
            if (isset($this->parameters[SessionParameter::OBJECT_FACTORY_CLASS])) {
176
                $objectFactoryClass = new $this->parameters[SessionParameter::OBJECT_FACTORY_CLASS];
177 9
            } else {
178 2
                $objectFactoryClass = $this->createDefaultObjectFactoryInstance();
179 2
            }
180 7
181
            if (!($objectFactoryClass instanceof ObjectFactoryInterface)) {
182
                throw new \RuntimeException('Class does not implement ObjectFactoryInterface!', 1408354119);
183 9
            }
184 1
185
            $objectFactoryClass->initialize($this, $this->parameters);
186
187 8
            return $objectFactoryClass;
188
        } catch (\Exception $exception) {
189 8
            throw new \RuntimeException(
190 1
                'Unable to create object factory: ' . $exception,
191 1
                1408354120
192 1
            );
193
        }
194 1
    }
195
196
    /**
197
     * Returns an instance of the ObjectFactory.
198
     * This methods is primarily required for unit testing.
199
     *
200
     * @return ObjectFactory
201
     */
202
    protected function createDefaultObjectFactoryInstance()
203
    {
204 6
        return new ObjectFactory();
205
    }
206 6
207
    /**
208
     * Create a cache instance based on the given session parameter SessionParameter::CACHE_CLASS.
209
     * If no session parameter SessionParameter::CACHE_CLASS is defined, the default Cache implementation will be used.
210
     *
211
     * @return Cache
212
     * @throws \InvalidArgumentException
213
     */
214
    protected function createCache()
215
    {
216 9
        try {
217
            if (isset($this->parameters[SessionParameter::CACHE_CLASS])) {
218
                $cache = new $this->parameters[SessionParameter::CACHE_CLASS];
219 9
            } else {
220 2
                $cache = $this->createDefaultCacheInstance();
221 2
            }
222 7
223
            if (!($cache instanceof CacheProvider)) {
224
                throw new \RuntimeException(
225 9
                    sprintf(
226 1
                        'Class %s does not subclass %s!',
227 1
                        get_class($cache),
228 1
                        CacheProvider::class
229 1
                    ),
230
                    1408354124
231 1
                );
232
            }
233 1
234
            return $cache;
235
        } catch (\Exception $exception) {
236 8
            throw new CmisInvalidArgumentException(
237 1
                'Unable to create cache: ' . $exception,
238 1
                1408354123
239 1
            );
240
        }
241 1
    }
242
243
    /**
244
     * Returns an instance of the Doctrine ArrayCache.
245
     * This methods is primarily required for unit testing.
246
     *
247
     * @return CacheProvider
248
     */
249
    protected function createDefaultCacheInstance()
250
    {
251 7
        return new ArrayCache();
252
    }
253 7
254
    /**
255
     * Get the cache instance
256
     *
257
     * @return CacheProvider
258
     */
259
    public function getCache()
260
    {
261 3
        return $this->cache;
262
    }
263 3
264
    /**
265
     * Applies ACL changes to an object and dependent objects. Only direct ACEs can be added and removed.
266
     *
267
     * @param ObjectIdInterface $objectId the ID the object
268
     * @param AceInterface[] $addAces of ACEs to be added or <code>null</code> if no ACEs should be added
269
     * @param AceInterface[] $removeAces list of ACEs to be removed or <code>null</code> if no ACEs should be removed
270
     * @param AclPropagation|null $aclPropagation value that defines the propagation of the ACE changes;
271
     *      <code>null</code> is equal to AclPropagation.REPOSITORYDETERMINED
272
     * @return AclInterface the new ACL of the object
273
     */
274
    public function applyAcl(
275
        ObjectIdInterface $objectId,
276
        $addAces = [],
277
        $removeAces = [],
278
        AclPropagation $aclPropagation = null
279
    ) {
280
        // TODO: Implement applyAcl() method.
281
    }
282
283
    /**
284
     * Applies a set of policies to an object.
285
     *
286
     * @param ObjectIdInterface $objectId the ID the object
287
     * @param ObjectIdInterface[] $policyIds the IDs of the policies to be applied
288
     * @return mixed
289
     */
290
    public function applyPolicies(ObjectIdInterface $objectId, array $policyIds)
291
    {
292
        // TODO: Implement applyPolicy() method.
293
    }
294
295
    /**
296
     * Updates multiple objects in one request.
297
     *
298
     * @param CmisObjectInterface[] $objects
299
     * @param mixed[] $properties
300
     * @param string[] $addSecondaryTypeIds
301
     * @param string[] $removeSecondaryTypeIds
302
     * @return BulkUpdateObjectIdAndChangeTokenInterface[]
303
     */
304
    public function bulkUpdateProperties(
305
        array $objects,
306
        array $properties,
307
        array $addSecondaryTypeIds,
308
        array $removeSecondaryTypeIds
309
    ) {
310
        // TODO: Implement bulkUpdateProperties() method.
311
    }
312
313
    /**
314
     * Clears all cached data.
315
     */
316
    public function clear()
317
    {
318
        $this->getCache()->flushAll();
319
    }
320
321
    /**
322
     * Creates a new document. The stream in contentStream is consumed but not closed by this method.
323
     *
324
     * @param string[] $properties The property values that MUST be applied to the newly-created document object.
325
     * @param ObjectIdInterface|null $folderId If specified, the identifier for the folder that MUST be the parent
326
     *      folder for the newly-created document object. This parameter MUST be specified if the repository does NOT
327
     *      support the optional "unfiling" capability.
328
     * @param StreamInterface|null $contentStream The content stream that MUST be stored for the newly-created document
329
     *      object. The method of passing the contentStream to the server and the encoding mechanism will be specified
330
     *      by each specific binding. MUST be required if the type requires it.
331
     * @param VersioningState|null $versioningState An enumeration specifying what the versioning state of the
332
     *     newly-created object MUST be. Valid values are:
333
     *      <code>none</code>
334
     *          (default, if the object-type is not versionable) The document MUST be created as a non-versionable
335
     *          document.
336
     *     <code>checkedout</code>
337
     *          The document MUST be created in the checked-out state. The checked-out document MAY be
338
     *          visible to other users.
339
     *     <code>major</code>
340
     *          (default, if the object-type is versionable) The document MUST be created as a major version.
341
     *     <code>minor</code>
342
     *          The document MUST be created as a minor version.
343
     * @param PolicyInterface[] $policies A list of policy ids that MUST be applied to the newly-created
344
     *      document object.
345
     * @param AceInterface[] $addAces A list of ACEs that MUST be added to the newly-created document object,
346
     *      either using the ACL from folderId if specified, or being applied if no folderId is specified.
347
     * @param AceInterface[] $removeAces A list of ACEs that MUST be removed from the newly-created document
348
     *      object, either using the ACL from folderId if specified, or being ignored if no folderId is specified.
349
     * @return ObjectIdInterface|null the object ID of the new document or <code>null</code> if the document could not
350
     *      be created.
351
     * @throws CmisInvalidArgumentException Throws an <code>CmisInvalidArgumentException</code> if empty
352
     *      property list is given
353
     */
354
    public function createDocument(
355
        array $properties,
356
        ObjectIdInterface $folderId = null,
357
        StreamInterface $contentStream = null,
358
        VersioningState $versioningState = null,
359
        array $policies = [],
360
        array $addAces = [],
361
        array $removeAces = []
362
    ) {
363
        if (empty($properties)) {
364
            throw new CmisInvalidArgumentException('Properties must not be empty!');
365
        }
366
367
        $objectId = $this->getBinding()->getObjectService()->createDocument(
368
            $this->getRepositoryId(),
369
            $this->getObjectFactory()->convertProperties(
370
                $properties,
371
                null,
372
                [],
373
                self::$createAndCheckoutUpdatability
374
            ),
375
            $folderId === null ? null : $folderId->getId(),
376
            $contentStream,
377
            $versioningState,
378
            $this->getObjectFactory()->convertPolicies($policies),
379
            $this->getObjectFactory()->convertAces($addAces),
380
            $this->getObjectFactory()->convertAces($removeAces),
381
            null
382
        );
383
384
        if ($objectId === null) {
385
            return null;
386
        }
387
388
        return $this->createObjectId($objectId);
389
    }
390
391
    /**
392
     * Creates a new document from a source document.
393
     *
394
     * @param ObjectIdInterface $source The identifier for the source document.
395
     * @param string[] $properties The property values that MUST be applied to the object. This list of properties
396
     *      SHOULD only contain properties whose values differ from the source document.
397
     * @param ObjectIdInterface|null $folderId If specified, the identifier for the folder that MUST be the parent
398
     *      folder for the newly-created document object. This parameter MUST be specified if the repository does NOT
399
     *      support the optional "unfiling" capability.
400
     * @param VersioningState|null $versioningState An enumeration specifying what the versioning state of the
401
     *     newly-created object MUST be. Valid values are:
402
     *      <code>none</code>
403
     *          (default, if the object-type is not versionable) The document MUST be created as a non-versionable
404
     *          document.
405
     *     <code>checkedout</code>
406
     *          The document MUST be created in the checked-out state. The checked-out document MAY be
407
     *          visible to other users.
408
     *     <code>major</code>
409
     *          (default, if the object-type is versionable) The document MUST be created as a major version.
410
     *     <code>minor</code>
411
     *          The document MUST be created as a minor version.
412
     * @param PolicyInterface[] $policies A list of policy ids that MUST be applied to the newly-created
413
     *      document object.
414
     * @param AceInterface[] $addAces A list of ACEs that MUST be added to the newly-created document object,
415
     *      either using the ACL from folderId if specified, or being applied if no folderId is specified.
416
     * @param AceInterface[] $removeAces A list of ACEs that MUST be removed from the newly-created document
417
     *      object, either using the ACL from folderId if specified, or being ignored if no folderId is specified.
418
     * @return ObjectIdInterface|null the object ID of the new document or <code>null</code> if the document could not
419
     *      be created.
420
     * @throws CmisInvalidArgumentException Throws an <code>CmisInvalidArgumentException</code> if empty
421
     *      property list is given
422
     */
423
    public function createDocumentFromSource(
424
        ObjectIdInterface $source,
425
        array $properties = [],
426
        ObjectIdInterface $folderId = null,
427
        VersioningState $versioningState = null,
428
        array $policies = [],
429
        array $addAces = [],
430
        array $removeAces = []
431
    ) {
432
        if (!$source instanceof CmisObjectInterface) {
433
            $sourceObject = $this->getObject($source);
434
        } else {
435
            $sourceObject = $source;
436
        }
437
438
        $type = $sourceObject->getType();
439
        $secondaryTypes = $sourceObject->getSecondaryTypes();
440
441
        if ($secondaryTypes === null) {
442
            $secondaryTypes = [];
443
        }
444
445
        if (!BaseTypeId::cast($type->getBaseTypeId())->equals(BaseTypeId::CMIS_DOCUMENT)) {
446
            throw new CmisInvalidArgumentException('Source object must be a document!');
447
        }
448
449
        $objectId = $this->getBinding()->getObjectService()->createDocumentFromSource(
450
            $this->getRepositoryId(),
451
            $source->getId(),
452
            $this->getObjectFactory()->convertProperties(
453
                $properties,
454
                $type,
455
                $secondaryTypes,
456
                self::$createAndCheckoutUpdatability
457
            ),
458
            $folderId === null ? null : $folderId->getId(),
459
            $versioningState,
460
            $this->getObjectFactory()->convertPolicies($policies),
461
            $this->getObjectFactory()->convertAces($addAces),
462
            $this->getObjectFactory()->convertAces($removeAces),
463
            null
464
        );
465
466
        if ($objectId === null) {
467
            return null;
468
        }
469
470
        return $this->createObjectId($objectId);
471
    }
472
473
    /**
474
     * Creates a new folder.
475
     *
476
     * @param string[] $properties
477
     * @param ObjectIdInterface $folderId
478
     * @param PolicyInterface[] $policies
479
     * @param AceInterface[] $addAces
480
     * @param AceInterface[] $removeAces
481
     * @return ObjectIdInterface the object ID of the new folder
482
     * @throws CmisInvalidArgumentException Throws an <code>CmisInvalidArgumentException</code> if empty
483
     *      property list is given
484
     */
485 View Code Duplication
    public function createFolder(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
486
        array $properties,
487
        ObjectIdInterface $folderId,
488
        array $policies = [],
489
        array $addAces = [],
490
        array $removeAces = []
491
    ) {
492
        if (empty($properties)) {
493
            throw new CmisInvalidArgumentException('Properties must not be empty!');
494
        }
495
496
        $objectId = $this->getBinding()->getObjectService()->createFolder(
497
            $this->getRepositoryId(),
498
            $this->getObjectFactory()->convertProperties($properties),
499
            $folderId->getId(),
500
            $this->getObjectFactory()->convertPolicies($policies),
501
            $this->getObjectFactory()->convertAces($addAces),
502
            $this->getObjectFactory()->convertAces($removeAces),
503
            null
504
        );
505
506
        return $this->createObjectId($objectId);
507
    }
508
509
    /**
510
     * Creates a new item.
511
     *
512
     * @param string[] $properties
513
     * @param ObjectIdInterface $folderId
514
     * @param PolicyInterface[] $policies
515
     * @param AceInterface[] $addAces
516
     * @param AceInterface[] $removeAces
517
     * @return ObjectIdInterface the object ID of the new item
518
     * @throws CmisInvalidArgumentException Throws an <code>CmisInvalidArgumentException</code> if empty
519
     *      property list is given
520
     */
521 View Code Duplication
    public function createItem(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
522
        array $properties,
523
        ObjectIdInterface $folderId,
524
        array $policies = [],
525
        array $addAces = [],
526
        array $removeAces = []
527
    ) {
528
        if (empty($properties)) {
529
            throw new CmisInvalidArgumentException('Properties must not be empty!');
530
        }
531
532
        $objectId = $this->getBinding()->getObjectService()->createItem(
533
            $this->getRepositoryId(),
534
            $this->getObjectFactory()->convertProperties($properties),
535
            $folderId->getId(),
536
            $this->getObjectFactory()->convertPolicies($policies),
537
            $this->getObjectFactory()->convertAces($addAces),
538
            $this->getObjectFactory()->convertAces($removeAces),
539
            null
540
        );
541
542
        return $this->createObjectId($objectId);
543
    }
544
545
    /**
546
     * Creates an object ID from a String.
547
     *
548
     * @param string $id
549
     * @return ObjectIdInterface the object ID object
550
     */
551
    public function createObjectId($id)
552
    {
553
        return new ObjectId($id);
554
    }
555
556
    /**
557
     * Creates a new operation context object with the given properties.
558
     *
559
     * @param string[] $filter the property filter, a comma separated string of query names or "*" for all
560
     *      properties or <code>null</code> to let the repository determine a set of properties
561
     * @param boolean $includeAcls indicates whether ACLs should be included or not
562
     * @param boolean $includeAllowableActions indicates whether Allowable Actions should be included or not
563
     * @param boolean $includePolicies indicates whether policies should be included or not
564
     * @param IncludeRelationships|null $includeRelationships enum that indicates if and which
565
     *      relationships should be includes
566
     * @param string[] $renditionFilter the rendition filter or <code>null</code> for no renditions
567
     * @param boolean $includePathSegments indicates whether path segment or the relative path segment should
568
     *      be included or not
569
     * @param string|null $orderBy the object order, a comma-separated list of query names and the ascending
570
     * modifier "ASC" or the descending modifier "DESC" for each query name
571
     * @param boolean $cacheEnabled flag that indicates if the object cache should be used
572
     * @param integer $maxItemsPerPage the max items per page/batch
573
     * @return OperationContextInterface the newly created operation context object
574
     */
575
    public function createOperationContext(
576
        $filter = [],
577
        $includeAcls = false,
578
        $includeAllowableActions = true,
579
        $includePolicies = false,
580
        IncludeRelationships $includeRelationships = null,
581
        array $renditionFilter = [],
582
        $includePathSegments = true,
583
        $orderBy = null,
584
        $cacheEnabled = false,
585
        $maxItemsPerPage = 100
586
    ) {
587
        $operationContext = new OperationContext();
588
        $operationContext->setFilter($filter);
589
        $operationContext->setIncludeAcls($includeAcls);
590
        $operationContext->setIncludeAllowableActions($includeAllowableActions);
591
        $operationContext->setIncludePolicies($includePolicies);
592
        if ($includeRelationships !== null) {
593
            $operationContext->setIncludeRelationships($includeRelationships);
594
        }
595
        $operationContext->setRenditionFilter($renditionFilter);
596
        $operationContext->setIncludePathSegments($includePathSegments);
597
        if (!empty($orderBy)) {
598
            $operationContext->setOrderBy($orderBy);
599
        }
600
        $operationContext->setCacheEnabled($cacheEnabled);
601
        $operationContext->setMaxItemsPerPage($maxItemsPerPage);
602
603
        return $operationContext;
604
    }
605
606
    /**
607
     * Creates a new policy.
608
     *
609
     * @param string[] $properties
610
     * @param ObjectIdInterface $folderId
611
     * @param PolicyInterface[] $policies
612
     * @param AceInterface[] $addAces
613
     * @param AceInterface[] $removeAces
614
     * @return ObjectIdInterface the object ID of the new policy
615
     */
616
    public function createPolicy(
617
        array $properties,
618
        ObjectIdInterface $folderId,
619
        array $policies = [],
620
        array $addAces = [],
621
        array $removeAces = []
622
    ) {
623
        // TODO: Implement createPolicy() method.
624
    }
625
626
    /**
627
     * Creates a query statement for a query of one primary type joined by zero or more secondary types.
628
     *
629
     * Generates something like this:
630
     * `SELECT d.cmis:name,s.SecondaryStringProp FROM cmis:document AS d JOIN MySecondaryType AS s ON
631
     * d.cmis:objectId=s.cmis:objectId WHERE d.cmis:name LIKE ? ORDER BY d.cmis:name,s.SecondaryIntegerProp`
632
     *
633
     * @param string[] $selectPropertyIds the property IDs in the SELECT statement,
634
     *      if <code>null</code> all properties are selected
635
     * @param string[] $fromTypes a Map of type aliases (keys) and type IDs (values), the Map must contain
636
     *      exactly one primary type and zero or more secondary types
637
     * @param string|null $whereClause an optional WHERE clause with placeholders ('?'), see QueryStatement for details
638
     * @param string[] $orderByPropertyIds an optional list of properties IDs for the ORDER BY clause
639
     * @return QueryStatementInterface a new query statement object
640
     * @throws CmisInvalidArgumentException
641
     */
642
    public function createQueryStatement(
643
        array $selectPropertyIds,
644 2
        array $fromTypes,
645
        $whereClause = null,
646
        array $orderByPropertyIds = []
647
    ) {
648
        if (empty($selectPropertyIds)) {
649
            throw new CmisInvalidArgumentException('Select property IDs must not be empty');
650 2
        }
651 1
        if (empty($fromTypes)) {
652
            throw new CmisInvalidArgumentException('From types must not be empty');
653 1
        }
654 1
655
        return new QueryStatement($this, null, $selectPropertyIds, $fromTypes, $whereClause, $orderByPropertyIds);
656
    }
657
658
    /**
659
     * Creates a new relationship between 2 objects.
660
     *
661
     * @param string[] $properties
662
     * @param PolicyInterface[] $policies
663
     * @param AceInterface[] $addAces
664
     * @param AceInterface[] $removeAces
665
     * @return ObjectIdInterface|null the object ID of the new relationship or <code>null</code> if the relationship
666
     *      could not be created
667
     */
668
    public function createRelationship(
669
        array $properties,
670
        array $policies = [],
671
        array $addAces = [],
672
        array $removeAces = []
673
    ) {
674
        if (empty($properties)) {
675
            throw new CmisInvalidArgumentException('Properties must not be empty!');
676
        }
677
678
        $newObjectId = $this->getBinding()->getObjectService()->createRelationship(
679
            $this->getRepositoryId(),
680
            $this->getObjectFactory()->convertProperties($properties, null, [], self::$createUpdatability),
681
            $this->getObjectFactory()->convertPolicies($policies),
682
            $this->getObjectFactory()->convertAces($addAces),
683
            $this->getObjectFactory()->convertAces($removeAces)
684
        );
685
686
        if ($newObjectId === null) {
687
            return null;
688
        }
689
690
        return $this->createObjectId($newObjectId);
691
    }
692
693
    /**
694
     * Creates a new type.
695
     *
696
     * @param TypeDefinitionInterface $type
697
     * @return ObjectTypeInterface the new type definition
698
     * @throws CmisNotSupportedException If repository version 1.0
699
     */
700 View Code Duplication
    public function createType(TypeDefinitionInterface $type)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
701
    {
702
        if ($this->getRepositoryInfo()->getCmisVersion() == CmisVersion::cast(CmisVersion::CMIS_1_0)) {
703
            throw new CmisNotSupportedException('This method is not supported for CMIS 1.0 repositories.');
704
        }
705
706
        return $this->convertTypeDefinition(
707
            $this->getBinding()->getRepositoryService()->createType($this->getRepositoryInfo()->getId(), $type)
708
        );
709
    }
710
711
    /**
712
     * Deletes an object and, if it is a document, all versions in the version series.
713
     *
714
     * @param ObjectIdInterface $objectId the ID of the object
715
     * @param boolean $allVersions if this object is a document this parameter defines
716
     *      if only this version or all versions should be deleted
717
     */
718
    public function delete(ObjectIdInterface $objectId, $allVersions = true)
719
    {
720
        $this->getBinding()->getObjectService()->deleteObject(
721
            $this->getRepositoryId(),
722
            $objectId->getId(),
723
            $allVersions
724
        );
725
        $this->removeObjectFromCache($objectId);
726
    }
727
728
    /**
729
     * Deletes a type.
730
     *
731
     * @param string $typeId the ID of the type to delete
732
     * @throws CmisNotSupportedException If repository version 1.0
733
     */
734 View Code Duplication
    public function deleteType($typeId)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
735
    {
736
        if ($this->getRepositoryInfo()->getCmisVersion() == CmisVersion::cast(CmisVersion::CMIS_1_0)) {
737
            throw new CmisNotSupportedException('This method is not supported for CMIS 1.0 repositories.');
738
        }
739
740
        $this->getBinding()->getRepositoryService()->deleteType($this->getRepositoryId(), $typeId);
741
        $this->removeObjectFromCache($this->createObjectId($typeId));
742
    }
743
744
    /**
745
     * Fetches the ACL of an object from the repository.
746
     *
747
     * @param ObjectIdInterface $objectId the ID the object
748
     * @param boolean $onlyBasicPermissions if <code>true</code> the repository should express the ACL only with the
749
     *      basic permissions defined in the CMIS specification; if <code>false</code> the repository can express the
750
     *      ACL with basic and repository specific permissions
751
     * @return AclInterface the ACL of the object
752
     */
753
    public function getAcl(ObjectIdInterface $objectId, $onlyBasicPermissions)
754
    {
755
        // TODO: Implement getAcl() method.
756
    }
757
758
    /**
759
     * Returns the underlying binding object.
760
     *
761
     * @return CmisBindingInterface the binding object
762
     */
763
    public function getBinding()
764
    {
765 8
        return $this->binding;
766
    }
767 8
768
    /**
769
     * Returns all checked out documents with the given OperationContext.
770
     *
771
     * @param OperationContextInterface|null $context
772
     * @return DocumentInterface[]
773
     */
774
    public function getCheckedOutDocs(OperationContextInterface $context = null)
775
    {
776
        // TODO: Implement getCheckedOutDocs() method.
777
    }
778
779
    /**
780
     * @return CmisBindingsHelper
781
     */
782
    protected function getCmisBindingHelper()
783
    {
784 8
        return $this->cmisBindingHelper;
785
    }
786 8
787
    /**
788
     * Returns the content changes.
789
     *
790
     * @param string $changeLogToken the change log token to start from or <code>null</code> to start from
791
     *      the first available event in the repository
792
     * @param boolean $includeProperties indicates whether changed properties should be included in the result or not
793
     * @param integer|null $maxNumItems maximum numbers of events
794
     * @param OperationContextInterface|null $context the OperationContext
795
     * @return ChangeEventsInterface the change events
796
     */
797
    public function getContentChanges(
798
        $changeLogToken,
799
        $includeProperties,
800
        $maxNumItems = null,
801
        OperationContextInterface $context = null
802
    ) {
803
        if ($context === null) {
804
            $context = $this->getDefaultContext();
805
        }
806
807
        $objectList = $this->getBinding()->getDiscoveryService()->getContentChanges(
808
            $this->getRepositoryInfo()->getId(),
809
            $changeLogToken,
810
            $includeProperties,
811
            $context->isIncludePolicies(),
812
            $context->isIncludeAcls(),
813
            $maxNumItems
814
        );
815
816
        return $this->getObjectFactory()->convertChangeEvents($changeLogToken, $objectList);
817
    }
818
819
    /**
820
     * Retrieves the main content stream of a document.
821
     *
822
     * @param ObjectIdInterface $docId the ID of the document
823
     * @param string|null $streamId the stream ID
824
     * @param integer|null $offset the offset of the stream or <code>null</code> to read the stream from the beginning
825
     * @param integer|null $length the maximum length of the stream or <code>null</code> to read to the end of the
826
     *      stream
827
     * @return StreamInterface|null the content stream or <code>null</code> if the
828
     *      document has no content stream
829
     */
830
    public function getContentStream(ObjectIdInterface $docId, $streamId = null, $offset = null, $length = null)
831
    {
832
        return $this->getBinding()->getObjectService()->getContentStream(
833
            $this->getRepositoryId(),
834
            $docId->getId(),
835
            $streamId,
836
            $offset,
837
            $length
838
        );
839
    }
840
841
    /**
842
     * Returns the current default operation parameters for filtering, paging and caching.
843
     *
844
     * @return OperationContextInterface the default operation context
845
     */
846
    public function getDefaultContext()
847
    {
848
        return $this->defaultContext;
849
    }
850 1
851
    /**
852 1
     * Returns the latest change log token.
853
     *
854
     * In contrast to the repository info, this change log token is *not cached*.
855
     * This method requests the token from the repository every single time it is called.
856
     *
857
     * @return string|null the latest change log token or <code>null</code> if the repository doesn't provide one
858
     */
859
    public function getLatestChangeLogToken()
860
    {
861
        // TODO: Implement getLatestChangeLogToken() method.
862
    }
863
864
    /**
865
     * Returns the latest version in a version series.
866
     *
867
     * @param ObjectIdInterface $objectId the document ID of an arbitrary version in the version series
868
     * @param boolean $major if <code>true</code> the latest major version will be returned,
869
     *      otherwise the very last version will be returned
870
     * @param OperationContextInterface|null $context the OperationContext to use
871
     * @return DocumentInterface the latest document version
872
     */
873
    public function getLatestDocumentVersion(
874
        ObjectIdInterface $objectId,
875
        $major = false,
876
        OperationContextInterface $context = null
877
    ) {
878
        // TODO: Implement getLatestDocumentVersion() method.
879
    }
880
881
    /**
882
     * Get the current locale to be used for this session.
883
     *
884
     * @return \Locale the current locale, may be <code>null</code>
885
     */
886
    public function getLocale()
887
    {
888
        // TODO: Implement getLocale() method.
889
    }
890
891
    /**
892
     * @param ObjectIdInterface $objectId the object ID
893
     * @param OperationContextInterface|null $context the OperationContext to use
894
     * @return CmisObjectInterface the requested object
895
     * @throws CmisObjectNotFoundException - if an object with the given ID doesn't exist
896
     */
897
    public function getObject(ObjectIdInterface $objectId, OperationContextInterface $context = null)
898
    {
899
        if ($context === null) {
900
            $context = $this->getDefaultContext();
901
        }
902
903
        $objectIdString = $objectId->getId();
904
        $cacheIdentity = $objectIdString . '|' . $context->getCacheKey();
905
906
        if ($this->getCache()->contains($cacheIdentity)) {
907
            return $this->getCache()->fetch($cacheIdentity);
908
        }
909
910
        $objectData = $this->getBinding()->getObjectService()->getObject(
911
            $this->getRepositoryInfo()->getId(),
912
            $objectIdString,
913
            $context->getQueryFilterString(),
914
            $context->isIncludeAllowableActions(),
915
            $context->getIncludeRelationships(),
916
            $context->getRenditionFilterString(),
917
            $context->isIncludePolicies(),
918
            $context->isIncludeAcls(),
919
            null
920
        );
921
922
        if (!$objectData instanceof ObjectDataInterface) {
923
            throw new CmisObjectNotFoundException('Could not find object for given id.');
924
        }
925
926
        $object = $this->getObjectFactory()->convertObject($objectData, $context);
927
        $this->getCache()->save($cacheIdentity, $object);
928
        return $object;
929
    }
930
931
    /**
932
     * Returns a CMIS object from the session cache. If the object is not in the cache or the given OperationContext
933
     * has caching turned off, it will load the object from the repository and puts it into the cache.
934
     * This method might return a stale object if the object has been found in the cache and has been changed in or
935
     * removed from the repository. Use CmisObject::refresh() and CmisObject::refreshIfOld() to update the object
936
     * if necessary.
937
     *
938
     * @param string $path the object path
939
     * @param OperationContextInterface|null $context the OperationContext to use
940
     * @return CmisObjectInterface Returns a CMIS object from the session cache.
941
     * @throws CmisInvalidArgumentException Throws an <code>CmisInvalidArgumentException</code>
942
     *      if path is empty.
943
     * @throws CmisObjectNotFoundException - if an object with the given path doesn't exist
944
     */
945
    public function getObjectByPath($path, OperationContextInterface $context = null)
946
    {
947
        if (empty($path)) {
948
            throw new CmisInvalidArgumentException('Path must not be empty.');
949
        }
950
951
        if ($context === null) {
952
            $context = $this->getDefaultContext();
953
        }
954
955
        $objectData = $this->getBinding()->getObjectService()->getObjectByPath(
956
            $this->getRepositoryInfo()->getId(),
957
            $path,
958
            $context->getQueryFilterString(),
959
            $context->isIncludeAllowableActions(),
960
            $context->getIncludeRelationships(),
961
            $context->getRenditionFilterString(),
962
            $context->isIncludePolicies(),
963
            $context->isIncludeAcls()
964
        );
965
966
        if (!$objectData instanceof ObjectDataInterface) {
967
            throw new CmisObjectNotFoundException(sprintf('Could not find object for given path "%s".', $path));
968
        }
969
970
        // TODO: Implement cache!
971
972
        return $this->getObjectFactory()->convertObject($objectData, $context);
973
    }
974
975
    /**
976
     * Gets a factory object that provides methods to create the objects used by this API.
977
     *
978
     * @return ObjectFactoryInterface the repository info
979
     */
980
    public function getObjectFactory()
981
    {
982
        return $this->objectFactory;
983
    }
984 3
985
    /**
986 3
     * Fetches the relationships from or to an object from the repository.
987
     *
988
     * @param ObjectIdInterface $objectId
989
     * @param boolean $includeSubRelationshipTypes
990
     * @param RelationshipDirection $relationshipDirection
991
     * @param ObjectTypeInterface $type
992
     * @param OperationContextInterface|null $context
993
     * @return RelationshipInterface[]
994
     */
995
    public function getRelationships(
996
        ObjectIdInterface $objectId,
997
        $includeSubRelationshipTypes,
998
        RelationshipDirection $relationshipDirection,
999 1
        ObjectTypeInterface $type,
1000
        OperationContextInterface $context = null
1001
    ) {
1002
1003
        if ($context === null) {
1004
            $context = $this->getDefaultContext();
1005
        }
1006
1007 1
        // TODO: Implement cache!
1008 1
1009 1
        return $this->getBinding()->getRelationshipService()->getObjectRelationships(
1010
            $this->getRepositoryId(),
1011
            $objectId->getId(),
1012
            $includeSubRelationshipTypes,
1013 1
            $relationshipDirection,
1014 1
            $type->getId()
1015 1
        );
1016 1
    }
1017 1
1018 1
    /**
1019 1
     * Returns the repository info of the repository associated with this session.
1020
     *
1021
     * @return RepositoryInfoInterface the repository info
1022
     */
1023
    public function getRepositoryInfo()
1024
    {
1025
        return $this->repositoryInfo;
1026
    }
1027 1
1028
    /**
1029 1
     * Returns the repository id.
1030
     *
1031
     * @return string the repository id
1032
     */
1033
    public function getRepositoryId()
1034
    {
1035
        return $this->getRepositoryInfo()->getId();
1036
    }
1037 1
1038
    /**
1039 1
     * Gets the root folder of the repository with the given OperationContext.
1040
     *
1041
     * @param OperationContextInterface|null $context
1042
     * @return FolderInterface the root folder object
1043
     * @throws CmisRuntimeException
1044
     */
1045
    public function getRootFolder(OperationContextInterface $context = null)
1046
    {
1047
        $rootFolderId = $this->getRepositoryInfo()->getRootFolderId();
1048
1049
        $rootFolder = $this->getObject(
1050
            $this->createObjectId($rootFolderId),
1051
            $context === null ? $this->getDefaultContext() : $context
1052
        );
1053
1054
        if (!($rootFolder instanceof FolderInterface)) {
1055
            throw new CmisRuntimeException('Root folder object is not a folder!', 1423735889);
1056
        }
1057
1058
        return $rootFolder;
1059
    }
1060
1061
    /**
1062
     * Gets the type children of a type.
1063
     *
1064
     * @param string $typeId the type ID or <code>null</code> to request the base types
1065
     * @param boolean $includePropertyDefinitions indicates whether the property definitions should be included or not
1066
     * @return TypeDefinitionListInterface the type iterator
1067
     * @throws CmisObjectNotFoundException - if a type with the given type ID doesn't exist
1068
     */
1069
    public function getTypeChildren($typeId, $includePropertyDefinitions)
1070
    {
1071
        return $this->getBinding()->getRepositoryService()->getTypeChildren(
1072
            $this->getRepositoryId(),
1073
            $typeId,
1074
            $includePropertyDefinitions,
1075
            999, // set max items to 999 - TODO: Implement CollectionIterable() method to iterate over all objects.
1076
            0 // TODO: Implement CollectionIterable() method to iterate over all objects.
1077
        );
1078
    }
1079
1080
    /**
1081
     * Gets the definition of a type.
1082
     *
1083
     * @param string $typeId the ID of the type
1084
     * @param boolean $useCache specifies if the type definition should be first looked up in the type definition
1085
     *     cache, if it is set to <code>false</code> or the type definition is not in the cache, the type definition is
1086
     *     loaded from the repository
1087
     * @return ObjectTypeInterface the type definition
1088
     * @throws CmisObjectNotFoundException - if a type with the given type ID doesn't exist
1089
     */
1090
    public function getTypeDefinition($typeId, $useCache = true)
1091
    {
1092
        // TODO: Implement cache!
1093
        $typeDefinition = $this->getBinding()->getRepositoryService()->getTypeDefinition(
1094
            $this->getRepositoryId(),
1095
            $typeId
1096
        );
1097
1098
        return $this->convertTypeDefinition($typeDefinition);
1099
    }
1100
1101
    /**
1102
     * Gets the type descendants of a type.
1103
     *
1104
     * @param string $typeId the type ID or <code>null</code> to request the base types
1105
     * @param integer $depth indicates whether the property definitions should be included or not
1106
     * @param boolean $includePropertyDefinitions the tree depth, must be greater than 0 or -1 for infinite depth
1107
     * @return TypeDefinitionContainerInterface[] A tree that contains ObjectTypeInterface objects
1108
     * @see ObjectTypeInterface ObjectTypeInterface contained in returned Tree
1109
     * @throws CmisObjectNotFoundException - if a type with the given type ID doesn't exist
1110
     */
1111
    public function getTypeDescendants($typeId, $depth, $includePropertyDefinitions)
1112
    {
1113
        return $this->getBinding()->getRepositoryService()->getTypeDescendants(
1114
            $this->getRepositoryId(),
1115
            $typeId,
1116
            (integer) $depth,
1117
            $includePropertyDefinitions
1118
        );
1119
    }
1120
1121
    /**
1122
     * Sends a query to the repository using the given OperationContext. (See CMIS spec "2.1.10 Query".)
1123
     *
1124
     * @param string $statement the query statement (CMIS query language)
1125
     * @param boolean $searchAllVersions specifies whether non-latest document versions should be included or not,
1126
     *      <code>true</code> searches all document versions, <code>false</code> only searches latest document versions
1127
     * @param OperationContextInterface|null $context the operation context to use
1128
     * @return QueryResultInterface[]
1129
     * @throws CmisInvalidArgumentException If statement is empty
1130
     */
1131
    public function query($statement, $searchAllVersions = false, OperationContextInterface $context = null)
1132
    {
1133
        if (empty($statement)) {
1134
            throw new CmisInvalidArgumentException('Statement must not be empty.');
1135
        }
1136
1137
        if ($context === null) {
1138
            $context = $this->getDefaultContext();
1139
        }
1140
1141
        $queryResults = [];
1142
        $skipCount = 0;
1143
1144
        $objectList = $this->getBinding()->getDiscoveryService()->query(
1145
            $this->getRepositoryInfo()->getId(),
1146
            $statement,
1147
            $searchAllVersions,
1148
            $context->getIncludeRelationships(),
1149
            $context->getRenditionFilterString(),
1150
            $context->isIncludeAllowableActions(),
1151
            $context->getMaxItemsPerPage(),
1152
            $skipCount
1153
        );
1154
1155
        foreach ($objectList->getObjects() as $objectData) {
1156
            $queryResult = $this->getObjectFactory()->convertQueryResult($objectData);
1157
            if ($queryResult instanceof QueryResultInterface) {
1158
                $queryResults[] = $queryResult;
1159
            }
1160
        }
1161
1162
        // TODO: Implement pagination using skipCount
1163
1164
        return $queryResults;
1165
    }
1166
1167
    /**
1168
     * Builds a CMIS query and returns the query results as an iterator of CmisObject objects.
1169
     *
1170
     * @param string $typeId the ID of the object type
1171
     * @param string|null $where the WHERE part of the query
1172
     * @param boolean $searchAllVersions specifies whether non-latest document versions should be included or not,
1173
     *      <code>true</code> searches all document versions, <code>false</code> only searches latest document versions
1174
     * @param OperationContextInterface|null $context the operation context to use
1175
     * @return CmisObjectInterface[]
1176
     * @throws CmisInvalidArgumentException If type id is empty
1177
     */
1178
    public function queryObjects(
1179
        $typeId,
1180
        $where = null,
1181
        $searchAllVersions = false,
1182
        OperationContextInterface $context = null
1183
    ) {
1184
        if (empty($typeId)) {
1185
            throw new CmisInvalidArgumentException('Type id must not be empty.');
1186
        }
1187
1188
        if ($context === null) {
1189
            $context = $this->getDefaultContext();
1190
        }
1191
1192
        $queryFilterString = $context->getQueryFilterString();
1193
        if (!empty($queryFilterString)) {
1194
            $querySelect = $queryFilterString;
1195
        } else {
1196
            $querySelect = '*';
1197
        }
1198
1199
        $whereClause = '';
1200
        if (!empty($where)) {
1201
            $whereClause = ' WHERE ' . $where;
1202
        }
1203
1204
        $orderBy = $context->getOrderBy();
1205
        if (!empty($orderBy)) {
1206
            $orderBy = ' ORDER BY ' . $orderBy;
1207
        }
1208
1209
        $typeDefinition = $this->getTypeDefinition($typeId);
1210
        $statement = 'SELECT ' . $querySelect . ' FROM ' . $typeDefinition->getQueryName() . $whereClause . $orderBy;
1211
        $queryStatement = new QueryStatement($this, $statement);
1212
1213
        $resultObjects = [];
1214
        $skipCount = 0;
1215
1216
        $objectList = $this->getBinding()->getDiscoveryService()->query(
1217
            $this->getRepositoryInfo()->getId(),
1218
            $queryStatement->toQueryString(),
1219
            $searchAllVersions,
1220
            $context->getIncludeRelationships(),
1221
            $context->getRenditionFilterString(),
1222
            $context->isIncludeAllowableActions(),
1223
            $context->getMaxItemsPerPage(),
1224
            $skipCount
1225
        );
1226
1227
        foreach ($objectList->getObjects() as $objectData) {
1228
            $object = $this->getObjectFactory()->convertObject($objectData, $context);
1229
            if ($object instanceof CmisObjectInterface) {
1230
                $resultObjects[] = $object;
1231
            }
1232
        }
1233
1234
        // TODO: Implement pagination using skipCount
1235
1236
        return $resultObjects;
1237
    }
1238
1239
    /**
1240
     * Removes the given object from the cache.
1241
     *
1242
     * Note about specific implementation: in order to avoid an over-engineered
1243
     * taggable cache mechanism and with it, extensive traversal of objects when
1244
     * creating tags, objects are not tagged in the cache. In addition, objects
1245
     * are added to the cache with a secondary identification; the context - and
1246
     * the context is not available here when removing a single object from the
1247
     * cache. Instead, we opt to simply flush the entire cache and let it refill.
1248
     *
1249
     * @param ObjectIdInterface $objectId
1250
     */
1251
    public function removeObjectFromCache(ObjectIdInterface $objectId)
1252
    {
1253
        $this->clear();
1254
    }
1255
1256
    /**
1257
     * Removes a set of policies from an object. This operation is not atomic.
1258
     * If it fails some policies might already be removed.
1259
     *
1260
     * @param ObjectIdInterface $objectId the ID the object
1261
     * @param ObjectIdInterface[] $policyIds the IDs of the policies to be removed
1262
     */
1263
    public function removePolicy(ObjectIdInterface $objectId, array $policyIds)
1264
    {
1265
        // TODO: Implement removePolicy() method.
1266
    }
1267
1268
    /**
1269
     * Removes the direct ACEs of an object and sets the provided ACEs.
1270
     * The changes are local to the given object and are not propagated to dependent objects.
1271
     *
1272
     * @param ObjectIdInterface $objectId
1273
     * @param AceInterface[] $aces
1274
     * @return AclInterface the new ACL of the object
1275
     */
1276
    public function setAcl(ObjectIdInterface $objectId, array $aces)
1277
    {
1278
        // TODO: Implement setAcl() method.
1279
    }
1280
1281
    /**
1282
     * Sets the current session parameters for filtering, paging and caching.
1283
     *
1284
     * @param OperationContextInterface $context the OperationContext to be used for the session;
1285
     *      if null, a default context is used
1286
     */
1287
    public function setDefaultContext(OperationContextInterface $context)
1288
    {
1289
        $this->defaultContext = $context;
1290
    }
1291
1292
    /**
1293
     * Updates an existing type.
1294
     *
1295
     * @param TypeDefinitionInterface $type the type definition updates
1296
     * @return ObjectTypeInterface the updated type definition
1297
     */
1298
    public function updateType(TypeDefinitionInterface $type)
1299
    {
1300
        // TODO: Implement updateType() method.
1301
    }
1302
1303
    /**
1304
     * Converts a type definition into an object type. If the object type is
1305
     * cached, it returns the cached object. Otherwise it creates an object type
1306
     * object and puts it into the cache.
1307
     *
1308
     * @param TypeDefinitionInterface $typeDefinition
1309
     * @return ObjectTypeInterface
1310
     */
1311
    private function convertTypeDefinition(TypeDefinitionInterface $typeDefinition)
1312
    {
1313
        // TODO: Implement cache. See Java Implementation for example
1314
        return $this->getObjectFactory()->convertTypeDefinition($typeDefinition);
1315
    }
1316
}
1317