1
|
|
|
<?php |
2
|
|
|
namespace Dkd\PhpCmis\Bindings\Browser; |
3
|
|
|
|
4
|
|
|
/* |
5
|
|
|
* This file is part of php-cmis-client. |
6
|
|
|
* |
7
|
|
|
* (c) Sascha Egerer <[email protected]> |
8
|
|
|
* |
9
|
|
|
* For the full copyright and license information, please view the LICENSE |
10
|
|
|
* file that was distributed with this source code. |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
use Dkd\PhpCmis\Bindings\BindingSessionInterface; |
14
|
|
|
use Dkd\PhpCmis\Bindings\CmisBindingsHelper; |
15
|
|
|
use Dkd\PhpCmis\Bindings\LinkAccessInterface; |
16
|
|
|
use Dkd\PhpCmis\Constants; |
17
|
|
|
use Dkd\PhpCmis\Data\AclInterface; |
18
|
|
|
use Dkd\PhpCmis\Data\PropertiesInterface; |
19
|
|
|
use Dkd\PhpCmis\DataObjects\RepositoryInfo; |
20
|
|
|
use Dkd\PhpCmis\DataObjects\RepositoryInfoBrowserBinding; |
21
|
|
|
use Dkd\PhpCmis\Definitions\TypeDefinitionInterface; |
22
|
|
|
use Dkd\PhpCmis\Enum\DateTimeFormat; |
23
|
|
|
use Dkd\PhpCmis\Exception\CmisBaseException; |
24
|
|
|
use Dkd\PhpCmis\Exception\CmisConnectionException; |
25
|
|
|
use Dkd\PhpCmis\Exception\CmisConstraintException; |
26
|
|
|
use Dkd\PhpCmis\Exception\CmisInvalidArgumentException; |
27
|
|
|
use Dkd\PhpCmis\Exception\CmisNotSupportedException; |
28
|
|
|
use Dkd\PhpCmis\Exception\CmisObjectNotFoundException; |
29
|
|
|
use Dkd\PhpCmis\Exception\CmisPermissionDeniedException; |
30
|
|
|
use Dkd\PhpCmis\Exception\CmisProxyAuthenticationException; |
31
|
|
|
use Dkd\PhpCmis\Exception\CmisRuntimeException; |
32
|
|
|
use Dkd\PhpCmis\Exception\CmisUnauthorizedException; |
33
|
|
|
use Dkd\PhpCmis\SessionParameter; |
34
|
|
|
use GuzzleHttp\Client; |
35
|
|
|
use GuzzleHttp\Exception\RequestException; |
36
|
|
|
use GuzzleHttp\Psr7\Response; |
37
|
|
|
use GuzzleHttp\Stream\StreamInterface; |
38
|
|
|
use League\Url\Url; |
39
|
|
|
use Psr\Http\Message\ResponseInterface; |
40
|
|
|
use function basename; |
41
|
|
|
use function is_array; |
42
|
|
|
use function is_object; |
43
|
|
|
use function is_resource; |
44
|
|
|
use function json_decode; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Base class for all Browser Binding client services. |
48
|
|
|
*/ |
49
|
|
|
abstract class AbstractBrowserBindingService implements LinkAccessInterface |
50
|
|
|
{ |
51
|
|
|
/** |
52
|
|
|
* @var BindingSessionInterface |
53
|
|
|
*/ |
54
|
|
|
protected $session; |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* @var boolean |
58
|
|
|
*/ |
59
|
|
|
protected $succinct; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* @var CmisBindingsHelper |
63
|
|
|
*/ |
64
|
|
|
protected $cmisBindingsHelper; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* @var DateTimeFormat |
68
|
|
|
*/ |
69
|
168 |
|
protected $dateTimeFormat; |
70
|
|
|
|
71
|
168 |
|
/** |
72
|
168 |
|
* @param BindingSessionInterface $session |
73
|
168 |
|
* @param CmisBindingsHelper|null $cmisBindingsHelper |
74
|
|
|
*/ |
75
|
|
|
public function __construct(BindingSessionInterface $session, $cmisBindingsHelper = null) |
76
|
|
|
{ |
77
|
|
|
$this->setCmisBindingsHelper($cmisBindingsHelper); |
78
|
|
|
$this->setSession($session); |
79
|
|
|
} |
80
|
|
|
|
81
|
168 |
|
/** |
82
|
|
|
* Set cmis binding helper property |
83
|
168 |
|
* |
84
|
168 |
|
* @param CmisBindingsHelper|null $cmisBindingsHelper The cmis binding helper that should be defined. |
85
|
|
|
* If <code>null</code> is given a new instance of CmisBindingsHelper will be created. |
86
|
|
|
*/ |
87
|
|
|
protected function setCmisBindingsHelper($cmisBindingsHelper = null) |
88
|
|
|
{ |
89
|
|
|
$this->cmisBindingsHelper = ($cmisBindingsHelper === null) ? new CmisBindingsHelper() : $cmisBindingsHelper; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Get the url for an object |
94
|
|
|
* |
95
|
|
|
* @param string $repositoryId |
96
|
2 |
|
* @param string $objectId |
97
|
|
|
* @param string|null $selector |
98
|
2 |
|
* @throws CmisConnectionException |
99
|
|
|
* @throws CmisObjectNotFoundException |
100
|
2 |
|
* @return Url |
101
|
1 |
|
*/ |
102
|
1 |
View Code Duplication |
protected function getObjectUrl($repositoryId, $objectId, $selector = null) |
|
|
|
|
103
|
1 |
|
{ |
104
|
|
|
$result = $this->getRepositoryUrlCache()->getObjectUrl($repositoryId, $objectId, $selector); |
105
|
2 |
|
|
106
|
1 |
|
if ($result === null) { |
107
|
1 |
|
$this->getRepositoriesInternal($repositoryId); |
108
|
1 |
|
$result = $this->getRepositoryUrlCache()->getObjectUrl($repositoryId, $objectId, $selector); |
109
|
1 |
|
} |
110
|
1 |
|
|
111
|
|
|
if ($result === null) { |
112
|
1 |
|
throw new CmisObjectNotFoundException( |
113
|
1 |
|
sprintf( |
114
|
|
|
'Unknown Object! Repository: "%s" | Object: "%s" | Selector: "%s"', |
115
|
|
|
$repositoryId, |
116
|
1 |
|
$objectId, |
117
|
|
|
$selector |
118
|
|
|
) |
119
|
|
|
); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
return $result; |
123
|
|
|
} |
124
|
|
|
|
125
|
2 |
|
/** |
126
|
|
|
* Returns the repository URL cache or creates a new cache if it doesn't |
127
|
2 |
|
* exist. |
128
|
2 |
|
* |
129
|
1 |
|
* @return RepositoryUrlCache |
130
|
1 |
|
*/ |
131
|
1 |
|
protected function getRepositoryUrlCache() |
132
|
|
|
{ |
133
|
2 |
|
$repositoryUrlCache = $this->getSession()->get(SessionParameter::REPOSITORY_URL_CACHE); |
134
|
|
|
if ($repositoryUrlCache === null) { |
135
|
|
|
$repositoryUrlCache = new RepositoryUrlCache(); |
136
|
|
|
$this->getSession()->put(SessionParameter::REPOSITORY_URL_CACHE, $repositoryUrlCache); |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
return $repositoryUrlCache; |
140
|
|
|
} |
141
|
66 |
|
|
142
|
|
|
/** |
143
|
66 |
|
* Get current session |
144
|
|
|
* |
145
|
|
|
* @return BindingSessionInterface |
146
|
|
|
*/ |
147
|
|
|
public function getSession() |
148
|
|
|
{ |
149
|
|
|
return $this->session; |
150
|
|
|
} |
151
|
168 |
|
|
152
|
|
|
/** |
153
|
168 |
|
* Sets the current session. |
154
|
168 |
|
* |
155
|
168 |
|
* @param BindingSessionInterface $session |
156
|
|
|
*/ |
157
|
168 |
|
protected function setSession(BindingSessionInterface $session) |
158
|
168 |
|
{ |
159
|
|
|
$this->session = $session; |
160
|
|
|
$succinct = $session->get(SessionParameter::BROWSER_SUCCINCT); |
161
|
|
|
$this->succinct = $succinct ?? true; |
162
|
|
|
|
163
|
|
|
$this->dateTimeFormat = DateTimeFormat::cast($session->get(SessionParameter::BROWSER_DATETIME_FORMAT)); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
8 |
|
* Retrieves the the repository info objects. |
168
|
|
|
* |
169
|
8 |
|
* @param string|null $repositoryId |
170
|
|
|
* @throws CmisConnectionException |
171
|
8 |
|
* @return RepositoryInfo[] Returns ALL Repository Infos that are available and not just the one requested by id. |
172
|
|
|
*/ |
173
|
6 |
|
protected function getRepositoriesInternal($repositoryId = null) |
174
|
6 |
|
{ |
175
|
|
|
$repositoryUrlCache = $this->getRepositoryUrlCache(); |
176
|
2 |
|
|
177
|
2 |
|
if ($repositoryId === null) { |
178
|
|
|
// no repository id provided -> get all |
179
|
1 |
|
$url = $repositoryUrlCache->buildUrl($this->getServiceUrl()); |
180
|
1 |
|
} else { |
181
|
|
|
// use URL of the specified repository |
182
|
|
|
$url = $repositoryUrlCache->getRepositoryUrl($repositoryId, Constants::SELECTOR_REPOSITORY_INFO) ?? |
183
|
8 |
|
$repositoryUrlCache->buildUrl($this->getServiceUrl()); |
184
|
8 |
|
} |
185
|
8 |
|
|
186
|
|
|
$repositoryInfos = []; |
187
|
8 |
|
$result = $this->readJson($url); |
188
|
8 |
|
if (!is_array($result)) { |
189
|
1 |
|
throw new CmisConnectionException( |
190
|
1 |
|
'Could not fetch repository info! Response is not a valid JSON.', |
191
|
|
|
1416343166 |
192
|
1 |
|
); |
193
|
|
|
} |
194
|
7 |
|
foreach ($result as $item) { |
195
|
7 |
|
if (is_array($item)) { |
196
|
6 |
|
$repositoryInfo = $this->getJsonConverter()->convertRepositoryInfo($item); |
197
|
|
|
|
198
|
6 |
|
if ($repositoryInfo instanceof RepositoryInfoBrowserBinding) { |
199
|
6 |
|
$id = $repositoryInfo->getId(); |
200
|
6 |
|
$repositoryUrl = $repositoryInfo->getRepositoryUrl(); |
201
|
6 |
|
$rootUrl = $repositoryInfo->getRootUrl(); |
202
|
|
|
|
203
|
6 |
|
if (empty($id) || empty($repositoryUrl) || empty($rootUrl)) { |
204
|
3 |
|
throw new CmisConnectionException( |
205
|
3 |
|
sprintf('Found invalid Repository Info! (id: %s)', $id), |
206
|
|
|
1415187765 |
207
|
3 |
|
); |
208
|
|
|
} |
209
|
|
|
|
210
|
3 |
|
$this->getRepositoryUrlCache()->addRepository($id, $repositoryUrl, $rootUrl); |
211
|
|
|
|
212
|
3 |
|
$repositoryInfos[] = $repositoryInfo; |
213
|
3 |
|
} |
214
|
3 |
|
} else { |
215
|
1 |
|
throw new CmisConnectionException( |
216
|
1 |
|
sprintf( |
217
|
|
|
'Found invalid repository info! Value of type "array" was expected' |
218
|
1 |
|
. 'but value of type "%s" was given.', |
219
|
1 |
|
gettype($item) |
220
|
1 |
|
), |
221
|
|
|
1415187764 |
222
|
1 |
|
); |
223
|
|
|
} |
224
|
3 |
|
} |
225
|
|
|
|
226
|
3 |
|
return $repositoryInfos; |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* Returns the service URL of this session. |
231
|
|
|
* |
232
|
|
|
* @return string|null |
233
|
|
|
*/ |
234
|
2 |
|
protected function getServiceUrl() |
235
|
|
|
{ |
236
|
2 |
|
return $this->getSession()->get(SessionParameter::BROWSER_URL); |
237
|
2 |
|
} |
238
|
1 |
|
|
239
|
|
|
/** |
240
|
|
|
* Wrapper to read URL response as JSON as is the general use case. |
241
|
1 |
|
* |
242
|
|
|
* @param Url $url |
243
|
|
|
* @return mixed |
244
|
|
|
*/ |
245
|
|
|
protected function readJson(Url $url) |
246
|
|
|
{ |
247
|
|
|
return json_decode($this->read($url)->getBody(), true); |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* Do a get request for the given url |
252
|
3 |
|
* |
253
|
|
|
* @param Url $url |
254
|
|
|
* @return Response |
255
|
|
|
* @throws CmisBaseException an more specific exception of this type could be thrown. For more details see |
256
|
3 |
|
* @see AbstractBrowserBindingService::convertStatusCode() |
257
|
3 |
|
*/ |
258
|
2 |
|
protected function read(Url $url) |
259
|
2 |
|
{ |
260
|
2 |
|
/** @var Response $response */ |
261
|
2 |
|
try { |
262
|
2 |
|
$response = $this->getHttpInvoker()->get((string) $url); |
263
|
2 |
|
} catch (RequestException $exception) { |
264
|
2 |
|
$code = 0; |
265
|
2 |
|
$message = null; |
266
|
2 |
|
if ($exception->getResponse()) { |
267
|
|
|
$code = $exception->getResponse()->getStatusCode(); |
268
|
2 |
|
$message = $exception->getResponse()->getBody(); |
269
|
|
|
} |
270
|
|
|
throw $this->convertStatusCode( |
271
|
1 |
|
$code, |
272
|
|
|
(string) $message, |
273
|
|
|
$exception |
274
|
|
|
); |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
return $response; |
278
|
|
|
} |
279
|
4 |
|
|
280
|
|
|
/** |
281
|
|
|
* Get a HTTP Invoker instance |
282
|
4 |
|
* |
283
|
|
|
* @return Client |
284
|
4 |
|
*/ |
285
|
|
|
protected function getHttpInvoker() |
286
|
|
|
{ |
287
|
|
|
return $this->cmisBindingsHelper->getHttpInvoker($this->getSession()); |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
/** |
291
|
|
|
* Converts an error message or a HTTP status code into an Exception. |
292
|
|
|
* |
293
|
|
|
* @see http://docs.oasis-open.org/cmis/CMIS/v1.1/os/CMIS-v1.1-os.html#x1-551021r549 |
294
|
|
|
* |
295
|
|
|
* @param integer $code |
296
|
|
|
* @param string $message |
297
|
26 |
|
* @param null|\Exception $exception |
298
|
|
|
* @return CmisBaseException |
299
|
26 |
|
*/ |
300
|
|
|
protected function convertStatusCode($code, $message, \Exception $exception = null) |
301
|
26 |
|
{ |
302
|
13 |
|
$messageData = json_decode($message, true); |
303
|
|
|
|
304
|
13 |
|
if (is_array($messageData) && !empty($messageData[JSONConstants::ERROR_EXCEPTION])) { |
305
|
13 |
|
$jsonError = $messageData[JSONConstants::ERROR_EXCEPTION]; |
306
|
13 |
|
|
307
|
13 |
|
if (!empty($messageData[JSONConstants::ERROR_MESSAGE]) |
308
|
13 |
|
&& is_string($messageData[JSONConstants::ERROR_MESSAGE]) |
309
|
|
|
) { |
310
|
13 |
|
$message = $messageData[JSONConstants::ERROR_MESSAGE]; |
311
|
|
|
} |
312
|
13 |
|
|
313
|
12 |
|
$exceptionName = '\\Dkd\\PhpCmis\\Exception\\Cmis' . ucfirst($jsonError) . 'Exception'; |
314
|
|
|
|
315
|
1 |
|
if (class_exists($exceptionName)) { |
316
|
|
|
return new $exceptionName($message, null, $exception); |
317
|
14 |
|
} |
318
|
|
|
} |
319
|
|
|
|
320
|
|
|
if (empty($message) && $exception !== null) { |
321
|
|
|
$message = $exception->getMessage(); |
322
|
|
|
} |
323
|
14 |
|
|
324
|
14 |
|
// fall back to status code |
325
|
14 |
|
switch ($code) { |
326
|
14 |
|
case 301: |
327
|
4 |
|
case 302: |
328
|
4 |
|
case 303: |
329
|
4 |
|
case 307: |
330
|
|
|
return new CmisConnectionException( |
331
|
4 |
|
'Redirects are not supported (HTTP status code ' . $code . '): ' . $message, |
332
|
10 |
|
null, |
333
|
1 |
|
$exception |
334
|
9 |
|
); |
335
|
1 |
|
case 400: |
336
|
8 |
|
return new CmisInvalidArgumentException($message, null, $exception); |
337
|
1 |
|
case 401: |
338
|
7 |
|
return new CmisUnauthorizedException($message, null, $exception); |
339
|
1 |
|
case 403: |
340
|
6 |
|
return new CmisPermissionDeniedException($message, null, $exception); |
341
|
1 |
|
case 404: |
342
|
5 |
|
return new CmisObjectNotFoundException($message, null, $exception); |
343
|
1 |
|
case 405: |
344
|
4 |
|
return new CmisNotSupportedException($message, null, $exception); |
345
|
1 |
|
case 407: |
346
|
3 |
|
return new CmisProxyAuthenticationException($message, null, $exception); |
347
|
3 |
|
case 409: |
348
|
3 |
|
return new CmisConstraintException($message, null, $exception); |
349
|
|
|
default: |
350
|
|
|
return new CmisRuntimeException($message, null, $exception); |
351
|
|
|
} |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
// ---- helpers ---- |
355
|
|
|
|
356
|
|
|
/** |
357
|
|
|
* Returns JSON Converter instance |
358
|
65 |
|
* |
359
|
|
|
* @return \Dkd\PhpCmis\Converter\JsonConverter |
360
|
65 |
|
*/ |
361
|
|
|
protected function getJsonConverter() |
362
|
|
|
{ |
363
|
|
|
return $this->cmisBindingsHelper->getJsonConverter($this->getSession()); |
364
|
|
|
} |
365
|
|
|
|
366
|
|
|
/** |
367
|
|
|
* Generate url for a given path of a given repository. |
368
|
|
|
* |
369
|
|
|
* @param string $repositoryId |
370
|
|
|
* @param string $path |
371
|
|
|
* @param string|null $selector |
372
|
|
|
* @throws CmisConnectionException |
373
|
2 |
|
* @throws CmisObjectNotFoundException |
374
|
|
|
* @return Url |
375
|
2 |
|
*/ |
376
|
|
View Code Duplication |
protected function getPathUrl($repositoryId, $path, $selector = null) |
|
|
|
|
377
|
2 |
|
{ |
378
|
1 |
|
$result = $this->getRepositoryUrlCache()->getPathUrl($repositoryId, $path, $selector); |
379
|
1 |
|
|
380
|
1 |
|
if ($result === null) { |
381
|
|
|
$this->getRepositoriesInternal($repositoryId); |
382
|
2 |
|
$result = $this->getRepositoryUrlCache()->getPathUrl($repositoryId, $path, $selector); |
383
|
1 |
|
} |
384
|
1 |
|
|
385
|
1 |
|
if ($result === null) { |
386
|
1 |
|
throw new CmisObjectNotFoundException( |
387
|
1 |
|
sprintf( |
388
|
|
|
'Unknown path! Repository: "%s" | Path: "%s" | Selector: "%s"', |
389
|
1 |
|
$repositoryId, |
390
|
1 |
|
$path, |
391
|
|
|
$selector |
392
|
|
|
) |
393
|
1 |
|
); |
394
|
|
|
} |
395
|
|
|
|
396
|
|
|
return $result; |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
// ---- URL ---- |
400
|
|
|
|
401
|
|
|
/** |
402
|
|
|
* Get if succinct mode is used |
403
|
46 |
|
* |
404
|
|
|
* @return boolean |
405
|
46 |
|
*/ |
406
|
|
|
protected function getSuccinct() |
407
|
|
|
{ |
408
|
|
|
return $this->succinct; |
409
|
|
|
} |
410
|
|
|
|
411
|
|
|
/** |
412
|
|
|
* Wrapper for calling post() and reading response as JSON, as is the general use case. |
413
|
|
|
* |
414
|
|
|
* @param Url $url |
415
|
|
|
* @param array $content |
416
|
|
|
* @param array $headers |
417
|
|
|
* @return mixed |
418
|
|
|
*/ |
419
|
2 |
|
protected function postJson(Url $url, $content = [], array $headers = []) |
420
|
|
|
{ |
421
|
2 |
|
return \json_decode($this->post($url, $content, $headers)->getBody(), true); |
422
|
|
|
} |
423
|
|
|
|
424
|
|
|
/** |
425
|
2 |
|
* Performs a POST on an URL, checks the response code and returns the |
426
|
2 |
|
* result. |
427
|
1 |
|
* |
428
|
1 |
|
* @param Url $url Request url |
429
|
1 |
|
* @param resource|string|StreamInterface|array $content Entity body data or an array for POST fields and files |
430
|
|
|
* @param array $headers Additional header options |
431
|
1 |
|
* @return ResponseInterface |
432
|
|
|
* @throws CmisBaseException an more specific exception of this type could be thrown. For more details see |
433
|
|
|
* @see AbstractBrowserBindingService::convertStatusCode() |
434
|
1 |
|
*/ |
435
|
|
|
protected function post(Url $url, $content = [], array $headers = []) |
436
|
|
|
{ |
437
|
|
|
if (is_resource($content) || is_object($content)) { |
438
|
|
|
$headers['body'] = $content; |
439
|
|
|
} elseif (is_array($content)) { |
440
|
|
|
$headers['multipart'] = $this->convertQueryArrayToMultiPart($content); |
441
|
|
|
} |
442
|
|
|
|
443
|
|
|
try { |
444
|
|
|
return $this->getHttpInvoker()->post((string) $url, $headers); |
445
|
3 |
|
} catch (RequestException $exception) { |
446
|
|
|
throw $this->convertStatusCode( |
447
|
3 |
|
$exception->getResponse()->getStatusCode(), |
448
|
1 |
|
(string) $exception->getResponse()->getBody(), |
449
|
|
|
$exception |
450
|
|
|
); |
451
|
2 |
|
} |
452
|
1 |
|
} |
453
|
|
|
|
454
|
|
|
/** |
455
|
|
|
* @param array $queryArray |
456
|
1 |
|
* @param null $prefix |
457
|
1 |
|
* @return array |
458
|
|
|
*/ |
459
|
1 |
|
protected function convertQueryArrayToMultiPart(array $queryArray, $prefix = null) |
460
|
1 |
|
{ |
461
|
1 |
|
$multipart = []; |
462
|
|
|
foreach ($queryArray as $name => $value) { |
463
|
1 |
|
$prefixedName = $prefix ? $prefix . '[' . $name . ']' : $name; |
464
|
1 |
|
if (is_array($value)) { |
465
|
|
|
$multipart = array_merge($multipart, $this->convertQueryArrayToMultiPart($value, $prefixedName)); |
466
|
|
|
} elseif ($value instanceof StreamInterface) { |
467
|
|
|
$streamPart = [ |
468
|
|
|
'name' => '', |
469
|
|
|
'contents' => $value, |
470
|
|
|
'filename' => basename( $value->getMetadata('uri')) |
471
|
|
|
]; |
472
|
|
|
$mimetype = $value->getMetadata('mimetype'); |
473
|
|
|
if ($mimetype) { |
474
|
|
|
$streamPart['headers'] = ['Content-type' => $mimetype]; |
475
|
|
|
} |
476
|
2 |
|
$multipart[] = $streamPart; |
477
|
|
|
} else { |
478
|
2 |
|
$multipart[] = [ |
479
|
|
|
'name' => $prefix ? $prefixedName : $name, |
480
|
2 |
|
'contents' => $value |
481
|
1 |
|
]; |
482
|
1 |
|
} |
483
|
1 |
|
} |
484
|
|
|
return $multipart; |
485
|
2 |
|
} |
486
|
1 |
|
|
487
|
1 |
|
/** |
488
|
1 |
|
* Retrieves a type definition. |
489
|
1 |
|
* |
490
|
|
|
* @param string $repositoryId |
491
|
1 |
|
* @param string $typeId |
492
|
1 |
|
* @return TypeDefinitionInterface|null |
493
|
|
|
* @throws CmisInvalidArgumentException if repository id or type id is <code>null</code> |
494
|
|
|
*/ |
495
|
1 |
|
protected function getTypeDefinitionInternal($repositoryId, $typeId) |
496
|
|
|
{ |
497
|
|
|
if (empty($repositoryId)) { |
498
|
|
|
throw new CmisInvalidArgumentException('Repository id must not be empty!'); |
499
|
|
|
} |
500
|
|
|
|
501
|
|
|
if (empty($typeId)) { |
502
|
|
|
throw new CmisInvalidArgumentException('Type id must not be empty!'); |
503
|
|
|
} |
504
|
|
|
|
505
|
|
|
// build URL |
506
|
13 |
|
$url = $this->getRepositoryUrl($repositoryId, Constants::SELECTOR_TYPE_DEFINITION); |
507
|
|
|
$url->getQuery()->modify([Constants::PARAM_TYPE_ID => $typeId]); |
508
|
13 |
|
|
509
|
|
|
return $this->getJsonConverter()->convertTypeDefinition( |
510
|
13 |
|
(array) $this->readJson($url) |
511
|
13 |
|
); |
512
|
13 |
|
} |
513
|
13 |
|
|
514
|
13 |
|
/** |
515
|
|
|
* Get url for a repository |
516
|
13 |
|
* |
517
|
|
|
* @param string $repositoryId |
518
|
13 |
|
* @param string|null $selector |
519
|
13 |
|
* @throws CmisConnectionException |
520
|
13 |
|
* @throws CmisObjectNotFoundException |
521
|
13 |
|
* @return Url |
522
|
13 |
|
*/ |
523
|
13 |
View Code Duplication |
protected function getRepositoryUrl($repositoryId, $selector = null) |
|
|
|
|
524
|
1 |
|
{ |
525
|
1 |
|
$result = $this->getRepositoryUrlCache()->getRepositoryUrl($repositoryId, $selector); |
526
|
1 |
|
|
527
|
1 |
|
if ($result === null) { |
528
|
1 |
|
$this->getRepositoriesInternal($repositoryId); |
529
|
|
|
$result = $this->getRepositoryUrlCache()->getRepositoryUrl($repositoryId, $selector); |
530
|
1 |
|
} |
531
|
1 |
|
|
532
|
1 |
|
if ($result === null) { |
533
|
1 |
|
throw new CmisObjectNotFoundException( |
534
|
|
|
sprintf( |
535
|
13 |
|
'Unknown repository! Repository: "%s" | Selector: "%s"', |
536
|
13 |
|
$repositoryId, |
537
|
|
|
$selector |
538
|
13 |
|
) |
539
|
|
|
); |
540
|
|
|
} |
541
|
|
|
|
542
|
|
|
return $result; |
543
|
|
|
} |
544
|
|
|
|
545
|
|
|
/** |
546
|
|
|
* Converts a Properties list into an array that can be used for the CMIS request. |
547
|
13 |
|
* |
548
|
|
|
* @param PropertiesInterface $properties |
549
|
13 |
|
* @return array Example <code> |
550
|
|
|
* array('propertyId' => array(0 => 'myId'), 'propertyValue' => array(0 => 'valueOfMyId')) |
551
|
1 |
|
* </code> |
552
|
13 |
|
*/ |
553
|
|
|
protected function convertPropertiesToQueryArray(PropertiesInterface $properties) |
554
|
1 |
|
{ |
555
|
1 |
|
$propertiesArray = []; |
556
|
|
|
|
557
|
13 |
|
$propertyCounter = 0; |
558
|
|
|
$propertiesArray[Constants::CONTROL_PROP_ID] = []; |
559
|
|
|
$propertiesArray[Constants::CONTROL_PROP_VALUE] = []; |
560
|
|
|
foreach ($properties->getProperties() as $property) { |
561
|
|
|
$propertiesArray[Constants::CONTROL_PROP_ID][$propertyCounter] = $property->getId(); |
562
|
|
|
|
563
|
|
|
$propertyValues = $property->getValues(); |
564
|
|
|
|
565
|
|
|
if (count($propertyValues) === 1) { |
566
|
|
|
$propertiesArray[Constants::CONTROL_PROP_VALUE][$propertyCounter] = |
567
|
|
|
$this->convertPropertyValueToSimpleType( |
568
|
|
|
$property->getFirstValue() |
569
|
|
|
); |
570
|
|
|
} elseif (count($propertyValues) > 1) { |
571
|
|
|
$propertyValueCounter = 0; |
572
|
|
|
$propertiesArray[Constants::CONTROL_PROP_VALUE][$propertyCounter] = []; |
573
|
7 |
|
foreach ($propertyValues as $propertyValue) { |
574
|
|
|
$propertiesArray[Constants::CONTROL_PROP_VALUE][$propertyCounter][$propertyValueCounter] = |
575
|
7 |
|
$this->convertPropertyValueToSimpleType( |
576
|
7 |
|
$propertyValue |
577
|
|
|
); |
578
|
7 |
|
$propertyValueCounter ++; |
579
|
7 |
|
} |
580
|
7 |
|
} |
581
|
7 |
|
|
582
|
7 |
|
$propertyCounter ++; |
583
|
7 |
|
} |
584
|
|
|
|
585
|
7 |
|
return $propertiesArray; |
586
|
7 |
|
} |
587
|
7 |
|
|
588
|
7 |
|
/** |
589
|
|
|
* Converts values to a format that can be used for the CMIS Browser binding request. |
590
|
7 |
|
* |
591
|
7 |
|
* @param mixed $value |
592
|
7 |
|
* @return mixed |
593
|
|
|
*/ |
594
|
7 |
|
protected function convertPropertyValueToSimpleType($value) |
595
|
|
|
{ |
596
|
|
|
if ($value instanceof \DateTime) { |
597
|
|
|
// CMIS expects a timestamp in milliseconds |
598
|
|
|
$value = $value->getTimestamp() * 1000; |
599
|
|
|
} elseif (is_bool($value)) { |
600
|
|
|
// Booleans must be represented in string form since request will fail if cast to integer |
601
|
|
|
$value = $value ? 'true' : 'false'; |
602
|
|
|
} |
603
|
10 |
|
|
604
|
|
|
return $value; |
605
|
10 |
|
} |
606
|
10 |
|
|
607
|
|
|
/** |
608
|
10 |
|
* Converts a Access Control list into an array that can be used for the CMIS request |
609
|
6 |
|
* |
610
|
6 |
|
* @param AclInterface $acl |
611
|
10 |
|
* @param string $principalControl one of principal ace constants |
612
|
|
|
* CONTROL_ADD_ACE_PRINCIPAL or CONTROL_REMOVE_ACE_PRINCIPAL |
613
|
10 |
|
* @param string $permissionControl one of permission ace constants |
614
|
|
|
* CONTROL_REMOVE_ACE_PRINCIPAL or CONTROL_REMOVE_ACE_PERMISSION |
615
|
|
|
* @return array Example <code> |
616
|
|
|
* array('addACEPrincipal' => array(0 => 'principalId'), |
617
|
|
|
* 'addACEPermission' => array(0 => array(0 => 'permissonValue'))) |
618
|
|
|
* </code> |
619
|
|
|
*/ |
620
|
|
|
protected function convertAclToQueryArray(AclInterface $acl, $principalControl, $permissionControl) |
621
|
32 |
|
{ |
622
|
|
|
$acesArray = []; |
623
|
32 |
|
$principalCounter = 0; |
624
|
|
|
|
625
|
|
|
foreach ($acl->getAces() as $ace) { |
626
|
|
|
$permissions = $ace->getPermissions(); |
627
|
|
|
if ($ace->getPrincipal() !== null && $ace->getPrincipal()->getId() && !empty($permissions)) { |
628
|
|
|
$acesArray[$principalControl][$principalCounter] = $ace->getPrincipal()->getId(); |
629
|
|
|
$permissionCounter = 0; |
630
|
|
|
$acesArray[$permissionControl][$principalCounter] = []; |
631
|
1 |
|
|
632
|
|
|
foreach ($permissions as $permission) { |
633
|
1 |
|
$acesArray[$permissionControl][$principalCounter][$permissionCounter] = $permission; |
634
|
1 |
|
$permissionCounter ++; |
635
|
|
|
} |
636
|
|
|
|
637
|
|
|
$principalCounter ++; |
638
|
|
|
} |
639
|
|
|
} |
640
|
|
|
|
641
|
|
|
return $acesArray; |
642
|
|
|
} |
643
|
|
|
|
644
|
|
|
/** |
645
|
|
|
* Converts a policies array into an array that can be used for the CMIS request |
646
|
|
|
* |
647
|
|
|
* @param string[] $policies A list of policy string representations |
648
|
|
|
* @return array |
649
|
|
|
*/ |
650
|
|
|
protected function convertPolicyIdArrayToQueryArray(array $policies) |
651
|
|
|
{ |
652
|
|
|
$policiesArray = []; |
653
|
|
|
$policyCounter = 0; |
654
|
|
|
|
655
|
|
|
foreach ($policies as $policy) { |
656
|
|
|
$policiesArray[Constants::CONTROL_POLICY][$policyCounter] = (string) $policy; |
657
|
|
|
$policyCounter ++; |
658
|
|
|
} |
659
|
|
|
|
660
|
|
|
return $policiesArray; |
661
|
|
|
} |
662
|
|
|
|
663
|
|
|
/** |
664
|
|
|
* Returns the date time format |
665
|
|
|
* |
666
|
|
|
* @return DateTimeFormat |
667
|
|
|
*/ |
668
|
|
|
public function getDateTimeFormat() |
669
|
|
|
{ |
670
|
|
|
return $this->dateTimeFormat; |
671
|
|
|
} |
672
|
|
|
|
673
|
|
|
/** |
674
|
|
|
* Sets the date time format |
675
|
|
|
* |
676
|
|
|
* @param DateTimeFormat $dateTimeFormat |
677
|
|
|
*/ |
678
|
|
|
public function setDateTimeFormat(DateTimeFormat $dateTimeFormat) |
679
|
|
|
{ |
680
|
|
|
$this->dateTimeFormat = $dateTimeFormat; |
681
|
|
|
} |
682
|
|
|
|
683
|
|
|
/** |
684
|
|
|
* Appends policies parameters to url |
685
|
|
|
* |
686
|
|
|
* @param Url $url |
687
|
|
|
* @param string[] $policies A list of policy IDs that must be applied to the newly created document object |
688
|
|
|
*/ |
689
|
|
|
protected function appendPoliciesToUrl(Url $url, array $policies) |
690
|
|
|
{ |
691
|
|
|
if (!empty($policies)) { |
692
|
|
|
$url->getQuery()->modify($this->convertPolicyIdArrayToQueryArray($policies)); |
693
|
|
|
} |
694
|
|
|
} |
695
|
|
|
|
696
|
|
|
/** |
697
|
|
|
* Appends addAces parameters to url |
698
|
|
|
* |
699
|
|
|
* @param Url $url |
700
|
|
|
* @param AclInterface|null $addAces A list of ACEs |
701
|
|
|
*/ |
702
|
|
View Code Duplication |
protected function appendAddAcesToUrl(Url $url, AclInterface $addAces = null) |
|
|
|
|
703
|
|
|
{ |
704
|
|
|
if ($addAces !== null) { |
705
|
|
|
$url->getQuery()->modify( |
706
|
|
|
$this->convertAclToQueryArray( |
707
|
|
|
$addAces, |
708
|
|
|
Constants::CONTROL_ADD_ACE_PRINCIPAL, |
709
|
|
|
Constants::CONTROL_ADD_ACE_PERMISSION |
710
|
|
|
) |
711
|
|
|
); |
712
|
|
|
} |
713
|
|
|
} |
714
|
|
|
|
715
|
|
|
/** |
716
|
|
|
* Appends removeAces parameters to url |
717
|
|
|
* |
718
|
|
|
* @param Url $url |
719
|
|
|
* @param AclInterface|null $removeAces A list of ACEs |
720
|
|
|
*/ |
721
|
|
View Code Duplication |
protected function appendRemoveAcesToUrl(Url $url, AclInterface $removeAces = null) |
|
|
|
|
722
|
|
|
{ |
723
|
|
|
if ($removeAces !== null) { |
724
|
|
|
$url->getQuery()->modify( |
725
|
|
|
$this->convertAclToQueryArray( |
726
|
|
|
$removeAces, |
727
|
|
|
Constants::CONTROL_REMOVE_ACE_PRINCIPAL, |
728
|
|
|
Constants::CONTROL_REMOVE_ACE_PERMISSION |
729
|
|
|
) |
730
|
|
|
); |
731
|
|
|
} |
732
|
|
|
} |
733
|
|
|
|
734
|
|
|
/** |
735
|
|
|
* Gets the content link from the cache if it is there or loads it into the |
736
|
|
|
* cache if it is not there. |
737
|
|
|
* |
738
|
|
|
* @param string $repositoryId |
739
|
|
|
* @param string $documentId |
740
|
|
|
* @return string|null |
741
|
|
|
*/ |
742
|
|
|
public function loadContentLink($repositoryId, $documentId) |
743
|
|
|
{ |
744
|
|
|
$result = $this->getRepositoryUrlCache()->getObjectUrl($repositoryId, $documentId, Constants::SELECTOR_CONTENT); |
745
|
|
|
return $result === null ? null : (string) $result; |
746
|
|
|
} |
747
|
|
|
|
748
|
|
|
/** |
749
|
|
|
* Gets a rendition content link from the cache if it is there or loads it |
750
|
|
|
* into the cache if it is not there. |
751
|
|
|
* |
752
|
|
|
* @param string $repositoryId |
753
|
|
|
* @param string $documentId |
754
|
|
|
* @param string $streamId |
755
|
|
|
* @return string|null |
756
|
|
|
*/ |
757
|
|
|
public function loadRenditionContentLink($repositoryId, $documentId, $streamId) |
758
|
|
|
{ |
759
|
|
|
$result = $this->getRepositoryUrlCache()->getObjectUrl($repositoryId, $documentId, Constants::SELECTOR_CONTENT); |
760
|
|
|
if ($result !== null) { |
761
|
|
|
$result->getQuery()->modify([Constants::PARAM_STREAM_ID => $streamId]); |
762
|
|
|
$result = (string) $result; |
763
|
|
|
} |
764
|
|
|
return $result; |
765
|
|
|
} |
766
|
|
|
} |
767
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.