Completed
Push — 7.5 ( 22ec60...932e58 )
by André
23:01
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
     * @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
        $this->createTrashItem();
699
700
        // Create a search query for all trashed items
701
        $query = new Query();
702
        $query->limit = 2;
703
704
        // Load all trashed locations
705
        $searchResult = $trashService->findTrashItems($query);
706
707
        $this->assertInstanceOf(
708
            SearchResult::class,
709
            $searchResult
710
        );
711
712
        // 4 trashed locations from the sub tree, but only 2 in results
713
        $this->assertCount(2, $searchResult->items);
714
        $this->assertEquals(4, $searchResult->count);
715
        $this->assertEquals(4, $searchResult->totalCount);
716
    }
717
718
    /**
719
     * Test for the findTrashItems() method.
720
     *
721
     * @see \eZ\Publish\API\Repository\TrashService::findTrashItems()
722
     * @depends \eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
723
     */
724
    public function testFindTrashItemsLimitedAccess()
725
    {
726
        $repository = $this->getRepository();
727
        $trashService = $repository->getTrashService();
728
729
        /* BEGIN: Use Case */
730
        $this->createTrashItem();
731
732
        // Create a search query for all trashed items
733
        $query = new Query();
734
        $query->filter = new Criterion\LogicalAnd(
735
            [
736
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
737
            ]
738
        );
739
740
        // Create a user in the Editor user group.
741
        $user = $this->createUserVersion1();
742
743
        // Set the Editor user as current user, these users have no access to Trash by default.
744
        $repository->getPermissionResolver()->setCurrentUserReference($user);
745
746
        // Load all trashed locations
747
        $searchResult = $trashService->findTrashItems($query);
748
        /* END: Use Case */
749
750
        $this->assertInstanceOf(
751
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\SearchResult',
752
            $searchResult
753
        );
754
755
        // 0 trashed locations found, though 4 exist
756
        $this->assertEquals(0, $searchResult->count);
757
    }
758
759
    /**
760
     * Test for the emptyTrash() method.
761
     *
762
     * @see \eZ\Publish\API\Repository\TrashService::emptyTrash()
763
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
764
     */
765
    public function testEmptyTrash()
766
    {
767
        $repository = $this->getRepository();
768
        $trashService = $repository->getTrashService();
769
        $contentService = $repository->getContentService();
770
771
        /* BEGIN: Use Case */
772
        $trashItem = $this->createTrashItem();
773
774
        // Empty the trash
775
        $trashService->emptyTrash();
776
777
        // Create a search query for all trashed items
778
        $query = new Query();
779
        $query->filter = new Criterion\LogicalAnd(
780
            [
781
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
782
            ]
783
        );
784
        // Load all trashed locations, search result should be empty
785
        $searchResult = $trashService->findTrashItems($query);
786
        /* END: Use Case */
787
788
        $this->assertEquals(0, $searchResult->count);
789
790
        // Try to load content
791
        $this->expectException(NotFoundException::class);
792
        $contentService->loadContent($trashItem->contentId);
793
    }
794
795
    /**
796
     * Test for the emptyTrash() method with user which has subtree limitations.
797
     *
798
     * @see \eZ\Publish\API\Repository\TrashService::emptyTrash()
799
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
800
     */
801
    public function testEmptyTrashForUserWithSubtreeLimitation()
802
    {
803
        $repository = $this->getRepository();
804
        $trashService = $repository->getTrashService();
805
        $contentService = $repository->getContentService();
806
807
        /* BEGIN: Use Case */
808
        $trashItem = $this->createTrashItem();
809
810
        $this->createRoleWithPolicies('roleTrashCleaner', [
811
            ['module' => 'content', 'function' => 'cleantrash'],
812
            ['module' => 'content', 'function' => 'read'],
813
        ]);
814
        $user = $this->createCustomUserWithLogin(
815
            'user',
816
            '[email protected]',
817
            'roleTrashCleaners',
818
            'roleTrashCleaner',
819
            new SubtreeLimitation(['limitationValues' => ['/1/2/']])
820
        );
821
        $repository->getPermissionResolver()->setCurrentUserReference($user);
822
823
        // Empty the trash
824
        $trashService->emptyTrash();
825
826
        // Create a search query for all trashed items
827
        $query = new Query();
828
        $query->filter = new Criterion\LogicalAnd(
829
            [
830
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
831
            ]
832
        );
833
        // Load all trashed locations, search result should be empty
834
        $searchResult = $trashService->findTrashItems($query);
835
        /* END: Use Case */
836
837
        $this->assertEquals(0, $searchResult->totalCount);
838
839
        // Try to load content
840
        $this->expectException(NotFoundException::class);
841
        $contentService->loadContent($trashItem->contentId);
842
    }
843
844
    /**
845
     * Test for the deleteTrashItem() method.
846
     *
847
     * @see \eZ\Publish\API\Repository\TrashService::deleteTrashItem()
848
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
849
     */
850
    public function testDeleteTrashItem()
