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.
Completed
Pull Request — master (#3)
by
unknown
14:53 queued 10:33
created

ObjectService   F

Complexity

Total Complexity 91

Size/Duplication

Total Lines 885
Duplicated Lines 20.34 %

Coupling/Cohesion

Components 1
Dependencies 14

Test Coverage

Coverage 87.76%

Importance

Changes 21
Bugs 2 Features 6
Metric Value
wmc 91
c 21
b 2
f 6
lcom 1
cbo 14
dl 180
loc 885
ccs 258
cts 294
cp 0.8776
rs 1.5999

20 Methods

Rating   Name   Duplication   Size   Complexity  
A appendContentStream() 0 10 1
A bulkUpdateProperties() 0 10 1
B createDocument() 5 55 7
B createDocumentFromSource() 5 40 5
B createFolder() 29 29 3
B createItem() 5 34 4
A createPolicy() 0 11 1
B createRelationship() 28 28 3
D deleteContentStream() 12 38 9
A deleteObject() 0 16 2
B deleteTree() 0 26 4
A getAllowableActions() 0 4 1
B getContentStream() 0 32 6
C getObject() 36 36 7
C getObjectByPath() 36 36 7
B getProperties() 0 27 4
B getRenditions() 0 32 4
B moveObject() 0 25 3
D setContentStream() 12 45 10
D updateProperties() 12 35 9

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

1
<?php
2
namespace Dkd\PhpCmis\Bindings\Browser;
3
4
/**
5
 * This file is part of php-cmis-lib.
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\Constants;
14
use Dkd\PhpCmis\Data\AclInterface;
15
use Dkd\PhpCmis\Data\AllowableActionsInterface;
16
use Dkd\PhpCmis\Data\BulkUpdateObjectIdAndChangeTokenInterface;
17
use Dkd\PhpCmis\Data\ExtensionDataInterface;
18
use Dkd\PhpCmis\Data\FailedToDeleteDataInterface;
19
use Dkd\PhpCmis\Data\ObjectDataInterface;
20
use Dkd\PhpCmis\Data\PropertiesInterface;
21
use Dkd\PhpCmis\Data\RenditionDataInterface;
22
use Dkd\PhpCmis\Enum\IncludeRelationships;
23
use Dkd\PhpCmis\Enum\UnfileObject;
24
use Dkd\PhpCmis\Enum\VersioningState;
25
use Dkd\PhpCmis\Exception\CmisInvalidArgumentException;
26
use Dkd\PhpCmis\ObjectServiceInterface;
27
use Dkd\PhpCmis\PropertyIds;
28
use Dkd\PhpCmis\SessionParameter;
29
use GuzzleHttp\Post\PostFile;
30
use GuzzleHttp\Stream\LimitStream;
31
use GuzzleHttp\Message\Response;
32
use GuzzleHttp\Stream\StreamInterface;
33
34
/**
35
 * Object Service Browser Binding client.
36
 */
37
class ObjectService extends AbstractBrowserBindingService implements ObjectServiceInterface
38
{
39
    /**
40
     * Appends the content stream to the content of the document.
41
     *
42
     * The stream in contentStream is consumed but not closed by this method.
43
     *
44
     * @param string $repositoryId the identifier for the repository
45
     * @param string $objectId The identifier for the object. The repository might return a different/new object id
46
     * @param StreamInterface $contentStream The content stream to append
47
     * @param boolean $isLastChunk Indicates if this content stream is the last chunk
48
     * @param string|null $changeToken The last change token of this object that the client received.
49
     *      The repository might return a new change token (default is <code>null</code>)
50
     * @param ExtensionDataInterface|null $extension
51
     */
52
    public function appendContentStream(
53
        $repositoryId,
54
        & $objectId,
55
        StreamInterface $contentStream,
56
        $isLastChunk,
57
        & $changeToken = null,
58
        ExtensionDataInterface $extension = null
59
    ) {
60
        // TODO: Implement appendContentStream() method.
61
    }
62
63
    /**
64
     * Updates properties and secondary types of one or more objects.
65
     *
66
     * @param string $repositoryId the identifier for the repository
67
     * @param BulkUpdateObjectIdAndChangeTokenInterface[] $objectIdsAndChangeTokens
68
     * @param PropertiesInterface $properties
69
     * @param string[] $addSecondaryTypeIds the secondary types to apply
70
     * @param string[] $removeSecondaryTypeIds the secondary types to remove
71
     * @param ExtensionDataInterface|null $extension
72
     * @return BulkUpdateObjectIdAndChangeTokenInterface[]
73
     */
74
    public function bulkUpdateProperties(
75
        $repositoryId,
76
        array $objectIdsAndChangeTokens,
77
        PropertiesInterface $properties,
78
        array $addSecondaryTypeIds,
79
        array $removeSecondaryTypeIds,
80
        ExtensionDataInterface $extension = null
81
    ) {
82
        // TODO: Implement bulkUpdateProperties() method.
83
    }
84
85
    /**
86
     * Creates a document object of the specified type (given by the cmis:objectTypeId property)
87
     * in the (optionally) specified location.
88
     *
89
     * @param string $repositoryId the identifier for the repository
90
     * @param PropertiesInterface $properties the property values that must be applied to the newly
91
     *      created document object
92
     * @param string|null $folderId if specified, the identifier for the folder that must be the parent
93
     *      folder for the newly created document object
94
     * @param StreamInterface|null $contentStream the content stream that must be stored for the newly
95
     *      created document object
96
     * @param VersioningState|null $versioningState specifies what the versioning state of the newly created object
97
     *      must be (default is <code>VersioningState::MAJOR</code>)
98
     * @param string[] $policies a list of policy IDs that must be applied to the newly created document object
99
     * @param AclInterface|null $addAces a list of ACEs that must be added to the newly created document object,
100
     *      either using the ACL from folderId if specified, or being applied if no folderId is specified
101
     * @param AclInterface|null $removeAces a list of ACEs that must be removed from the newly created document object,
102
     *      either using the ACL from folderId if specified, or being ignored if no folderId is specified
103
     * @param ExtensionDataInterface|null $extension
104
     * @return string|null Returns the new object id or <code>null</code> if the repository sent an empty
105
     *      result (which should not happen)
106
     */
107 3
    public function createDocument(
108
        $repositoryId,
109
        PropertiesInterface $properties,
110
        $folderId = null,
111
        StreamInterface $contentStream = null,
112
        VersioningState $versioningState = null,
113
        array $policies = array(),
114
        AclInterface $addAces = null,
115
        AclInterface $removeAces = null,
116
        ExtensionDataInterface $extension = null
117
    ) {
118 3 View Code Duplication
        if ($folderId === null) {
119 1
            $url = $this->getRepositoryUrl($repositoryId);
120 1
        } else {
121 2
            $url = $this->getObjectUrl($repositoryId, $folderId);
122
        }
123
124 3
        $url->getQuery()->modify(
125
            array(
126 3
                Constants::CONTROL_CMISACTION => Constants::CMISACTION_CREATE_DOCUMENT,
127 3
                Constants::PARAM_SUCCINCT => $this->getSuccinct() ? 'true' : 'false'
128 3
            )
129 3
        );
130
131 3
        if ($versioningState !== null) {
132 2
            $url->getQuery()->modify(array(Constants::PARAM_VERSIONING_STATE => (string) $versioningState));
133 2
        }
134
135 3
        $this->appendAddAcesToUrl($url, $addAces);
136 3
        $this->appendRemoveAcesToUrl($url, $removeAces);
137 3
        $this->appendPoliciesToUrl($url, $policies);
138
139
        // Guzzle gets the mime type for a file by the filename extension. Sometimes the filename does not contain
140
        // the correct filename extension for example when a file is uploaded in php it gets a temporary name without
141
        // a file extension. If the filename does not contain a file extension we use the given 'cmis:name' property
142
        // as filename. See also https://github.com/guzzle/guzzle/issues/571
143 3
        if ($contentStream !== null && pathinfo($contentStream->getMetadata('uri'), PATHINFO_EXTENSION) === '') {
144 1
            $contentStream = new PostFile(
145 1
                'content',
146 1
                $contentStream,
147 1
                $properties->getProperties()['cmis:name']->getFirstValue()
148 1
            );
149 1
        }
150
151 3
        $queryArray = $this->convertPropertiesToQueryArray($properties);
152 3
        $queryArray['content'] = $contentStream;
153 3
        $responseData = $this->post(
154 3
            $url,
155
            $queryArray
156 3
        )->json();
157
158
        $newObject = $this->getJsonConverter()->convertObject($responseData);
159
160
        return ($newObject === null) ? null : $newObject->getId();
161
    }
162
163
    /**
164
     * Creates a document object as a copy of the given source document in the (optionally) specified location.
165
     *
166
     * @param string $repositoryId the identifier for the repository
167
     * @param string $sourceId the identifier for the source document
168
     * @param PropertiesInterface $properties the property values that must be applied to the newly
169
     *      created document object
170
     * @param string|null $folderId if specified, the identifier for the folder that must be the parent folder for the
171
     *      newly created document object
172
     * @param VersioningState|null $versioningState specifies what the versioning state of the newly created object
173
     *      must be (default is <code>VersioningState::MAJOR</code>)
174
     * @param string[] $policies a list of policy IDs that must be applied to the newly created document object
175
     * @param AclInterface|null $addAces a list of ACEs that must be added to the newly created document object,
176
     *      either using the ACL from folderId if specified, or being applied if no folderId is specified
177
     * @param AclInterface|null $removeAces a list of ACEs that must be removed from the newly created document object,
178
     *      either using the ACL from folderId if specified, or being ignored if no folderId is specified
179
     * @param ExtensionDataInterface|null $extension
180
     * @return string|null Returns the new object id or <code>null</code> if the repository sent an empty
181
     *      result (which should not happen)
182
     */
183 2
    public function createDocumentFromSource(
184
        $repositoryId,
185
        $sourceId,
186
        PropertiesInterface $properties,
187
        $folderId = null,
188
        VersioningState $versioningState = null,
189
        array $policies = array(),
190
        AclInterface $addAces = null,
191
        AclInterface $removeAces = null,
192
        ExtensionDataInterface $extension = null
193
    ) {
194 2 View Code Duplication
        if ($folderId === null) {
195
            $url = $this->getRepositoryUrl($repositoryId);
196
        } else {
197 2
            $url = $this->getObjectUrl($repositoryId, $folderId);
198
        }
199
200 2
        $url->getQuery()->modify($this->convertPropertiesToQueryArray($properties));
201 2
        $url->getQuery()->modify(
202
            array(
203 2
                Constants::CONTROL_CMISACTION => Constants::CMISACTION_CREATE_DOCUMENT_FROM_SOURCE,
204 2
                Constants::PARAM_SUCCINCT => $this->getSuccinct() ? 'true' : 'false',
205 2
                Constants::PARAM_SOURCE_ID => (string) $sourceId
206 2
            )
207 2
        );
208
209 2
        if ($versioningState !== null) {
210 1
            $url->getQuery()->modify(array(Constants::PARAM_VERSIONING_STATE => (string) $versioningState));
211 1
        }
212
213 2
        $this->appendAddAcesToUrl($url, $addAces);
214 2
        $this->appendRemoveAcesToUrl($url, $removeAces);
215 2
        $this->appendPoliciesToUrl($url, $policies);
216
217 2
        $responseData = $this->post($url)->json();
218
219 2
        $newObject = $this->getJsonConverter()->convertObject($responseData);
220
221 2
        return ($newObject === null) ? null : $newObject->getId();
222
    }
223
224
    /**
225
     * Creates a folder object of the specified type (given by the cmis:objectTypeId property) in
226
     * the specified location.
227
     *
228
     * @param string $repositoryId the identifier for the repository
229
     * @param PropertiesInterface $properties the property values that must be applied to the newly
230
     *      created document object
231
     * @param string $folderId if specified, the identifier for the folder that must be the parent folder for the
232
     *      newly created document object
233
     * @param string[] $policies a list of policy IDs that must be applied to the newly created document object
234
     * @param AclInterface|null $addAces a list of ACEs that must be added to the newly created document object,
235
     *      either using the ACL from folderId if specified, or being applied if no folderId is specified
236
     * @param AclInterface|null $removeAces a list of ACEs that must be removed from the newly created document object,
237
     *      either using the ACL from folderId if specified, or being ignored if no folderId is specified
238
     * @param ExtensionDataInterface|null $extension
239
     * @return string|null Returns the new object id or <code>null</code> if the repository sent an empty
240
     *      result (which should not happen)
241
     */
242 2 View Code Duplication
    public function createFolder(
243
        $repositoryId,
244
        PropertiesInterface $properties,
245
        $folderId,
246
        array $policies = array(),
247
        AclInterface $addAces = null,
248
        AclInterface $removeAces = null,
249
        ExtensionDataInterface $extension = null
250
    ) {
251 2
        $url = $this->getObjectUrl($repositoryId, $folderId);
252 2
        $url->getQuery()->modify(
253
            array(
254 2
                Constants::CONTROL_CMISACTION => Constants::CMISACTION_CREATE_FOLDER,
255 2
                Constants::PARAM_SUCCINCT => $this->getSuccinct() ? 'true' : 'false'
256 2
            )
257 2
        );
258
259 2
        $url->getQuery()->modify($this->convertPropertiesToQueryArray($properties));
260
261 2
        $this->appendPoliciesToUrl($url, $policies);
262 2
        $this->appendAddAcesToUrl($url, $addAces);
263 2
        $this->appendRemoveAcesToUrl($url, $removeAces);
264
265 2
        $responseData = $this->post($url)->json();
266
267 2
        $newObject = $this->getJsonConverter()->convertObject($responseData);
268
269 2
        return ($newObject === null) ? null : $newObject->getId();
270
    }
271
272
    /**
273
     * Creates an item object of the specified type (given by the cmis:objectTypeId property).
274
     *
275
     * @param string $repositoryId The identifier for the repository
276
     * @param PropertiesInterface $properties The property values that must be applied to the newly
277
     *      created document object
278
     * @param string|null $folderId If specified, the identifier for the folder that must be the parent folder for the
279
     *      newly created document object
280
     * @param string[] $policies A list of policy IDs that must be applied to the newly created document object
281
     * @param AclInterface|null $addAces A list of ACEs that must be added to the newly created document object,
282
     *      either using the ACL from folderId if specified, or being applied if no folderId is specified
283
     * @param AclInterface|null $removeAces A list of ACEs that must be removed from the newly created document object,
284
     *      either using the ACL from folderId if specified, or being ignored if no folderId is specified
285
     * @param ExtensionDataInterface|null $extension
286
     * @return string|null Returns the new item id or <code>null</code> if the repository sent an empty
287
     *      result (which should not happen)
288
     */
289 2
    public function createItem(
290
        $repositoryId,
291
        PropertiesInterface $properties,
292
        $folderId = null,
293
        array $policies = array(),
294
        AclInterface $addAces = null,
295
        AclInterface $removeAces = null,
296
        ExtensionDataInterface $extension = null
297
    ) {
298 2 View Code Duplication
        if ($folderId === null) {
299
            $url = $this->getRepositoryUrl($repositoryId);
300
        } else {
301 2
            $url = $this->getObjectUrl($repositoryId, $folderId);
302
        }
303
304 2
        $url->getQuery()->modify(
305
            array(
306 2
                Constants::CONTROL_CMISACTION => Constants::CMISACTION_CREATE_ITEM,
307 2
                Constants::PARAM_SUCCINCT => $this->getSuccinct() ? 'true' : 'false'
308 2
            )
309 2
        );
310
311 2
        $url->getQuery()->modify($this->convertPropertiesToQueryArray($properties));
312
313 2
        $this->appendPoliciesToUrl($url, $policies);
314 2
        $this->appendAddAcesToUrl($url, $addAces);
315 2
        $this->appendRemoveAcesToUrl($url, $removeAces);
316
317 2
        $responseData = $this->post($url)->json();
318
319 2
        $newObject = $this->getJsonConverter()->convertObject($responseData);
320
321 2
        return ($newObject === null) ? null : $newObject->getId();
322
    }
323
324
    /**
325
     * Creates a policy object of the specified type (given by the cmis:objectTypeId property).
326
     *
327
     * @param string $repositoryId The identifier for the repository
328
     * @param PropertiesInterface $properties The property values that must be applied to the newly
329
     *      created document object
330
     * @param string|null $folderId If specified, the identifier for the folder that must be the parent folder for the
331
     *      newly created document object
332
     * @param string[] $policies A list of policy IDs that must be applied to the newly created document object
333
     * @param AclInterface|null $addAces A list of ACEs that must be added to the newly created document object,
334
     *      either using the ACL from folderId if specified, or being applied if no folderId is specified
335
     * @param AclInterface|null $removeAces A list of ACEs that must be removed from the newly created document object,
336
     *      either using the ACL from folderId if specified, or being ignored if no folderId is specified
337
     * @param ExtensionDataInterface|null $extension
338
     * @return string The id of the newly-created policy.
339
     */
340
    public function createPolicy(
341
        $repositoryId,
342
        PropertiesInterface $properties,
343
        $folderId = null,
344
        array $policies = array(),
345
        AclInterface $addAces = null,
346
        AclInterface $removeAces = null,
347
        ExtensionDataInterface $extension = null
348
    ) {
349
        // TODO: Implement createPolicy() method.
350
    }
351
352
    /**
353
     * Creates a relationship object of the specified type (given by the cmis:objectTypeId property).
354
     *
355
     * @param string $repositoryId the identifier for the repository
356
     * @param PropertiesInterface $properties the property values that must be applied to the newly
357
     *      created document object
358
     * @param string[] $policies a list of policy IDs that must be applied to the newly created document object
359
     * @param AclInterface|null $addAces a list of ACEs that must be added to the newly created document object,
360
     *      either using the ACL from folderId if specified, or being applied if no folderId is specified
361
     * @param AclInterface|null $removeAces a list of ACEs that must be removed from the newly created document object,
362
     *      either using the ACL from folderId if specified, or being ignored if no folderId is specified
363
     * @param ExtensionDataInterface|null $extension
364
     * @return string|null Returns the new item id of the relationship object or <code>null</code> if the repository
365
     *      sent an empty result (which should not happen)
366
     */
367 View Code Duplication
    public function createRelationship(
368
        $repositoryId,
369
        PropertiesInterface $properties,
370
        array $policies = array(),
371
        AclInterface $addAces = null,
372
        AclInterface $removeAces = null,
373
        ExtensionDataInterface $extension = null
374
    ) {
375
        $url = $this->getRepositoryUrl($repositoryId);
376
377
        $url->getQuery()->modify(
378
            array(
379
                Constants::CONTROL_CMISACTION => Constants::CMISACTION_CREATE_RELATIONSHIP,
380
                Constants::PARAM_SUCCINCT => $this->getSuccinct() ? 'true' : 'false'
381
            )
382
        );
383
384
        $url->getQuery()->modify($this->convertPropertiesToQueryArray($properties));
385
        $this->appendPoliciesToUrl($url, $policies);
386
        $this->appendAddAcesToUrl($url, $addAces);
387
        $this->appendRemoveAcesToUrl($url, $removeAces);
388
389
        $responseData = $this->post($url)->json();
390
391
        $newObject = $this->getJsonConverter()->convertObject($responseData);
392
393
        return ($newObject === null) ? null : $newObject->getId();
394
    }
395
396
    /**
397
     * Deletes the content stream for the specified document object.
398
     *
399
     * @param string $repositoryId the identifier for the repository
400
     * @param string $objectId the identifier for the object. The repository might return a different/new object id
401
     * @param string|null $changeToken the last change token of this object that the client received.
402
     *      The repository might return a new change token (default is <code>null</code>)
403
     * @param ExtensionDataInterface|null $extension
404
     * @throws CmisInvalidArgumentException If $objectId is empty
405
     */
406 3
    public function deleteContentStream(
407
        $repositoryId,
408
        & $objectId,
409
        & $changeToken = null,
410
        ExtensionDataInterface $extension = null
411
    ) {
412 3
        if (empty($objectId)) {
413
            throw new CmisInvalidArgumentException('Object id must not be empty!');
414
        }
415
416 3
        $url = $this->getObjectUrl($repositoryId, $objectId);
417
418 3
        $url->getQuery()->modify(
419
            array(
420 3
                Constants::CONTROL_CMISACTION => Constants::CMISACTION_DELETE_CONTENT,
421 3
                Constants::PARAM_SUCCINCT => $this->getSuccinct() ? 'true' : 'false'
422 3
            )
423 3
        );
424
425 3 View Code Duplication
        if ($changeToken !== null && !$this->getSession()->get(SessionParameter::OMIT_CHANGE_TOKENS, false)) {
426 1
            $url->getQuery()->modify(array(Constants::PARAM_CHANGE_TOKEN => $changeToken));
427 1
        }
428
429 3
        $responseData = $this->post($url)->json();
430 3
        $newObject = $this->getJsonConverter()->convertObject($responseData);
431
432
        // $objectId was passed by reference. The value is changed here to new object id
433 3
        $objectId = null;
434 3 View Code Duplication
        if ($newObject !== null) {
435 3
            $objectId = $newObject->getId();
436 3
            $newObjectProperties = $newObject->getProperties()->getProperties();
437 3
            if ($changeToken !== null && count($newObjectProperties) > 0) {
438 2
                $newChangeToken = $newObjectProperties[PropertyIds::CHANGE_TOKEN];
439
                // $changeToken was passed by reference. The value is changed here
440 2
                $changeToken = $newChangeToken === null ? null : $newChangeToken->getFirstValue();
441 2
            }
442 3
        }
443 3
    }
444
445
    /**
446
     * Deletes the specified object.
447
     *
448
     * @param string $repositoryId the identifier for the repository
449
     * @param string $objectId the identifier for the object
450
     * @param boolean $allVersions If <code>true</code> then delete all versions of the document, otherwise delete only
451
     *      the document object specified (default is <code>true</code>)
452
     * @param ExtensionDataInterface|null $extension
453
     */
454 2
    public function deleteObject(
455
        $repositoryId,
456
        $objectId,
457
        $allVersions = true,
458
        ExtensionDataInterface $extension = null
459
    ) {
460 2
        $url = $this->getObjectUrl($repositoryId, $objectId);
461 2
        $url->getQuery()->modify(
462
            array(
463 2
                Constants::CONTROL_CMISACTION => Constants::CMISACTION_DELETE,
464 2
                Constants::PARAM_ALL_VERSIONS => $allVersions ? 'true' : 'false',
465
            )
466 2
        );
467
468 2
        $this->post($url);
469 2
    }
470
471
    /**
472
     * Deletes the specified folder object and all of its child- and descendant-objects.
473
     *
474
     * @param string $repositoryId the identifier for the repository
475
     * @param string $folderId the identifier for the folder
476
     * @param boolean $allVersions If <code>true</code> then delete all versions of the document, otherwise delete only
477
     *      the document object specified (default is <code>true</code>)
478
     * @param UnfileObject|null $unfileObjects defines how the repository must process file-able child- or
479
     *      descendant-objects (default is <code>UnfileObject::DELETE</code>)
480
     * @param boolean $continueOnFailure If <code>true</code>, then the repository should continue attempting to
481
     *      perform this operation even if deletion of a child- or descendant-object in the specified folder cannot
482
     *      be deleted
483
     * @param ExtensionDataInterface|null $extension
484
     * @return FailedToDeleteDataInterface Returns a list of object ids that could not be deleted
485
     */
486 4
    public function deleteTree(
487
        $repositoryId,
488
        $folderId,
489
        $allVersions = true,
490
        UnfileObject $unfileObjects = null,
491
        $continueOnFailure = false,
492
        ExtensionDataInterface $extension = null
493
    ) {
494 4
        $url = $this->getObjectUrl($repositoryId, $folderId);
495 4
        $url->getQuery()->modify(
496
            array(
497 4
                Constants::CONTROL_CMISACTION => Constants::CMISACTION_DELETE_TREE,
498 4
                Constants::PARAM_FOLDER_ID => $folderId,
499 4
                Constants::PARAM_ALL_VERSIONS => $allVersions ? 'true' : 'false',
500 4
                Constants::PARAM_CONTINUE_ON_FAILURE => $continueOnFailure ? 'true' : 'false'
501 4
            )
502 4
        );
503
504 4
        if ($unfileObjects !== null) {
505 1
            $url->getQuery()->modify(array(Constants::PARAM_UNFILE_OBJECTS => (string) $unfileObjects));
506 1
        }
507
508 4
        $response = $this->post($url);
509
510 4
        return $this->getJsonConverter()->convertFailedToDelete((array) $response->json());
511
    }
512
513
    /**
514
     * Gets the list of allowable actions for an object.
515
     *
516
     * @param string $repositoryId the identifier for the repository
517
     * @param string $objectId the identifier for the object
518
     * @param ExtensionDataInterface|null $extension
519
     * @return AllowableActionsInterface
520
     */
521
    public function getAllowableActions($repositoryId, $objectId, ExtensionDataInterface $extension = null)
522
    {
523
        // TODO: Implement getAllowableActions() method.
524
    }
525
526
    /**
527
     * Gets the content stream for the specified document object, or gets a rendition stream for
528
     * a specified rendition of a document or folder object.
529
     *
530
     * @param string $repositoryId the identifier for the repository
531
     * @param string $objectId the identifier for the object
532
     * @param string|null $streamId The identifier for the rendition stream, when used to get a rendition stream.
533
     *      For documents, if not provided then this method returns the content stream. For folders,
534
     *      it MUST be provided.
535
     * @param integer|null $offset
536
     * @param integer|null $length
537
     * @param ExtensionDataInterface|null $extension
538
     * @return StreamInterface|null
539
     * @throws CmisInvalidArgumentException If object id is empty
540
     */
541 3
    public function getContentStream(
542
        $repositoryId,
543
        $objectId,
544
        $streamId = null,
545
        $offset = null,
546
        $length = null,
547
        ExtensionDataInterface $extension = null
548
    ) {
549 3
        if (empty($objectId)) {
550
            throw new CmisInvalidArgumentException('Object id must not be empty!');
551
        }
552
553 3
        $url = $this->getObjectUrl($repositoryId, $objectId, Constants::SELECTOR_CONTENT);
554
555 3
        if ($streamId !== null) {
556 1
            $url->getQuery()->modify(array(Constants::PARAM_STREAM_ID => $streamId));
557 1
        }
558
559
        /** @var Response $response */
560 3
        $response = $this->getHttpInvoker()->get($url);
561
562 3
        $contentStream = $response->getBody();
563 3
        if (!$contentStream instanceof StreamInterface) {
564
            return null;
565
        }
566
567 3
        if ($offset !== null) {
568 1
            $contentStream = new LimitStream($contentStream, $length !== null ? $length : - 1, $offset);
569 1
        }
570
571 3
        return $contentStream;
572
    }
573
574
    /**
575
     * Gets the specified information for the object specified by id.
576
     *
577
     * @param string $repositoryId the identifier for the repository
578
     * @param string $objectId the identifier for the object
579
     * @param string|null $filter a comma-separated list of query names that defines which properties must be
580
     *      returned by the repository (default is repository specific)
581
     * @param boolean $includeAllowableActions if <code>true</code>, then the repository must return the allowable
582
     *      actions for the object (default is <code>false</code>)
583
     * @param IncludeRelationships|null $includeRelationships indicates what relationships in which the objects
584
     *      participate must be returned (default is <code>IncludeRelationships::NONE</code>)
585
     * @param string $renditionFilter indicates what set of renditions the repository must return whose kind
586
     *      matches this filter (default is "cmis:none")
587
     * @param boolean $includePolicyIds if <code>true</code>, then the repository must return the policy ids for
588
     *      the object (default is <code>false</code>)
589
     * @param boolean $includeAcl if <code>true</code>, then the repository must return the ACL for the object
590
     *      (default is <code>false</code>)
591
     * @param ExtensionDataInterface|null $extension
592
     * @return ObjectDataInterface|null Returns object of type ObjectDataInterface or <code>null</code>
593
     *     if the repository response was empty
594
     */
595 3 View Code Duplication
    public function getObject(
596
        $repositoryId,
597
        $objectId,
598
        $filter = null,
599
        $includeAllowableActions = false,
600
        IncludeRelationships $includeRelationships = null,
601
        $renditionFilter = Constants::RENDITION_NONE,
602
        $includePolicyIds = false,
603
        $includeAcl = false,
604
        ExtensionDataInterface $extension = null
605
    ) {
606 3
        $url = $this->getObjectUrl($repositoryId, $objectId, Constants::SELECTOR_OBJECT);
607 3
        $url->getQuery()->modify(
608
            array(
609 3
                Constants::PARAM_ALLOWABLE_ACTIONS => $includeAllowableActions ? 'true' : 'false',
610 3
                Constants::PARAM_RENDITION_FILTER => $renditionFilter,
611 3
                Constants::PARAM_POLICY_IDS => $includePolicyIds ? 'true' : 'false',
612 3
                Constants::PARAM_ACL => $includeAcl ? 'true' : 'false',
613 3
                Constants::PARAM_SUCCINCT => $this->getSuccinct() ? 'true' : 'false',
614 3
                Constants::PARAM_DATETIME_FORMAT => (string) $this->getDateTimeFormat()
615 3
            )
616 3
        );
617
618 3
        if (!empty($filter)) {
619 2
            $url->getQuery()->modify(array(Constants::PARAM_FILTER => (string) $filter));
620 2
        }
621
622 3
        if ($includeRelationships !== null) {
623 2
            $url->getQuery()->modify(array(Constants::PARAM_RELATIONSHIPS => (string) $includeRelationships));
624 2
        }
625
626 3
        $responseData = $this->read($url)->json();
627
628
        // TODO: Implement Cache
629 3
        return $this->getJsonConverter()->convertObject($responseData);
630
    }
631
632
    /**
633
     * Gets the specified information for the object specified by path.
634
     *
635
     * @param string $repositoryId the identifier for the repository
636
     * @param string $path the path to the object
637
     * @param string|null $filter a comma-separated list of query names that defines which properties must be
638
     *      returned by the repository (default is repository specific)
639
     * @param boolean $includeAllowableActions if <code>true</code>, then the repository must return the allowable
640
     *      actions for the object (default is <code>false</code>)
641
     * @param IncludeRelationships|null $includeRelationships indicates what relationships in which the objects
642
     *      participate must be returned (default is <code>IncludeRelationships::NONE</code>)
643
     * @param string $renditionFilter indicates what set of renditions the repository must return whose kind
644
     *      matches this filter (default is "cmis:none")
645
     * @param boolean $includePolicyIds if <code>true</code>, then the repository must return the policy ids for
646
     *      the object (default is <code>false</code>)
647
     * @param boolean $includeAcl if <code>true</code>, then the repository must return the ACL for the object
648
     *      (default is <code>false</code>)
649
     * @param ExtensionDataInterface|null $extension
650
     * @return ObjectDataInterface|null Returns object of type <code>ObjectDataInterface</code> or <code>null</code>
651
     *      if the repository response was empty
652
     */
653 3 View Code Duplication
    public function getObjectByPath(
654
        $repositoryId,
655
        $path,
656
        $filter = null,
657
        $includeAllowableActions = false,
658
        IncludeRelationships $includeRelationships = null,
659
        $renditionFilter = Constants::RENDITION_NONE,
660
        $includePolicyIds = false,
661
        $includeAcl = false,
662
        ExtensionDataInterface $extension = null
663
    ) {
664 3
        $url = $this->getPathUrl($repositoryId, $path, Constants::SELECTOR_OBJECT);
665 3
        $url->getQuery()->modify(
666
            array(
667 3
                Constants::PARAM_ALLOWABLE_ACTIONS => $includeAllowableActions ? 'true' : 'false',
668 3
                Constants::PARAM_RENDITION_FILTER => $renditionFilter,
669 3
                Constants::PARAM_POLICY_IDS => $includePolicyIds ? 'true' : 'false',
670 3
                Constants::PARAM_ACL => $includeAcl ? 'true' : 'false',
671 3
                Constants::PARAM_SUCCINCT => $this->getSuccinct() ? 'true' : 'false',
672 3
                Constants::PARAM_DATETIME_FORMAT => (string) $this->getDateTimeFormat()
673 3
            )
674 3
        );
675
676 3
        if (!empty($filter)) {
677 2
            $url->getQuery()->modify(array(Constants::PARAM_FILTER => (string) $filter));
678 2
        }
679
680 3
        if ($includeRelationships !== null) {
681 2
            $url->getQuery()->modify(array(Constants::PARAM_RELATIONSHIPS => (string) $includeRelationships));
682 2
        }
683
684 3
        $responseData = $this->read($url)->json();
685
686
        // TODO Implement Cache
687 3
        return $this->getJsonConverter()->convertObject($responseData);
688
    }
689
690
    /**
691
     * Gets the list of properties for an object.
692
     *
693
     * @param string $repositoryId the identifier for the repository
694
     * @param string $objectId the identifier for the object
695
     * @param string|null $filter a comma-separated list of query names that defines which properties must be
696
     *      returned by the repository (default is repository specific)
697
     * @param ExtensionDataInterface|null $extension
698
     * @return PropertiesInterface
699
     */
700 2
    public function getProperties(
701
        $repositoryId,
702
        $objectId,
703
        $filter = null,
704
        ExtensionDataInterface $extension = null
705
    ) {
706 2
        $url = $this->getObjectUrl($repositoryId, $objectId, Constants::SELECTOR_PROPERTIES);
707 2
        $url->getQuery()->modify(
708
            array(
709 2
                Constants::PARAM_SUCCINCT => $this->getSuccinct() ? 'true' : 'false',
710 2
                Constants::PARAM_DATETIME_FORMAT => (string) $this->getDateTimeFormat()
711 2
            )
712 2
        );
713
714 2
        if (!empty($filter)) {
715 1
            $url->getQuery()->modify(array(Constants::PARAM_FILTER => (string) $filter));
716 1
        }
717
718 2
        $responseData = $this->read($url)->json();
719
720
        // TODO: Implement Cache
721 2
        if ($this->getSuccinct()) {
722
            return $this->getJsonConverter()->convertSuccinctProperties($responseData);
723
        } else {
724 2
            return $this->getJsonConverter()->convertProperties($responseData);
725
        }
726
    }
727
728
    /**
729
     * Gets the list of associated renditions for the specified object.
730
     * Only rendition attributes are returned, not rendition stream.
731
     *
732
     * @param string $repositoryId the identifier for the repository
733
     * @param string $objectId the identifier for the object
734
     * @param string $renditionFilter indicates what set of renditions the repository must return whose kind
735
     *      matches this filter (default is "cmis:none")
736
     * @param integer|null $maxItems the maximum number of items to return in a response
737
     *       (default is repository specific)
738
     * @param integer $skipCount number of potential results that the repository MUST skip/page over before
739
     *      returning any results (default is 0)
740
     * @param ExtensionDataInterface|null $extension
741
     * @return RenditionDataInterface[]
742
     * @throws CmisInvalidArgumentException If object id is empty or skip count not of type integer
743
     */
744 2
    public function getRenditions(
745
        $repositoryId,
746
        $objectId,
747
        $renditionFilter = Constants::RENDITION_NONE,
748
        $maxItems = null,
749
        $skipCount = 0,
750
        ExtensionDataInterface $extension = null
751
    ) {
752 2
        if (empty($objectId)) {
753
            throw new CmisInvalidArgumentException('Object id must not be empty!');
754
        }
755
756 2
        if (!is_int($skipCount)) {
757
            throw new CmisInvalidArgumentException('Skip count must be of type integer!');
758
        }
759
760 2
        $url = $this->getObjectUrl($repositoryId, $objectId, Constants::SELECTOR_RENDITIONS);
761 2
        $url->getQuery()->modify(
762
            array(
763 2
                Constants::PARAM_RENDITION_FILTER => $renditionFilter,
764 2
                Constants::PARAM_SKIP_COUNT => (string) $skipCount,
765
            )
766 2
        );
767
768 2
        if ($maxItems !== null) {
769 1
            $url->getQuery()->modify(array(Constants::PARAM_MAX_ITEMS => (string) $maxItems));
770 1
        }
771
772 2
        $responseData = $this->read($url)->json();
773
774 2
        return $this->getJsonConverter()->convertRenditions($responseData);
775
    }
776
777
    /**
778
     * Moves the specified file-able object from one folder to another.
779
     *
780
     * @param string $repositoryId the identifier for the repository
781
     * @param string $objectId the identifier for the object. The repository might return a different/new object id
782
     * @param string $targetFolderId the identifier for the target folder
783
     * @param string $sourceFolderId the identifier for the source folder
784
     * @param ExtensionDataInterface|null $extension
785
     * @return ObjectDataInterface|null Returns object of type ObjectDataInterface or <code>null</code>
786
     *     if the repository response was empty
787
     */
788 1
    public function moveObject(
789
        $repositoryId,
790
        & $objectId,
791
        $targetFolderId,
792
        $sourceFolderId,
793
        ExtensionDataInterface $extension = null
794
    ) {
795 1
        $url = $this->getObjectUrl($repositoryId, $objectId);
796 1
        $url->getQuery()->modify(
797
            array(
798 1
                Constants::CONTROL_CMISACTION => Constants::CMISACTION_MOVE,
799 1
                Constants::PARAM_TARGET_FOLDER_ID => $targetFolderId,
800 1
                Constants::PARAM_SOURCE_FOLDER_ID => $sourceFolderId,
801 1
                Constants::PARAM_SUCCINCT => $this->getSuccinct() ? 'true' : 'false'
802 1
            )
803 1
        );
804
805 1
        $responseData = $this->post($url)->json();
806 1
        $newObject = $this->getJsonConverter()->convertObject($responseData);
807
808
        // $objectId was passed by reference. The value is changed here to new object id
809 1
        $objectId = ($newObject === null) ? null : $newObject->getId();
810
811 1
        return $newObject;
812
    }
813
814
    /**
815
     * Sets the content stream for the specified document object.
816
     *
817
     * @param string $repositoryId The identifier for the repository
818
     * @param string $objectId The identifier for the object. The repository might return a different/new object id
819
     * @param StreamInterface $contentStream The content stream
820
     * @param boolean $overwriteFlag If <code>true</code>, then the repository must replace the existing content stream
821
     *      for the object (if any) with the input content stream. If <code>false</code>, then the repository must
822
     *      only set the input content stream for the object if the object currently does not have a content stream
823
     *      (default is <code>true</code>)
824
     * @param string|null $changeToken The last change token of this object that the client received.
825
     *      The repository might return a new change token (default is <code>null</code>)
826
     * @param ExtensionDataInterface|null $extension
827
     * @throws CmisInvalidArgumentException If object id is empty
828
     */
829 3
    public function setContentStream(
830
        $repositoryId,
831
        & $objectId,
832
        StreamInterface $contentStream,
833
        $overwriteFlag = true,
834
        & $changeToken = null,
835
        ExtensionDataInterface $extension = null
836
    ) {
837 3
        if (empty($objectId)) {
838
            throw new CmisInvalidArgumentException('Object id must not be empty!');
839
        }
840
841 3
        $url = $this->getObjectUrl($repositoryId, $objectId);
842
843 3
        $url->getQuery()->modify(
844
            array(
845 3
                Constants::CONTROL_CMISACTION => Constants::CMISACTION_SET_CONTENT,
846 3
                Constants::PARAM_OVERWRITE_FLAG => $overwriteFlag ? 'true' : 'false',
847 3
                Constants::PARAM_SUCCINCT => $this->getSuccinct() ? 'true' : 'false'
848 3
            )
849 3
        );
850
851 3 View Code Duplication
        if ($changeToken !== null && !$this->getSession()->get(SessionParameter::OMIT_CHANGE_TOKENS, false)) {
852 1
            $url->getQuery()->modify(array(Constants::PARAM_CHANGE_TOKEN => $changeToken));
853 1
        }
854
855 3
        $responseData = $this->post(
856 3
            $url,
857
            $contentStream
858 3
        )->json();
859
860 3
        $newObject = $this->getJsonConverter()->convertObject($responseData);
861
862
        // $objectId was passed by reference. The value is changed here to new object id
863 3
        $objectId = null;
864 3 View Code Duplication
        if ($newObject !== null) {
865 3
            $objectId = $newObject->getId();
866 3
            $newObjectProperties = $newObject->getProperties()->getProperties();
867 3
            if ($changeToken !== null && count($newObjectProperties) > 0) {
868 2
                $newChangeToken = $newObjectProperties[PropertyIds::CHANGE_TOKEN];
869
                // $changeToken was passed by reference. The value is changed here
870 2
                $changeToken = $newChangeToken === null ? null : $newChangeToken->getFirstValue();
871 2
            }
872 3
        }
873 3
    }
874
875
    /**
876
     * Updates properties of the specified object.
877
     *
878
     * @param string $repositoryId The identifier for the repository
879
     * @param string $objectId The identifier for the object. The repository might return a different/new object id
880
     * @param PropertiesInterface $properties The updated property values that must be applied to the object
881
     * @param string|null $changeToken The last change token of this object that the client received.
882
     *      The repository might return a new change token (default is <code>null</code>)
883
     * @param ExtensionDataInterface|null $extension
884
     * @throws CmisInvalidArgumentException If $objectId is empty
885
     */
886 3
    public function updateProperties(
887
        $repositoryId,
888
        & $objectId,
889
        PropertiesInterface $properties,
890
        & $changeToken = null,
891
        ExtensionDataInterface $extension = null
892
    ) {
893 3
        if (empty($objectId)) {
894
            throw new CmisInvalidArgumentException('Object id must not be empty!');
895
        }
896
897 3
        $url = $this->getObjectUrl($repositoryId, $objectId);
898
899 3 View Code Duplication
        if ($changeToken !== null && !$this->getSession()->get(SessionParameter::OMIT_CHANGE_TOKENS, false)) {
900 1
            $url->getQuery()->modify(array(Constants::PARAM_CHANGE_TOKEN => $changeToken));
901 1
        }
902
903 3
        $queryArray = $this->convertPropertiesToQueryArray($properties);
904 3
        $queryArray[Constants::CONTROL_CMISACTION] = Constants::CMISACTION_UPDATE_PROPERTIES;
905 3
        $queryArray[Constants::PARAM_SUCCINCT] = $this->getSuccinct() ? 'true' : 'false';
906 3
        $responseData = $this->post($url, $queryArray)->json();
907 3
        $newObject = $this->getJsonConverter()->convertObject($responseData);
908
909
        // $objectId was passed by reference. The value is changed here to new object id
910 3
        $objectId = null;
911 3 View Code Duplication
        if ($newObject !== null) {
912 3
            $objectId = $newObject->getId();
913 3
            $newObjectProperties = $newObject->getProperties()->getProperties();
914 3
            if ($changeToken !== null && count($newObjectProperties) > 0) {
915 2
                $newChangeToken = $newObjectProperties[PropertyIds::CHANGE_TOKEN];
916
                // $changeToken was passed by reference. The value is changed here
917 2
                $changeToken = $newChangeToken === null ? null : $newChangeToken->getFirstValue();
918 2
            }
919 3
        }
920 3
    }
921
}
922