Completed
Push — EZP-31084-part1 ( b47545 )
by André
19:34
created

TrashServiceTest::testFindTrashItemsLimits()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 26
rs 9.504
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
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
93
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
94
     */
95
    public function testTrashRemovesLocationFromMainStorage()
96
    {
97
        $repository = $this->getRepository();
98
99
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
100
101
        /* BEGIN: Use Case */
102
        $this->createTrashItem();
103
104
        // Load the location service
105
        $locationService = $repository->getLocationService();
106
107
        // This call will fail with a "NotFoundException", because the media
108
        // location was marked as trashed in the main storage
109
        $locationService->loadLocationByRemoteId($mediaRemoteId);
110
        /* END: Use Case */
111
    }
112
113
    /**
114
     * Test for the trash() method.
115
     *
116
     * @see \eZ\Publish\API\Repository\TrashService::trash()
117
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
118
     */
119
    public function testTrashRemovesChildLocationsFromMainStorage()
120
    {
121
        $repository = $this->getRepository();
122
123
        /* BEGIN: Use Case */
124
        $remoteIds = $this->createRemoteIdList();
125
126
        $this->createTrashItem();
127
128
        // All invocations to loadLocationByRemoteId() to one of the above
129
        // collected remoteIds will return in an "NotFoundException"
130
        /* END: Use Case */
131
132
        $locationService = $repository->getLocationService();
133
        foreach ($remoteIds as $remoteId) {
134
            try {
135
                $locationService->loadLocationByRemoteId($remoteId);
136
                $this->fail("Location '{$remoteId}' should exist.'");
137
            } catch (NotFoundException $e) {
138
                // echo $e->getFile(), ' +', $e->getLine(), PHP_EOL;
139
            }
140
        }
141
142
        $this->assertGreaterThan(
143
            0,
144
            count($remoteIds),
145
            "There should be at least one 'Community' child location."
146
        );
147
    }
148
149
    /**
150
     * Test for the trash() method.
151
     *
152
     * @see \eZ\Publish\API\Repository\TrashService::trash()
153
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
154
     */
155
    public function testTrashDecrementsChildCountOnParentLocation()
156
    {
157
        $repository = $this->getRepository();
158
        $locationService = $repository->getLocationService();
159
160
        $baseLocationId = $this->generateId('location', 1);
161
162
        $location = $locationService->loadLocation($baseLocationId);
163
164
        $childCount = $locationService->getLocationChildCount($location);
165
166
        $this->createTrashItem();
167
168
        $this->refreshSearch($repository);
169
170
        $this->assertEquals(
171
            $childCount - 1,
172
            $locationService->getLocationChildCount($location)
173
        );
174
    }
175
176
    /**
177
     * Test sending a location to trash updates Content mainLocation.
178
     *
179
     * @covers \eZ\Publish\API\Repository\TrashService::trash
180
     */
181
    public function testTrashUpdatesMainLocation()
182
    {
183
        $repository = $this->getRepository();
184
        $contentService = $repository->getContentService();
185
        $locationService = $repository->getLocationService();
186
        $trashService = $repository->getTrashService();
187
188
        $contentInfo = $contentService->loadContentInfo(42);
189
190
        // Create additional location that will become new main location
191
        $location = $locationService->createLocation(
192
            $contentInfo,
193
            new LocationCreateStruct(['parentLocationId' => 2])
194
        );
195
196
        $trashService->trash(
197
            $locationService->loadLocation($contentInfo->mainLocationId)
198
        );
199
200
        self::assertEquals(
201
            $location->id,
202
            $contentService->loadContentInfo(42)->mainLocationId
203
        );
204
    }
205
206
    /**
207
     * Test sending a location to trash.
208
     *
209
     * @covers \eZ\Publish\API\Repository\TrashService::trash
210
     */
211 View Code Duplication
    public function testTrashReturnsNull()
