Completed
Push — ezp_30981_content_info_proxy ( 6fc040...a78a98 )
by
unknown
15:33
created

TrashServiceTest::testFindTrashItemsLimits()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 24
rs 9.536
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the TrashServiceTest class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\API\Repository\Tests;
10
11
use eZ\Publish\API\Repository\Repository;
12
use eZ\Publish\API\Repository\URLAliasService;
13
use eZ\Publish\API\Repository\Values\Content\Content;
14
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
15
use eZ\Publish\API\Repository\Values\Content\Location as APILocation;
16
use eZ\Publish\API\Repository\Values\Content\LocationCreateStruct;
17
use eZ\Publish\API\Repository\Values\Content\Query;
18
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
19
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
20
use eZ\Publish\API\Repository\Values\Content\Trash\SearchResult;
21
use eZ\Publish\API\Repository\Values\Content\TrashItem as APITrashItem;
22
use eZ\Publish\API\Repository\Values\User\Limitation\SubtreeLimitation;
23
use eZ\Publish\Core\Repository\Values\Content\TrashItem;
24
use eZ\Publish\Core\Repository\Values\Content\Location;
25
use DateTime;
26
27
/**
28
 * Test case for operations in the TrashService using in memory storage.
29
 *
30
 * @see eZ\Publish\API\Repository\TrashService
31
 * @group integration
32
 * @group trash
33
 */
