Completed
Push — EZEE-3159 ( bbbcb6...cb5cc2 )
by
unknown
20:04
created

testFindTrashItemsSubtreeLimitation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 51

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 51
rs 9.069
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 View Code Duplication
    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 Section Role Assignment Limitation against user/login.
806
     */
807
    public function testFindTrashItemsSubtreeLimitation()
808
    {
809
        $repository = $this->getRepository();
810
        $contentService = $repository->getContentService();
811
        $locationService = $repository->getLocationService();
812
        $contentTypeService = $repository->getContentTypeService();
813
        $trashService = $repository->getTrashService();
814
815
        $folder1 = $this->createFolder(['eng-GB' => 'Folder1'], 2);
816
        $folderLocationId = $folder1->contentInfo->mainLocationId;
817
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
818
        $newContent = $contentService->newContentCreateStruct($contentType, 'eng-US');
819
        $newContent->setField('name', 'Media');
820
        $draftContent = $contentService->createContent($newContent, [new LocationCreateStruct(['parentLocationId' => $folderLocationId])]);
821
        $published = $contentService->publishVersion($draftContent->versionInfo);
822
        $location = $locationService->loadLocation($published->contentInfo->mainLocationId);
823
        $trashService->trash($location);
824
825
        $this->createRoleWithPolicies('roleTrashCleaner', [
826
            [
827
                'module' => 'content',
828
                'function' => 'cleantrash',
829
            ],
830
            [
831
                'module' => 'content',
832
                'function' => 'read',
833
                'limitations' => [
834
                    new SubtreeLimitation(['limitationValues' => [sprintf('/1/2/%d/', $folderLocationId)]]),
835
                ],
836
            ],
837
        ]);
838
        $user = $this->createCustomUserWithLogin(
839
            'user',
840
            '[email protected]',
841
            'roleTrashCleaners',
842
            'roleTrashCleaner'
843
        );
844
        $repository->getPermissionResolver()->setCurrentUserReference($user);
845
846
        $query = new Query();
847
848
        // Load all trashed locations
849
        $searchResult = $trashService->findTrashItems($query);
850
        /* END: Use Case */
851
        $this->assertInstanceOf(
852
            SearchResult::class,
853
            $searchResult
854
        );
855
856
        $this->assertEquals(1, count($searchResult->items));
857
    }
858
859
    /**
860
     * Test for the emptyTrash() method.
861
     *
862
     * @see \eZ\Publish\API\Repository\TrashService::emptyTrash()
863
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
864
     */
865
    public function testEmptyTrash()
866
    {
867
        $repository = $this->getRepository();
868
        $trashService = $repository->getTrashService();
869
        $contentService = $repository->getContentService();
870
871
        /* BEGIN: Use Case */
872
        $trashItem = $this->createTrashItem();
873
874
        // Empty the trash
875
        $trashService->emptyTrash();
876
877
        // Create a search query for all trashed items
878
        $query = new Query();
879
        $query->filter = new Criterion\LogicalAnd(
880
            [
881
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
882
            ]
883
        );
884
        // Load all trashed locations, search result should be empty
885
        $searchResult = $trashService->findTrashItems($query);
886
        /* END: Use Case */
887
888
        $this->assertEquals(0, $searchResult->count);
889
890
        // Try to load content
891
        $this->expectException(NotFoundException::class);
892
        $contentService->loadContent($trashItem->contentId);
893
    }
894
895
    /**
896
     * Test for the emptyTrash() method with user which has subtree limitations.
897
     *
898
     * @see \eZ\Publish\API\Repository\TrashService::emptyTrash()
899
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
900
     */
901
    public function testEmptyTrashForUserWithSubtreeLimitation()
902
    {
903
        $repository = $this->getRepository();
904
        $trashService = $repository->getTrashService();
905
        $contentService = $repository->getContentService();
906
907
        /* BEGIN: Use Case */
908
        $trashItem = $this->createTrashItem();
909
910
        $this->createRoleWithPolicies('roleTrashCleaner', [
911
            ['module' => 'content', 'function' => 'cleantrash'],
912
            ['module' => 'content', 'function' => 'read'],
913
        ]);
914
        $user = $this->createCustomUserWithLogin(
915
            'user',
916
            '[email protected]',
917
            'roleTrashCleaners',
918
            'roleTrashCleaner',
919
            new SubtreeLimitation(['limitationValues' => ['/1/2/']])
920
        );
921
        $repository->getPermissionResolver()->setCurrentUserReference($user);
922
923
        // Empty the trash
924
        $trashService->emptyTrash();
925
926
        // Create a search query for all trashed items
927
        $query = new Query();
928
        $query->filter = new Criterion\LogicalAnd(
929
            [
930
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
931
            ]
932
        );
933
        // Load all trashed locations, search result should be empty
934
        $searchResult = $trashService->findTrashItems($query);
935
        /* END: Use Case */
936
937
        $this->assertEquals(0, $searchResult->totalCount);
938
939
        // Try to load content
940
        $this->expectException(NotFoundException::class);
941
        $contentService->loadContent($trashItem->contentId);
942
    }
943
944
    /**
945
     * Test for the deleteTrashItem() method.
946
     *
947
     * @see \eZ\Publish\API\Repository\TrashService::deleteTrashItem()
948
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
949
     */
950
    public function testDeleteTrashItem()
