1
|
|
|
<?php |
2
|
|
|
namespace Dkd\PhpCmis; |
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\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
|
|
|
* @author Sascha Egerer <[email protected]> |
52
|
|
|
*/ |
53
|
|
|
class Session implements SessionInterface |
54
|
|
|
{ |
55
|
|
|
/** |
56
|
|
|
* @var CmisBindingInterface |
57
|
|
|
*/ |
58
|
|
|
protected $binding; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* @var Cache |
62
|
|
|
*/ |
63
|
|
|
protected $cache; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* @var OperationContextInterface |
67
|
|
|
*/ |
68
|
|
|
private $defaultContext; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @var CmisBindingsHelper |
72
|
|
|
*/ |
73
|
|
|
protected $cmisBindingHelper; |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @var ObjectFactoryInterface |
77
|
|
|
*/ |
78
|
|
|
private $objectFactory; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @var RepositoryInfoInterface |
82
|
|
|
*/ |
83
|
|
|
protected $repositoryInfo; |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* @var array |
87
|
|
|
*/ |
88
|
|
|
protected $parameters = array(); |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @var Cache |
92
|
|
|
*/ |
93
|
|
|
protected $typeDefinitionCache; |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @var Cache |
97
|
|
|
*/ |
98
|
|
|
protected $objectTypeCache; |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* @var Updatability[] |
102
|
|
|
*/ |
103
|
|
|
protected static $createUpdatability = array(); |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* @var Updatability[] |
107
|
|
|
*/ |
108
|
|
|
protected static $createAndCheckoutUpdatability = array(); |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* @param array $parameters |
112
|
|
|
* @param ObjectFactoryInterface|null $objectFactory |
113
|
|
|
* @param Cache|null $cache |
114
|
|
|
* @param Cache|null $typeDefinitionCache |
115
|
|
|
* @param Cache|null $objectTypeCache |
116
|
|
|
* @param CmisBindingsHelper|null $cmisBindingHelper |
117
|
|
|
* @throws CmisInvalidArgumentException |
118
|
|
|
* @throws IllegalStateException |
119
|
|
|
*/ |
120
|
11 |
|
public function __construct( |
121
|
|
|
array $parameters, |
122
|
|
|
ObjectFactoryInterface $objectFactory = null, |
123
|
|
|
Cache $cache = null, |
124
|
|
|
Cache $typeDefinitionCache = null, |
125
|
|
|
Cache $objectTypeCache = null, |
126
|
|
|
CmisBindingsHelper $cmisBindingHelper = null |
127
|
|
|
) { |
128
|
11 |
|
if (empty($parameters)) { |
129
|
1 |
|
throw new CmisInvalidArgumentException('No parameters provided!', 1408115280); |
130
|
|
|
} |
131
|
|
|
|
132
|
10 |
|
$this->parameters = $parameters; |
133
|
10 |
|
$this->objectFactory = $objectFactory === null ? $this->createObjectFactory() : $objectFactory; |
134
|
9 |
|
$this->cache = $cache === null ? $this->createCache() : $cache; |
135
|
8 |
|
$this->typeDefinitionCache = $typeDefinitionCache === null ? $this->createCache() : $typeDefinitionCache; |
136
|
8 |
|
$this->objectTypeCache = $objectTypeCache === null ? $this->createCache() : $objectTypeCache; |
137
|
8 |
|
$this->cmisBindingHelper = $cmisBindingHelper === null ? new CmisBindingsHelper() : $cmisBindingHelper; |
138
|
|
|
|
139
|
8 |
|
$this->defaultContext = new OperationContext(); |
140
|
8 |
|
$this->defaultContext->setCacheEnabled(true); |
141
|
|
|
|
142
|
8 |
|
$this->binding = $this->getCmisBindingHelper()->createBinding( |
143
|
8 |
|
$this->parameters, |
144
|
8 |
|
$this->typeDefinitionCache |
145
|
8 |
|
); |
146
|
|
|
|
147
|
8 |
|
if (!isset($this->parameters[SessionParameter::REPOSITORY_ID])) { |
148
|
|
|
throw new IllegalStateException('Repository ID is not set!'); |
149
|
|
|
} |
150
|
|
|
|
151
|
8 |
|
$this->repositoryInfo = $this->getBinding()->getRepositoryService()->getRepositoryInfo( |
152
|
8 |
|
$this->parameters[SessionParameter::REPOSITORY_ID] |
153
|
8 |
|
); |
154
|
|
|
|
155
|
8 |
|
self::$createUpdatability = array( |
156
|
8 |
|
Updatability::cast(Updatability::ONCREATE), |
157
|
8 |
|
Updatability::cast(Updatability::READWRITE) |
158
|
8 |
|
); |
159
|
|
|
|
160
|
8 |
|
self::$createAndCheckoutUpdatability = array( |
161
|
8 |
|
Updatability::cast(Updatability::ONCREATE), |
162
|
8 |
|
Updatability::cast(Updatability::READWRITE), |
163
|
8 |
|
Updatability::cast(Updatability::WHENCHECKEDOUT) |
164
|
8 |
|
); |
165
|
8 |
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* Create an object factory based on the SessionParameter::OBJECT_FACTORY_CLASS. If not set it returns an instance |
169
|
|
|
* of ObjectFactory. |
170
|
|
|
* |
171
|
|
|
* @return ObjectFactoryInterface |
172
|
|
|
* @throws \RuntimeException |
173
|
|
|
*/ |
174
|
9 |
|
protected function createObjectFactory() |
175
|
|
|
{ |
176
|
|
|
try { |
177
|
9 |
|
if (isset($this->parameters[SessionParameter::OBJECT_FACTORY_CLASS])) { |
178
|
2 |
|
$objectFactoryClass = new $this->parameters[SessionParameter::OBJECT_FACTORY_CLASS]; |
179
|
2 |
|
} else { |
180
|
7 |
|
$objectFactoryClass = $this->createDefaultObjectFactoryInstance(); |
181
|
|
|
} |
182
|
|
|
|
183
|
9 |
|
if (!($objectFactoryClass instanceof ObjectFactoryInterface)) { |
184
|
1 |
|
throw new \RuntimeException('Class does not implement ObjectFactoryInterface!', 1408354119); |
185
|
|
|
} |
186
|
|
|
|
187
|
8 |
|
$objectFactoryClass->initialize($this, $this->parameters); |
188
|
|
|
|
189
|
8 |
|
return $objectFactoryClass; |
190
|
1 |
|
} catch (\Exception $exception) { |
191
|
1 |
|
throw new \RuntimeException( |
192
|
1 |
|
'Unable to create object factory: ' . $exception, |
193
|
|
|
1408354120 |
194
|
1 |
|
); |
195
|
|
|
} |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Returns an instance of the ObjectFactory. |
200
|
|
|
* This methods is primarily required for unit testing. |
201
|
|
|
* |
202
|
|
|
* @return ObjectFactory |
203
|
|
|
*/ |
204
|
6 |
|
protected function createDefaultObjectFactoryInstance() |
205
|
|
|
{ |
206
|
6 |
|
return new ObjectFactory(); |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* Create a cache instance based on the given session parameter SessionParameter::CACHE_CLASS. |
211
|
|
|
* If no session parameter SessionParameter::CACHE_CLASS is defined, the default Cache implementation will be used. |
212
|
|
|
* |
213
|
|
|
* @return Cache |
214
|
|
|
* @throws \InvalidArgumentException |
215
|
|
|
*/ |
216
|
9 |
|
protected function createCache() |
217
|
|
|
{ |
218
|
|
|
try { |
219
|
9 |
|
if (isset($this->parameters[SessionParameter::CACHE_CLASS])) { |
220
|
2 |
|
$cache = new $this->parameters[SessionParameter::CACHE_CLASS]; |
221
|
2 |
|
} else { |
222
|
7 |
|
$cache = $this->createDefaultCacheInstance(); |
223
|
|
|
} |
224
|
|
|
|
225
|
9 |
|
if (!($cache instanceof CacheProvider)) { |
226
|
1 |
|
throw new \RuntimeException( |
227
|
1 |
|
sprintf( |
228
|
1 |
|
'Class %s does not subclass \\Doctrine\\Common\\Cache\\CacheProvider!', |
229
|
1 |
|
get_class($cache) |
230
|
1 |
|
), |
231
|
|
|
1408354124 |
232
|
1 |
|
); |
233
|
|
|
} |
234
|
|
|
|
235
|
8 |
|
return $cache; |
236
|
1 |
|
} catch (\Exception $exception) { |
237
|
1 |
|
throw new CmisInvalidArgumentException( |
238
|
1 |
|
'Unable to create cache: ' . $exception, |
239
|
|
|
1408354123 |
240
|
1 |
|
); |
241
|
|
|
} |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
/** |
245
|
|
|
* Returns an instance of the Doctrine ArrayCache. |
246
|
|
|
* This methods is primarily required for unit testing. |
247
|
|
|
* |
248
|
|
|
* @return CacheProvider |
249
|
|
|
*/ |
250
|
7 |
|
protected function createDefaultCacheInstance() |
251
|
|
|
{ |
252
|
7 |
|
return new ArrayCache(); |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* Get the cache instance |
257
|
|
|
* |
258
|
|
|
* @return CacheProvider |
259
|
|
|
*/ |
260
|
3 |
|
public function getCache() |
261
|
|
|
{ |
262
|
3 |
|
return $this->cache; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Applies ACL changes to an object and dependent objects. Only direct ACEs can be added and removed. |
267
|
|
|
* |
268
|
|
|
* @param ObjectIdInterface $objectId the ID the object |
269
|
|
|
* @param AceInterface[] $addAces of ACEs to be added or <code>null</code> if no ACEs should be added |
270
|
|
|
* @param AceInterface[] $removeAces list of ACEs to be removed or <code>null</code> if no ACEs should be removed |
271
|
|
|
* @param AclPropagation|null $aclPropagation value that defines the propagation of the ACE changes; |
272
|
|
|
* <code>null</code> is equal to AclPropagation.REPOSITORYDETERMINED |
273
|
|
|
* @return AclInterface the new ACL of the object |
274
|
|
|
*/ |
275
|
|
|
public function applyAcl( |
276
|
|
|
ObjectIdInterface $objectId, |
277
|
|
|
$addAces = array(), |
278
|
|
|
$removeAces = array(), |
279
|
|
|
AclPropagation $aclPropagation = null |
280
|
|
|
) { |
281
|
|
|
// TODO: Implement applyAcl() method. |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
/** |
285
|
|
|
* Applies a set of policies to an object. |
286
|
|
|
* |
287
|
|
|
* @param ObjectIdInterface $objectId the ID the object |
288
|
|
|
* @param ObjectIdInterface[] $policyIds the IDs of the policies to be applied |
289
|
|
|
* @return mixed |
290
|
|
|
*/ |
291
|
|
|
public function applyPolicies(ObjectIdInterface $objectId, array $policyIds) |
292
|
|
|
{ |
293
|
|
|
// TODO: Implement applyPolicy() method. |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
/** |
297
|
|
|
* Updates multiple objects in one request. |
298
|
|
|
* |
299
|
|
|
* @param CmisObjectInterface[] $objects |
300
|
|
|
* @param mixed[] $properties |
301
|
|
|
* @param string[] $addSecondaryTypeIds |
302
|
|
|
* @param string[] $removeSecondaryTypeIds |
303
|
|
|
* @return BulkUpdateObjectIdAndChangeTokenInterface[] |
304
|
|
|
*/ |
305
|
|
|
public function bulkUpdateProperties( |
306
|
|
|
array $objects, |
307
|
|
|
array $properties, |
308
|
|
|
array $addSecondaryTypeIds, |
309
|
|
|
array $removeSecondaryTypeIds |
310
|
|
|
) { |
311
|
|
|
// TODO: Implement bulkUpdateProperties() method. |
312
|
|
|
} |
313
|
|
|
|
314
|
|
|
/** |
315
|
|
|
* Clears all cached data. |
316
|
|
|
*/ |
317
|
|
|
public function clear() |
318
|
|
|
{ |
319
|
|
|
$this->getCache()->flushAll(); |
320
|
|
|
} |
321
|
|
|
|
322
|
|
|
/** |
323
|
|
|
* Creates a new document. The stream in contentStream is consumed but not closed by this method. |
324
|
|
|
* |
325
|
|
|
* @param string[] $properties The property values that MUST be applied to the newly-created document object. |
326
|
|
|
* @param ObjectIdInterface|null $folderId If specified, the identifier for the folder that MUST be the parent |
327
|
|
|
* folder for the newly-created document object. This parameter MUST be specified if the repository does NOT |
328
|
|
|
* support the optional "unfiling" capability. |
329
|
|
|
* @param StreamInterface|null $contentStream The content stream that MUST be stored for the newly-created document |
330
|
|
|
* object. The method of passing the contentStream to the server and the encoding mechanism will be specified |
331
|
|
|
* by each specific binding. MUST be required if the type requires it. |
332
|
|
|
* @param VersioningState|null $versioningState An enumeration specifying what the versioning state of the |
333
|
|
|
* newly-created object MUST be. Valid values are: |
334
|
|
|
* <code>none</code> |
335
|
|
|
* (default, if the object-type is not versionable) The document MUST be created as a non-versionable |
336
|
|
|
* document. |
337
|
|
|
* <code>checkedout</code> |
338
|
|
|
* The document MUST be created in the checked-out state. The checked-out document MAY be |
339
|
|
|
* visible to other users. |
340
|
|
|
* <code>major</code> |
341
|
|
|
* (default, if the object-type is versionable) The document MUST be created as a major version. |
342
|
|
|
* <code>minor</code> |
343
|
|
|
* The document MUST be created as a minor version. |
344
|
|
|
* @param PolicyInterface[] $policies A list of policy ids that MUST be applied to the newly-created |
345
|
|
|
* document object. |
346
|
|
|
* @param AceInterface[] $addAces A list of ACEs that MUST be added to the newly-created document object, |
347
|
|
|
* either using the ACL from folderId if specified, or being applied if no folderId is specified. |
348
|
|
|
* @param AceInterface[] $removeAces A list of ACEs that MUST be removed from the newly-created document |
349
|
|
|
* object, either using the ACL from folderId if specified, or being ignored if no folderId is specified. |
350
|
|
|
* @return ObjectIdInterface|null the object ID of the new document or <code>null</code> if the document could not |
351
|
|
|
* be created. |
352
|
|
|
* @throws CmisInvalidArgumentException Throws an <code>CmisInvalidArgumentException</code> if empty |
353
|
|
|
* property list is given |
354
|
|
|
*/ |
355
|
|
|
public function createDocument( |
356
|
|
|
array $properties, |
357
|
|
|
ObjectIdInterface $folderId = null, |
358
|
|
|
StreamInterface $contentStream = null, |
359
|
|
|
VersioningState $versioningState = null, |
360
|
|
|
array $policies = array(), |
361
|
|
|
array $addAces = array(), |
362
|
|
|
array $removeAces = array() |
363
|
|
|
) { |
364
|
|
|
if (empty($properties)) { |
365
|
|
|
throw new CmisInvalidArgumentException('Properties must not be empty!'); |
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
$objectId = $this->getBinding()->getObjectService()->createDocument( |
369
|
|
|
$this->getRepositoryId(), |
370
|
|
|
$this->getObjectFactory()->convertProperties( |
371
|
|
|
$properties, |
372
|
|
|
null, |
373
|
|
|
array(), |
374
|
|
|
self::$createAndCheckoutUpdatability |
375
|
|
|
), |
376
|
|
|
$folderId === null ? null : $folderId->getId(), |
377
|
|
|
$contentStream, |
378
|
|
|
$versioningState, |
379
|
|
|
$this->getObjectFactory()->convertPolicies($policies), |
380
|
|
|
$this->getObjectFactory()->convertAces($addAces), |
381
|
|
|
$this->getObjectFactory()->convertAces($removeAces), |
382
|
|
|
null |
383
|
|
|
); |
384
|
|
|
|
385
|
|
|
if ($objectId === null) { |
386
|
|
|
return null; |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
return $this->createObjectId($objectId); |
390
|
|
|
} |
391
|
|
|
|
392
|
|
|
/** |
393
|
|
|
* Creates a new document from a source document. |
394
|
|
|
* |
395
|
|
|
* @param ObjectIdInterface $source The identifier for the source document. |
396
|
|
|
* @param string[] $properties The property values that MUST be applied to the object. This list of properties |
397
|
|
|
* SHOULD only contain properties whose values differ from the source document. |
398
|
|
|
* @param ObjectIdInterface|null $folderId If specified, the identifier for the folder that MUST be the parent |
399
|
|
|
* folder for the newly-created document object. This parameter MUST be specified if the repository does NOT |
400
|
|
|
* support the optional "unfiling" capability. |
401
|
|
|
* @param VersioningState|null $versioningState An enumeration specifying what the versioning state of the |
402
|
|
|
* newly-created object MUST be. Valid values are: |
403
|
|
|
* <code>none</code> |
404
|
|
|
* (default, if the object-type is not versionable) The document MUST be created as a non-versionable |
405
|
|
|
* document. |
406
|
|
|
* <code>checkedout</code> |
407
|
|
|
* The document MUST be created in the checked-out state. The checked-out document MAY be |
408
|
|
|
* visible to other users. |
409
|
|
|
* <code>major</code> |
410
|
|
|
* (default, if the object-type is versionable) The document MUST be created as a major version. |
411
|
|
|
* <code>minor</code> |
412
|
|
|
* The document MUST be created as a minor version. |
413
|
|
|
* @param PolicyInterface[] $policies A list of policy ids that MUST be applied to the newly-created |
414
|
|
|
* document object. |
415
|
|
|
* @param AceInterface[] $addAces A list of ACEs that MUST be added to the newly-created document object, |
416
|
|
|
* either using the ACL from folderId if specified, or being applied if no folderId is specified. |
417
|
|
|
* @param AceInterface[] $removeAces A list of ACEs that MUST be removed from the newly-created document |
418
|
|
|
* object, either using the ACL from folderId if specified, or being ignored if no folderId is specified. |
419
|
|
|
* @return ObjectIdInterface|null the object ID of the new document or <code>null</code> if the document could not |
420
|
|
|
* be created. |
421
|
|
|
* @throws CmisInvalidArgumentException Throws an <code>CmisInvalidArgumentException</code> if empty |
422
|
|
|
* property list is given |
423
|
|
|
*/ |
424
|
|
|
public function createDocumentFromSource( |
425
|
|
|
ObjectIdInterface $source, |
426
|
|
|
array $properties = array(), |
427
|
|
|
ObjectIdInterface $folderId = null, |
428
|
|
|
VersioningState $versioningState = null, |
429
|
|
|
array $policies = array(), |
430
|
|
|
array $addAces = array(), |
431
|
|
|
array $removeAces = array() |
432
|
|
|
) { |
433
|
|
|
if (!$source instanceof CmisObjectInterface) { |
434
|
|
|
$sourceObject = $this->getObject($source); |
435
|
|
|
} else { |
436
|
|
|
$sourceObject = $source; |
437
|
|
|
} |
438
|
|
|
|
439
|
|
|
$type = $sourceObject->getType(); |
440
|
|
|
$secondaryTypes = $sourceObject->getSecondaryTypes(); |
441
|
|
|
|
442
|
|
|
if ($secondaryTypes === null) { |
443
|
|
|
$secondaryTypes = array(); |
444
|
|
|
} |
445
|
|
|
|
446
|
|
|
if (!BaseTypeId::cast($type->getBaseTypeId())->equals(BaseTypeId::CMIS_DOCUMENT)) { |
447
|
|
|
throw new CmisInvalidArgumentException('Source object must be a document!'); |
448
|
|
|
} |
449
|
|
|
|
450
|
|
|
$objectId = $this->getBinding()->getObjectService()->createDocumentFromSource( |
451
|
|
|
$this->getRepositoryId(), |
452
|
|
|
$source->getId(), |
453
|
|
|
$this->getObjectFactory()->convertProperties( |
454
|
|
|
$properties, |
455
|
|
|
$type, |
456
|
|
|
$secondaryTypes, |
457
|
|
|
self::$createAndCheckoutUpdatability |
458
|
|
|
), |
459
|
|
|
$folderId === null ? null : $folderId->getId(), |
460
|
|
|
$versioningState, |
461
|
|
|
$this->getObjectFactory()->convertPolicies($policies), |
462
|
|
|
$this->getObjectFactory()->convertAces($addAces), |
463
|
|
|
$this->getObjectFactory()->convertAces($removeAces), |
464
|
|
|
null |
465
|
|
|
); |
466
|
|
|
|
467
|
|
|
if ($objectId === null) { |
468
|
|
|
return null; |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
return $this->createObjectId($objectId); |
472
|
|
|
} |
473
|
|
|
|
474
|
|
|
/** |
475
|
|
|
* Creates a new folder. |
476
|
|
|
* |
477
|
|
|
* @param string[] $properties |
478
|
|
|
* @param ObjectIdInterface $folderId |
479
|
|
|
* @param PolicyInterface[] $policies |
480
|
|
|
* @param AceInterface[] $addAces |
481
|
|
|
* @param AceInterface[] $removeAces |
482
|
|
|
* @return ObjectIdInterface the object ID of the new folder |
483
|
|
|
* @throws CmisInvalidArgumentException Throws an <code>CmisInvalidArgumentException</code> if empty |
484
|
|
|
* property list is given |
485
|
|
|
*/ |
486
|
|
View Code Duplication |
public function createFolder( |
487
|
|
|
array $properties, |
488
|
|
|
ObjectIdInterface $folderId, |
489
|
|
|
array $policies = array(), |
490
|
|
|
array $addAces = array(), |
491
|
|
|
array $removeAces = array() |
492
|
|
|
) { |
493
|
|
|
if (empty($properties)) { |
494
|
|
|
throw new CmisInvalidArgumentException('Properties must not be empty!'); |
495
|
|
|
} |
496
|
|
|
|
497
|
|
|
$objectId = $this->getBinding()->getObjectService()->createFolder( |
498
|
|
|
$this->getRepositoryId(), |
499
|
|
|
$this->getObjectFactory()->convertProperties($properties), |
500
|
|
|
$folderId->getId(), |
501
|
|
|
$this->getObjectFactory()->convertPolicies($policies), |
502
|
|
|
$this->getObjectFactory()->convertAces($addAces), |
503
|
|
|
$this->getObjectFactory()->convertAces($removeAces), |
504
|
|
|
null |
505
|
|
|
); |
506
|
|
|
|
507
|
|
|
return $this->createObjectId($objectId); |
508
|
|
|
} |
509
|
|
|
|
510
|
|
|
/** |
511
|
|
|
* Creates a new item. |
512
|
|
|
* |
513
|
|
|
* @param string[] $properties |
514
|
|
|
* @param ObjectIdInterface $folderId |
515
|
|
|
* @param PolicyInterface[] $policies |
516
|
|
|
* @param AceInterface[] $addAces |
517
|
|
|
* @param AceInterface[] $removeAces |
518
|
|
|
* @return ObjectIdInterface the object ID of the new item |
519
|
|
|
* @throws CmisInvalidArgumentException Throws an <code>CmisInvalidArgumentException</code> if empty |
520
|
|
|
* property list is given |
521
|
|
|
*/ |
522
|
|
View Code Duplication |
public function createItem( |
523
|
|
|
array $properties, |
524
|
|
|
ObjectIdInterface $folderId, |
525
|
|
|
array $policies = array(), |
526
|
|
|
array $addAces = array(), |
527
|
|
|
array $removeAces = array() |
528
|
|
|
) { |
529
|
|
|
if (empty($properties)) { |
530
|
|
|
throw new CmisInvalidArgumentException('Properties must not be empty!'); |
531
|
|
|
} |
532
|
|
|
|
533
|
|
|
$objectId = $this->getBinding()->getObjectService()->createItem( |
534
|
|
|
$this->getRepositoryId(), |
535
|
|
|
$this->getObjectFactory()->convertProperties($properties), |
536
|
|
|
$folderId->getId(), |
537
|
|
|
$this->getObjectFactory()->convertPolicies($policies), |
538
|
|
|
$this->getObjectFactory()->convertAces($addAces), |
539
|
|
|
$this->getObjectFactory()->convertAces($removeAces), |
540
|
|
|
null |
541
|
|
|
); |
542
|
|
|
|
543
|
|
|
return $this->createObjectId($objectId); |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
/** |
547
|
|
|
* Creates an object ID from a String. |
548
|
|
|
* |
549
|
|
|
* @param string $id |
550
|
|
|
* @return ObjectIdInterface the object ID object |
551
|
|
|
*/ |
552
|
|
|
public function createObjectId($id) |
553
|
|
|
{ |
554
|
|
|
return new ObjectId($id); |
555
|
|
|
} |
556
|
|
|
|
557
|
|
|
/** |
558
|
|
|
* Creates a new operation context object with the given properties. |
559
|
|
|
* |
560
|
|
|
* @param string[] $filter the property filter, a comma separated string of query names or "*" for all |
561
|
|
|
* properties or <code>null</code> to let the repository determine a set of properties |
562
|
|
|
* @param boolean $includeAcls indicates whether ACLs should be included or not |
563
|
|
|
* @param boolean $includeAllowableActions indicates whether Allowable Actions should be included or not |
564
|
|
|
* @param boolean $includePolicies indicates whether policies should be included or not |
565
|
|
|
* @param IncludeRelationships|null $includeRelationships enum that indicates if and which |
566
|
|
|
* relationships should be includes |
567
|
|
|
* @param string[] $renditionFilter the rendition filter or <code>null</code> for no renditions |
568
|
|
|
* @param boolean $includePathSegments indicates whether path segment or the relative path segment should |
569
|
|
|
* be included or not |
570
|
|
|
* @param string|null $orderBy the object order, a comma-separated list of query names and the ascending |
571
|
|
|
* modifier "ASC" or the descending modifier "DESC" for each query name |
572
|
|
|
* @param boolean $cacheEnabled flag that indicates if the object cache should be used |
573
|
|
|
* @param integer $maxItemsPerPage the max items per page/batch |
574
|
|
|
* @return OperationContextInterface the newly created operation context object |
575
|
|
|
*/ |
576
|
|
|
public function createOperationContext( |
577
|
|
|
$filter = array(), |
578
|
|
|
$includeAcls = false, |
579
|
|
|
$includeAllowableActions = true, |
580
|
|
|
$includePolicies = false, |
581
|
|
|
IncludeRelationships $includeRelationships = null, |
582
|
|
|
array $renditionFilter = array(), |
583
|
|
|
$includePathSegments = true, |
584
|
|
|
$orderBy = null, |
585
|
|
|
$cacheEnabled = false, |
586
|
|
|
$maxItemsPerPage = 100 |
587
|
|
|
) { |
588
|
|
|
$operationContext = new OperationContext(); |
589
|
|
|
$operationContext->setFilter($filter); |
590
|
|
|
$operationContext->setIncludeAcls($includeAcls); |
591
|
|
|
$operationContext->setIncludeAllowableActions($includeAllowableActions); |
592
|
|
|
$operationContext->setIncludePolicies($includePolicies); |
593
|
|
|
if ($includeRelationships !== null) { |
594
|
|
|
$operationContext->setIncludeRelationships($includeRelationships); |
595
|
|
|
} |
596
|
|
|
$operationContext->setRenditionFilter($renditionFilter); |
597
|
|
|
$operationContext->setIncludePathSegments($includePathSegments); |
598
|
|
|
if (!empty($orderBy)) { |
599
|
|
|
$operationContext->setOrderBy($orderBy); |
600
|
|
|
} |
601
|
|
|
$operationContext->setCacheEnabled($cacheEnabled); |
602
|
|
|
$operationContext->setMaxItemsPerPage($maxItemsPerPage); |
603
|
|
|
|
604
|
|
|
return $operationContext; |
605
|
|
|
} |
606
|
|
|
|
607
|
|
|
/** |
608
|
|
|
* Creates a new policy. |
609
|
|
|
* |
610
|
|
|
* @param string[] $properties |
611
|
|
|
* @param ObjectIdInterface $folderId |
612
|
|
|
* @param PolicyInterface[] $policies |
613
|
|
|
* @param AceInterface[] $addAces |
614
|
|
|
* @param AceInterface[] $removeAces |
615
|
|
|
* @return ObjectIdInterface the object ID of the new policy |
616
|
|
|
*/ |
617
|
|
|
public function createPolicy( |
618
|
|
|
array $properties, |
619
|
|
|
ObjectIdInterface $folderId, |
620
|
|
|
array $policies = array(), |
621
|
|
|
array $addAces = array(), |
622
|
|
|
array $removeAces = array() |
623
|
|
|
) { |
624
|
|
|
// TODO: Implement createPolicy() method. |
625
|
|
|
} |
626
|
|
|
|
627
|
|
|
/** |
628
|
|
|
* Creates a query statement for a query of one primary type joined by zero or more secondary types. |
629
|
|
|
* |
630
|
|
|
* Generates something like this: |
631
|
|
|
* `SELECT d.cmis:name,s.SecondaryStringProp FROM cmis:document AS d JOIN MySecondaryType AS s ON |
632
|
|
|
* d.cmis:objectId=s.cmis:objectId WHERE d.cmis:name LIKE ? ORDER BY d.cmis:name,s.SecondaryIntegerProp` |
633
|
|
|
* |
634
|
|
|
* @param string[] $selectPropertyIds the property IDs in the SELECT statement, |
635
|
|
|
* if <code>null</code> all properties are selected |
636
|
|
|
* @param string[] $fromTypes a Map of type aliases (keys) and type IDs (values), the Map must contain |
637
|
|
|
* exactly one primary type and zero or more secondary types |
638
|
|
|
* @param string|null $whereClause an optional WHERE clause with placeholders ('?'), see QueryStatement for details |
639
|
|
|
* @param string[] $orderByPropertyIds an optional list of properties IDs for the ORDER BY clause |
640
|
|
|
* @return QueryStatementInterface a new query statement object |
641
|
|
|
* @throws CmisInvalidArgumentException |
642
|
|
|
*/ |
643
|
2 |
|
public function createQueryStatement( |
644
|
|
|
array $selectPropertyIds, |
645
|
|
|
array $fromTypes, |
646
|
|
|
$whereClause = null, |
647
|
|
|
array $orderByPropertyIds = array() |
648
|
|
|
) { |
649
|
2 |
|
if (empty($selectPropertyIds)) { |
650
|
1 |
|
throw new CmisInvalidArgumentException('Select property IDs must not be empty'); |
651
|
|
|
} |
652
|
1 |
|
if (empty($fromTypes)) { |
653
|
1 |
|
throw new CmisInvalidArgumentException('From types must not be empty'); |
654
|
|
|
} |
655
|
|
|
|
656
|
|
|
return new QueryStatement($this, null, $selectPropertyIds, $fromTypes, $whereClause, $orderByPropertyIds); |
657
|
|
|
} |
658
|
|
|
|
659
|
|
|
/** |
660
|
|
|
* Creates a new relationship between 2 objects. |
661
|
|
|
* |
662
|
|
|
* @param string[] $properties |
663
|
|
|
* @param PolicyInterface[] $policies |
664
|
|
|
* @param AceInterface[] $addAces |
665
|
|
|
* @param AceInterface[] $removeAces |
666
|
|
|
* @return ObjectIdInterface|null the object ID of the new relationship or <code>null</code> if the relationship |
667
|
|
|
* could not be created |
668
|
|
|
*/ |
669
|
|
|
public function createRelationship( |
670
|
|
|
array $properties, |
671
|
|
|
array $policies = array(), |
672
|
|
|
array $addAces = array(), |
673
|
|
|
array $removeAces = array() |
674
|
|
|
) { |
675
|
|
|
if (empty($properties)) { |
676
|
|
|
throw new CmisInvalidArgumentException('Properties must not be empty!'); |
677
|
|
|
} |
678
|
|
|
|
679
|
|
|
$newObjectId = $this->getBinding()->getObjectService()->createRelationship( |
680
|
|
|
$this->getRepositoryId(), |
681
|
|
|
$this->getObjectFactory()->convertProperties($properties, null, array(), self::$createUpdatability), |
682
|
|
|
$this->getObjectFactory()->convertPolicies($policies), |
683
|
|
|
$this->getObjectFactory()->convertAces($addAces), |
684
|
|
|
$this->getObjectFactory()->convertAces($removeAces) |
685
|
|
|
); |
686
|
|
|
|
687
|
|
|
if ($newObjectId === null) { |
688
|
|
|
return null; |
689
|
|
|
} |
690
|
|
|
|
691
|
|
|
return $this->createObjectId($newObjectId); |
692
|
|
|
} |
693
|
|
|
|
694
|
|
|
/** |
695
|
|
|
* Creates a new type. |
696
|
|
|
* |
697
|
|
|
* @param TypeDefinitionInterface $type |
698
|
|
|
* @return ObjectTypeInterface the new type definition |
699
|
|
|
* @throws CmisNotSupportedException If repository version 1.0 |
700
|
|
|
*/ |
701
|
|
View Code Duplication |
public function createType(TypeDefinitionInterface $type) |
702
|
|
|
{ |
703
|
|
|
if ($this->getRepositoryInfo()->getCmisVersion() == CmisVersion::cast(CmisVersion::CMIS_1_0)) { |
704
|
|
|
throw new CmisNotSupportedException('This method is not supported for CMIS 1.0 repositories.'); |
705
|
|
|
} |
706
|
|
|
|
707
|
|
|
return $this->convertTypeDefinition( |
708
|
|
|
$this->getBinding()->getRepositoryService()->createType($this->getRepositoryInfo()->getId(), $type) |
709
|
|
|
); |
710
|
|
|
} |
711
|
|
|
|
712
|
|
|
/** |
713
|
|
|
* Deletes an object and, if it is a document, all versions in the version series. |
714
|
|
|
* |
715
|
|
|
* @param ObjectIdInterface $objectId the ID of the object |
716
|
|
|
* @param boolean $allVersions if this object is a document this parameter defines |
717
|
|
|
* if only this version or all versions should be deleted |
718
|
|
|
*/ |
719
|
|
|
public function delete(ObjectIdInterface $objectId, $allVersions = true) |
720
|
|
|
{ |
721
|
|
|
$this->getBinding()->getObjectService()->deleteObject( |
722
|
|
|
$this->getRepositoryId(), |
723
|
|
|
$objectId->getId(), |
724
|
|
|
$allVersions |
725
|
|
|
); |
726
|
|
|
$this->removeObjectFromCache($objectId); |
727
|
|
|
} |
728
|
|
|
|
729
|
|
|
/** |
730
|
|
|
* Deletes a type. |
731
|
|
|
* |
732
|
|
|
* @param string $typeId the ID of the type to delete |
733
|
|
|
* @throws CmisNotSupportedException If repository version 1.0 |
734
|
|
|
*/ |
735
|
|
View Code Duplication |
public function deleteType($typeId) |
736
|
|
|
{ |
737
|
|
|
if ($this->getRepositoryInfo()->getCmisVersion() == CmisVersion::cast(CmisVersion::CMIS_1_0)) { |
738
|
|
|
throw new CmisNotSupportedException('This method is not supported for CMIS 1.0 repositories.'); |
739
|
|
|
} |
740
|
|
|
|
741
|
|
|
$this->getBinding()->getRepositoryService()->deleteType($this->getRepositoryId(), $typeId); |
742
|
|
|
$this->removeObjectFromCache($this->createObjectId($typeId)); |
743
|
|
|
} |
744
|
|
|
|
745
|
|
|
/** |
746
|
|
|
* Fetches the ACL of an object from the repository. |
747
|
|
|
* |
748
|
|
|
* @param ObjectIdInterface $objectId the ID the object |
749
|
|
|
* @param boolean $onlyBasicPermissions if <code>true</code> the repository should express the ACL only with the |
750
|
|
|
* basic permissions defined in the CMIS specification; if <code>false</code> the repository can express the |
751
|
|
|
* ACL with basic and repository specific permissions |
752
|
|
|
* @return AclInterface the ACL of the object |
753
|
|
|
*/ |
754
|
|
|
public function getAcl(ObjectIdInterface $objectId, $onlyBasicPermissions) |
755
|
|
|
{ |
756
|
|
|
// TODO: Implement getAcl() method. |
757
|
|
|
} |
758
|
|
|
|
759
|
|
|
/** |
760
|
|
|
* Returns the underlying binding object. |
761
|
|
|
* |
762
|
|
|
* @return CmisBindingInterface the binding object |
763
|
|
|
*/ |
764
|
8 |
|
public function getBinding() |
765
|
|
|
{ |
766
|
8 |
|
return $this->binding; |
767
|
|
|
} |
768
|
|
|
|
769
|
|
|
/** |
770
|
|
|
* Returns all checked out documents with the given OperationContext. |
771
|
|
|
* |
772
|
|
|
* @param OperationContextInterface|null $context |
773
|
|
|
* @return DocumentInterface[] |
774
|
|
|
*/ |
775
|
|
|
public function getCheckedOutDocs(OperationContextInterface $context = null) |
776
|
|
|
{ |
777
|
|
|
// TODO: Implement getCheckedOutDocs() method. |
778
|
|
|
} |
779
|
|
|
|
780
|
|
|
/** |
781
|
|
|
* @return CmisBindingsHelper |
782
|
|
|
*/ |
783
|
8 |
|
protected function getCmisBindingHelper() |
784
|
|
|
{ |
785
|
8 |
|
return $this->cmisBindingHelper; |
786
|
|
|
} |
787
|
|
|
|
788
|
|
|
/** |
789
|
|
|
* Returns the content changes. |
790
|
|
|
* |
791
|
|
|
* @param string $changeLogToken the change log token to start from or <code>null</code> to start from |
792
|
|
|
* the first available event in the repository |
793
|
|
|
* @param boolean $includeProperties indicates whether changed properties should be included in the result or not |
794
|
|
|
* @param integer|null $maxNumItems maximum numbers of events |
795
|
|
|
* @param OperationContextInterface|null $context the OperationContext |
796
|
|
|
* @return ChangeEventsInterface the change events |
797
|
|
|
*/ |
798
|
|
|
public function getContentChanges( |
799
|
|
|
$changeLogToken, |
800
|
|
|
$includeProperties, |
801
|
|
|
$maxNumItems = null, |
802
|
|
|
OperationContextInterface $context = null |
803
|
|
|
) { |
804
|
|
|
if ($context === null) { |
805
|
|
|
$context = $this->getDefaultContext(); |
806
|
|
|
} |
807
|
|
|
|
808
|
|
|
$objectList = $this->getBinding()->getDiscoveryService()->getContentChanges( |
809
|
|
|
$this->getRepositoryInfo()->getId(), |
810
|
|
|
$changeLogToken, |
811
|
|
|
$includeProperties, |
812
|
|
|
$context->isIncludePolicies(), |
813
|
|
|
$context->isIncludeAcls(), |
814
|
|
|
$maxNumItems |
815
|
|
|
); |
816
|
|
|
|
817
|
|
|
return $this->getObjectFactory()->convertChangeEvents($changeLogToken, $objectList); |
818
|
|
|
} |
819
|
|
|
|
820
|
|
|
/** |
821
|
|
|
* Retrieves the main content stream of a document. |
822
|
|
|
* |
823
|
|
|
* @param ObjectIdInterface $docId the ID of the document |
824
|
|
|
* @param string|null $streamId the stream ID |
825
|
|
|
* @param integer|null $offset the offset of the stream or <code>null</code> to read the stream from the beginning |
826
|
|
|
* @param integer|null $length the maximum length of the stream or <code>null</code> to read to the end of the |
827
|
|
|
* stream |
828
|
|
|
* @return StreamInterface|null the content stream or <code>null</code> if the |
829
|
|
|
* document has no content stream |
830
|
|
|
*/ |
831
|
|
|
public function getContentStream(ObjectIdInterface $docId, $streamId = null, $offset = null, $length = null) |
832
|
|
|
{ |
833
|
|
|
$contentStream = $this->getBinding()->getObjectService()->getContentStream( |
834
|
|
|
$this->getRepositoryId(), |
835
|
|
|
$docId->getId(), |
836
|
|
|
$streamId, |
837
|
|
|
$offset, |
838
|
|
|
$length |
839
|
|
|
); |
840
|
|
|
|
841
|
|
|
return $contentStream instanceof StreamInterface ? $contentStream : null; |
842
|
|
|
} |
843
|
|
|
|
844
|
|
|
/** |
845
|
|
|
* Returns the current default operation parameters for filtering, paging and caching. |
846
|
|
|
* |
847
|
|
|
* @return OperationContextInterface the default operation context |
848
|
|
|
*/ |
849
|
1 |
|
public function getDefaultContext() |
850
|
|
|
{ |
851
|
1 |
|
return $this->defaultContext; |
852
|
|
|
} |
853
|
|
|
|
854
|
|
|
/** |
855
|
|
|
* Returns the latest change log token. |
856
|
|
|
* |
857
|
|
|
* In contrast to the repository info, this change log token is *not cached*. |
858
|
|
|
* This method requests the token from the repository every single time it is called. |
859
|
|
|
* |
860
|
|
|
* @return string|null the latest change log token or <code>null</code> if the repository doesn't provide one |
861
|
|
|
*/ |
862
|
|
|
public function getLatestChangeLogToken() |
863
|
|
|
{ |
864
|
|
|
// TODO: Implement getLatestChangeLogToken() method. |
865
|
|
|
} |
866
|
|
|
|
867
|
|
|
/** |
868
|
|
|
* Returns the latest version in a version series. |
869
|
|
|
* |
870
|
|
|
* @param ObjectIdInterface $objectId the document ID of an arbitrary version in the version series |
871
|
|
|
* @param boolean $major if <code>true</code> the latest major version will be returned, |
872
|
|
|
* otherwise the very last version will be returned |
873
|
|
|
* @param OperationContextInterface|null $context the OperationContext to use |
874
|
|
|
* @return DocumentInterface the latest document version |
875
|
|
|
*/ |
876
|
|
|
public function getLatestDocumentVersion( |
877
|
|
|
ObjectIdInterface $objectId, |
878
|
|
|
$major = false, |
879
|
|
|
OperationContextInterface $context = null |
880
|
|
|
) { |
881
|
|
|
// TODO: Implement getLatestDocumentVersion() method. |
882
|
|
|
} |
883
|
|
|
|
884
|
|
|
/** |
885
|
|
|
* Get the current locale to be used for this session. |
886
|
|
|
* |
887
|
|
|
* @return \Locale the current locale, may be <code>null</code> |
888
|
|
|
*/ |
889
|
|
|
public function getLocale() |
890
|
|
|
{ |
891
|
|
|
// TODO: Implement getLocale() method. |
892
|
|
|
} |
893
|
|
|
|
894
|
|
|
/** |
895
|
|
|
* @param ObjectIdInterface $objectId the object ID |
896
|
|
|
* @param OperationContextInterface|null $context the OperationContext to use |
897
|
|
|
* @return CmisObjectInterface the requested object |
898
|
|
|
* @throws CmisObjectNotFoundException - if an object with the given ID doesn't exist |
899
|
|
|
*/ |
900
|
|
|
public function getObject(ObjectIdInterface $objectId, OperationContextInterface $context = null) |
901
|
|
|
{ |
902
|
|
|
if ($context === null) { |
903
|
|
|
$context = $this->getDefaultContext(); |
904
|
|
|
} |
905
|
|
|
|
906
|
|
|
$objectIdString = $objectId->getId(); |
907
|
|
|
$cacheIdentity = $objectIdString . '|' . $context->getCacheKey(); |
908
|
|
|
|
909
|
|
|
if ($this->getCache()->contains($cacheIdentity)) { |
910
|
|
|
return $this->getCache()->fetch($cacheIdentity); |
911
|
|
|
} |
912
|
|
|
|
913
|
|
|
$objectData = $this->getBinding()->getObjectService()->getObject( |
914
|
|
|
$this->getRepositoryInfo()->getId(), |
915
|
|
|
$objectIdString, |
916
|
|
|
$context->getQueryFilterString(), |
917
|
|
|
$context->isIncludeAllowableActions(), |
918
|
|
|
$context->getIncludeRelationships(), |
919
|
|
|
$context->getRenditionFilterString(), |
920
|
|
|
$context->isIncludePolicies(), |
921
|
|
|
$context->isIncludeAcls(), |
922
|
|
|
null |
923
|
|
|
); |
924
|
|
|
|
925
|
|
|
if (!$objectData instanceof ObjectDataInterface) { |
926
|
|
|
throw new CmisObjectNotFoundException('Could not find object for given id.'); |
927
|
|
|
} |
928
|
|
|
|
929
|
|
|
$object = $this->getObjectFactory()->convertObject($objectData, $context); |
930
|
|
|
$this->getCache()->save($cacheIdentity, $object); |
931
|
|
|
return $object; |
932
|
|
|
} |
933
|
|
|
|
934
|
|
|
/** |
935
|
|
|
* Returns a CMIS object from the session cache. If the object is not in the cache or the given OperationContext |
936
|
|
|
* has caching turned off, it will load the object from the repository and puts it into the cache. |
937
|
|
|
* This method might return a stale object if the object has been found in the cache and has been changed in or |
938
|
|
|
* removed from the repository. Use CmisObject::refresh() and CmisObject::refreshIfOld() to update the object |
939
|
|
|
* if necessary. |
940
|
|
|
* |
941
|
|
|
* @param string $path the object path |
942
|
|
|
* @param OperationContextInterface|null $context the OperationContext to use |
943
|
|
|
* @return CmisObjectInterface Returns a CMIS object from the session cache. |
944
|
|
|
* @throws CmisInvalidArgumentException Throws an <code>CmisInvalidArgumentException</code> |
945
|
|
|
* if path is empty. |
946
|
|
|
* @throws CmisObjectNotFoundException - if an object with the given path doesn't exist |
947
|
|
|
*/ |
948
|
|
|
public function getObjectByPath($path, OperationContextInterface $context = null) |
949
|
|
|
{ |
950
|
|
|
if (empty($path)) { |
951
|
|
|
throw new CmisInvalidArgumentException('Path must not be empty.'); |
952
|
|
|
} |
953
|
|
|
|
954
|
|
|
if ($context === null) { |
955
|
|
|
$context = $this->getDefaultContext(); |
956
|
|
|
} |
957
|
|
|
|
958
|
|
|
$objectData = $this->getBinding()->getObjectService()->getObjectByPath( |
959
|
|
|
$this->getRepositoryInfo()->getId(), |
960
|
|
|
$path, |
961
|
|
|
$context->getQueryFilterString(), |
962
|
|
|
$context->isIncludeAllowableActions(), |
963
|
|
|
$context->getIncludeRelationships(), |
964
|
|
|
$context->getRenditionFilterString(), |
965
|
|
|
$context->isIncludePolicies(), |
966
|
|
|
$context->isIncludeAcls() |
967
|
|
|
); |
968
|
|
|
|
969
|
|
|
if (!$objectData instanceof ObjectDataInterface) { |
970
|
|
|
throw new CmisObjectNotFoundException(sprintf('Could not find object for given path "%s".', $path)); |
971
|
|
|
} |
972
|
|
|
|
973
|
|
|
// TODO: Implement cache! |
974
|
|
|
|
975
|
|
|
return $this->getObjectFactory()->convertObject($objectData, $context); |
976
|
|
|
} |
977
|
|
|
|
978
|
|
|
/** |
979
|
|
|
* Gets a factory object that provides methods to create the objects used by this API. |
980
|
|
|
* |
981
|
|
|
* @return ObjectFactoryInterface the repository info |
982
|
|
|
*/ |
983
|
3 |
|
public function getObjectFactory() |
984
|
|
|
{ |
985
|
3 |
|
return $this->objectFactory; |
986
|
|
|
} |
987
|
|
|
|
988
|
|
|
/** |
989
|
|
|
* Fetches the relationships from or to an object from the repository. |
990
|
|
|
* |
991
|
|
|
* @param ObjectIdInterface $objectId |
992
|
|
|
* @param boolean $includeSubRelationshipTypes |
993
|
|
|
* @param RelationshipDirection $relationshipDirection |
994
|
|
|
* @param ObjectTypeInterface $type |
995
|
|
|
* @param OperationContextInterface|null $context |
996
|
|
|
* @return RelationshipInterface[] |
997
|
|
|
*/ |
998
|
1 |
|
public function getRelationships( |
999
|
|
|
ObjectIdInterface $objectId, |
1000
|
|
|
$includeSubRelationshipTypes, |
1001
|
|
|
RelationshipDirection $relationshipDirection, |
1002
|
|
|
ObjectTypeInterface $type, |
1003
|
|
|
OperationContextInterface $context = null |
1004
|
|
|
) { |
1005
|
|
|
|
1006
|
1 |
|
if ($context === null) { |
1007
|
1 |
|
$context = $this->getDefaultContext(); |
1008
|
1 |
|
} |
1009
|
|
|
|
1010
|
|
|
// TODO: Implement cache! |
1011
|
|
|
|
1012
|
1 |
|
return $this->getBinding()->getRelationshipService()->getObjectRelationships( |
1013
|
1 |
|
$this->getRepositoryId(), |
1014
|
1 |
|
$objectId->getId(), |
1015
|
1 |
|
$includeSubRelationshipTypes, |
1016
|
1 |
|
$relationshipDirection, |
1017
|
1 |
|
$type->getId() |
1018
|
1 |
|
); |
1019
|
|
|
} |
1020
|
|
|
|
1021
|
|
|
/** |
1022
|
|
|
* Returns the repository info of the repository associated with this session. |
1023
|
|
|
* |
1024
|
|
|
* @return RepositoryInfoInterface the repository info |
1025
|
|
|
*/ |
1026
|
1 |
|
public function getRepositoryInfo() |
1027
|
|
|
{ |
1028
|
1 |
|
return $this->repositoryInfo; |
1029
|
|
|
} |
1030
|
|
|
|
1031
|
|
|
/** |
1032
|
|
|
* Returns the repository id. |
1033
|
|
|
* |
1034
|
|
|
* @return string the repository id |
1035
|
|
|
*/ |
1036
|
1 |
|
public function getRepositoryId() |
1037
|
|
|
{ |
1038
|
1 |
|
return $this->getRepositoryInfo()->getId(); |
1039
|
|
|
} |
1040
|
|
|
|
1041
|
|
|
/** |
1042
|
|
|
* Gets the root folder of the repository with the given OperationContext. |
1043
|
|
|
* |
1044
|
|
|
* @param OperationContextInterface|null $context |
1045
|
|
|
* @return FolderInterface the root folder object |
1046
|
|
|
* @throws CmisRuntimeException |
1047
|
|
|
*/ |
1048
|
|
|
public function getRootFolder(OperationContextInterface $context = null) |
1049
|
|
|
{ |
1050
|
|
|
$rootFolderId = $this->getRepositoryInfo()->getRootFolderId(); |
1051
|
|
|
|
1052
|
|
|
$rootFolder = $this->getObject( |
1053
|
|
|
$this->createObjectId($rootFolderId), |
1054
|
|
|
$context === null ? $this->getDefaultContext() : $context |
1055
|
|
|
); |
1056
|
|
|
|
1057
|
|
|
if (!($rootFolder instanceof FolderInterface)) { |
1058
|
|
|
throw new CmisRuntimeException('Root folder object is not a folder!', 1423735889); |
1059
|
|
|
} |
1060
|
|
|
|
1061
|
|
|
return $rootFolder; |
1062
|
|
|
} |
1063
|
|
|
|
1064
|
|
|
/** |
1065
|
|
|
* Gets the type children of a type. |
1066
|
|
|
* |
1067
|
|
|
* @param string $typeId the type ID or <code>null</code> to request the base types |
1068
|
|
|
* @param boolean $includePropertyDefinitions indicates whether the property definitions should be included or not |
1069
|
|
|
* @return TypeDefinitionListInterface the type iterator |
1070
|
|
|
* @throws CmisObjectNotFoundException - if a type with the given type ID doesn't exist |
1071
|
|
|
*/ |
1072
|
|
|
public function getTypeChildren($typeId, $includePropertyDefinitions) |
1073
|
|
|
{ |
1074
|
|
|
return $this->getBinding()->getRepositoryService()->getTypeChildren( |
1075
|
|
|
$this->getRepositoryId(), |
1076
|
|
|
$typeId, |
1077
|
|
|
$includePropertyDefinitions, |
1078
|
|
|
999, // set max items to 999 - TODO: Implement CollectionIterable() method to iterate over all objects. |
1079
|
|
|
0 // TODO: Implement CollectionIterable() method to iterate over all objects. |
1080
|
|
|
); |
1081
|
|
|
} |
1082
|
|
|
|
1083
|
|
|
/** |
1084
|
|
|
* Gets the definition of a type. |
1085
|
|
|
* |
1086
|
|
|
* @param string $typeId the ID of the type |
1087
|
|
|
* @param boolean $useCache specifies if the type definition should be first looked up in the type definition |
1088
|
|
|
* cache, if it is set to <code>false</code> or the type definition is not in the cache, the type definition is |
1089
|
|
|
* loaded from the repository |
1090
|
|
|
* @return ObjectTypeInterface the type definition |
1091
|
|
|
* @throws CmisObjectNotFoundException - if a type with the given type ID doesn't exist |
1092
|
|
|
*/ |
1093
|
|
|
public function getTypeDefinition($typeId, $useCache = true) |
1094
|
|
|
{ |
1095
|
|
|
// TODO: Implement cache! |
1096
|
|
|
$typeDefinition = $this->getBinding()->getRepositoryService()->getTypeDefinition( |
1097
|
|
|
$this->getRepositoryId(), |
1098
|
|
|
$typeId |
1099
|
|
|
); |
1100
|
|
|
|
1101
|
|
|
return $this->convertTypeDefinition($typeDefinition); |
1102
|
|
|
} |
1103
|
|
|
|
1104
|
|
|
/** |
1105
|
|
|
* Gets the type descendants of a type. |
1106
|
|
|
* |
1107
|
|
|
* @param string $typeId the type ID or <code>null</code> to request the base types |
1108
|
|
|
* @param integer $depth indicates whether the property definitions should be included or not |
1109
|
|
|
* @param boolean $includePropertyDefinitions the tree depth, must be greater than 0 or -1 for infinite depth |
1110
|
|
|
* @return TypeDefinitionContainerInterface[] A tree that contains ObjectTypeInterface objects |
1111
|
|
|
* @see ObjectTypeInterface ObjectTypeInterface contained in returned Tree |
1112
|
|
|
* @throws CmisObjectNotFoundException - if a type with the given type ID doesn't exist |
1113
|
|
|
*/ |
1114
|
|
|
public function getTypeDescendants($typeId, $depth, $includePropertyDefinitions) |
1115
|
|
|
{ |
1116
|
|
|
return $this->getBinding()->getRepositoryService()->getTypeDescendants( |
1117
|
|
|
$this->getRepositoryId(), |
1118
|
|
|
$typeId, |
1119
|
|
|
(integer) $depth, |
1120
|
|
|
$includePropertyDefinitions |
1121
|
|
|
); |
1122
|
|
|
} |
1123
|
|
|
|
1124
|
|
|
/** |
1125
|
|
|
* Sends a query to the repository using the given OperationContext. (See CMIS spec "2.1.10 Query".) |
1126
|
|
|
* |
1127
|
|
|
* @param string $statement the query statement (CMIS query language) |
1128
|
|
|
* @param boolean $searchAllVersions specifies whether non-latest document versions should be included or not, |
1129
|
|
|
* <code>true</code> searches all document versions, <code>false</code> only searches latest document versions |
1130
|
|
|
* @param OperationContextInterface|null $context the operation context to use |
1131
|
|
|
* @return QueryResultInterface[] |
1132
|
|
|
* @throws CmisInvalidArgumentException If statement is empty |
1133
|
|
|
*/ |
1134
|
|
|
public function query($statement, $searchAllVersions = false, OperationContextInterface $context = null) |
1135
|
|
|
{ |
1136
|
|
|
if (empty($statement)) { |
1137
|
|
|
throw new CmisInvalidArgumentException('Statement must not be empty.'); |
1138
|
|
|
} |
1139
|
|
|
|
1140
|
|
|
if ($context === null) { |
1141
|
|
|
$context = $this->getDefaultContext(); |
1142
|
|
|
} |
1143
|
|
|
|
1144
|
|
|
$queryResults = array(); |
1145
|
|
|
$skipCount = 0; |
1146
|
|
|
|
1147
|
|
|
$objectList = $this->getBinding()->getDiscoveryService()->query( |
1148
|
|
|
$this->getRepositoryInfo()->getId(), |
1149
|
|
|
$statement, |
1150
|
|
|
$searchAllVersions, |
1151
|
|
|
$context->getIncludeRelationships(), |
1152
|
|
|
$context->getRenditionFilterString(), |
1153
|
|
|
$context->isIncludeAllowableActions(), |
1154
|
|
|
$context->getMaxItemsPerPage(), |
1155
|
|
|
$skipCount |
1156
|
|
|
); |
1157
|
|
|
|
1158
|
|
|
foreach ($objectList->getObjects() as $objectData) { |
1159
|
|
|
$queryResult = $this->getObjectFactory()->convertQueryResult($objectData); |
1160
|
|
|
if ($queryResult instanceof QueryResultInterface) { |
1161
|
|
|
$queryResults[] = $queryResult; |
1162
|
|
|
} |
1163
|
|
|
} |
1164
|
|
|
|
1165
|
|
|
// TODO: Implement pagination using skipCount |
1166
|
|
|
|
1167
|
|
|
return $queryResults; |
1168
|
|
|
} |
1169
|
|
|
|
1170
|
|
|
/** |
1171
|
|
|
* Builds a CMIS query and returns the query results as an iterator of CmisObject objects. |
1172
|
|
|
* |
1173
|
|
|
* @param string $typeId the ID of the object type |
1174
|
|
|
* @param string|null $where the WHERE part of the query |
1175
|
|
|
* @param boolean $searchAllVersions specifies whether non-latest document versions should be included or not, |
1176
|
|
|
* <code>true</code> searches all document versions, <code>false</code> only searches latest document versions |
1177
|
|
|
* @param OperationContextInterface|null $context the operation context to use |
1178
|
|
|
* @return CmisObjectInterface[] |
1179
|
|
|
* @throws CmisInvalidArgumentException If type id is empty |
1180
|
|
|
*/ |
1181
|
|
|
public function queryObjects( |
1182
|
|
|
$typeId, |
1183
|
|
|
$where = null, |
1184
|
|
|
$searchAllVersions = false, |
1185
|
|
|
OperationContextInterface $context = null |
1186
|
|
|
) { |
1187
|
|
|
if (empty($typeId)) { |
1188
|
|
|
throw new CmisInvalidArgumentException('Type id must not be empty.'); |
1189
|
|
|
} |
1190
|
|
|
|
1191
|
|
|
if ($context === null) { |
1192
|
|
|
$context = $this->getDefaultContext(); |
1193
|
|
|
} |
1194
|
|
|
|
1195
|
|
|
$queryFilterString = $context->getQueryFilterString(); |
1196
|
|
|
if (!empty($queryFilterString)) { |
1197
|
|
|
$querySelect = $queryFilterString; |
1198
|
|
|
} else { |
1199
|
|
|
$querySelect = '*'; |
1200
|
|
|
} |
1201
|
|
|
|
1202
|
|
|
$whereClause = ''; |
1203
|
|
|
if (!empty($where)) { |
1204
|
|
|
$whereClause = ' WHERE ' . $where; |
1205
|
|
|
} |
1206
|
|
|
|
1207
|
|
|
$orderBy = $context->getOrderBy(); |
1208
|
|
|
if (!empty($orderBy)) { |
1209
|
|
|
$orderBy = ' ORDER BY ' . $orderBy; |
1210
|
|
|
} |
1211
|
|
|
|
1212
|
|
|
$typeDefinition = $this->getTypeDefinition($typeId); |
1213
|
|
|
$statement = 'SELECT ' . $querySelect . ' FROM ' . $typeDefinition->getQueryName() . $whereClause . $orderBy; |
1214
|
|
|
$queryStatement = new QueryStatement($this, $statement); |
1215
|
|
|
|
1216
|
|
|
$resultObjects = array(); |
1217
|
|
|
$skipCount = 0; |
1218
|
|
|
|
1219
|
|
|
$objectList = $this->getBinding()->getDiscoveryService()->query( |
1220
|
|
|
$this->getRepositoryInfo()->getId(), |
1221
|
|
|
$queryStatement->toQueryString(), |
1222
|
|
|
$searchAllVersions, |
1223
|
|
|
$context->getIncludeRelationships(), |
1224
|
|
|
$context->getRenditionFilterString(), |
1225
|
|
|
$context->isIncludeAllowableActions(), |
1226
|
|
|
$context->getMaxItemsPerPage(), |
1227
|
|
|
$skipCount |
1228
|
|
|
); |
1229
|
|
|
|
1230
|
|
|
foreach ($objectList->getObjects() as $objectData) { |
1231
|
|
|
$object = $this->getObjectFactory()->convertObject($objectData, $context); |
1232
|
|
|
if ($object instanceof CmisObjectInterface) { |
1233
|
|
|
$resultObjects[] = $object; |
1234
|
|
|
} |
1235
|
|
|
} |
1236
|
|
|
|
1237
|
|
|
// TODO: Implement pagination using skipCount |
1238
|
|
|
|
1239
|
|
|
return $resultObjects; |
1240
|
|
|
} |
1241
|
|
|
|
1242
|
|
|
/** |
1243
|
|
|
* Removes the given object from the cache. |
1244
|
|
|
* |
1245
|
|
|
* Note about specific implementation: in order to avoid an over-engineered |
1246
|
|
|
* taggable cache mechanism and with it, extensive traversal of objects when |
1247
|
|
|
* creating tags, objects are not tagged in the cache. In addition, objects |
1248
|
|
|
* are added to the cache with a secondary identification; the context - and |
1249
|
|
|
* the context is not available here when removing a single object from the |
1250
|
|
|
* cache. Instead, we opt to simply flush the entire cache and let it refill. |
1251
|
|
|
* |
1252
|
|
|
* @param ObjectIdInterface $objectId |
1253
|
|
|
*/ |
1254
|
|
|
public function removeObjectFromCache(ObjectIdInterface $objectId) |
1255
|
|
|
{ |
1256
|
|
|
$this->clear(); |
1257
|
|
|
} |
1258
|
|
|
|
1259
|
|
|
/** |
1260
|
|
|
* Removes a set of policies from an object. This operation is not atomic. |
1261
|
|
|
* If it fails some policies might already be removed. |
1262
|
|
|
* |
1263
|
|
|
* @param ObjectIdInterface $objectId the ID the object |
1264
|
|
|
* @param ObjectIdInterface[] $policyIds the IDs of the policies to be removed |
1265
|
|
|
*/ |
1266
|
|
|
public function removePolicy(ObjectIdInterface $objectId, array $policyIds) |
1267
|
|
|
{ |
1268
|
|
|
// TODO: Implement removePolicy() method. |
1269
|
|
|
} |
1270
|
|
|
|
1271
|
|
|
/** |
1272
|
|
|
* Removes the direct ACEs of an object and sets the provided ACEs. |
1273
|
|
|
* The changes are local to the given object and are not propagated to dependent objects. |
1274
|
|
|
* |
1275
|
|
|
* @param ObjectIdInterface $objectId |
1276
|
|
|
* @param AceInterface[] $aces |
1277
|
|
|
* @return AclInterface the new ACL of the object |
1278
|
|
|
*/ |
1279
|
|
|
public function setAcl(ObjectIdInterface $objectId, array $aces) |
1280
|
|
|
{ |
1281
|
|
|
// TODO: Implement setAcl() method. |
1282
|
|
|
} |
1283
|
|
|
|
1284
|
|
|
/** |
1285
|
|
|
* Sets the current session parameters for filtering, paging and caching. |
1286
|
|
|
* |
1287
|
|
|
* @param OperationContextInterface $context the OperationContext to be used for the session; |
1288
|
|
|
* if null, a default context is used |
1289
|
|
|
*/ |
1290
|
|
|
public function setDefaultContext(OperationContextInterface $context) |
1291
|
|
|
{ |
1292
|
|
|
$this->defaultContext = $context; |
1293
|
|
|
} |
1294
|
|
|
|
1295
|
|
|
/** |
1296
|
|
|
* Updates an existing type. |
1297
|
|
|
* |
1298
|
|
|
* @param TypeDefinitionInterface $type the type definition updates |
1299
|
|
|
* @return ObjectTypeInterface the updated type definition |
1300
|
|
|
*/ |
1301
|
|
|
public function updateType(TypeDefinitionInterface $type) |
1302
|
|
|
{ |
1303
|
|
|
// TODO: Implement updateType() method. |
1304
|
|
|
} |
1305
|
|
|
|
1306
|
|
|
/** |
1307
|
|
|
* Converts a type definition into an object type. If the object type is |
1308
|
|
|
* cached, it returns the cached object. Otherwise it creates an object type |
1309
|
|
|
* object and puts it into the cache. |
1310
|
|
|
* |
1311
|
|
|
* @param TypeDefinitionInterface $typeDefinition |
1312
|
|
|
* @return ObjectTypeInterface |
1313
|
|
|
*/ |
1314
|
|
|
private function convertTypeDefinition(TypeDefinitionInterface $typeDefinition) |
1315
|
|
|
{ |
1316
|
|
|
// TODO: Implement cache. See Java Implementation for example |
1317
|
|
|
return $this->getObjectFactory()->convertTypeDefinition($typeDefinition); |
1318
|
|
|
} |
1319
|
|
|
} |
1320
|
|
|
|