34
class TrashServiceTest extends BaseTrashServiceTest
35
{
36
    /**
37
     * Test for the trash() method.
38
     *
39
     * @see \eZ\Publish\API\Repository\TrashService::trash()
40
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationByRemoteId
41
     */
42
    public function testTrash()
43
    {
44
        /* BEGIN: Use Case */
45
        $trashItem = $this->createTrashItem();
46
        /* END: Use Case */
47
48
        $this->assertInstanceOf(
49
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\TrashItem',
50
            $trashItem
51
        );
52
    }
53
54
    /**
55
     * Test for the trash() method.
56
     *
57
     * @see \eZ\Publish\API\Repository\TrashService::trash()
58
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
59
     */
60
    public function testTrashSetsExpectedTrashItemProperties()
61
    {
62
        $repository = $this->getRepository();
63
64
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
65
66
        // Load the location that will be trashed
67
        $location = $repository->getLocationService()
68
            ->loadLocationByRemoteId($mediaRemoteId);
69
70
        $expected = [
71
            'id' => $location->id,
72
            'depth' => $location->depth,
73
            'hidden' => $location->hidden,
74
            'invisible' => $location->invisible,
75
            'parentLocationId' => $location->parentLocationId,
76
            'pathString' => $location->pathString,
77
            'priority' => $location->priority,
78
            'remoteId' => $location->remoteId,
79
            'sortField' => $location->sortField,
80
            'sortOrder' => $location->sortOrder,
81
        ];
82
83
        $trashItem = $this->createTrashItem();
84
85
        $this->assertPropertiesCorrect($expected, $trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 83 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...
86
    }
87
88
    /**
89
     * Test for the trash() method.
90
     *
91
     * @see \eZ\Publish\API\Repository\TrashService::trash()
92
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
93
     */
94 View Code Duplication
    public function testTrashRemovesLocationFromMainStorage()
95
    {
96
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
97
98
        $repository = $this->getRepository();
99
100
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
101
102
        /* BEGIN: Use Case */
103
        $this->createTrashItem();
104
105
        // Load the location service
106
        $locationService = $repository->getLocationService();
107
108
        // This call will fail with a "NotFoundException", because the media
109
        // location was marked as trashed in the main storage
110
        $locationService->loadLocationByRemoteId($mediaRemoteId);
111
        /* END: Use Case */
112
    }
113
114
    /**
115
     * Test for the trash() method.
116
     *
117
     * @see \eZ\Publish\API\Repository\TrashService::trash()
118
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
119
     */
120
    public function testTrashRemovesChildLocationsFromMainStorage()
121
    {
122
        $repository = $this->getRepository();
123
124
        /* BEGIN: Use Case */
125
        $remoteIds = $this->createRemoteIdList();
126
127
        $this->createTrashItem();
128
129
        // All invocations to loadLocationByRemoteId() to one of the above
130
        // collected remoteIds will return in an "NotFoundException"
131
        /* END: Use Case */
132
133
        $locationService = $repository->getLocationService();
134
        foreach ($remoteIds as $remoteId) {
135
            try {
136
                $locationService->loadLocationByRemoteId($remoteId);
137
                $this->fail("Location '{$remoteId}' should exist.'");
138
            } catch (NotFoundException $e) {
139
                // echo $e->getFile(), ' +', $e->getLine(), PHP_EOL;
140
            }
141
        }
142
143
        $this->assertGreaterThan(
144
            0,
145
            count($remoteIds),
146
            "There should be at least one 'Community' child location."
147
        );
148
    }
149
150
    /**
151
     * Test for the trash() method.
152
     *
153
     * @see \eZ\Publish\API\Repository\TrashService::trash()
154
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
155
     */
156
    public function testTrashDecrementsChildCountOnParentLocation()
157
    {
158
        $repository = $this->getRepository();
159
        $locationService = $repository->getLocationService();
160
161
        $baseLocationId = $this->generateId('location', 1);
162
163
        $location = $locationService->loadLocation($baseLocationId);
164
165
        $childCount = $locationService->getLocationChildCount($location);
166
167
        $this->createTrashItem();
168
169
        $this->refreshSearch($repository);
170
171
        $this->assertEquals(
172
            $childCount - 1,
173
            $locationService->getLocationChildCount($location)
174
        );
175
    }
176
177
    /**
178
     * Test sending a location to trash updates Content mainLocation.
179
     *
180
     * @covers \eZ\Publish\API\Repository\TrashService::trash
181
     */
182
    public function testTrashUpdatesMainLocation()
183
    {
184
        $repository = $this->getRepository();
185
        $contentService = $repository->getContentService();
186
        $locationService = $repository->getLocationService();
187
        $trashService = $repository->getTrashService();
188
189
        $contentInfo = $contentService->loadContentInfo(42);
190
191
        // Create additional location that will become new main location
192
        $location = $locationService->createLocation(
193
            $contentInfo,
194
            new LocationCreateStruct(['parentLocationId' => 2])
195
        );
196
197
        $trashService->trash(
198
            $locationService->loadLocation($contentInfo->mainLocationId)
199
        );
200
201
        self::assertEquals(
202
            $location->id,
203
            $contentService->loadContentInfo(42)->mainLocationId
204
        );
205
    }
206
207
    /**
208
     * Test sending a location to trash.
209
     *
210
     * @covers \eZ\Publish\API\Repository\TrashService::trash
211
     */
212
    public function testTrashReturnsNull()
213
    {
214
        $repository = $this->getRepository();
215
        $contentService = $repository->getContentService();
216
        $locationService = $repository->getLocationService();
217
        $trashService = $repository->getTrashService();
218
219
        // Create additional location to trash
220
        $location = $locationService->createLocation(
221
            $contentService->loadContentInfo(42),
222
            new LocationCreateStruct(['parentLocationId' => 2])
223
        );
224
225
        $trashItem = $trashService->trash($location);
226
227
        self::assertNull($trashItem);
228
    }
229
230
    /**
231
     * Test for the loadTrashItem() method.
232
     *
233
     * @covers \eZ\Publish\API\Repository\TrashService::loadTrashItem
234
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
235
     */
236
    public function testLoadTrashItem()
237
    {
238
        $repository = $this->getRepository();
239
        $trashService = $repository->getTrashService();
240
241
        /* BEGIN: Use Case */
242
        $trashItem = $this->createTrashItem();
243
244
        // Reload the trash item
245
        $trashItemReloaded = $trashService->loadTrashItem($trashItem->id);
246
        /* END: Use Case */
247
248
        $this->assertInstanceOf(
249
            APITrashItem::class,
250
            $trashItemReloaded
251
        );
252
253
        $this->assertEquals(
254
            $trashItem->pathString,
255
            $trashItemReloaded->pathString
256
        );
257
258
        $this->assertEquals(
259
            $trashItem,
260
            $trashItemReloaded
261
        );
262
263
        $this->assertInstanceOf(
264
            DateTime::class,
265
            $trashItemReloaded->trashed
266
        );
267
268
        $this->assertEquals(
269
            $trashItem->trashed->getTimestamp(),
270
            $trashItemReloaded->trashed->getTimestamp()
271
        );
272
273
        $this->assertGreaterThan(
274
            0,
275
            $trashItemReloaded->trashed->getTimestamp()
276
        );
277
278
        $this->assertInstanceOf(
279
            Content::class,
280
            $content = $trashItemReloaded->getContent()
281
        );
282
        $this->assertEquals($trashItem->contentId, $content->contentInfo->id);
283
    }
284
285
    /**
286
     * Test for the loadTrashItem() method.
287
     *
288
     * @see \eZ\Publish\API\Repository\TrashService::loadTrashItem()
289
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testLoadTrashItem
290
     */
291
    public function testLoadTrashItemThrowsNotFoundException()
292
    {
293
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
294
295
        $repository = $this->getRepository();
296
297
        $nonExistingTrashId = $this->generateId('trash', 2342);
298
        /* BEGIN: Use Case */
299
        $trashService = $repository->getTrashService();
300
301
        // This call will fail with a "NotFoundException", because no trash item
302
        // with the ID 1342 should exist in an eZ Publish demo installation
303
        $trashService->loadTrashItem($nonExistingTrashId);
304
        /* END: Use Case */
305
    }
306
307
    /**
308
     * Test for the recover() method.
309
     *
310
     * @covers \eZ\Publish\API\Repository\TrashService::recover
311
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
312
     */
313
    public function testRecover()
314
    {
315
        $repository = $this->getRepository();
316
        $trashService = $repository->getTrashService();
317
        $locationService = $repository->getLocationService();
318
319
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
320
321
        /* BEGIN: Use Case */
322
        $trashItem = $this->createTrashItem();
323
324
        // Recover the trashed item
325
        $location = $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 322 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...
326
327
        // Load the recovered location
328
        $locationReloaded = $locationService->loadLocationByRemoteId(
329
            $mediaRemoteId
330
        );
331
        /* END: Use Case */
332
333
        $this->assertInstanceOf(
334
            APILocation::class,
335
            $location
336
        );
337
338
        $this->assertEquals(
339
            $location,
340
            $locationReloaded
341
        );
342
343
        try {
344
            $trashService->loadTrashItem($trashItem->id);
345
            $this->fail('Trash item was not removed after being recovered.');
346
        } catch (NotFoundException $e) {
347
            // All well
348
        }
349
    }
350
351
    /**
352
     * Test recovering a non existing trash item results in a NotFoundException.
353
     *
354
     * @covers \eZ\Publish\API\Repository\TrashService::recover
355
     */
356 View Code Duplication
    public function testRecoverThrowsNotFoundExceptionForNonExistingTrashItem()
357
    {
358
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
359
360
        $repository = $this->getRepository();
361
        $trashService = $repository->getTrashService();
362
363
        $trashService->recover(
364
            $this->getTrashItemDouble(
365
                12364,
366
                12345,
367
                12363
368
            )
369
        );
370
    }
371
372
    /**
373
     * Test for the trash() method.
374
     *
375
     * @see \eZ\Publish\API\Repository\TrashService::recover()
376
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
377
     */
378
    public function testNotFoundAliasAfterRemoveIt()
379
    {
380
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
381
382
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
383
384
        $repository = $this->getRepository();
385
        $trashService = $repository->getTrashService();
386
        $urlAliasService = $repository->getURLAliasService();
387
        $locationService = $repository->getLocationService();
388
389
        // Double ->lookup() call because there where issue that one call was not enough to spot bug
390
        $urlAliasService->lookup('/Media');
391
        $urlAliasService->lookup('/Media');
392
393
        $mediaLocation = $locationService->loadLocationByRemoteId($mediaRemoteId);
394
        $trashService->trash($mediaLocation);
395
396
        $urlAliasService->lookup('/Media');
397
    }
398
399
    /**
400
     * Test for the recover() method.
401
     *
402
     * @see \eZ\Publish\API\Repository\TrashService::recover()
403
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
404
     */
405
    public function testAliasesForRemovedItems()
406
    {
407
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
408
409
        $repository = $this->getRepository();
410
        $trashService = $repository->getTrashService();
411
        $urlAliasService = $repository->getURLAliasService();
412
        $locationService = $repository->getLocationService();
413
414
        // Double ->lookup() call because there where issue that one call was not enough to spot bug
415
        $urlAliasService->lookup('/Media');
416
        $trashedLocationAlias = $urlAliasService->lookup('/Media');
417
418
        $mediaLocation = $locationService->loadLocationByRemoteId($mediaRemoteId);
419
        $trashItem = $trashService->trash($mediaLocation);
420
        $this->assertAliasNotExists($urlAliasService, '/Media');
421
422
        $this->createNewContentInPlaceTrashedOne($repository, $mediaLocation->parentLocationId);
423
424
        $createdLocationAlias = $urlAliasService->lookup('/Media');
425
426
        $this->assertNotEquals(
427
            $trashedLocationAlias->destination,
428
            $createdLocationAlias->destination,
429
            'Destination for /media url should changed'
430
        );
431
432
        $recoveredLocation = $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $trashService->trash($mediaLocation) on line 419 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...
433
        $recoveredLocationAlias = $urlAliasService->lookup('/Media2');
434
        $recoveredLocationAliasReverse = $urlAliasService->reverseLookup($recoveredLocation);
435
436
        $this->assertEquals($recoveredLocationAlias->destination, $recoveredLocationAliasReverse->destination);
437
438
        $this->assertNotEquals($recoveredLocationAliasReverse->destination, $trashedLocationAlias->destination);
439
        $this->assertNotEquals($recoveredLocationAliasReverse->destination, $createdLocationAlias->destination);
440
    }
441
442
    /**
443
     * Test for the recover() method.
444
     *
445
     * @see \eZ\Publish\API\Repository\TrashService::recover()
446
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
447
     */
448
    public function testRecoverDoesNotRestoreChildLocations()
449
    {
450
        $repository = $this->getRepository();
451
        $trashService = $repository->getTrashService();
452
        $locationService = $repository->getLocationService();
453
454
        $remoteIds = $this->createRemoteIdList();
455
456
        // Unset remote ID of actually restored location
457
        unset($remoteIds[array_search('3f6d92f8044aed134f32153517850f5a', $remoteIds)]);
458
459
        $trashItem = $this->createTrashItem();
460
461
        $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 459 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...
462
463
        $this->assertGreaterThan(
464
            0,
465
            count($remoteIds),
466
            "There should be at least one 'Community' child location."
467
        );
468
469
        // None of the child locations will be available again
470
        foreach ($remoteIds as $remoteId) {
471
            try {
472
                $locationService->loadLocationByRemoteId($remoteId);
473
                $this->fail(
474
                    sprintf(
475
                        'Location with remote ID "%s" unexpectedly restored.',
476
                        $remoteId
477
                    )
478
                );
479
            } catch (NotFoundException $e) {
480
                // All well
481
            }
482
        }
483
484
        try {
485
            $trashService->loadTrashItem($trashItem->id);
486
            $this->fail('Trash item was not removed after being recovered.');
487
        } catch (NotFoundException $e) {
488
            // All well
489
        }
490
    }
491
492
    /**
493
     * Test for the recover() method.
494
     *
495
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem, $newParentLocation)
496
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
497
     *
498
     * @todo Fix naming
499
     */
500
    public function testRecoverWithLocationCreateStructParameter()
501
    {
502
        $repository = $this->getRepository();
503
        $trashService = $repository->getTrashService();
504
        $locationService = $repository->getLocationService();
505
506
        $homeLocationId = $this->generateId('location', 2);
507
        /* BEGIN: Use Case */
508
        // $homeLocationId is the ID of the "Home" location in an eZ Publish
509
        // demo installation
510
511
        $trashItem = $this->createTrashItem();
512
513
        // Get the new parent location
514
        $newParentLocation = $locationService->loadLocation($homeLocationId);
515
516
        // Recover location with new location
517
        $location = $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 511 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...
518
        /* END: Use Case */
519
520
        $this->assertPropertiesCorrect(
521
            [
522
                'remoteId' => $trashItem->remoteId,
523
                'parentLocationId' => $homeLocationId,
524
                // Not the full sub tree is restored
525
                'depth' => $newParentLocation->depth + 1,
526
                'hidden' => false,
527
                'invisible' => $trashItem->invisible,
528
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $location->id) . '/',
529
                'priority' => 0,
530
                'sortField' => APILocation::SORT_FIELD_NAME,
531
                'sortOrder' => APILocation::SORT_ORDER_ASC,
532
            ],
533
            $location
534
        );
535
536
        try {
537
            $trashService->loadTrashItem($trashItem->id);
538
            $this->fail('Trash item was not removed after being recovered.');
539
        } catch (NotFoundException $e) {
540
            // All well
541
        }
542
    }
543
544
    /**
545
     * Test for the recover() method.
546
     *
547
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem)
548
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
549
     */
550
    public function testRecoverIncrementsChildCountOnOriginalParent()
551
    {
552
        $repository = $this->getRepository();
553
        $trashService = $repository->getTrashService();
554
        $locationService = $repository->getLocationService();
555
556
        $location = $locationService->loadLocation($this->generateId('location', 1));
557
558
        $trashItem = $this->createTrashItem();
559
560
        $this->refreshSearch($repository);
561
562
        /* BEGIN: Use Case */
563
        $childCount = $locationService->getLocationChildCount($location);
564
565
        // Recover location with new location
566
        $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 558 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...
567
        /* END: Use Case */
568
569
        $this->refreshSearch($repository);
570
571
        $this->assertEquals(
572
            $childCount + 1,
573
            $locationService->getLocationChildCount($location)
574
        );
575
576
        try {
577
            $trashService->loadTrashItem($trashItem->id);
578
            $this->fail('Trash item was not removed after being recovered.');
579
        } catch (NotFoundException $e) {
580
            // All well
581
        }
582
    }
583
584
    /**
585
     * Test for the recover() method.
586
     *
587
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem, $newParentLocation)
588
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecoverWithLocationCreateStructParameter
589
     */
590
    public function testRecoverWithLocationCreateStructParameterIncrementsChildCountOnNewParent()
591
    {
592
        $repository = $this->getRepository();
593
        $trashService = $repository->getTrashService();
594
        $locationService = $repository->getLocationService();
595
596
        $homeLocationId = $this->generateId('location', 2);
597
598
        $location = $locationService->loadLocation($homeLocationId);
599
600
        $childCount = $locationService->getLocationChildCount($location);
601
602
        /* BEGIN: Use Case */
603
        // $homeLocationId is the ID of the "Home" location in an eZ Publish
604
        // demo installation
605
606
        $trashItem = $this->createTrashItem();
607
608
        // Get the new parent location
609
        $newParentLocation = $locationService->loadLocation($homeLocationId);
610
611
        // Recover location with new location
612
        $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 606 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...
613
        /* END: Use Case */
614
615
        $this->refreshSearch($repository);
616
617
        $this->assertEquals(
618
            $childCount + 1,
619
            $locationService->getLocationChildCount($location)
620
        );
621
622
        try {
623
            $trashService->loadTrashItem($trashItem->id);
624
            $this->fail('Trash item was not removed after being recovered.');
625
        } catch (NotFoundException $e) {
626
            // All well
627
        }
628
    }
629
630
    /**
631
     * Test recovering a location from trash to non existing location.
632
     *
633
     * @covers \eZ\Publish\API\Repository\TrashService::recover
634
     */
635
    public function testRecoverToNonExistingLocation()
636
    {
637
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
638
639
        $repository = $this->getRepository();
640
        $trashService = $repository->getTrashService();
641
        $locationService = $repository->getLocationService();
642
643
        $location = $locationService->loadLocation(44);
644
        $trashItem = $trashService->trash($location);
645
646
        $newParentLocation = new Location(
647
            [
648
                'id' => 123456,
649
                'parentLocationId' => 123455,
650
            ]
651
        );
652
        $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $trashService->trash($location) on line 644 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...
653
    }
654
655
    /**
656
     * Test for the findTrashItems() method.
657
     *
658
     * @see \eZ\Publish\API\Repository\TrashService::findTrashItems()
659
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
660
     */
661
    public function testFindTrashItems()
662
    {
663
        $repository = $this->getRepository();
664
        $trashService = $repository->getTrashService();
665
666
        /* BEGIN: Use Case */
667
        $this->createTrashItem();
668
669
        // Create a search query for all trashed items
670
        $query = new Query();
671
        $query->filter = new Criterion\LogicalAnd(
672
            [
673
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
674
            ]
675
        );
676
677
        // Load all trashed locations
678
        $searchResult = $trashService->findTrashItems($query);
679
        /* END: Use Case */
680
681
        $this->assertInstanceOf(
682
            SearchResult::class,
683
            $searchResult
684
        );
685
686
        // 4 trashed locations from the sub tree
687
        $this->assertEquals(4, $searchResult->count);
688
        $this->assertEquals(4, $searchResult->totalCount);
689
    }
690
691
    /**
692
     * Test for the findTrashItems() method for it's result structure.
693
     *
694
     * @see \eZ\Publish\API\Repository\TrashService::findTrashItems()
695
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
696
     */
697
    public function testFindTrashItemsLimits()
698
    {
699
        $repository = $this->getRepository();
700
        $trashService = $repository->getTrashService();
701
702
        $this->createTrashItem();
703
704
        // Create a search query for all trashed items
705
        $query = new Query();
706
        $query->limit = 2;
707
708
        // Load all trashed locations
709
        $searchResult = $trashService->findTrashItems($query);
710
711
        $this->assertInstanceOf(
712
            SearchResult::class,
713
            $searchResult
714
        );
715
716
        // 4 trashed locations from the sub tree, but only 2 in results
717
        $this->assertCount(2, $searchResult->items);
718
        $this->assertEquals(4, $searchResult->count);
719
        $this->assertEquals(4, $searchResult->totalCount);
720
    }
721
722
    /**
723
     * Test for the findTrashItems() method.
724
     *
725
     * @see \eZ\Publish\API\Repository\TrashService::findTrashItems()
726
     * @depends \eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
727
     */
728
    public function testFindTrashItemsLimitedAccess()
729
    {
730
        $repository = $this->getRepository();
731
        $trashService = $repository->getTrashService();
732
733
        /* BEGIN: Use Case */
734
        $this->createTrashItem();
735
736
        // Create a search query for all trashed items
737
        $query = new Query();
738
        $query->filter = new Criterion\LogicalAnd(
739
            [
740
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
741
            ]
742
        );
743
744
        // Create a user in the Editor user group.
745
        $user = $this->createUserVersion1();
746
747
        // Set the Editor user as current user, these users have no access to Trash by default.
748
        $repository->getPermissionResolver()->setCurrentUserReference($user);
749
750
        // Load all trashed locations
751
        $searchResult = $trashService->findTrashItems($query);
752
        /* END: Use Case */
753
754
        $this->assertInstanceOf(
755
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\SearchResult',
756
            $searchResult
757
        );
758
759
        // 0 trashed locations found, though 4 exist
760
        $this->assertEquals(0, $searchResult->count);
761
    }
762
763
    /**
764
     * Test for the emptyTrash() method.
765
     *
766
     * @see \eZ\Publish\API\Repository\TrashService::emptyTrash()
767
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
768
     */
769
    public function testEmptyTrash()
770
    {
771
        $repository = $this->getRepository();
772
        $trashService = $repository->getTrashService();
773
        $contentService = $repository->getContentService();
774
775
        /* BEGIN: Use Case */
776
        $trashItem = $this->createTrashItem();
777
778
        // Empty the trash
779
        $trashService->emptyTrash();
780
781
        // Create a search query for all trashed items
782
        $query = new Query();
783
        $query->filter = new Criterion\LogicalAnd(
784
            [
785
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
786
            ]
787
        );
788
        // Load all trashed locations, search result should be empty
789
        $searchResult = $trashService->findTrashItems($query);
790
        /* END: Use Case */
791
792
        $this->assertEquals(0, $searchResult->count);
793
794
        // Try to load content
795
        $this->expectException(NotFoundException::class);
796
        $contentService->loadContent($trashItem->contentId);
797
    }
798
799
    /**
800
     * Test for the emptyTrash() method with user which has subtree limitations.
801
     *
802
     * @see \eZ\Publish\API\Repository\TrashService::emptyTrash()
803
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
804
     */
805
    public function testEmptyTrashForUserWithSubtreeLimitation()
806
    {
807
        $repository = $this->getRepository();
808
        $trashService = $repository->getTrashService();
809
        $contentService = $repository->getContentService();
810
811
        /* BEGIN: Use Case */
812
        $trashItem = $this->createTrashItem();
813
814
        $this->createRoleWithPolicies('roleTrashCleaner', [
815
            ['module' => 'content', 'function' => 'cleantrash'],
816
            ['module' => 'content', 'function' => 'read'],
817
        ]);
818
        $user = $this->createCustomUserWithLogin(
819
            'user',
820
            '[email protected]',
821
            'roleTrashCleaners',
822
            'roleTrashCleaner',
823
            new SubtreeLimitation(['limitationValues' => ['/1/2/']])
824
        );
825
        $repository->getPermissionResolver()->setCurrentUserReference($user);
826
827
        // Empty the trash
828
        $trashService->emptyTrash();
829
830
        // Create a search query for all trashed items
831
        $query = new Query();
832
        $query->filter = new Criterion\LogicalAnd(
833
            [
834
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
835
            ]
836
        );
837
        // Load all trashed locations, search result should be empty
838
        $searchResult = $trashService->findTrashItems($query);
839
        /* END: Use Case */
840
841
        $this->assertEquals(0, $searchResult->totalCount);
842
843
        // Try to load content
844
        $this->expectException(NotFoundException::class);
845
        $contentService->loadContent($trashItem->contentId);
846
    }
847
848
    /**
849
     * Test for the deleteTrashItem() method.
850
     *
851
     * @see \eZ\Publish\API\Repository\TrashService::deleteTrashItem()
852
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
853
     */
854
    public function testDeleteTrashItem()
855
    {
856
        $repository = $this->getRepository();
857
        $trashService = $repository->getTrashService();
858
        $locationService = $repository->getLocationService();
859
        $contentService = $repository->getContentService();
860
861
        $demoDesignLocationId = $this->generateId('location', 56);
862
        /* BEGIN: Use Case */
863
        // $demoDesignLocationId is the ID of the "Demo Design" location in an eZ
864
        // Publish demo installation
865
866
        $trashItem = $this->createTrashItem();
867
868
        // Trash one more location
869
        $trashService->trash(
870
            $locationService->loadLocation($demoDesignLocationId)
871
        );
872
873
        // Empty the trash
874
        $trashService->deleteTrashItem($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 866 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...
875
876
        // Create a search query for all trashed items
877
        $query = new Query();
878
        $query->filter = new Criterion\LogicalAnd(
879
            [
880
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
881
            ]
882
        );
883
884
        // Load all trashed locations, should only contain the Demo Design location
885
        $searchResult = $trashService->findTrashItems($query);
886
        /* END: Use Case */
887
888
        $foundIds = array_map(
889
            function ($trashItem) {
890
                return $trashItem->id;
891
            },
892
            $searchResult->items
893
        );
894
895
        $this->assertEquals(4, $searchResult->count);
896
        $this->assertTrue(
897
            in_array($demoDesignLocationId, $foundIds)
898
        );
899
900
        // Try to load Content
901
        $this->expectException(NotFoundException::class);
902
        $contentService->loadContent($trashItem->contentId);
903
    }
904
905
    /**
906
     * Test deleting a non existing trash item.
907
     *
908
     * @covers \eZ\Publish\API\Repository\TrashService::deleteTrashItem
909
     */
910 View Code Duplication
    public function testDeleteThrowsNotFoundExceptionForNonExistingTrashItem()
911
    {
912
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
913
914
        $repository = $this->getRepository();
915
        $trashService = $repository->getTrashService();
916
917
        $trashService->deleteTrashItem($this->getTrashItemDouble(
918
            12364,
919
            12345,
920
            12363
921
        ));
922
    }
923
924
    /**
925
     * Returns an array with the remoteIds of all child locations of the
926
     * <b>Community</b> location. It is stored in a local variable named
927
     * <b>$remoteIds</b>.
928
     *
929
     * @return string[]
930
     */
931
    private function createRemoteIdList()
932
    {
933
        $repository = $this->getRepository();
934
935
        /* BEGIN: Inline */
936
        // remoteId of the "Community" location in an eZ Publish demo installation
937
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
938
939
        // Load the location service
940
        $locationService = $repository->getLocationService();
941
942
        $remoteIds = [];
943
        $children = $locationService->loadLocationChildren($locationService->loadLocationByRemoteId($mediaRemoteId));
944
        foreach ($children->locations as $child) {
945
            $remoteIds[] = $child->remoteId;
946
            foreach ($locationService->loadLocationChildren($child)->locations as $grandChild) {
947
                $remoteIds[] = $grandChild->remoteId;
948
            }
949
        }
950
        /* END: Inline */
951
952
        return $remoteIds;
953
    }
954
955
    /**
956
     * @param Repository $repository
957
     * @param int $parentLocationId
958
     *
959
     * @return \eZ\Publish\API\Repository\Values\Content\Content
960
     */
961 View Code Duplication
    protected function createNewContentInPlaceTrashedOne(Repository $repository, $parentLocationId)
962
    {
963
        $contentService = $repository->getContentService();
964
        $locationService = $repository->getLocationService();
965
        $contentTypeService = $repository->getContentTypeService();
966
967
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
968
        $newContent = $contentService->newContentCreateStruct($contentType, 'eng-US');
969
        $newContent->setField('name', 'Media');
970
971
        $location = $locationService->newLocationCreateStruct($parentLocationId);
972
973
        $draftContent = $contentService->createContent($newContent, [$location]);
974
975
        return $contentService->publishVersion($draftContent->versionInfo);
976
    }
977
978
    /**
979
     * @param URLAliasService $urlAliasService
980
     * @param string $urlPath Url alias path
981
     *
982
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
983
     */
984
    private function assertAliasExists(URLAliasService $urlAliasService, $urlPath)
985
    {
986
        $urlAlias = $urlAliasService->lookup($urlPath);
987
988
        $this->assertInstanceOf('\eZ\Publish\API\Repository\Values\Content\URLAlias', $urlAlias);
989
990
        return $urlAlias;
991
    }
992
993
    /**
994
     * @param URLAliasService $urlAliasService
995
     * @param string $urlPath Url alias path
996
     */
997
    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...
998
    {
999
        try {
1000
            $this->getRepository()->getURLAliasService()->lookup($urlPath);
1001
            $this->fail(sprintf('Alias [%s] should not exists', $urlPath));
1002
        } catch (\eZ\Publish\API\Repository\Exceptions\NotFoundException $e) {
1003
            $this->assertTrue(true);
1004
        }
1005
    }
1006
1007
    /**
1008
     * Get Test Double for TrashItem for exception testing and similar.
1009
     *
1010
     * @param int $trashId
1011
     * @param int $contentId
1012
     * @param int $parentLocationId
1013
     *
1014
     * @return \eZ\Publish\API\Repository\Values\Content\TrashItem
1015
     */
1016
    private function getTrashItemDouble(int $trashId, int $contentId = 44, int $parentLocationId = 2): APITrashItem
1017
    {
1018
        return new TrashItem([
1019
            'id' => $trashId,
1020
            'parentLocationId' => $parentLocationId,
1021
            'contentInfo' => new ContentInfo(['id' => $contentId]),
1022
        ]);
1023
    }
1024
}
1025