212
    {
213
        $repository = $this->getRepository();
214
        $contentService = $repository->getContentService();
215
        $locationService = $repository->getLocationService();
216
        $trashService = $repository->getTrashService();
217
218
        // Create additional location to trash
219
        $location = $locationService->createLocation(
220
            $contentService->loadContentInfo(42),
221
            new LocationCreateStruct(['parentLocationId' => 2])
222
        );
223
224
        $trashItem = $trashService->trash($location);
225
226
        self::assertNull($trashItem);
227
    }
228
229
    /**
230
     * Test for the loadTrashItem() method.
231
     *
232
     * @covers \eZ\Publish\API\Repository\TrashService::loadTrashItem
233
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
234
     */
235
    public function testLoadTrashItem()
236
    {
237
        $repository = $this->getRepository();
238
        $trashService = $repository->getTrashService();
239
240
        /* BEGIN: Use Case */
241
        $trashItem = $this->createTrashItem();
242
243
        // Reload the trash item
244
        $trashItemReloaded = $trashService->loadTrashItem($trashItem->id);
245
        /* END: Use Case */
246
247
        $this->assertInstanceOf(
248
            APITrashItem::class,
249
            $trashItemReloaded
250
        );
251
252
        $this->assertEquals(
253
            $trashItem->pathString,
254
            $trashItemReloaded->pathString
255
        );
256
257
        $this->assertEquals(
258
            $trashItem,
259
            $trashItemReloaded
260
        );
261
262
        $this->assertInstanceOf(
263
            DateTime::class,
264
            $trashItemReloaded->trashed
265
        );
266
267
        $this->assertEquals(
268
            $trashItem->trashed->getTimestamp(),
269
            $trashItemReloaded->trashed->getTimestamp()
270
        );
271
272
        $this->assertGreaterThan(
273
            0,
274
            $trashItemReloaded->trashed->getTimestamp()
275
        );
276
277
        $this->assertInstanceOf(
278
            Content::class,
279
            $content = $trashItemReloaded->getContent()
280
        );
281
        $this->assertEquals($trashItem->contentId, $content->contentInfo->id);
282
    }
283
284
    /**
285
     * Test for the loadTrashItem() method.
286
     *
287
     * @see \eZ\Publish\API\Repository\TrashService::loadTrashItem()
288
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
289
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testLoadTrashItem
290
     */
291
    public function testLoadTrashItemThrowsNotFoundException()
292
    {
293
        $repository = $this->getRepository();
294
295
        $nonExistingTrashId = $this->generateId('trash', 2342);
296
        /* BEGIN: Use Case */
297
        $trashService = $repository->getTrashService();
298
299
        // This call will fail with a "NotFoundException", because no trash item
300
        // with the ID 1342 should exist in an eZ Publish demo installation
301
        $trashService->loadTrashItem($nonExistingTrashId);
302
        /* END: Use Case */
303
    }
304
305
    /**
306
     * Test for the recover() method.
307
     *
308
     * @covers \eZ\Publish\API\Repository\TrashService::recover
309
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
310
     */
311
    public function testRecover()
312
    {
313
        $repository = $this->getRepository();
314
        $trashService = $repository->getTrashService();
315
        $locationService = $repository->getLocationService();
316
317
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
318
319
        /* BEGIN: Use Case */
320
        $trashItem = $this->createTrashItem();
321
322
        // Recover the trashed item
323
        $location = $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 320 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...
324
325
        // Load the recovered location
326
        $locationReloaded = $locationService->loadLocationByRemoteId(
327
            $mediaRemoteId
328
        );
329
        /* END: Use Case */
330
331
        $this->assertInstanceOf(
332
            APILocation::class,
333
            $location
334
        );
335
336
        $this->assertEquals(
337
            $location,
338
            $locationReloaded
339
        );
340
341
        try {
342
            $trashService->loadTrashItem($trashItem->id);
343
            $this->fail('Trash item was not removed after being recovered.');
344
        } catch (NotFoundException $e) {
345
            // All well
346
        }
347
    }
348
349
    /**
350
     * Test recovering a non existing trash item results in a NotFoundException.
351
     *
352
     * @covers \eZ\Publish\API\Repository\TrashService::recover
353
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
354
     */
