Completed
Push — 7.5 ( bfacdc...966769 )
by
unknown
17:53
created

TrashServiceTest   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 1032
Duplicated Lines 4.84 %

Coupling/Cohesion

Components 1
Dependencies 25

Importance

Changes 0
Metric Value
dl 50
loc 1032
rs 8.432
c 0
b 0
f 0
wmc 43
lcom 1
cbo 25

31 Methods

Rating   Name   Duplication   Size   Complexity  
A testTrash() 0 11 1
A testTrashSetsExpectedTrashItemProperties() 0 27 1
A testTrashRemovesLocationFromMainStorage() 0 17 1
A testTrashRemovesChildLocationsFromMainStorage() 0 29 3
A testTrashUpdatesMainLocation() 0 24 1
A testTrashReturnsNull() 17 17 1
A testLoadTrashItem() 0 48 1
A testLoadTrashItemThrowsNotFoundException() 0 13 1
A testRecover() 0 37 2
A testRecoverThrowsNotFoundExceptionForNonExistingTrashItem() 0 13 1
A testNotFoundAliasAfterRemoveIt() 0 18 1
A testAliasesForRemovedItems() 0 36 1
A testRecoverDoesNotRestoreChildLocations() 0 43 4
A testRecoverWithLocationCreateStructParameter() 0 43 2
A testRecoverIncrementsChildCountOnOriginalParent() 0 33 2
A testRecoverWithLocationCreateStructParameterIncrementsChildCountOnNewParent() 0 39 2
A testRecoverToNonExistingLocation() 17 17 1
A testFindTrashItems() 0 29 1
A testTrashDecrementsChildCountOnParentLocation() 0 20 1
A testFindTrashItemsSortedByDateTrashed() 0 37 1
A testFindTrashItemsLimits() 0 24 1
A testFindTrashItemsLimitedAccess() 0 34 1
A testEmptyTrash() 0 29 1
A testEmptyTrashForUserWithSubtreeLimitation() 0 42 1
A testDeleteTrashItem() 0 50 1
A testDeleteThrowsNotFoundExceptionForNonExistingTrashItem() 0 11 1
A createRemoteIdList() 0 23 3
A createNewContentInPlaceTrashedOne() 16 16 1
A assertAliasExists() 0 8 1
A assertAliasNotExists() 0 9 2
A getTrashItemDouble() 0 8 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like TrashServiceTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TrashServiceTest, and based on these observations, apply Extract Interface, too.

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\API\Repository\Tests;
8
9
use eZ\Publish\API\Repository\Repository;
10
use eZ\Publish\API\Repository\URLAliasService;
11
use eZ\Publish\API\Repository\Values\Content\Content;
12
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
13
use eZ\Publish\API\Repository\Values\Content\Location as APILocation;
14
use eZ\Publish\API\Repository\Values\Content\LocationCreateStruct;
15
use eZ\Publish\API\Repository\Values\Content\Query;
16
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
17
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
18
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
19
use eZ\Publish\API\Repository\Values\Content\Trash\SearchResult;
20
use eZ\Publish\API\Repository\Values\Content\TrashItem as APITrashItem;
21
use eZ\Publish\API\Repository\Values\User\Limitation\SubtreeLimitation;
22
use eZ\Publish\Core\Repository\Values\Content\TrashItem;
23
use eZ\Publish\Core\Repository\Values\Content\Location;
24
use DateTime;
25
26
/**
27
 * Test case for operations in the TrashService using in memory storage.
28
 *
29
 * @see eZ\Publish\API\Repository\TrashService
30
 * @group integration
31
 * @group trash
32
 */
