|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* @copyright Copyright (C) eZ Systems AS. All rights reserved. |
|
5
|
|
|
* @license For full copyright and license information view LICENSE file distributed with this source code. |
|
6
|
|
|
*/ |
|
7
|
|
|
namespace eZ\Publish\Core\REST\Client; |
|
8
|
|
|
|
|
9
|
|
|
use eZ\Publish\API\Repository\LocationService as APILocationService; |
|
10
|
|
|
use eZ\Publish\API\Repository\Values\Content\LocationUpdateStruct; |
|
11
|
|
|
use eZ\Publish\API\Repository\Values\Content\LocationCreateStruct; |
|
12
|
|
|
use eZ\Publish\API\Repository\Values\Content\ContentInfo; |
|
13
|
|
|
use eZ\Publish\API\Repository\Values\Content\Location; |
|
14
|
|
|
use eZ\Publish\API\Repository\Values\Content\VersionInfo; |
|
15
|
|
|
use eZ\Publish\Core\REST\Common\RequestParser; |
|
16
|
|
|
use eZ\Publish\Core\REST\Common\Input\Dispatcher; |
|
17
|
|
|
use eZ\Publish\Core\REST\Common\Output\Visitor; |
|
18
|
|
|
use eZ\Publish\Core\REST\Common\Message; |
|
19
|
|
|
use eZ\Publish\API\Repository\Values\ContentType\ContentType; |
|
20
|
|
|
|
|
21
|
|
|
/** |
|
22
|
|
|
* Location service, used for complex subtree operations. |
|
23
|
|
|
* |
|
24
|
|
|
* @example Examples/location.php |
|
25
|
|
|
*/ |
|
26
|
|
|
class LocationService implements APILocationService, Sessionable |
|
27
|
|
|
{ |
|
28
|
|
|
/** @var \eZ\Publish\Core\REST\Client\HttpClient */ |
|
29
|
|
|
private $client; |
|
30
|
|
|
|
|
31
|
|
|
/** @var \eZ\Publish\Core\REST\Common\Input\Dispatcher */ |
|
32
|
|
|
private $inputDispatcher; |
|
33
|
|
|
|
|
34
|
|
|
/** @var \eZ\Publish\Core\REST\Common\Output\Visitor */ |
|
35
|
|
|
private $outputVisitor; |
|
36
|
|
|
|
|
37
|
|
|
/** @var \eZ\Publish\Core\REST\Common\RequestParser */ |
|
38
|
|
|
private $requestParser; |
|
39
|
|
|
|
|
40
|
|
|
/** |
|
41
|
|
|
* @param \eZ\Publish\Core\REST\Client\HttpClient $client |
|
42
|
|
|
* @param \eZ\Publish\Core\REST\Common\Input\Dispatcher $inputDispatcher |
|
43
|
|
|
* @param \eZ\Publish\Core\REST\Common\Output\Visitor $outputVisitor |
|
44
|
|
|
* @param \eZ\Publish\Core\REST\Common\RequestParser $requestParser |
|
45
|
|
|
*/ |
|
46
|
|
|
public function __construct(HttpClient $client, Dispatcher $inputDispatcher, Visitor $outputVisitor, RequestParser $requestParser) |
|
47
|
|
|
{ |
|
48
|
|
|
$this->client = $client; |
|
49
|
|
|
$this->inputDispatcher = $inputDispatcher; |
|
50
|
|
|
$this->outputVisitor = $outputVisitor; |
|
51
|
|
|
$this->requestParser = $requestParser; |
|
52
|
|
|
} |
|
53
|
|
|
|
|
54
|
|
|
/** |
|
55
|
|
|
* Set session ID. |
|
56
|
|
|
* |
|
57
|
|
|
* Only for testing |
|
58
|
|
|
* |
|
59
|
|
|
* @param mixed $id |
|
60
|
|
|
* |
|
61
|
|
|
* @private |
|
62
|
|
|
*/ |
|
63
|
|
|
public function setSession($id) |
|
64
|
|
|
{ |
|
65
|
|
|
if ($this->outputVisitor instanceof Sessionable) { |
|
66
|
|
|
$this->outputVisitor->setSession($id); |
|
67
|
|
|
} |
|
68
|
|
|
} |
|
69
|
|
|
|
|
70
|
|
|
/** |
|
71
|
|
|
* Instantiates a new location create class. |
|
72
|
|
|
* |
|
73
|
|
|
* @param mixed $parentLocationId the parent under which the new location should be created |
|
74
|
|
|
* @param \eZ\Publish\API\Repository\Values\ContentType\ContentType|null $contentType |
|
75
|
|
|
* |
|
76
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct |
|
77
|
|
|
*/ |
|
78
|
|
View Code Duplication |
public function newLocationCreateStruct($parentLocationId, ContentType $contentType = null) |
|
79
|
|
|
{ |
|
80
|
|
|
$properties = [ |
|
81
|
|
|
'parentLocationId' => $parentLocationId, |
|
82
|
|
|
]; |
|
83
|
|
|
if ($contentType) { |
|
84
|
|
|
$properties['sortField'] = $contentType->defaultSortField; |
|
85
|
|
|
$properties['sortOrder'] = $contentType->defaultSortOrder; |
|
86
|
|
|
} |
|
87
|
|
|
|
|
88
|
|
|
return new LocationCreateStruct($properties); |
|
89
|
|
|
} |
|
90
|
|
|
|
|
91
|
|
|
/** |
|
92
|
|
|
* Creates the new $location in the content repository for the given content. |
|
93
|
|
|
* |
|
94
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user user is not allowed to create this location |
|
95
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the content is already below the specified parent |
|
96
|
|
|
* or the parent is a sub location of the location the content |
|
97
|
|
|
* or if set the remoteId exists already |
|
98
|
|
|
* |
|
99
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo |
|
100
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct $locationCreateStruct |
|
101
|
|
|
* |
|
102
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Location the newly created Location |
|
103
|
|
|
*/ |
|
104
|
|
|
public function createLocation(ContentInfo $contentInfo, LocationCreateStruct $locationCreateStruct) |
|
105
|
|
|
{ |
|
106
|
|
|
$inputMessage = $this->outputVisitor->visit($locationCreateStruct); |
|
107
|
|
|
$inputMessage->headers['Accept'] = $this->outputVisitor->getMediaType('Location'); |
|
108
|
|
|
|
|
109
|
|
|
$values = $this->requestParser->parse('object', $contentInfo->id); |
|
110
|
|
|
$result = $this->client->request( |
|
111
|
|
|
'POST', |
|
112
|
|
|
$this->requestParser->generate('objectLocations', ['object' => $values['object']]), |
|
113
|
|
|
$inputMessage |
|
114
|
|
|
); |
|
115
|
|
|
|
|
116
|
|
|
return $this->inputDispatcher->parse($result); |
|
117
|
|
|
} |
|
118
|
|
|
|
|
119
|
|
|
/** |
|
120
|
|
|
* {@inheritdoc). |
|
121
|
|
|
*/ |
|
122
|
|
|
public function loadLocation($locationId, array $prioritizedLanguages = null, bool $useAlwaysAvailable = null) |
|
123
|
|
|
{ |
|
124
|
|
|
$response = $this->client->request( |
|
125
|
|
|
'GET', |
|
126
|
|
|
$locationId, |
|
127
|
|
|
new Message( |
|
128
|
|
|
['Accept' => $this->outputVisitor->getMediaType('Location')] |
|
129
|
|
|
) |
|
130
|
|
|
); |
|
131
|
|
|
|
|
132
|
|
|
return $this->inputDispatcher->parse($response); |
|
133
|
|
|
} |
|
134
|
|
|
|
|
135
|
|
|
/** |
|
136
|
|
|
* {@inheritdoc). |
|
137
|
|
|
*/ |
|
138
|
|
View Code Duplication |
public function loadLocationList(array $locationIds, array $prioritizedLanguages = null, bool $useAlwaysAvailable = null): iterable |
|
139
|
|
|
{ |
|
140
|
|
|
// @todo Implement server part, ala: https://gist.github.com/andrerom/f2f328029ae7a9d78b363282b3ddf4a4 |
|
141
|
|
|
|
|
142
|
|
|
$response = $this->client->request( |
|
143
|
|
|
'GET', |
|
144
|
|
|
$this->requestParser->generate('locationsByIds', ['locations' => $locationIds]), |
|
145
|
|
|
new Message(['Accept' => $this->outputVisitor->getMediaType('LocationList')]) |
|
146
|
|
|
); |
|
147
|
|
|
|
|
148
|
|
|
return $this->inputDispatcher->parse($response); |
|
|
|
|
|
|
149
|
|
|
} |
|
150
|
|
|
|
|
151
|
|
|
/** |
|
152
|
|
|
* {@inheritdoc). |
|
153
|
|
|
*/ |
|
154
|
|
View Code Duplication |
public function loadLocationByRemoteId($remoteId, array $prioritizedLanguages = null, bool $useAlwaysAvailable = null) |
|
155
|
|
|
{ |
|
156
|
|
|
$response = $this->client->request( |
|
157
|
|
|
'GET', |
|
158
|
|
|
$this->requestParser->generate('locationByRemote', ['location' => $remoteId]), |
|
159
|
|
|
new Message( |
|
160
|
|
|
['Accept' => $this->outputVisitor->getMediaType('LocationList')] |
|
161
|
|
|
) |
|
162
|
|
|
); |
|
163
|
|
|
|
|
164
|
|
|
return reset($this->inputDispatcher->parse($response)); |
|
|
|
|
|
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
/** |
|
168
|
|
|
* Instantiates a new location update class. |
|
169
|
|
|
* |
|
170
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\LocationUpdateStruct |
|
171
|
|
|
*/ |
|
172
|
|
|
public function newLocationUpdateStruct() |
|
173
|
|
|
{ |
|
174
|
|
|
return new LocationUpdateStruct(); |
|
175
|
|
|
} |
|
176
|
|
|
|
|
177
|
|
|
/** |
|
178
|
|
|
* Updates $location in the content repository. |
|
179
|
|
|
* |
|
180
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user user is not allowed to update this location |
|
181
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if if set the remoteId exists already |
|
182
|
|
|
* |
|
183
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $location |
|
184
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\LocationUpdateStruct $locationUpdateStruct |
|
185
|
|
|
* |
|
186
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Location the updated Location |
|
187
|
|
|
*/ |
|
188
|
|
|
public function updateLocation(Location $location, LocationUpdateStruct $locationUpdateStruct) |
|
189
|
|
|
{ |
|
190
|
|
|
$inputMessage = $this->outputVisitor->visit($locationUpdateStruct); |
|
191
|
|
|
$inputMessage->headers['Accept'] = $this->outputVisitor->getMediaType('Location'); |
|
192
|
|
|
$inputMessage->headers['X-HTTP-Method-Override'] = 'PATCH'; |
|
193
|
|
|
|
|
194
|
|
|
$result = $this->client->request( |
|
195
|
|
|
'POST', |
|
196
|
|
|
$location->id, |
|
197
|
|
|
$inputMessage |
|
198
|
|
|
); |
|
199
|
|
|
|
|
200
|
|
|
return $this->inputDispatcher->parse($result); |
|
201
|
|
|
} |
|
202
|
|
|
|
|
203
|
|
|
/** |
|
204
|
|
|
* Loads the locations for the given content object. |
|
205
|
|
|
* |
|
206
|
|
|
* If a $rootLocation is given, only locations that belong to this location are returned. |
|
207
|
|
|
* The location list is also filtered by permissions on reading locations. |
|
208
|
|
|
* |
|
209
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\BadStateException if there is no published version yet |
|
210
|
|
|
* |
|
211
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo |
|
212
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $rootLocation |
|
213
|
|
|
* @param string[]|null $prioritizedLanguages Used as prioritized language code on translated properties of returned object. |
|
214
|
|
|
* |
|
215
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Location[] |
|
216
|
|
|
*/ |
|
217
|
|
|
public function loadLocations(ContentInfo $contentInfo, Location $rootLocation = null, array $prioritizedLanguages = null) |
|
218
|
|
|
{ |
|
219
|
|
|
$values = $this->requestParser->parse('object', $contentInfo->id); |
|
220
|
|
|
$response = $this->client->request( |
|
221
|
|
|
'GET', |
|
222
|
|
|
$this->requestParser->generate('objectLocations', ['object' => $values['object']]), |
|
223
|
|
|
new Message( |
|
224
|
|
|
['Accept' => $this->outputVisitor->getMediaType('LocationList')] |
|
225
|
|
|
) |
|
226
|
|
|
); |
|
227
|
|
|
|
|
228
|
|
|
return $this->inputDispatcher->parse($response); |
|
|
|
|
|
|
229
|
|
|
} |
|
230
|
|
|
|
|
231
|
|
|
/** |
|
232
|
|
|
* Loads children which are readable by the current user of a location object sorted by sortField and sortOrder. |
|
233
|
|
|
* |
|
234
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $location |
|
235
|
|
|
* @param int $offset the start offset for paging |
|
236
|
|
|
* @param int $limit the number of locations returned |
|
237
|
|
|
* @param string[]|null $prioritizedLanguages Used as prioritized language code on translated properties of returned object. |
|
238
|
|
|
* |
|
239
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\LocationList |
|
240
|
|
|
*/ |
|
241
|
|
View Code Duplication |
public function loadLocationChildren(Location $location, $offset = 0, $limit = 25, array $prioritizedLanguages = null) |
|
242
|
|
|
{ |
|
243
|
|
|
$values = $this->requestParser->parse('location', $location->id); |
|
244
|
|
|
$response = $this->client->request( |
|
245
|
|
|
'GET', |
|
246
|
|
|
$this->requestParser->generate('locationChildren', ['location' => $values['location']]), |
|
247
|
|
|
new Message( |
|
248
|
|
|
['Accept' => $this->outputVisitor->getMediaType('LocationList')] |
|
249
|
|
|
) |
|
250
|
|
|
); |
|
251
|
|
|
|
|
252
|
|
|
return $this->inputDispatcher->parse($response); |
|
253
|
|
|
} |
|
254
|
|
|
|
|
255
|
|
|
/** |
|
256
|
|
|
* Load parent Locations for Content Draft. |
|
257
|
|
|
* |
|
258
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\VersionInfo $versionInfo |
|
259
|
|
|
* @param string[]|null $prioritizedLanguages Used as prioritized language code on translated properties of returned object. |
|
260
|
|
|
* |
|
261
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Location[] List of parent Locations |
|
262
|
|
|
*/ |
|
263
|
|
|
public function loadParentLocationsForDraftContent(VersionInfo $versionInfo, array $prioritizedLanguages = null) |
|
264
|
|
|
{ |
|
265
|
|
|
throw new \Exception('@todo: Implement.'); |
|
266
|
|
|
} |
|
267
|
|
|
|
|
268
|
|
|
/** |
|
269
|
|
|
* Returns the number of children which are readable by the current user of a location object. |
|
270
|
|
|
* |
|
271
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $location |
|
272
|
|
|
* |
|
273
|
|
|
* @return int |
|
274
|
|
|
*/ |
|
275
|
|
|
public function getLocationChildCount(Location $location) |
|
276
|
|
|
{ |
|
277
|
|
|
throw new \Exception('@todo: Implement.'); |
|
278
|
|
|
} |
|
279
|
|
|
|
|
280
|
|
|
/** |
|
281
|
|
|
* Swaps the contents hold by the $location1 and $location2. |
|
282
|
|
|
* |
|
283
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user user is not allowed to swap content |
|
284
|
|
|
* |
|
285
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $location1 |
|
286
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $location2 |
|
287
|
|
|
*/ |
|
288
|
|
|
public function swapLocation(Location $location1, Location $location2) |
|
289
|
|
|
{ |
|
290
|
|
|
throw new \Exception('@todo: Implement.'); |
|
291
|
|
|
} |
|
292
|
|
|
|
|
293
|
|
|
/** |
|
294
|
|
|
* Hides the $location and marks invisible all descendants of $location. |
|
295
|
|
|
* |
|
296
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user user is not allowed to hide this location |
|
297
|
|
|
* |
|
298
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $location |
|
299
|
|
|
* |
|
300
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Location $location, with updated hidden value |
|
301
|
|
|
*/ |
|
302
|
|
|
public function hideLocation(Location $location) |
|
303
|
|
|
{ |
|
304
|
|
|
throw new \Exception('@todo: Implement.'); |
|
305
|
|
|
} |
|
306
|
|
|
|
|
307
|
|
|
/** |
|
308
|
|
|
* Unhides the $location. |
|
309
|
|
|
* |
|
310
|
|
|
* This method and marks visible all descendants of $locations |
|
311
|
|
|
* until a hidden location is found. |
|
312
|
|
|
* |
|
313
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user user is not allowed to unhide this location |
|
314
|
|
|
* |
|
315
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $location |
|
316
|
|
|
* |
|
317
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Location $location, with updated hidden value |
|
318
|
|
|
*/ |
|
319
|
|
|
public function unhideLocation(Location $location) |
|
320
|
|
|
{ |
|
321
|
|
|
throw new \Exception('@todo: Implement.'); |
|
322
|
|
|
} |
|
323
|
|
|
|
|
324
|
|
|
/** |
|
325
|
|
|
* Deletes $location and all its descendants. |
|
326
|
|
|
* |
|
327
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user is not allowed to delete this location or a descendant |
|
328
|
|
|
* |
|
329
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $location |
|
330
|
|
|
*/ |
|
331
|
|
|
public function deleteLocation(Location $location) |
|
332
|
|
|
{ |
|
333
|
|
|
throw new \Exception('@todo: Implement.'); |
|
334
|
|
|
} |
|
335
|
|
|
|
|
336
|
|
|
/** |
|
337
|
|
|
* Copies the subtree starting from $subtree as a new subtree of $targetLocation. |
|
338
|
|
|
* |
|
339
|
|
|
* Only the items on which the user has read access are copied. |
|
340
|
|
|
* |
|
341
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user user is not allowed copy the subtree to the given parent location |
|
342
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if the target location is a sub location of the given location |
|
343
|
|
|
* |
|
344
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $subtree - the subtree denoted by the location to copy |
|
345
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $targetParentLocation - the target parent location for the copy operation |
|
346
|
|
|
* |
|
347
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Location The newly created location of the copied subtree |
|
348
|
|
|
* |
|
349
|
|
|
* @todo enhancement - this method should return a result structure containing the new location and a list |
|
350
|
|
|
* of locations which are not copied due to permission denials. |
|
351
|
|
|
*/ |
|
352
|
|
|
public function copySubtree(Location $subtree, Location $targetParentLocation) |
|
353
|
|
|
{ |
|
354
|
|
|
throw new \Exception('@todo: Implement.'); |
|
355
|
|
|
} |
|
356
|
|
|
|
|
357
|
|
|
/** |
|
358
|
|
|
* Moves the subtree to $newParentLocation. |
|
359
|
|
|
* |
|
360
|
|
|
* If a user has the permission to move the location to a target location |
|
361
|
|
|
* he can do it regardless of an existing descendant on which the user has no permission. |
|
362
|
|
|
* |
|
363
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException If the current user user is not allowed to move this location to the target |
|
364
|
|
|
* |
|
365
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $location |
|
366
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $newParentLocation |
|
367
|
|
|
*/ |
|
368
|
|
|
public function moveSubtree(Location $location, Location $newParentLocation) |
|
369
|
|
|
{ |
|
370
|
|
|
throw new \Exception('@todo: Implement.'); |
|
371
|
|
|
} |
|
372
|
|
|
|
|
373
|
|
|
public function getAllLocationsCount(): int |
|
374
|
|
|
{ |
|
375
|
|
|
throw new \Exception('@todo: Implement.'); |
|
376
|
|
|
} |
|
377
|
|
|
|
|
378
|
|
|
/** |
|
379
|
|
|
* @param int $limit |
|
380
|
|
|
* @param int $offset |
|
381
|
|
|
* |
|
382
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Location[] |
|
383
|
|
|
* |
|
384
|
|
|
* @throws \Exception |
|
385
|
|
|
*/ |
|
386
|
|
|
public function loadAllLocations(int $offset = 0, int $limit = 25): array |
|
387
|
|
|
{ |
|
388
|
|
|
throw new \Exception('@todo: Implement.'); |
|
389
|
|
|
} |
|
390
|
|
|
|
|
391
|
|
|
/** |
|
392
|
|
|
* @throws \Exception |
|
393
|
|
|
*/ |
|
394
|
|
|
public function loadFirstAvailableLocation(ContentInfo $contentInfo, array $prioritizedLanguages = null): Location |
|
395
|
|
|
{ |
|
396
|
|
|
throw new \Exception('@todo: Implement.'); |
|
397
|
|
|
} |
|
398
|
|
|
} |
|
399
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_functionexpects aPostobject, and outputs the author of the post. The base classPostreturns a simple string and outputting a simple string will work just fine. However, the child classBlogPostwhich is a sub-type ofPostinstead decided to return anobject, and is therefore violating the SOLID principles. If aBlogPostwere passed tomy_function, PHP would not complain, but ultimately fail when executing thestrtouppercall in its body.