355
    public function testRecoverThrowsNotFoundExceptionForNonExistingTrashItem()
356
    {
357
        $repository = $this->getRepository();
358
        $trashService = $repository->getTrashService();
359
360
        $trashService->recover(
361
            $this->getTrashItemDouble(
362
                12364,
363
                12345,
364
                12363
365
            )
366
        );
367
    }
368
369
    /**
370
     * Test for the trash() method.
371
     *
372
     * @see \eZ\Publish\API\Repository\TrashService::recover()
373
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
374
     *
375
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
376
     */
377
    public function testNotFoundAliasAfterRemoveIt()
378
    {
379
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
380
381
        $repository = $this->getRepository();
382
        $trashService = $repository->getTrashService();
383
        $urlAliasService = $repository->getURLAliasService();
384
        $locationService = $repository->getLocationService();
385
386
        // Double ->lookup() call because there where issue that one call was not enough to spot bug
387
        $urlAliasService->lookup('/Media');
388
        $urlAliasService->lookup('/Media');
389
390
        $mediaLocation = $locationService->loadLocationByRemoteId($mediaRemoteId);
391
        $trashService->trash($mediaLocation);
392
393
        $urlAliasService->lookup('/Media');
394
    }
395
396
    /**
397
     * Test for the recover() method.
398
     *
399
     * @see \eZ\Publish\API\Repository\TrashService::recover()
400
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
401
     */
402
    public function testAliasesForRemovedItems()
403
    {
404
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
405
406
        $repository = $this->getRepository();
407
        $trashService = $repository->getTrashService();
408
        $urlAliasService = $repository->getURLAliasService();
409
        $locationService = $repository->getLocationService();
410
411
        // Double ->lookup() call because there where issue that one call was not enough to spot bug
412
        $urlAliasService->lookup('/Media');
413
        $trashedLocationAlias = $urlAliasService->lookup('/Media');
414
415
        $mediaLocation = $locationService->loadLocationByRemoteId($mediaRemoteId);
416
        $trashItem = $trashService->trash($mediaLocation);
417
        $this->assertAliasNotExists($urlAliasService, '/Media');
418
419
        $this->createNewContentInPlaceTrashedOne($repository, $mediaLocation->parentLocationId);
420
421
        $createdLocationAlias = $urlAliasService->lookup('/Media');
422
423
        $this->assertNotEquals(
424
            $trashedLocationAlias->destination,
425
            $createdLocationAlias->destination,
426
            'Destination for /media url should changed'
427
        );
428
429
        $recoveredLocation = $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $trashService->trash($mediaLocation) on line 416 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...
430
        $recoveredLocationAlias = $urlAliasService->lookup('/Media2');
431
        $recoveredLocationAliasReverse = $urlAliasService->reverseLookup($recoveredLocation);
432
433
        $this->assertEquals($recoveredLocationAlias->destination, $recoveredLocationAliasReverse->destination);
434
435
        $this->assertNotEquals($recoveredLocationAliasReverse->destination, $trashedLocationAlias->destination);
436
        $this->assertNotEquals($recoveredLocationAliasReverse->destination, $createdLocationAlias->destination);
437
    }
438
439
    /**
440
     * Test for the recover() method.
441
     *
442
     * @see \eZ\Publish\API\Repository\TrashService::recover()
443
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
444
     */
445
    public function testRecoverDoesNotRestoreChildLocations()