851
    {
852
        $repository = $this->getRepository();
853
        $trashService = $repository->getTrashService();
854
        $locationService = $repository->getLocationService();
855
        $contentService = $repository->getContentService();
856
857
        $demoDesignLocationId = $this->generateId('location', 56);
858
        /* BEGIN: Use Case */
859
        // $demoDesignLocationId is the ID of the "Demo Design" location in an eZ
860
        // Publish demo installation
861
862
        $trashItem = $this->createTrashItem();
863
864
        // Trash one more location
865
        $trashService->trash(
866
            $locationService->loadLocation($demoDesignLocationId)
867
        );
868
869
        // Empty the trash
870
        $trashService->deleteTrashItem($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 862 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...
871
872
        // Create a search query for all trashed items
873
        $query = new Query();
874
        $query->filter = new Criterion\LogicalAnd(
875
            [
876
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
877
            ]
878
        );
879
880
        // Load all trashed locations, should only contain the Demo Design location
881
        $searchResult = $trashService->findTrashItems($query);
882
        /* END: Use Case */
883
884
        $foundIds = array_map(
885
            function ($trashItem) {
886
                return $trashItem->id;
887
            },
888
            $searchResult->items
889
        );
890
891
        $this->assertEquals(4, $searchResult->count);
892
        $this->assertTrue(
893
            in_array($demoDesignLocationId, $foundIds)
894
        );
895
896
        // Try to load Content
897
        $this->expectException(NotFoundException::class);
898
        $contentService->loadContent($trashItem->contentId);
899
    }
900
901
    /**
902
     * Test deleting a non existing trash item.
903
     *
904
     * @covers \eZ\Publish\API\Repository\TrashService::deleteTrashItem
905
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
906
     */
907
    public function testDeleteThrowsNotFoundExceptionForNonExistingTrashItem()
908
    {
909
        $repository = $this->getRepository();
910
        $trashService = $repository->getTrashService();
911
912
        $trashService->deleteTrashItem($this->getTrashItemDouble(
913
            12364,
914
            12345,
915
            12363
916
        ));
917
    }
918
919
    /**
920
     * Returns an array with the remoteIds of all child locations of the
921
     * <b>Community</b> location. It is stored in a local variable named
922
     * <b>$remoteIds</b>.
923
     *
924
     * @return string[]
925
     */
926
    private function createRemoteIdList()
927
    {
928
        $repository = $this->getRepository();
929
930
        /* BEGIN: Inline */
931
        // remoteId of the "Community" location in an eZ Publish demo installation
932
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
933
934
        // Load the location service
935
        $locationService = $repository->getLocationService();
936
937
        $remoteIds = [];
938
        $children = $locationService->loadLocationChildren($locationService->loadLocationByRemoteId($mediaRemoteId));
939
        foreach ($children->locations as $child) {
940
            $remoteIds[] = $child->remoteId;
941
            foreach ($locationService->loadLocationChildren($child)->locations as $grandChild) {
942
                $remoteIds[] = $grandChild->remoteId;
943
            }
944
        }
945
        /* END: Inline */
946
947
        return $remoteIds;
948
    }
949
950
    /**
951
     * @param Repository $repository
952
     * @param int $parentLocationId
953
     *
954
     * @return \eZ\Publish\API\Repository\Values\Content\Content
955
     */
956 View Code Duplication
    protected function createNewContentInPlaceTrashedOne(Repository $repository, $parentLocationId)
957
    {
958
        $contentService = $repository->getContentService();
959
        $locationService = $repository->getLocationService();
960
        $contentTypeService = $repository->getContentTypeService();
961
962
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
963
        $newContent = $contentService->newContentCreateStruct($contentType, 'eng-US');
964
        $newContent->setField('name', 'Media');
965
966
        $location = $locationService->newLocationCreateStruct($parentLocationId);
967
968
        $draftContent = $contentService->createContent($newContent, [$location]);
969
970
        return $contentService->publishVersion($draftContent->versionInfo);
971
    }
972
973
    /**
974
     * @param URLAliasService $urlAliasService
975
     * @param string $urlPath Url alias path
976
     *
977
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
978
     */
979
    private function assertAliasExists(URLAliasService $urlAliasService, $urlPath)
980
    {
981
        $urlAlias = $urlAliasService->lookup($urlPath);
982
983
        $this->assertInstanceOf('\eZ\Publish\API\Repository\Values\Content\URLAlias', $urlAlias);
984
985
        return $urlAlias;
986
    }
987
988
    /**
989
     * @param URLAliasService $urlAliasService
990
     * @param string $urlPath Url alias path
991
     */
992
    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...
993
    {
994
        try {
995
            $this->getRepository()->getURLAliasService()->lookup($urlPath);
996
            $this->fail(sprintf('Alias [%s] should not exists', $urlPath));
997
        } catch (\eZ\Publish\API\Repository\Exceptions\NotFoundException $e) {
998
            $this->assertTrue(true);
999
        }
1000
    }
1001
1002
    /**
1003
     * Get Test Double for TrashItem for exception testing and similar.
1004
     *
1005
     * @param int $trashId
1006
     * @param int $contentId
1007
     * @param int $parentLocationId
1008
     *
1009
     * @return \eZ\Publish\API\Repository\Values\Content\TrashItem
1010
     */
1011
    private function getTrashItemDouble(int $trashId, int $contentId = 44, int $parentLocationId = 2): APITrashItem
1012
    {
1013
        return new TrashItem([
1014
            'id' => $trashId,
1015
            'parentLocationId' => $parentLocationId,
1016
            'contentInfo' => new ContentInfo(['id' => $contentId]),
1017
        ]);
1018
    }
1019
}
1020