33
class TrashServiceTest extends BaseTrashServiceTest
34
{
35
    /**
36
     * Test for the trash() method.
37
     *
38
     * @see \eZ\Publish\API\Repository\TrashService::trash()
39
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationByRemoteId
40
     */
41
    public function testTrash()
42
    {
43
        /* BEGIN: Use Case */
44
        $trashItem = $this->createTrashItem();
45
        /* END: Use Case */
46
47
        $this->assertInstanceOf(
48
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\TrashItem',
49
            $trashItem
50
        );
51
    }
52
53
    /**
54
     * Test for the trash() method.
55
     *
56
     * @see \eZ\Publish\API\Repository\TrashService::trash()
57
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
58
     */
59
    public function testTrashSetsExpectedTrashItemProperties()
60
    {
61
        $repository = $this->getRepository();
62
63
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
64
65
        // Load the location that will be trashed
66
        $location = $repository->getLocationService()
67
            ->loadLocationByRemoteId($mediaRemoteId);
68
69
        $expected = [
70
            'id' => $location->id,
71
            'depth' => $location->depth,
72
            'hidden' => $location->hidden,
73
            'invisible' => $location->invisible,
74
            'parentLocationId' => $location->parentLocationId,
75
            'pathString' => $location->pathString,
76
            'priority' => $location->priority,
77
            'remoteId' => $location->remoteId,
78
            'sortField' => $location->sortField,
79
            'sortOrder' => $location->sortOrder,
80
        ];
81
82
        $trashItem = $this->createTrashItem();
83
84
        $this->assertPropertiesCorrect($expected, $trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 82 can be null; however, eZ\Publish\API\Repositor...sertPropertiesCorrect() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
85
    }
86
87
    /**
88
     * Test for the trash() method.
89
     *
90
     * @see \eZ\Publish\API\Repository\TrashService::trash()
91
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
92
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
93
     */
94
    public function testTrashRemovesLocationFromMainStorage()
95
    {
96
        $repository = $this->getRepository();
97
98
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
99
100
        /* BEGIN: Use Case */
101
        $this->createTrashItem();
102
103
        // Load the location service
104
        $locationService = $repository->getLocationService();
105
106
        // This call will fail with a "NotFoundException", because the media
107
        // location was marked as trashed in the main storage
108
        $locationService->loadLocationByRemoteId($mediaRemoteId);
109
        /* END: Use Case */
110
    }
111
112
    /**
113
     * Test for the trash() method.
114
     *
115
     * @see \eZ\Publish\API\Repository\TrashService::trash()
116
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
117
     */
118
    public function testTrashRemovesChildLocationsFromMainStorage()
119
    {
120
        $repository = $this->getRepository();
121
122
        /* BEGIN: Use Case */
123
        $remoteIds = $this->createRemoteIdList();
124
125
        $this->createTrashItem();
126
127
        // All invocations to loadLocationByRemoteId() to one of the above
128
        // collected remoteIds will return in an "NotFoundException"
129
        /* END: Use Case */
130
131
        $locationService = $repository->getLocationService();
132
        foreach ($remoteIds as $remoteId) {
133
            try {
134
                $locationService->loadLocationByRemoteId($remoteId);
135
                $this->fail("Location '{$remoteId}' should exist.'");
136
            } catch (NotFoundException $e) {
137
                // echo $e->getFile(), ' +', $e->getLine(), PHP_EOL;
138
            }
139
        }
140
141
        $this->assertGreaterThan(
142
            0,
143
            count($remoteIds),
144
            "There should be at least one 'Community' child location."
145
        );
146
    }
147
148
    /**
149
     * Test for the trash() method.
150
     *
151
     * @see \eZ\Publish\API\Repository\TrashService::trash()
152
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
153
     */
154
    public function testTrashDecrementsChildCountOnParentLocation()
155
    {
156
        $repository = $this->getRepository();
157
        $locationService = $repository->getLocationService();
158
159
        $baseLocationId = $this->generateId('location', 1);
160
161
        $location = $locationService->loadLocation($baseLocationId);
162
163
        $childCount = $locationService->getLocationChildCount($location);
164
165
        $this->createTrashItem();
166
167
        $this->refreshSearch($repository);
168
169
        $this->assertEquals(
170
            $childCount - 1,
171
            $locationService->getLocationChildCount($location)
172
        );
173
    }
174
175
    /**
176
     * Test sending a location to trash updates Content mainLocation.
177
     *
178
     * @covers \eZ\Publish\API\Repository\TrashService::trash
179
     */
180
    public function testTrashUpdatesMainLocation()
181
    {
182
        $repository = $this->getRepository();
183
        $contentService = $repository->getContentService();
184
        $locationService = $repository->getLocationService();
185
        $trashService = $repository->getTrashService();
186
187
        $contentInfo = $contentService->loadContentInfo(42);
188
189
        // Create additional location that will become new main location
190
        $location = $locationService->createLocation(
191
            $contentInfo,
192
            new LocationCreateStruct(['parentLocationId' => 2])
193
        );
194
195
        $trashService->trash(
196
            $locationService->loadLocation($contentInfo->mainLocationId)
197
        );
198
199
        self::assertEquals(
200
            $location->id,
201
            $contentService->loadContentInfo(42)->mainLocationId
202
        );
203
    }
204
205
    /**
206
     * Test sending a location to trash.
207
     *
208
     * @covers \eZ\Publish\API\Repository\TrashService::trash
209
     */
210 View Code Duplication
    public function testTrashReturnsNull()
211
    {
212
        $repository = $this->getRepository();
213
        $contentService = $repository->getContentService();
214
        $locationService = $repository->getLocationService();
215
        $trashService = $repository->getTrashService();
216
217
        // Create additional location to trash
218
        $location = $locationService->createLocation(
219
            $contentService->loadContentInfo(42),
220
            new LocationCreateStruct(['parentLocationId' => 2])
221
        );
222
223
        $trashItem = $trashService->trash($location);
224
225
        self::assertNull($trashItem);
226
    }
227
228
    /**
229
     * Test for the loadTrashItem() method.
230
     *
231
     * @covers \eZ\Publish\API\Repository\TrashService::loadTrashItem
232
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
233
     */
234
    public function testLoadTrashItem()
235
    {
236
        $repository = $this->getRepository();
237
        $trashService = $repository->getTrashService();
238
239
        /* BEGIN: Use Case */
240
        $trashItem = $this->createTrashItem();
241
242
        // Reload the trash item
243
        $trashItemReloaded = $trashService->loadTrashItem($trashItem->id);
244
        /* END: Use Case */
245
246
        $this->assertInstanceOf(
247
            APITrashItem::class,
248
            $trashItemReloaded
249
        );
250
251
        $this->assertEquals(
252
            $trashItem->pathString,
253
            $trashItemReloaded->pathString
254
        );
255
256
        $this->assertEquals(
257
            $trashItem,
258
            $trashItemReloaded
259
        );
260
261
        $this->assertInstanceOf(
262
            DateTime::class,
263
            $trashItemReloaded->trashed
264
        );
265
266
        $this->assertEquals(
267
            $trashItem->trashed->getTimestamp(),
268
            $trashItemReloaded->trashed->getTimestamp()
269
        );
270
271
        $this->assertGreaterThan(
272
            0,
273
            $trashItemReloaded->trashed->getTimestamp()
274
        );
275
276
        $this->assertInstanceOf(
277
            Content::class,
278
            $content = $trashItemReloaded->getContent()
279
        );
280
        $this->assertEquals($trashItem->contentId, $content->contentInfo->id);
281
    }
282
283
    /**
284
     * Test for the loadTrashItem() method.
285
     *
286
     * @see \eZ\Publish\API\Repository\TrashService::loadTrashItem()
287
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
288
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testLoadTrashItem
289
     */
290
    public function testLoadTrashItemThrowsNotFoundException()
291
    {
292
        $repository = $this->getRepository();
293
294
        $nonExistingTrashId = $this->generateId('trash', 2342);
295
        /* BEGIN: Use Case */
296
        $trashService = $repository->getTrashService();
297
298
        // This call will fail with a "NotFoundException", because no trash item
299
        // with the ID 1342 should exist in an eZ Publish demo installation
300
        $trashService->loadTrashItem($nonExistingTrashId);
301
        /* END: Use Case */
302
    }
303
304
    /**
305
     * Test for the recover() method.
306
     *
307
     * @covers \eZ\Publish\API\Repository\TrashService::recover
308
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
309
     */
310
    public function testRecover()
311
    {
312
        $repository = $this->getRepository();
313
        $trashService = $repository->getTrashService();
314
        $locationService = $repository->getLocationService();
315
316
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
317
318
        /* BEGIN: Use Case */
319
        $trashItem = $this->createTrashItem();
320
321
        // Recover the trashed item
322
        $location = $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 319 can be null; however, eZ\Publish\API\Repository\TrashService::recover() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
323
324
        // Load the recovered location
325
        $locationReloaded = $locationService->loadLocationByRemoteId(
326
            $mediaRemoteId
327
        );
328
        /* END: Use Case */
329
330
        $this->assertInstanceOf(
331
            APILocation::class,
332
            $location
333
        );
334
335
        $this->assertEquals(
336
            $location,
337
            $locationReloaded
338
        );
339
340
        try {
341
            $trashService->loadTrashItem($trashItem->id);
342
            $this->fail('Trash item was not removed after being recovered.');
343
        } catch (NotFoundException $e) {
344
            // All well
345
        }
346
    }
347
348
    /**
349
     * Test recovering a non existing trash item results in a NotFoundException.
350
     *
351
     * @covers \eZ\Publish\API\Repository\TrashService::recover
352
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
353
     */
354
    public function testRecoverThrowsNotFoundExceptionForNonExistingTrashItem()
355
    {
356
        $repository = $this->getRepository();
357
        $trashService = $repository->getTrashService();
358
359
        $trashService->recover(
360
            $this->getTrashItemDouble(
361
                12364,
362
                12345,
363
                12363
364
            )
365
        );
366
    }
367
368
    /**
369
     * Test for the trash() method.
370
     *
371
     * @see \eZ\Publish\API\Repository\TrashService::recover()
372
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
373
     *
374
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
375
     */
376
    public function testNotFoundAliasAfterRemoveIt()
377
    {
378
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
379
380
        $repository = $this->getRepository();
381
        $trashService = $repository->getTrashService();
382
        $urlAliasService = $repository->getURLAliasService();
383
        $locationService = $repository->getLocationService();
384
385
        // Double ->lookup() call because there where issue that one call was not enough to spot bug
386
        $urlAliasService->lookup('/Media');
387
        $urlAliasService->lookup('/Media');
388
389
        $mediaLocation = $locationService->loadLocationByRemoteId($mediaRemoteId);
390
        $trashService->trash($mediaLocation);
391
392
        $urlAliasService->lookup('/Media');
393
    }
394
395
    /**
396
     * Test for the recover() method.
397
     *
398
     * @see \eZ\Publish\API\Repository\TrashService::recover()
399
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
400
     */
401
    public function testAliasesForRemovedItems()
402
    {
403
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
404
405
        $repository = $this->getRepository();
406
        $trashService = $repository->getTrashService();
407
        $urlAliasService = $repository->getURLAliasService();
408
        $locationService = $repository->getLocationService();
409
410
        // Double ->lookup() call because there where issue that one call was not enough to spot bug
411
        $urlAliasService->lookup('/Media');
412
        $trashedLocationAlias = $urlAliasService->lookup('/Media');
413
414
        $mediaLocation = $locationService->loadLocationByRemoteId($mediaRemoteId);
415
        $trashItem = $trashService->trash($mediaLocation);
416
        $this->assertAliasNotExists($urlAliasService, '/Media');
417
418
        $this->createNewContentInPlaceTrashedOne($repository, $mediaLocation->parentLocationId);
419
420
        $createdLocationAlias = $urlAliasService->lookup('/Media');
421
422
        $this->assertNotEquals(
423
            $trashedLocationAlias->destination,
424
            $createdLocationAlias->destination,
425
            'Destination for /media url should changed'
426
        );
427
428
        $recoveredLocation = $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $trashService->trash($mediaLocation) on line 415 can be null; however, eZ\Publish\API\Repository\TrashService::recover() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
429
        $recoveredLocationAlias = $urlAliasService->lookup('/Media2');
430
        $recoveredLocationAliasReverse = $urlAliasService->reverseLookup($recoveredLocation);
431
432
        $this->assertEquals($recoveredLocationAlias->destination, $recoveredLocationAliasReverse->destination);
433
434
        $this->assertNotEquals($recoveredLocationAliasReverse->destination, $trashedLocationAlias->destination);
435
        $this->assertNotEquals($recoveredLocationAliasReverse->destination, $createdLocationAlias->destination);
436
    }
437
438
    /**
439
     * Test for the recover() method.
440
     *
441
     * @see \eZ\Publish\API\Repository\TrashService::recover()
442
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
443
     */
444
    public function testRecoverDoesNotRestoreChildLocations()
445
    {
446
        $repository = $this->getRepository();
447
        $trashService = $repository->getTrashService();
448
        $locationService = $repository->getLocationService();
449
450
        $remoteIds = $this->createRemoteIdList();
451
452
        // Unset remote ID of actually restored location
453
        unset($remoteIds[array_search('3f6d92f8044aed134f32153517850f5a', $remoteIds)]);
454
455
        $trashItem = $this->createTrashItem();
456
457
        $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 455 can be null; however, eZ\Publish\API\Repository\TrashService::recover() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
458
459
        $this->assertGreaterThan(
460
            0,
461
            count($remoteIds),
462
            "There should be at least one 'Community' child location."
463
        );
464
465
        // None of the child locations will be available again
466
        foreach ($remoteIds as $remoteId) {
467
            try {
468
                $locationService->loadLocationByRemoteId($remoteId);
469
                $this->fail(
470
                    sprintf(
471
                        'Location with remote ID "%s" unexpectedly restored.',
472
                        $remoteId
473
                    )
474
                );
475
            } catch (NotFoundException $e) {
476
                // All well
477
            }
478
        }
479
480
        try {
481
            $trashService->loadTrashItem($trashItem->id);
482
            $this->fail('Trash item was not removed after being recovered.');
483
        } catch (NotFoundException $e) {
484
            // All well
485
        }
486
    }
487
488
    /**
489
     * Test for the recover() method.
490
     *
491
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem, $newParentLocation)
492
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
493
     *
494
     * @todo Fix naming
495
     */
496
    public function testRecoverWithLocationCreateStructParameter()
497
    {
498
        $repository = $this->getRepository();
499
        $trashService = $repository->getTrashService();
500
        $locationService = $repository->getLocationService();
501
502
        $homeLocationId = $this->generateId('location', 2);
503
        /* BEGIN: Use Case */
504
        // $homeLocationId is the ID of the "Home" location in an eZ Publish
505
        // demo installation
506
507
        $trashItem = $this->createTrashItem();
508
509
        // Get the new parent location
510
        $newParentLocation = $locationService->loadLocation($homeLocationId);
511
512
        // Recover location with new location
513
        $location = $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 507 can be null; however, eZ\Publish\API\Repository\TrashService::recover() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
514
        /* END: Use Case */
515
516
        $this->assertPropertiesCorrect(
517
            [
518
                'remoteId' => $trashItem->remoteId,
519
                'parentLocationId' => $homeLocationId,
520
                // Not the full sub tree is restored
521
                'depth' => $newParentLocation->depth + 1,
522
                'hidden' => false,
523
                'invisible' => $trashItem->invisible,
524
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $location->id) . '/',
525
                'priority' => 0,
526
                'sortField' => APILocation::SORT_FIELD_NAME,
527
                'sortOrder' => APILocation::SORT_ORDER_ASC,
528
            ],
529
            $location
530
        );
531
532
        try {
533
            $trashService->loadTrashItem($trashItem->id);
534
            $this->fail('Trash item was not removed after being recovered.');
535
        } catch (NotFoundException $e) {
536
            // All well
537
        }
538
    }
539
540
    /**
541
     * Test for the recover() method.
542
     *
543
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem)
544
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
545
     */
546
    public function testRecoverIncrementsChildCountOnOriginalParent()
547
    {
548
        $repository = $this->getRepository();
549
        $trashService = $repository->getTrashService();
550
        $locationService = $repository->getLocationService();
551
552
        $location = $locationService->loadLocation($this->generateId('location', 1));
553
554
        $trashItem = $this->createTrashItem();
555
556
        $this->refreshSearch($repository);
557
558
        /* BEGIN: Use Case */
559
        $childCount = $locationService->getLocationChildCount($location);
560
561
        // Recover location with new location
562
        $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 554 can be null; however, eZ\Publish\API\Repository\TrashService::recover() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
563
        /* END: Use Case */
564
565
        $this->refreshSearch($repository);
566
567
        $this->assertEquals(
568
            $childCount + 1,
569
            $locationService->getLocationChildCount($location)
570
        );
571
572
        try {
573
            $trashService->loadTrashItem($trashItem->id);
574
            $this->fail('Trash item was not removed after being recovered.');
575
        } catch (NotFoundException $e) {
576
            // All well
577
        }
578
    }
579
580
    /**
581
     * Test for the recover() method.
582
     *
583
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem, $newParentLocation)
584
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecoverWithLocationCreateStructParameter
585
     */
586
    public function testRecoverWithLocationCreateStructParameterIncrementsChildCountOnNewParent()
587
    {
588
        $repository = $this->getRepository();
589
        $trashService = $repository->getTrashService();
590
        $locationService = $repository->getLocationService();
591
592
        $homeLocationId = $this->generateId('location', 2);
593
594
        $location = $locationService->loadLocation($homeLocationId);
595
596
        $childCount = $locationService->getLocationChildCount($location);
597
598
        /* BEGIN: Use Case */
599
        // $homeLocationId is the ID of the "Home" location in an eZ Publish
600
        // demo installation
601
602
        $trashItem = $this->createTrashItem();
603
604
        // Get the new parent location
605
        $newParentLocation = $locationService->loadLocation($homeLocationId);
606
607
        // Recover location with new location
608
        $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 602 can be null; however, eZ\Publish\API\Repository\TrashService::recover() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
609
        /* END: Use Case */
610
611
        $this->refreshSearch($repository);
612
613
        $this->assertEquals(
614
            $childCount + 1,
615
            $locationService->getLocationChildCount($location)
616
        );
617
618
        try {
619
            $trashService->loadTrashItem($trashItem->id);
620
            $this->fail('Trash item was not removed after being recovered.');
621
        } catch (NotFoundException $e) {
622
            // All well
623
        }
624
    }
625
626
    /**
627
     * Test recovering a location from trash to non existing location.
628
     *
629
     * @covers \eZ\Publish\API\Repository\TrashService::recover
630
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
631
     */
632 View Code Duplication
    public function testRecoverToNonExistingLocation()
633
    {
634
        $repository = $this->getRepository();
635
        $trashService = $repository->getTrashService();
636
        $locationService = $repository->getLocationService();
637
638
        $location = $locationService->loadLocation(44);
639
        $trashItem = $trashService->trash($location);
640
641
        $newParentLocation = new Location(
642
            [
643
                'id' => 123456,
644
                'parentLocationId' => 123455,
645
            ]
646
        );
647
        $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $trashService->trash($location) on line 639 can be null; however, eZ\Publish\API\Repository\TrashService::recover() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
648
    }
649
650
    /**
651
     * Test for the findTrashItems() method.
652
     *
653
     * @see \eZ\Publish\API\Repository\TrashService::findTrashItems()
654
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
655
     */
656
    public function testFindTrashItems()
657
    {
658
        $repository = $this->getRepository();
659
        $trashService = $repository->getTrashService();
660
661
        /* BEGIN: Use Case */
662
        $this->createTrashItem();
663
664
        // Create a search query for all trashed items
665
        $query = new Query();
666
        $query->filter = new Criterion\LogicalAnd(
667
            [
668
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
669
            ]
670
        );
671
672
        // Load all trashed locations
673
        $searchResult = $trashService->findTrashItems($query);
674
        /* END: Use Case */
675
676
        $this->assertInstanceOf(
677
            SearchResult::class,
678
            $searchResult
679
        );
680
681
        // 4 trashed locations from the sub tree
682
        $this->assertEquals(4, $searchResult->count);
683
        $this->assertEquals(4, $searchResult->totalCount);
684
    }
685
686
    /**
687
     * @covers  \eZ\Publish\API\Repository\TrashService::findTrashItems
688
     *
689
     * @throws \ErrorException
690
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
691
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
692
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
693
     */
694
    public function testFindTrashItemsSortedByDateTrashed(): void
695
    {
696
        $repository = $this->getRepository();
697
        $trashService = $repository->getTrashService();
698
        $locationService = $repository->getLocationService();
699
700
        $folder1 = $this->createFolder(['eng-GB' => 'Folder1'], 2);
701
        $folder2 = $this->createFolder(['eng-GB' => 'Folder2'], 2);
702
703
        $firstTrashedItem = $trashService->trash(
704
            $locationService->loadLocation($folder1->contentInfo->mainLocationId)
705
        );
706
        $this->updateTrashedDate($firstTrashedItem->id, \time() - 100);
707
        $latestTrashItem = $trashService->trash(
708
            $locationService->loadLocation($folder2->contentInfo->mainLocationId)
709
        );
710
711
        $query = new Query();
712
        $query->filter = new Criterion\ContentId([
713
            $folder1->contentInfo->id,
714
            $folder2->contentInfo->id,
715
        ]);
716
717
        // Load all trashed locations, sorted by trashed date ASC
718
        $query->sortClauses = [new SortClause\Trash\DateTrashed(Query::SORT_ASC)];
719
        $searchResult = $trashService->findTrashItems($query);
720
        self::assertEquals(2, $searchResult->totalCount);
721
        self::assertEquals($firstTrashedItem->remoteId, $searchResult->items[0]->remoteId);
722
        self::assertEquals($latestTrashItem->remoteId, $searchResult->items[1]->remoteId);
723
724
        // Load all trashed locations, sorted by trashed date DESC
725
        $query->sortClauses = [new SortClause\Trash\DateTrashed(Query::SORT_DESC)];
726
        $searchResult = $trashService->findTrashItems($query);
727
        self::assertEquals(2, $searchResult->totalCount);
728
        self::assertEquals($latestTrashItem->remoteId, $searchResult->items[0]->remoteId);
729
        self::assertEquals($firstTrashedItem->remoteId, $searchResult->items[1]->remoteId);
730
    }
731
732
    /**
733
     * Test for the findTrashItems() method for it's result structure.
734
     *
735
     * @see \eZ\Publish\API\Repository\TrashService::findTrashItems()
736
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
737
     */
738
    public function testFindTrashItemsLimits()
739
    {
740
        $repository = $this->getRepository();
741
        $trashService = $repository->getTrashService();
742
743
        $this->createTrashItem();
744
745
        // Create a search query for all trashed items
746
        $query = new Query();
747
        $query->limit = 2;
748
749
        // Load all trashed locations
750
        $searchResult = $trashService->findTrashItems($query);
751
752
        $this->assertInstanceOf(
753
            SearchResult::class,
754
            $searchResult
755
        );
756
757
        // 4 trashed locations from the sub tree, but only 2 in results
758
        $this->assertCount(2, $searchResult->items);
759
        $this->assertEquals(4, $searchResult->count);
760
        $this->assertEquals(4, $searchResult->totalCount);
761
    }
762
763
    /**
764
     * Test for the findTrashItems() method.
765
     *
766
     * @see \eZ\Publish\API\Repository\TrashService::findTrashItems()
767
     * @depends \eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
768
     */
769
    public function testFindTrashItemsLimitedAccess()
770
    {
771
        $repository = $this->getRepository();
772
        $trashService = $repository->getTrashService();
773
774
        /* BEGIN: Use Case */
775
        $this->createTrashItem();
776
777
        // Create a search query for all trashed items
778
        $query = new Query();
779
        $query->filter = new Criterion\LogicalAnd(
780
            [
781
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
782
            ]
783
        );
784
785
        // Create a user in the Editor user group.
786
        $user = $this->createUserVersion1();
787
788
        // Set the Editor user as current user, these users have no access to Trash by default.
789
        $repository->getPermissionResolver()->setCurrentUserReference($user);
790
791
        // Load all trashed locations
792
        $searchResult = $trashService->findTrashItems($query);
793
        /* END: Use Case */
794
795
        $this->assertInstanceOf(
796
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\SearchResult',
797
            $searchResult
798
        );
799
800
        // 0 trashed locations found, though 4 exist
801
        $this->assertEquals(0, $searchResult->count);
802
    }
803
804
    /**
805
     * Test for the emptyTrash() method.
806
     *
807
     * @see \eZ\Publish\API\Repository\TrashService::emptyTrash()
808
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
809
     */
810
    public function testEmptyTrash()
811
    {
812
        $repository = $this->getRepository();
813
        $trashService = $repository->getTrashService();
814
        $contentService = $repository->getContentService();
815
816
        /* BEGIN: Use Case */
817
        $trashItem = $this->createTrashItem();
818
819
        // Empty the trash
820
        $trashService->emptyTrash();
821
822
        // Create a search query for all trashed items
823
        $query = new Query();
824
        $query->filter = new Criterion\LogicalAnd(
825
            [
826
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
827
            ]
828
        );
829
        // Load all trashed locations, search result should be empty
830
        $searchResult = $trashService->findTrashItems($query);
831
        /* END: Use Case */
832
833
        $this->assertEquals(0, $searchResult->count);
834
835
        // Try to load content
836
        $this->expectException(NotFoundException::class);
837
        $contentService->loadContent($trashItem->contentId);
838
    }
839
840
    /**
841
     * Test for the emptyTrash() method with user which has subtree limitations.
842
     *
843
     * @see \eZ\Publish\API\Repository\TrashService::emptyTrash()
844
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
845
     */
846
    public function testEmptyTrashForUserWithSubtreeLimitation()
847
    {
848
        $repository = $this->getRepository();
849
        $trashService = $repository->getTrashService();
850
        $contentService = $repository->getContentService();
851
852
        /* BEGIN: Use Case */
853
        $trashItem = $this->createTrashItem();
854
855
        $this->createRoleWithPolicies('roleTrashCleaner', [
856
            ['module' => 'content', 'function' => 'cleantrash'],
857
            ['module' => 'content', 'function' => 'read'],
858
        ]);
859
        $user = $this->createCustomUserWithLogin(
860
            'user',
861
            '[email protected]',
862
            'roleTrashCleaners',
863
            'roleTrashCleaner',
864
            new SubtreeLimitation(['limitationValues' => ['/1/2/']])
865
        );
866
        $repository->getPermissionResolver()->setCurrentUserReference($user);
867
868
        // Empty the trash
869
        $trashService->emptyTrash();
870
871
        // Create a search query for all trashed items
872
        $query = new Query();
873
        $query->filter = new Criterion\LogicalAnd(
874
            [
875
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
876
            ]
877
        );
878
        // Load all trashed locations, search result should be empty
879
        $searchResult = $trashService->findTrashItems($query);
880
        /* END: Use Case */
881
882
        $this->assertEquals(0, $searchResult->totalCount);
883
884
        // Try to load content
885
        $this->expectException(NotFoundException::class);
886
        $contentService->loadContent($trashItem->contentId);
887
    }
888
889
    /**
890
     * Test for the deleteTrashItem() method.
891
     *
892
     * @see \eZ\Publish\API\Repository\TrashService::deleteTrashItem()
893
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
894
     */
895
    public function testDeleteTrashItem()
896
    {
897
        $repository = $this->getRepository();
898
        $trashService = $repository->getTrashService();
899
        $locationService = $repository->getLocationService();
900
        $contentService = $repository->getContentService();
901
902
        $demoDesignLocationId = $this->generateId('location', 56);
903
        /* BEGIN: Use Case */
904
        // $demoDesignLocationId is the ID of the "Demo Design" location in an eZ
905
        // Publish demo installation
906
907
        $trashItem = $this->createTrashItem();
908
909
        // Trash one more location
910
        $trashService->trash(
911
            $locationService->loadLocation($demoDesignLocationId)
912
        );
913
914
        // Empty the trash
915
        $trashService->deleteTrashItem($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 907 can be null; however, eZ\Publish\API\Repositor...vice::deleteTrashItem() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
916
917
        // Create a search query for all trashed items
918
        $query = new Query();
919
        $query->filter = new Criterion\LogicalAnd(
920
            [
921
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
922
            ]
923
        );
924
925
        // Load all trashed locations, should only contain the Demo Design location
926
        $searchResult = $trashService->findTrashItems($query);
927
        /* END: Use Case */
928
929
        $foundIds = array_map(
930
            function ($trashItem) {
931
                return $trashItem->id;
932
            },
933
            $searchResult->items
934
        );
935
936
        $this->assertEquals(4, $searchResult->count);
937
        $this->assertTrue(
938
            in_array($demoDesignLocationId, $foundIds)
939
        );
940
941
        // Try to load Content
942
        $this->expectException(NotFoundException::class);
943
        $contentService->loadContent($trashItem->contentId);
944
    }
945
946
    /**
947
     * Test deleting a non existing trash item.
948
     *
949
     * @covers \eZ\Publish\API\Repository\TrashService::deleteTrashItem
950
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
951
     */
952
    public function testDeleteThrowsNotFoundExceptionForNonExistingTrashItem()
953
    {
954
        $repository = $this->getRepository();
955
        $trashService = $repository->getTrashService();
956
957
        $trashService->deleteTrashItem($this->getTrashItemDouble(
958
            12364,
959
            12345,
960
            12363
961
        ));
962
    }
963
964
    /**
965
     * Returns an array with the remoteIds of all child locations of the
966
     * <b>Community</b> location. It is stored in a local variable named
967
     * <b>$remoteIds</b>.
968
     *
969
     * @return string[]
970
     */
971
    private function createRemoteIdList()
972
    {
973
        $repository = $this->getRepository();
974
975
        /* BEGIN: Inline */
976
        // remoteId of the "Community" location in an eZ Publish demo installation
977
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
978
979
        // Load the location service
980
        $locationService = $repository->getLocationService();
981
982
        $remoteIds = [];
983
        $children = $locationService->loadLocationChildren($locationService->loadLocationByRemoteId($mediaRemoteId));
984
        foreach ($children->locations as $child) {
985
            $remoteIds[] = $child->remoteId;
986
            foreach ($locationService->loadLocationChildren($child)->locations as $grandChild) {
987
                $remoteIds[] = $grandChild->remoteId;
988
            }
989
        }
990
        /* END: Inline */
991
992
        return $remoteIds;
993
    }
994
995
    /**
996
     * @param Repository $repository
997
     * @param int $parentLocationId
998
     *
999
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1000
     */
1001 View Code Duplication
    protected function createNewContentInPlaceTrashedOne(Repository $repository, $parentLocationId)
1002
    {
1003
        $contentService = $repository->getContentService();
1004
        $locationService = $repository->getLocationService();
1005
        $contentTypeService = $repository->getContentTypeService();
1006
1007
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
1008
        $newContent = $contentService->newContentCreateStruct($contentType, 'eng-US');
1009
        $newContent->setField('name', 'Media');
1010
1011
        $location = $locationService->newLocationCreateStruct($parentLocationId);
1012
1013
        $draftContent = $contentService->createContent($newContent, [$location]);
1014
1015
        return $contentService->publishVersion($draftContent->versionInfo);
1016
    }
1017
1018
    /**
1019
     * @param URLAliasService $urlAliasService
1020
     * @param string $urlPath Url alias path
1021
     *
1022
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
1023
     */
1024
    private function assertAliasExists(URLAliasService $urlAliasService, $urlPath)
1025
    {
1026
        $urlAlias = $urlAliasService->lookup($urlPath);
1027
1028
        $this->assertInstanceOf('\eZ\Publish\API\Repository\Values\Content\URLAlias', $urlAlias);
1029
1030
        return $urlAlias;
1031
    }
1032
1033
    /**
1034
     * @param URLAliasService $urlAliasService
1035
     * @param string $urlPath Url alias path
1036
     */
1037
    private function assertAliasNotExists(URLAliasService $urlAliasService, $urlPath)
0 ignored issues
show
Unused Code introduced by
The parameter $urlAliasService is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1038
    {
1039
        try {
1040
            $this->getRepository()->getURLAliasService()->lookup($urlPath);
1041
            $this->fail(sprintf('Alias [%s] should not exists', $urlPath));
1042
        } catch (\eZ\Publish\API\Repository\Exceptions\NotFoundException $e) {
1043
            $this->assertTrue(true);
1044
        }
1045
    }
1046
1047
    /**
1048
     * Get Test Double for TrashItem for exception testing and similar.
1049
     *
1050
     * @param int $trashId
1051
     * @param int $contentId
1052
     * @param int $parentLocationId
1053
     *
1054
     * @return \eZ\Publish\API\Repository\Values\Content\TrashItem
1055
     */
1056
    private function getTrashItemDouble(int $trashId, int $contentId = 44, int $parentLocationId = 2): APITrashItem
1057
    {
1058
        return new TrashItem([
1059
            'id' => $trashId,
1060
            'parentLocationId' => $parentLocationId,
1061
            'contentInfo' => new ContentInfo(['id' => $contentId]),
1062
        ]);
1063
    }
1064
}
1065