446
    {
447
        $repository = $this->getRepository();
448
        $trashService = $repository->getTrashService();
449
        $locationService = $repository->getLocationService();
450
451
        $remoteIds = $this->createRemoteIdList();
452
453
        // Unset remote ID of actually restored location
454
        unset($remoteIds[array_search('3f6d92f8044aed134f32153517850f5a', $remoteIds)]);
455
456
        $trashItem = $this->createTrashItem();
457
458
        $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 456 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...
459
460
        $this->assertGreaterThan(
461
            0,
462
            count($remoteIds),
463
            "There should be at least one 'Community' child location."
464
        );
465
466
        // None of the child locations will be available again
467
        foreach ($remoteIds as $remoteId) {
468
            try {
469
                $locationService->loadLocationByRemoteId($remoteId);
470
                $this->fail(
471
                    sprintf(
472
                        'Location with remote ID "%s" unexpectedly restored.',
473
                        $remoteId
474
                    )
475
                );
476
            } catch (NotFoundException $e) {
477
                // All well
478
            }
479
        }
480
481
        try {
482
            $trashService->loadTrashItem($trashItem->id);
483
            $this->fail('Trash item was not removed after being recovered.');
484
        } catch (NotFoundException $e) {
485
            // All well
486
        }
487
    }
488
489
    /**
490
     * Test for the recover() method.
491
     *
492
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem, $newParentLocation)
493
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
494
     *
495
     * @todo Fix naming
496
     */
497
    public function testRecoverWithLocationCreateStructParameter()
498
    {
499
        $repository = $this->getRepository();
500
        $trashService = $repository->getTrashService();
501
        $locationService = $repository->getLocationService();
502
503
        $homeLocationId = $this->generateId('location', 2);
504
        /* BEGIN: Use Case */
505
        // $homeLocationId is the ID of the "Home" location in an eZ Publish
506
        // demo installation
507
508
        $trashItem = $this->createTrashItem();
509
510
        // Get the new parent location
511
        $newParentLocation = $locationService->loadLocation($homeLocationId);
512
513
        // Recover location with new location
514
        $location = $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 508 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...
515
        /* END: Use Case */
516
517
        $this->assertPropertiesCorrect(
518
            [
519
                'remoteId' => $trashItem->remoteId,
520
                'parentLocationId' => $homeLocationId,
521
                // Not the full sub tree is restored
522
                'depth' => $newParentLocation->depth + 1,
523
                'hidden' => false,
524
                'invisible' => $trashItem->invisible,
525
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $location->id) . '/',
526
                'priority' => 0,
527
                'sortField' => APILocation::SORT_FIELD_NAME,
528
                'sortOrder' => APILocation::SORT_ORDER_ASC,
529
            ],
530
            $location
531
        );
532
533
        try {
534
            $trashService->loadTrashItem($trashItem->id);
535
            $this->fail('Trash item was not removed after being recovered.');
536
        } catch (NotFoundException $e) {
537
            // All well
538
        }
539
    }
540
541
    /**
542
     * Test for the recover() method.
543
     *
544
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem)
545
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
546
     */
547
    public function testRecoverIncrementsChildCountOnOriginalParent()
548
    {
549
        $repository = $this->getRepository();
550
        $trashService = $repository->getTrashService();
551
        $locationService = $repository->getLocationService();
552
553
        $location = $locationService->loadLocation($this->generateId('location', 1));
554
555
        $trashItem = $this->createTrashItem();
556
557
        $this->refreshSearch($repository);
558
559
        /* BEGIN: Use Case */
560
        $childCount = $locationService->getLocationChildCount($location);
561
562
        // Recover location with new location
563
        $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 555 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...
564
        /* END: Use Case */
565
566
        $this->refreshSearch($repository);
567
568
        $this->assertEquals(
569
            $childCount + 1,
570
            $locationService->getLocationChildCount($location)
571
        );
572
573
        try {
574
            $trashService->loadTrashItem($trashItem->id);
575
            $this->fail('Trash item was not removed after being recovered.');
576
        } catch (NotFoundException $e) {
577
            // All well
578
        }
579
    }
580
581
    /**
582
     * Test for the recover() method.
583
     *
584
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem, $newParentLocation)
585
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecoverWithLocationCreateStructParameter
586
     */
587
    public function testRecoverWithLocationCreateStructParameterIncrementsChildCountOnNewParent()
