1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* File containing the eZ\Publish\Core\Repository\TrashService class. |
5
|
|
|
* |
6
|
|
|
* @copyright Copyright (C) eZ Systems AS. All rights reserved. |
7
|
|
|
* @license For full copyright and license information view LICENSE file distributed with this source code. |
8
|
|
|
*/ |
9
|
|
|
namespace eZ\Publish\Core\Repository; |
10
|
|
|
|
11
|
|
|
use eZ\Publish\API\Repository\TrashService as TrashServiceInterface; |
12
|
|
|
use eZ\Publish\API\Repository\Repository as RepositoryInterface; |
13
|
|
|
use eZ\Publish\SPI\Persistence\Handler; |
14
|
|
|
use eZ\Publish\API\Repository\Values\Content\Location; |
15
|
|
|
use eZ\Publish\Core\Repository\Values\Content\TrashItem; |
16
|
|
|
use eZ\Publish\API\Repository\Values\Content\TrashItem as APITrashItem; |
17
|
|
|
use eZ\Publish\API\Repository\Values\Content\Query; |
18
|
|
|
use eZ\Publish\SPI\Persistence\Content\Location\Trashed; |
19
|
|
|
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentValue; |
20
|
|
|
use eZ\Publish\Core\Base\Exceptions\UnauthorizedException; |
21
|
|
|
use eZ\Publish\API\Repository\Values\Content\SearchResult; |
22
|
|
|
use eZ\Publish\API\Repository\Values\Content\Query\Criterion; |
23
|
|
|
use eZ\Publish\API\Repository\Values\Content\Query\SortClause; |
24
|
|
|
use DateTime; |
25
|
|
|
use Exception; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Trash service, used for managing trashed content. |
29
|
|
|
*/ |
30
|
|
|
class TrashService implements TrashServiceInterface |
31
|
|
|
{ |
32
|
|
|
/** |
33
|
|
|
* @var \eZ\Publish\API\Repository\Repository |
34
|
|
|
*/ |
35
|
|
|
protected $repository; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @var \eZ\Publish\SPI\Persistence\Handler |
39
|
|
|
*/ |
40
|
|
|
protected $persistenceHandler; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @var array |
44
|
|
|
*/ |
45
|
|
|
protected $settings; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var \eZ\Publish\Core\Repository\Helper\NameSchemaService |
49
|
|
|
*/ |
50
|
|
|
protected $nameSchemaService; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Setups service with reference to repository object that created it & corresponding handler. |
54
|
|
|
* |
55
|
|
|
* @param \eZ\Publish\API\Repository\Repository $repository |
56
|
|
|
* @param \eZ\Publish\SPI\Persistence\Handler $handler |
57
|
|
|
* @param \eZ\Publish\Core\Repository\Helper\NameSchemaService $nameSchemaService |
58
|
|
|
* @param array $settings |
59
|
|
|
*/ |
60
|
|
|
public function __construct( |
61
|
|
|
RepositoryInterface $repository, |
62
|
|
|
Handler $handler, |
63
|
|
|
Helper\NameSchemaService $nameSchemaService, |
64
|
|
|
array $settings = array() |
65
|
|
|
) { |
66
|
|
|
$this->repository = $repository; |
67
|
|
|
$this->persistenceHandler = $handler; |
68
|
|
|
$this->nameSchemaService = $nameSchemaService; |
69
|
|
|
// Union makes sure default settings are ignored if provided in argument |
70
|
|
|
$this->settings = $settings + array( |
71
|
|
|
//'defaultSetting' => array(), |
72
|
|
|
); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* Loads a trashed location object from its $id. |
77
|
|
|
* |
78
|
|
|
* Note that $id is identical to original location, which has been previously trashed |
79
|
|
|
* |
80
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the user is not allowed to read the trashed location |
81
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException - if the location with the given id does not exist |
82
|
|
|
* |
83
|
|
|
* @param mixed $trashItemId |
84
|
|
|
* |
85
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\TrashItem |
86
|
|
|
*/ |
87
|
|
|
public function loadTrashItem($trashItemId) |
88
|
|
|
{ |
89
|
|
|
if ($this->repository->hasAccess('content', 'restore') !== true) { |
|
|
|
|
90
|
|
|
throw new UnauthorizedException('content', 'restore'); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
$spiTrashItem = $this->persistenceHandler->trashHandler()->loadTrashItem($trashItemId); |
94
|
|
|
$trash = $this->buildDomainTrashItemObject($spiTrashItem); |
95
|
|
|
if (!$this->repository->canUser('content', 'read', $trash->getContentInfo())) { |
|
|
|
|
96
|
|
|
throw new UnauthorizedException('content', 'read'); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
return $trash; |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Sends $location and all its children to trash and returns the corresponding trash item. |
104
|
|
|
* |
105
|
|
|
* Content is left untouched. |
106
|
|
|
* |
107
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the user is not allowed to trash the given location |
108
|
|
|
* |
109
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $location |
110
|
|
|
* |
111
|
|
|
* @return null|\eZ\Publish\API\Repository\Values\Content\TrashItem null if location was deleted, otherwise TrashItem |
112
|
|
|
*/ |
113
|
|
|
public function trash(Location $location) |
114
|
|
|
{ |
115
|
|
|
if (!is_numeric($location->id)) { |
116
|
|
|
throw new InvalidArgumentValue('id', $location->id, 'Location'); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
if ($this->repository->canUser('content', 'manage_locations', $location->getContentInfo(), $location) !== true) { |
|
|
|
|
120
|
|
|
throw new UnauthorizedException('content', 'manage_locations'); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
$this->repository->beginTransaction(); |
124
|
|
|
try { |
125
|
|
|
$spiTrashItem = $this->persistenceHandler->trashHandler()->trashSubtree($location->id); |
126
|
|
|
$this->persistenceHandler->urlAliasHandler()->locationDeleted($location->id); |
127
|
|
|
$this->repository->commit(); |
128
|
|
|
} catch (Exception $e) { |
129
|
|
|
$this->repository->rollback(); |
130
|
|
|
throw $e; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
return isset($spiTrashItem) |
134
|
|
|
? $this->buildDomainTrashItemObject($spiTrashItem) |
135
|
|
|
: null; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Recovers the $trashedLocation at its original place if possible. |
140
|
|
|
* |
141
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the user is not allowed to recover the trash item at the parent location location |
142
|
|
|
* |
143
|
|
|
* If $newParentLocation is provided, $trashedLocation will be restored under it. |
144
|
|
|
* |
145
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\TrashItem $trashItem |
146
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $newParentLocation |
147
|
|
|
* |
148
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Location the newly created or recovered location |
149
|
|
|
*/ |
150
|
|
|
public function recover(APITrashItem $trashItem, Location $newParentLocation = null) |
151
|
|
|
{ |
152
|
|
|
if (!is_numeric($trashItem->id)) { |
|
|
|
|
153
|
|
|
throw new InvalidArgumentValue('id', $trashItem->id, 'TrashItem'); |
|
|
|
|
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
if ($newParentLocation === null && !is_numeric($trashItem->parentLocationId)) { |
|
|
|
|
157
|
|
|
throw new InvalidArgumentValue('parentLocationId', $trashItem->parentLocationId, 'TrashItem'); |
|
|
|
|
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
if ($newParentLocation !== null && !is_numeric($newParentLocation->id)) { |
161
|
|
|
throw new InvalidArgumentValue('parentLocationId', $newParentLocation->id, 'Location'); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
if ($this->repository->hasAccess('content', 'restore') !== true) { |
|
|
|
|
165
|
|
|
throw new UnauthorizedException('content', 'restore'); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
$this->repository->beginTransaction(); |
169
|
|
|
try { |
170
|
|
|
$newParentLocationId = $newParentLocation ? $newParentLocation->id : $trashItem->parentLocationId; |
|
|
|
|
171
|
|
|
$newLocationId = $this->persistenceHandler->trashHandler()->recover( |
172
|
|
|
$trashItem->id, |
|
|
|
|
173
|
|
|
$newParentLocationId |
174
|
|
|
); |
175
|
|
|
|
176
|
|
|
$content = $this->repository->getContentService()->loadContent($trashItem->contentId); |
177
|
|
|
$urlAliasNames = $this->nameSchemaService->resolveUrlAliasSchema($content); |
178
|
|
|
|
179
|
|
|
// Publish URL aliases for recovered location |
180
|
|
|
foreach ($urlAliasNames as $languageCode => $name) { |
181
|
|
|
$this->persistenceHandler->urlAliasHandler()->publishUrlAliasForLocation( |
182
|
|
|
$newLocationId, |
183
|
|
|
$newParentLocationId, |
184
|
|
|
$name, |
185
|
|
|
$languageCode, |
186
|
|
|
$content->contentInfo->alwaysAvailable |
187
|
|
|
); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
$this->repository->commit(); |
191
|
|
|
} catch (Exception $e) { |
192
|
|
|
$this->repository->rollback(); |
193
|
|
|
throw $e; |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
return $this->repository->getLocationService()->loadLocation($newLocationId); |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* Empties trash. |
201
|
|
|
* |
202
|
|
|
* All locations contained in the trash will be removed. Content objects will be removed |
203
|
|
|
* if all locations of the content are gone. |
204
|
|
|
* |
205
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the user is not allowed to empty the trash |
206
|
|
|
*/ |
207
|
|
View Code Duplication |
public function emptyTrash() |
208
|
|
|
{ |
209
|
|
|
if ($this->repository->hasAccess('content', 'cleantrash') !== true) { |
|
|
|
|
210
|
|
|
throw new UnauthorizedException('content', 'cleantrash'); |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
$this->repository->beginTransaction(); |
214
|
|
|
try { |
215
|
|
|
// Persistence layer takes care of deleting content objects |
216
|
|
|
$this->persistenceHandler->trashHandler()->emptyTrash(); |
217
|
|
|
$this->repository->commit(); |
218
|
|
|
} catch (Exception $e) { |
219
|
|
|
$this->repository->rollback(); |
220
|
|
|
throw $e; |
221
|
|
|
} |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* Deletes a trash item. |
226
|
|
|
* |
227
|
|
|
* The corresponding content object will be removed |
228
|
|
|
* |
229
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException if the user is not allowed to delete this trash item |
230
|
|
|
* |
231
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\TrashItem $trashItem |
232
|
|
|
*/ |
233
|
|
View Code Duplication |
public function deleteTrashItem(APITrashItem $trashItem) |
234
|
|
|
{ |
235
|
|
|
if ($this->repository->hasAccess('content', 'cleantrash') !== true) { |
|
|
|
|
236
|
|
|
throw new UnauthorizedException('content', 'cleantrash'); |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
if (!is_numeric($trashItem->id)) { |
|
|
|
|
240
|
|
|
throw new InvalidArgumentValue('id', $trashItem->id, 'TrashItem'); |
|
|
|
|
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
$this->repository->beginTransaction(); |
244
|
|
|
try { |
245
|
|
|
$this->persistenceHandler->trashHandler()->deleteTrashItem($trashItem->id); |
|
|
|
|
246
|
|
|
$this->repository->commit(); |
247
|
|
|
} catch (Exception $e) { |
248
|
|
|
$this->repository->rollback(); |
249
|
|
|
throw $e; |
250
|
|
|
} |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
/** |
254
|
|
|
* Returns a collection of Trashed locations contained in the trash. |
255
|
|
|
* Only items that the current user has read access to are included. |
256
|
|
|
* |
257
|
|
|
* $query allows to filter/sort the elements to be contained in the collection. |
258
|
|
|
* |
259
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Query $query |
260
|
|
|
* |
261
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\SearchResult |
262
|
|
|
*/ |
263
|
|
|
public function findTrashItems(Query $query) |
264
|
|
|
{ |
265
|
|
|
if ($query->filter !== null && !$query->filter instanceof Criterion) { |
266
|
|
|
throw new InvalidArgumentValue('query->filter', $query->filter, 'Query'); |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
if ($query->sortClauses !== null) { |
270
|
|
|
if (!is_array($query->sortClauses)) { |
271
|
|
|
throw new InvalidArgumentValue('query->sortClauses', $query->sortClauses, 'Query'); |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
foreach ($query->sortClauses as $sortClause) { |
275
|
|
|
if (!$sortClause instanceof SortClause) { |
276
|
|
|
throw new InvalidArgumentValue('query->sortClauses', 'only instances of SortClause class are allowed'); |
277
|
|
|
} |
278
|
|
|
} |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
if ($query->offset !== null && !is_numeric($query->offset)) { |
282
|
|
|
throw new InvalidArgumentValue('query->offset', $query->offset, 'Query'); |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
if ($query->limit !== null && !is_numeric($query->limit)) { |
286
|
|
|
throw new InvalidArgumentValue('query->limit', $query->limit, 'Query'); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
$spiTrashItems = $this->persistenceHandler->trashHandler()->findTrashItems( |
290
|
|
|
$query->filter !== null ? $query->filter : null, |
291
|
|
|
$query->offset !== null && $query->offset > 0 ? (int)$query->offset : 0, |
292
|
|
|
$query->limit !== null && $query->limit >= 1 ? (int)$query->limit : null, |
293
|
|
|
$query->sortClauses !== null ? $query->sortClauses : null |
|
|
|
|
294
|
|
|
); |
295
|
|
|
|
296
|
|
|
$trashItems = array(); |
297
|
|
|
foreach ($spiTrashItems as $spiTrashItem) { |
298
|
|
|
try { |
299
|
|
|
$trashItems[] = $this->buildDomainTrashItemObject($spiTrashItem); |
300
|
|
|
} catch (UnauthorizedException $e) { |
301
|
|
|
// Do nothing, thus exclude items the current user doesn't have read access to. |
302
|
|
|
} |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
$searchResult = new SearchResult(); |
|
|
|
|
306
|
|
|
$searchResult->count = count($trashItems); |
307
|
|
|
$searchResult->items = $trashItems; |
308
|
|
|
$searchResult->query = $query; |
309
|
|
|
|
310
|
|
|
return $searchResult; |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
/** |
314
|
|
|
* Builds the domain TrashItem object from provided persistence trash item. |
315
|
|
|
* |
316
|
|
|
* @param \eZ\Publish\SPI\Persistence\Content\Location\Trashed $spiTrashItem |
317
|
|
|
* |
318
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\TrashItem |
319
|
|
|
*/ |
320
|
|
View Code Duplication |
protected function buildDomainTrashItemObject(Trashed $spiTrashItem) |
321
|
|
|
{ |
322
|
|
|
return new TrashItem( |
323
|
|
|
array( |
324
|
|
|
'contentInfo' => $this->repository->getContentService()->loadContentInfo($spiTrashItem->contentId), |
325
|
|
|
'id' => $spiTrashItem->id, |
326
|
|
|
'priority' => $spiTrashItem->priority, |
327
|
|
|
'hidden' => $spiTrashItem->hidden, |
328
|
|
|
'invisible' => $spiTrashItem->invisible, |
329
|
|
|
'remoteId' => $spiTrashItem->remoteId, |
330
|
|
|
'parentLocationId' => $spiTrashItem->parentId, |
331
|
|
|
'pathString' => $spiTrashItem->pathString, |
332
|
|
|
'depth' => $spiTrashItem->depth, |
333
|
|
|
'sortField' => $spiTrashItem->sortField, |
334
|
|
|
'sortOrder' => $spiTrashItem->sortOrder, |
335
|
|
|
) |
336
|
|
|
); |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
/** |
340
|
|
|
* @param int $timestamp |
341
|
|
|
* |
342
|
|
|
* @return \DateTime |
343
|
|
|
*/ |
344
|
|
|
protected function getDateTime($timestamp) |
345
|
|
|
{ |
346
|
|
|
$dateTime = new DateTime(); |
347
|
|
|
$dateTime->setTimestamp($timestamp); |
348
|
|
|
|
349
|
|
|
return $dateTime; |
350
|
|
|
} |
351
|
|
|
} |
352
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.