951
    {
952
        $repository = $this->getRepository();
953
        $trashService = $repository->getTrashService();
954
        $locationService = $repository->getLocationService();
955
        $contentService = $repository->getContentService();
956
957
        $demoDesignLocationId = $this->generateId('location', 56);
958
        /* BEGIN: Use Case */
959
        // $demoDesignLocationId is the ID of the "Demo Design" location in an eZ
960
        // Publish demo installation
961
962
        $trashItem = $this->createTrashItem();
963
964
        // Trash one more location
965
        $trashService->trash(
966
            $locationService->loadLocation($demoDesignLocationId)
967
        );
968
969
        // Empty the trash
970
        $trashService->deleteTrashItem($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 962 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...
971
972
        // Create a search query for all trashed items
973
        $query = new Query();
974
        $query->filter = new Criterion\LogicalAnd(
975
            [
976
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
977
            ]
978
        );
979
980
        // Load all trashed locations, should only contain the Demo Design location
981
        $searchResult = $trashService->findTrashItems($query);
982
        /* END: Use Case */
983
984
        $foundIds = array_map(
985
            function ($trashItem) {
986
                return $trashItem->id;
987
            },
988
            $searchResult->items
989
        );
990
991
        $this->assertEquals(4, $searchResult->count);
992
        $this->assertTrue(
993
            in_array($demoDesignLocationId, $foundIds)
994
        );
995
996
        // Try to load Content
997
        $this->expectException(NotFoundException::class);
998
        $contentService->loadContent($trashItem->contentId);
999
    }
1000
1001
    /**
1002
     * Test deleting a non existing trash item.
1003
     *
1004
     * @covers \eZ\Publish\API\Repository\TrashService::deleteTrashItem
1005
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
1006
     */
1007
    public function testDeleteThrowsNotFoundExceptionForNonExistingTrashItem()
1008
    {
1009
        $repository = $this->getRepository();
1010
        $trashService = $repository->getTrashService();
1011
1012
        $trashService->deleteTrashItem($this->getTrashItemDouble(
1013
            12364,
1014
            12345,
1015
            12363
1016
        ));
1017
    }
1018
1019
    /**
1020
     * Returns an array with the remoteIds of all child locations of the
1021
     * <b>Community</b> location. It is stored in a local variable named
1022
     * <b>$remoteIds</b>.
1023
     *
1024
     * @return string[]
1025
     */
1026
    private function createRemoteIdList()
1027
    {
1028
        $repository = $this->getRepository();
1029
1030
        /* BEGIN: Inline */
1031
        // remoteId of the "Community" location in an eZ Publish demo installation
1032
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
1033
1034
        // Load the location service
1035
        $locationService = $repository->getLocationService();
1036
1037
        $remoteIds = [];
1038
        $children = $locationService->loadLocationChildren($locationService->loadLocationByRemoteId($mediaRemoteId));
1039
        foreach ($children->locations as $child) {
1040
            $remoteIds[] = $child->remoteId;
1041
            foreach ($locationService->loadLocationChildren($child)->locations as $grandChild) {
1042
                $remoteIds[] = $grandChild->remoteId;
1043
            }
1044
        }
1045
        /* END: Inline */
1046
1047
        return $remoteIds;
1048
    }
1049
1050
    /**
1051
     * @param Repository $repository
1052
     * @param int $parentLocationId
1053
     *
1054
     * @return \eZ\Publish\API\Repository\Values\Content\Content
1055
     */
1056 View Code Duplication
    protected function createNewContentInPlaceTrashedOne(Repository $repository, $parentLocationId)
1057
    {
1058
        $contentService = $repository->getContentService();
1059
        $locationService = $repository->getLocationService();
1060
        $contentTypeService = $repository->getContentTypeService();
1061
1062
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
1063
        $newContent = $contentService->newContentCreateStruct($contentType, 'eng-US');
1064
        $newContent->setField('name', 'Media');
1065
1066
        $location = $locationService->newLocationCreateStruct($parentLocationId);
1067
1068
        $draftContent = $contentService->createContent($newContent, [$location]);
1069
1070
        return $contentService->publishVersion($draftContent->versionInfo);
1071
    }
1072
1073
    /**
1074
     * @param URLAliasService $urlAliasService
1075
     * @param string $urlPath Url alias path
1076
     *
1077
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
1078
     */
1079
    private function assertAliasExists(URLAliasService $urlAliasService, $urlPath)
1080
    {
1081
        $urlAlias = $urlAliasService->lookup($urlPath);
1082
1083
        $this->assertInstanceOf('\eZ\Publish\API\Repository\Values\Content\URLAlias', $urlAlias);
1084
1085
        return $urlAlias;
1086
    }
1087
1088
    /**
1089
     * @param URLAliasService $urlAliasService
1090
     * @param string $urlPath Url alias path
1091
     */
1092
    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...
1093
    {
1094
        try {
1095
            $this->getRepository()->getURLAliasService()->lookup($urlPath);
1096
            $this->fail(sprintf('Alias [%s] should not exists', $urlPath));
1097
        } catch (\eZ\Publish\API\Repository\Exceptions\NotFoundException $e) {
1098
            $this->assertTrue(true);
1099
        }
1100
    }
1101
1102
    /**
1103
     * Get Test Double for TrashItem for exception testing and similar.
1104
     *
1105
     * @param int $trashId
1106
     * @param int $contentId
1107
     * @param int $parentLocationId
1108
     *
1109
     * @return \eZ\Publish\API\Repository\Values\Content\TrashItem
1110
     */
1111
    private function getTrashItemDouble(int $trashId, int $contentId = 44, int $parentLocationId = 2): APITrashItem
1112
    {
1113
        return new TrashItem([
1114
            'id' => $trashId,
1115
            'parentLocationId' => $parentLocationId,
1116
            'contentInfo' => new ContentInfo(['id' => $contentId]),
1117
        ]);
1118
    }
1119
}
1120