Completed
Push — 7.5 ( 0209fd...886e6c )
by Łukasz
28:50 queued 09:25
created

testDeleteThrowsNotFoundExceptionForNonExistingTrashItem()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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