588
    {
589
        $repository = $this->getRepository();
590
        $trashService = $repository->getTrashService();
591
        $locationService = $repository->getLocationService();
592
593
        $homeLocationId = $this->generateId('location', 2);
594
595
        $location = $locationService->loadLocation($homeLocationId);
596
597
        $childCount = $locationService->getLocationChildCount($location);
598
599
        /* BEGIN: Use Case */
600
        // $homeLocationId is the ID of the "Home" location in an eZ Publish
601
        // demo installation
602
603
        $trashItem = $this->createTrashItem();
604
605
        // Get the new parent location
606
        $newParentLocation = $locationService->loadLocation($homeLocationId);
607
608
        // Recover location with new location
609
        $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 603 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...
610
        /* END: Use Case */
611
612
        $this->refreshSearch($repository);
613
614
        $this->assertEquals(
615
            $childCount + 1,
616
            $locationService->getLocationChildCount($location)
617
        );
618
619
        try {
620
            $trashService->loadTrashItem($trashItem->id);
621
            $this->fail('Trash item was not removed after being recovered.');
622
        } catch (NotFoundException $e) {
623
            // All well
624
        }
625
    }
626
627
    /**
628
     * Test recovering a location from trash to non existing location.
629
     *
630
     * @covers \eZ\Publish\API\Repository\TrashService::recover
631
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
632
     */
633 View Code Duplication
    public function testRecoverToNonExistingLocation()
634
    {
635
        $repository = $this->getRepository();
636
        $trashService = $repository->getTrashService();
637
        $locationService = $repository->getLocationService();
638
639
        $location = $locationService->loadLocation(44);
640
        $trashItem = $trashService->trash($location);
641
642
        $newParentLocation = new Location(
643
            [
644
                'id' => 123456,
645
                'parentLocationId' => 123455,
646
            ]
647
        );
648
        $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $trashService->trash($location) on line 640 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...
649
    }
650
651
    /**
652
     * Test for the findTrashItems() method.
653
     *
654
     * @see \eZ\Publish\API\Repository\TrashService::findTrashItems()
655
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
656
     */
657
    public function testFindTrashItems()
658
    {
659
        $repository = $this->getRepository();
660
        $trashService = $repository->getTrashService();
661
662
        /* BEGIN: Use Case */
663
        $this->createTrashItem();
664
665
        // Create a search query for all trashed items
666
        $query = new Query();
667
        $query->filter = new Criterion\LogicalAnd(
668
            [
669
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
670
            ]
671
        );
672
673
        // Load all trashed locations
674
        $searchResult = $trashService->findTrashItems($query);
675
        /* END: Use Case */
676
677
        $this->assertInstanceOf(
678
            SearchResult::class,
679
            $searchResult
680
        );
681
682
        // 4 trashed locations from the sub tree
683
        $this->assertEquals(4, $searchResult->count);
684
        $this->assertEquals(4, $searchResult->totalCount);
685
    }
686
687
    /**
688
     * Test for the findTrashItems() method for it's result structure.
689
     *
690
     * @see \eZ\Publish\API\Repository\TrashService::findTrashItems()
691
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
692
     */
693
    public function testFindTrashItemsLimits()
694
    {
695
        $repository = $this->getRepository();
696
        $trashService = $repository->getTrashService();
697
698
        /* BEGIN: Use Case */
699
        $this->createTrashItem();
700
701
        // Create a search query for all trashed items
702
        $query = new Query();
703
        $query->limit = 2;
704
705
        // Load all trashed locations
706
        $searchResult = $trashService->findTrashItems($query);
707
        /* END: Use Case */
708
709
        $this->assertInstanceOf(
710
            SearchResult::class,
711
            $searchResult
712
        );
713
714
        // 4 trashed locations from the sub tree, but only 2 in results
715
        $this->assertCount(2, $searchResult->items);
716
        $this->assertEquals(4, $searchResult->count);
717
        $this->assertEquals(4, $searchResult->totalCount);
718
    }
719
720
    /**
721
     * Test for the findTrashItems() method.
722
     *
723
     * @todo Should probably be on TrashServiceAuthorizationTest.
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
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
910
     */
911
    public function testDeleteThrowsNotFoundExceptionForNonExistingTrashItem()
912
    {
913
        $repository = $this->getRepository();
914
        $trashService = $repository->getTrashService();
915
916
        $trashService->deleteTrashItem($this->getTrashItemDouble(
917
            12364,
918
            12345,
919
            12363
920
        ));
921
    }
922
923
    /**
924
     * Returns an array with the remoteIds of all child locations of the
925
     * <b>Community</b> location. It is stored in a local variable named
926
     * <b>$remoteIds</b>.
927
     *
928
     * @return string[]
929
     */
930
    private function createRemoteIdList()
931
    {
932
        $repository = $this->getRepository();
933
934
        /* BEGIN: Inline */
935
        // remoteId of the "Community" location in an eZ Publish demo installation
936
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
937
938
        // Load the location service
939
        $locationService = $repository->getLocationService();
940
941
        $remoteIds = [];
942
        $children = $locationService->loadLocationChildren($locationService->loadLocationByRemoteId($mediaRemoteId));
943
        foreach ($children->locations as $child) {
944
            $remoteIds[] = $child->remoteId;
945
            foreach ($locationService->loadLocationChildren($child)->locations as $grandChild) {
946
                $remoteIds[] = $grandChild->remoteId;
947
            }
948
        }
949
        /* END: Inline */
950
951
        return $remoteIds;
952
    }
953
954
    /**
955
     * @param Repository $repository
956
     * @param int $parentLocationId
957
     *
958
     * @return \eZ\Publish\API\Repository\Values\Content\Content
959
     */
960 View Code Duplication
    protected function createNewContentInPlaceTrashedOne(Repository $repository, $parentLocationId)
961
    {
962
        $contentService = $repository->getContentService();
963
        $locationService = $repository->getLocationService();
964
        $contentTypeService = $repository->getContentTypeService();
965
966
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
967
        $newContent = $contentService->newContentCreateStruct($contentType, 'eng-US');
968
        $newContent->setField('name', 'Media');
969
970
        $location = $locationService->newLocationCreateStruct($parentLocationId);
971
972
        $draftContent = $contentService->createContent($newContent, [$location]);
973
974
        return $contentService->publishVersion($draftContent->versionInfo);
975
    }
976
977
    /**
978
     * @param URLAliasService $urlAliasService
979
     * @param string $urlPath Url alias path
980
     *
981
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
982
     */
983
    private function assertAliasExists(URLAliasService $urlAliasService, $urlPath)
984
    {
985
        $urlAlias = $urlAliasService->lookup($urlPath);
986
987
        $this->assertInstanceOf('\eZ\Publish\API\Repository\Values\Content\URLAlias', $urlAlias);
988
989
        return $urlAlias;
990
    }
991
992
    /**
993
     * @param URLAliasService $urlAliasService
994
     * @param string $urlPath Url alias path
995
     */
996
    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...
997
    {
998
        try {
999
            $this->getRepository()->getURLAliasService()->lookup($urlPath);
1000
            $this->fail(sprintf('Alias [%s] should not exists', $urlPath));
1001
        } catch (\eZ\Publish\API\Repository\Exceptions\NotFoundException $e) {
1002
            $this->assertTrue(true);
1003
        }
1004
    }
1005
1006
    /**
1007
     * Get Test Double for TrashItem for exception testing and similar.
1008
     *
1009
     * @param int $trashId
1010
     * @param int $contentId
1011
     * @param int $parentLocationId
1012
     *
1013
     * @return \eZ\Publish\API\Repository\Values\Content\TrashItem
1014
     */
1015
    private function getTrashItemDouble(int $trashId, int $contentId = 44, int $parentLocationId = 2): APITrashItem
1016
    {
1017
        return new TrashItem([
1018
            'id' => $trashId,
1019
            'parentLocationId' => $parentLocationId,
1020
            'contentInfo' => new ContentInfo(['id' => $contentId]),
1021
        ]);
1022
    }
1023
}
1024