Completed
Push — 6.12 ( 945ca3...d0ab56 )
by André
58:04 queued 42:29
created

testFindTrashItemsLimitedAccess()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 34
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 15
nc 1
nop 0
dl 0
loc 34
rs 8.8571
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\Location as APILocation;
14
use eZ\Publish\API\Repository\Values\Content\LocationCreateStruct;
15
use eZ\Publish\API\Repository\Values\Content\Query;
16
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
17
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
18
use eZ\Publish\API\Repository\Values\Content\TrashItem as APITrashItem;
19
use eZ\Publish\Core\Repository\Values\Content\TrashItem;
20
use eZ\Publish\Core\Repository\Values\Content\Location;
21
22
/**
23
 * Test case for operations in the TrashService using in memory storage.
24
 *
25
 * @see eZ\Publish\API\Repository\TrashService
26
 * @group integration
27
 * @group trash
28
 */
29
class TrashServiceTest extends BaseTrashServiceTest
30
{
31
    /**
32
     * Test for the trash() method.
33
     *
34
     * @see \eZ\Publish\API\Repository\TrashService::trash()
35
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationByRemoteId
36
     */
37
    public function testTrash()
38
    {
39
        /* BEGIN: Use Case */
40
        $trashItem = $this->createTrashItem();
41
        /* END: Use Case */
42
43
        $this->assertInstanceOf(
44
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\TrashItem',
45
            $trashItem
46
        );
47
    }
48
49
    /**
50
     * Test for the trash() method.
51
     *
52
     * @see \eZ\Publish\API\Repository\TrashService::trash()
53
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
54
     */
55
    public function testTrashSetsExpectedTrashItemProperties()
56
    {
57
        $repository = $this->getRepository();
58
59
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
60
61
        // Load the location that will be trashed
62
        $location = $repository->getLocationService()
63
            ->loadLocationByRemoteId($mediaRemoteId);
64
65
        $expected = array(
66
            'id' => $location->id,
67
            'depth' => $location->depth,
68
            'hidden' => $location->hidden,
69
            'invisible' => $location->invisible,
70
            'parentLocationId' => $location->parentLocationId,
71
            'pathString' => $location->pathString,
72
            'priority' => $location->priority,
73
            'remoteId' => $location->remoteId,
74
            'sortField' => $location->sortField,
75
            'sortOrder' => $location->sortOrder,
76
        );
77
78
        $trashItem = $this->createTrashItem();
79
80
        $this->assertPropertiesCorrect($expected, $trashItem);
81
    }
82
83
    /**
84
     * Test for the trash() method.
85
     *
86
     * @see \eZ\Publish\API\Repository\TrashService::trash()
87
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
88
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
89
     */
90
    public function testTrashRemovesLocationFromMainStorage()
91
    {
92
        $repository = $this->getRepository();
93
94
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
95
96
        /* BEGIN: Use Case */
97
        $this->createTrashItem();
98
99
        // Load the location service
100
        $locationService = $repository->getLocationService();
101
102
        // This call will fail with a "NotFoundException", because the media
103
        // location was marked as trashed in the main storage
104
        $locationService->loadLocationByRemoteId($mediaRemoteId);
105
        /* END: Use Case */
106
    }
107
108
    /**
109
     * Test for the trash() method.
110
     *
111
     * @see \eZ\Publish\API\Repository\TrashService::trash()
112
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
113
     */
114
    public function testTrashRemovesChildLocationsFromMainStorage()
115
    {
116
        $repository = $this->getRepository();
117
118
        /* BEGIN: Use Case */
119
        $remoteIds = $this->createRemoteIdList();
120
121
        $this->createTrashItem();
122
123
        // All invocations to loadLocationByRemoteId() to one of the above
124
        // collected remoteIds will return in an "NotFoundException"
125
        /* END: Use Case */
126
127
        $locationService = $repository->getLocationService();
128
        foreach ($remoteIds as $remoteId) {
129
            try {
130
                $locationService->loadLocationByRemoteId($remoteId);
131
                $this->fail("Location '{$remoteId}' should exist.'");
132
            } catch (NotFoundException $e) {
133
                // echo $e->getFile(), ' +', $e->getLine(), PHP_EOL;
134
            }
135
        }
136
137
        $this->assertGreaterThan(
138
            0,
139
            count($remoteIds),
140
            "There should be at least one 'Community' child location."
141
        );
142
    }
143
144
    /**
145
     * Test for the trash() method.
146
     *
147
     * @see \eZ\Publish\API\Repository\TrashService::trash()
148
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
149
     */
150 View Code Duplication
    public function testTrashDecrementsChildCountOnParentLocation()
151
    {
152
        $repository = $this->getRepository();
153
        $locationService = $repository->getLocationService();
154
155
        $baseLocationId = $this->generateId('location', 1);
156
157
        $location = $locationService->loadLocation($baseLocationId);
158
159
        $childCount = $locationService->getLocationChildCount($location);
160
161
        $this->createTrashItem();
162
163
        $this->refreshSearch($repository);
164
165
        $this->assertEquals(
166
            $childCount - 1,
167
            $locationService->getLocationChildCount($location)
168
        );
169
    }
170
171
    /**
172
     * Test sending a location to trash updates Content mainLocation.
173
     *
174
     * @covers \eZ\Publish\API\Repository\TrashService::trash
175
     */
176
    public function testTrashUpdatesMainLocation()
177
    {
178
        $repository = $this->getRepository();
179
        $contentService = $repository->getContentService();
180
        $locationService = $repository->getLocationService();
181
        $trashService = $repository->getTrashService();
182
183
        $contentInfo = $contentService->loadContentInfo(42);
184
185
        // Create additional location that will become new main location
186
        $location = $locationService->createLocation(
187
            $contentInfo,
188
            new LocationCreateStruct(['parentLocationId' => 2])
189
        );
190
191
        $trashService->trash(
192
            $locationService->loadLocation($contentInfo->mainLocationId)
193
        );
194
195
        self::assertEquals(
196
            $location->id,
197
            $contentService->loadContentInfo(42)->mainLocationId
198
        );
199
    }
200
201
    /**
202
     * Test sending a location to trash.
203
     *
204
     * @covers \eZ\Publish\API\Repository\TrashService::trash
205
     */
206 View Code Duplication
    public function testTrashReturnsNull()
207
    {
208
        $repository = $this->getRepository();
209
        $contentService = $repository->getContentService();
210
        $locationService = $repository->getLocationService();
211
        $trashService = $repository->getTrashService();
212
213
        // Create additional location to trash
214
        $location = $locationService->createLocation(
215
            $contentService->loadContentInfo(42),
216
            new LocationCreateStruct(['parentLocationId' => 2])
217
        );
218
219
        $trashItem = $trashService->trash($location);
220
221
        self::assertNull($trashItem);
222
    }
223
224
    /**
225
     * Test for the loadTrashItem() method.
226
     *
227
     * @covers \eZ\Publish\API\Repository\TrashService::loadTrashItem
228
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
229
     */
230
    public function testLoadTrashItem()
231
    {
232
        $repository = $this->getRepository();
233
        $trashService = $repository->getTrashService();
234
235
        /* BEGIN: Use Case */
236
        $trashItem = $this->createTrashItem();
237
238
        // Reload the trash item
239
        $trashItemReloaded = $trashService->loadTrashItem($trashItem->id);
240
        /* END: Use Case */
241
242
        $this->assertInstanceOf(
243
            APITrashItem::class,
244
            $trashItemReloaded
245
        );
246
247
        $this->assertEquals(
248
            $trashItem->pathString,
0 ignored issues
show
Documentation introduced by
The property $pathString is declared protected in eZ\Publish\API\Repository\Values\Content\Location. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
249
            $trashItemReloaded->pathString
0 ignored issues
show
Documentation introduced by
The property $pathString is declared protected in eZ\Publish\API\Repository\Values\Content\Location. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
250
        );
251
252
        $this->assertEquals(
253
            $trashItem,
254
            $trashItemReloaded
255
        );
256
    }
257
258
    /**
259
     * Test for the loadTrashItem() method.
260
     *
261
     * @see \eZ\Publish\API\Repository\TrashService::loadTrashItem()
262
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
263
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testLoadTrashItem
264
     */
265
    public function testLoadTrashItemThrowsNotFoundException()
266
    {
267
        $repository = $this->getRepository();
268
269
        $nonExistingTrashId = $this->generateId('trash', 2342);
270
        /* BEGIN: Use Case */
271
        $trashService = $repository->getTrashService();
272
273
        // This call will fail with a "NotFoundException", because no trash item
274
        // with the ID 1342 should exist in an eZ Publish demo installation
275
        $trashService->loadTrashItem($nonExistingTrashId);
276
        /* END: Use Case */
277
    }
278
279
    /**
280
     * Test for the recover() method.
281
     *
282
     * @covers \eZ\Publish\API\Repository\TrashService::recover
283
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
284
     */
285
    public function testRecover()
286
    {
287
        $repository = $this->getRepository();
288
        $trashService = $repository->getTrashService();
289
        $locationService = $repository->getLocationService();
290
291
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
292
293
        /* BEGIN: Use Case */
294
        $trashItem = $this->createTrashItem();
295
296
        // Recover the trashed item
297
        $location = $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 294 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...
298
299
        // Load the recovered location
300
        $locationReloaded = $locationService->loadLocationByRemoteId(
301
            $mediaRemoteId
302
        );
303
        /* END: Use Case */
304
305
        $this->assertInstanceOf(
306
            APILocation::class,
307
            $location
308
        );
309
310
        $this->assertEquals(
311
            $location,
312
            $locationReloaded
313
        );
314
315
        try {
316
            $trashService->loadTrashItem($trashItem->id);
317
            $this->fail('Trash item was not removed after being recovered.');
318
        } catch (NotFoundException $e) {
319
            // All well
320
        }
321
    }
322
323
    /**
324
     * Test recovering a non existing trash item results in a NotFoundException.
325
     *
326
     * @covers \eZ\Publish\API\Repository\TrashService::recover
327
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
328
     */
329
    public function testRecoverThrowsNotFoundExceptionForNonExistingTrashItem()
330
    {
331
        $repository = $this->getRepository();
332
        $trashService = $repository->getTrashService();
333
334
        $trashItem = new TrashItem(['id' => 12364, 'parentLocationId' => 12363]);
335
        $trashService->recover($trashItem);
336
    }
337
338
    /**
339
     * Test for the trash() method.
340
     *
341
     * @see \eZ\Publish\API\Repository\TrashService::recover()
342
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
343
     *
344
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
345
     */
346 View Code Duplication
    public function testNotFoundAliasAfterRemoveIt()
347
    {
348
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
349
350
        $repository = $this->getRepository();
351
        $trashService = $repository->getTrashService();
352
        $urlAliasService = $repository->getURLAliasService();
353
        $locationService = $repository->getLocationService();
354
355
        // Double ->lookup() call because there where issue that one call was not enough to spot bug
356
        $urlAliasService->lookup('/Media');
357
        $urlAliasService->lookup('/Media');
358
359
        $mediaLocation = $locationService->loadLocationByRemoteId($mediaRemoteId);
360
        $trashService->trash($mediaLocation);
361
362
        $urlAliasService->lookup('/Media');
363
    }
364
365
    /**
366
     * Test for the recover() method.
367
     *
368
     * @see \eZ\Publish\API\Repository\TrashService::recover()
369
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
370
     */
371
    public function testAliasesForRemovedItems()
372
    {
373
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
374
375
        $repository = $this->getRepository();
376
        $trashService = $repository->getTrashService();
377
        $urlAliasService = $repository->getURLAliasService();
378
        $locationService = $repository->getLocationService();
379
380
        // Double ->lookup() call because there where issue that one call was not enough to spot bug
381
        $urlAliasService->lookup('/Media');
382
        $trashedLocationAlias = $urlAliasService->lookup('/Media');
383
384
        $mediaLocation = $locationService->loadLocationByRemoteId($mediaRemoteId);
385
        $trashItem = $trashService->trash($mediaLocation);
386
        $this->assertAliasNotExists($urlAliasService, '/Media');
387
388
        $this->createNewContentInPlaceTrashedOne($repository, $mediaLocation->parentLocationId);
389
390
        $createdLocationAlias = $urlAliasService->lookup('/Media');
391
392
        $this->assertNotEquals(
393
            $trashedLocationAlias->destination,
394
            $createdLocationAlias->destination,
395
            'Destination for /media url should changed'
396
        );
397
398
        $recoveredLocation = $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $trashService->trash($mediaLocation) on line 385 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...
399
        $recoveredLocationAlias = $urlAliasService->lookup('/Media2');
400
        $recoveredLocationAliasReverse = $urlAliasService->reverseLookup($recoveredLocation);
401
402
        $this->assertEquals($recoveredLocationAlias->destination, $recoveredLocationAliasReverse->destination);
403
404
        $this->assertNotEquals($recoveredLocationAliasReverse->destination, $trashedLocationAlias->destination);
405
        $this->assertNotEquals($recoveredLocationAliasReverse->destination, $createdLocationAlias->destination);
406
    }
407
408
    /**
409
     * Test for the recover() method.
410
     *
411
     * @see \eZ\Publish\API\Repository\TrashService::recover()
412
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
413
     */
414
    public function testRecoverDoesNotRestoreChildLocations()
415
    {
416
        $repository = $this->getRepository();
417
        $trashService = $repository->getTrashService();
418
        $locationService = $repository->getLocationService();
419
420
        $remoteIds = $this->createRemoteIdList();
421
422
        // Unset remote ID of actually restored location
423
        unset($remoteIds[array_search('3f6d92f8044aed134f32153517850f5a', $remoteIds)]);
424
425
        $trashItem = $this->createTrashItem();
426
427
        $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 425 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...
428
429
        $this->assertGreaterThan(
430
            0,
431
            count($remoteIds),
432
            "There should be at least one 'Community' child location."
433
        );
434
435
        // None of the child locations will be available again
436
        foreach ($remoteIds as $remoteId) {
437
            try {
438
                $locationService->loadLocationByRemoteId($remoteId);
439
                $this->fail(
440
                    sprintf(
441
                        'Location with remote ID "%s" unexpectedly restored.',
442
                        $remoteId
443
                    )
444
                );
445
            } catch (NotFoundException $e) {
446
                // All well
447
            }
448
        }
449
450
        try {
451
            $trashService->loadTrashItem($trashItem->id);
452
            $this->fail('Trash item was not removed after being recovered.');
453
        } catch (NotFoundException $e) {
454
            // All well
455
        }
456
    }
457
458
    /**
459
     * Test for the recover() method.
460
     *
461
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem, $newParentLocation)
462
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
463
     *
464
     * @todo Fix naming
465
     */
466
    public function testRecoverWithLocationCreateStructParameter()
467
    {
468
        $repository = $this->getRepository();
469
        $trashService = $repository->getTrashService();
470
        $locationService = $repository->getLocationService();
471
472
        $homeLocationId = $this->generateId('location', 2);
473
        /* BEGIN: Use Case */
474
        // $homeLocationId is the ID of the "Home" location in an eZ Publish
475
        // demo installation
476
477
        $trashItem = $this->createTrashItem();
478
479
        // Get the new parent location
480
        $newParentLocation = $locationService->loadLocation($homeLocationId);
481
482
        // Recover location with new location
483
        $location = $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 477 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...
484
        /* END: Use Case */
485
486
        $this->assertPropertiesCorrect(
487
            array(
488
                'remoteId' => $trashItem->remoteId,
489
                'parentLocationId' => $homeLocationId,
490
                // Not the full sub tree is restored
491
                'depth' => $newParentLocation->depth + 1,
492
                'hidden' => false,
493
                'invisible' => $trashItem->invisible,
0 ignored issues
show
Documentation introduced by
The property $invisible is declared protected in eZ\Publish\API\Repository\Values\Content\Location. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
494
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $location->id) . '/',
495
                'priority' => 0,
496
                'sortField' => APILocation::SORT_FIELD_NAME,
497
                'sortOrder' => APILocation::SORT_ORDER_ASC,
498
            ),
499
            $location
500
        );
501
502
        try {
503
            $trashService->loadTrashItem($trashItem->id);
0 ignored issues
show
Documentation introduced by
The property $id is declared protected in eZ\Publish\API\Repository\Values\Content\Location. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
504
            $this->fail('Trash item was not removed after being recovered.');
505
        } catch (NotFoundException $e) {
506
            // All well
507
        }
508
    }
509
510
    /**
511
     * Test for the recover() method.
512
     *
513
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem)
514
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecover
515
     */
516
    public function testRecoverIncrementsChildCountOnOriginalParent()
517
    {
518
        $repository = $this->getRepository();
519
        $trashService = $repository->getTrashService();
520
        $locationService = $repository->getLocationService();
521
522
        $location = $locationService->loadLocation($this->generateId('location', 1));
523
524
        $trashItem = $this->createTrashItem();
525
526
        $this->refreshSearch($repository);
527
528
        /* BEGIN: Use Case */
529
        $childCount = $locationService->getLocationChildCount($location);
530
531
        // Recover location with new location
532
        $trashService->recover($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 524 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...
533
        /* END: Use Case */
534
535
        $this->refreshSearch($repository);
536
537
        $this->assertEquals(
538
            $childCount + 1,
539
            $locationService->getLocationChildCount($location)
540
        );
541
542
        try {
543
            $trashService->loadTrashItem($trashItem->id);
544
            $this->fail('Trash item was not removed after being recovered.');
545
        } catch (NotFoundException $e) {
546
            // All well
547
        }
548
    }
549
550
    /**
551
     * Test for the recover() method.
552
     *
553
     * @see \eZ\Publish\API\Repository\TrashService::recover($trashItem, $newParentLocation)
554
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testRecoverWithLocationCreateStructParameter
555
     */
556
    public function testRecoverWithLocationCreateStructParameterIncrementsChildCountOnNewParent()
557
    {
558
        $repository = $this->getRepository();
559
        $trashService = $repository->getTrashService();
560
        $locationService = $repository->getLocationService();
561
562
        $homeLocationId = $this->generateId('location', 2);
563
564
        $location = $locationService->loadLocation($homeLocationId);
565
566
        $childCount = $locationService->getLocationChildCount($location);
567
568
        /* BEGIN: Use Case */
569
        // $homeLocationId is the ID of the "Home" location in an eZ Publish
570
        // demo installation
571
572
        $trashItem = $this->createTrashItem();
573
574
        // Get the new parent location
575
        $newParentLocation = $locationService->loadLocation($homeLocationId);
576
577
        // Recover location with new location
578
        $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 572 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...
579
        /* END: Use Case */
580
581
        $this->refreshSearch($repository);
582
583
        $this->assertEquals(
584
            $childCount + 1,
585
            $locationService->getLocationChildCount($location)
586
        );
587
588
        try {
589
            $trashService->loadTrashItem($trashItem->id);
590
            $this->fail('Trash item was not removed after being recovered.');
591
        } catch (NotFoundException $e) {
592
            // All well
593
        }
594
    }
595
596
    /**
597
     * Test recovering a location from trash to non existing location.
598
     *
599
     * @covers \eZ\Publish\API\Repository\TrashService::recover
600
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
601
     */
602 View Code Duplication
    public function testRecoverToNonExistingLocation()
603
    {
604
        $repository = $this->getRepository();
605
        $trashService = $repository->getTrashService();
606
        $locationService = $repository->getLocationService();
607
608
        $location = $locationService->loadLocation(44);
609
        $trashItem = $trashService->trash($location);
610
611
        $newParentLocation = new Location(
612
            array(
613
                'id' => 123456,
614
                'parentLocationId' => 123455,
615
            )
616
        );
617
        $trashService->recover($trashItem, $newParentLocation);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $trashService->trash($location) on line 609 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...
618
    }
619
620
    /**
621
     * Test for the findTrashItems() method.
622
     *
623
     * @see \eZ\Publish\API\Repository\TrashService::findTrashItems()
624
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testTrash
625
     */
626 View Code Duplication
    public function testFindTrashItems()
627
    {
628
        $repository = $this->getRepository();
629
        $trashService = $repository->getTrashService();
630
631
        /* BEGIN: Use Case */
632
        $this->createTrashItem();
633
634
        // Create a search query for all trashed items
635
        $query = new Query();
636
        $query->filter = new Criterion\LogicalAnd(
637
            array(
638
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
639
            )
640
        );
641
642
        // Load all trashed locations
643
        $searchResult = $trashService->findTrashItems($query);
644
        /* END: Use Case */
645
646
        $this->assertInstanceOf(
647
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\SearchResult',
648
            $searchResult
649
        );
650
651
        // 4 trashed locations from the sub tree
652
        $this->assertEquals(4, $searchResult->count);
653
    }
654
655
    /**
656
     * Test for the findTrashItems() method.
657
     *
658
     * @see \eZ\Publish\API\Repository\TrashService::findTrashItems()
659
     * @depends \eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
660
     */
661
    public function testFindTrashItemsLimitedAccess()
662
    {
663
        $repository = $this->getRepository();
664
        $trashService = $repository->getTrashService();
665
666
        /* BEGIN: Use Case */
667
        $this->createTrashItem();
668
669
        // Create a search query for all trashed items
670
        $query = new Query();
671
        $query->filter = new Criterion\LogicalAnd(
672
            array(
673
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
674
            )
675
        );
676
677
        // Create a user in the Editor user group.
678
        $user = $this->createUserVersion1();
679
680
        // Set the Editor user as current user, these users have no access to Trash by default.
681
        $repository->getPermissionResolver()->setCurrentUserReference($user);
682
683
        // Load all trashed locations
684
        $searchResult = $trashService->findTrashItems($query);
685
        /* END: Use Case */
686
687
        $this->assertInstanceOf(
688
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\SearchResult',
689
            $searchResult
690
        );
691
692
        // 0 trashed locations found, though 4 exist
693
        $this->assertEquals(0, $searchResult->count);
694
    }
695
696
    /**
697
     * Test for the emptyTrash() method.
698
     *
699
     * @see \eZ\Publish\API\Repository\TrashService::emptyTrash()
700
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
701
     */
702 View Code Duplication
    public function testEmptyTrash()
703
    {
704
        $repository = $this->getRepository();
705
        $trashService = $repository->getTrashService();
706
707
        /* BEGIN: Use Case */
708
        $this->createTrashItem();
709
710
        // Empty the trash
711
        $trashService->emptyTrash();
712
713
        // Create a search query for all trashed items
714
        $query = new Query();
715
        $query->filter = new Criterion\LogicalAnd(
716
            array(
717
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
718
            )
719
        );
720
721
        // Load all trashed locations, search result should be empty
722
        $searchResult = $trashService->findTrashItems($query);
723
        /* END: Use Case */
724
725
        $this->assertEquals(0, $searchResult->count);
726
    }
727
728
    /**
729
     * Test for the deleteTrashItem() method.
730
     *
731
     * @see \eZ\Publish\API\Repository\TrashService::deleteTrashItem()
732
     * @depends eZ\Publish\API\Repository\Tests\TrashServiceTest::testFindTrashItems
733
     */
734
    public function testDeleteTrashItem()
735
    {
736
        $repository = $this->getRepository();
737
        $trashService = $repository->getTrashService();
738
        $locationService = $repository->getLocationService();
739
740
        $demoDesignLocationId = $this->generateId('location', 56);
741
        /* BEGIN: Use Case */
742
        // $demoDesignLocationId is the ID of the "Demo Design" location in an eZ
743
        // Publish demo installation
744
745
        $trashItem = $this->createTrashItem();
746
747
        // Trash one more location
748
        $trashService->trash(
749
            $locationService->loadLocation($demoDesignLocationId)
750
        );
751
752
        // Empty the trash
753
        $trashService->deleteTrashItem($trashItem);
0 ignored issues
show
Bug introduced by
It seems like $trashItem defined by $this->createTrashItem() on line 745 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...
754
755
        // Create a search query for all trashed items
756
        $query = new Query();
757
        $query->filter = new Criterion\LogicalAnd(
758
            array(
759
                new Criterion\Field('title', Criterion\Operator::LIKE, '*'),
760
            )
761
        );
762
763
        // Load all trashed locations, should only contain the Demo Design location
764
        $searchResult = $trashService->findTrashItems($query);
765
        /* END: Use Case */
766
767
        $foundIds = array_map(
768
            function ($trashItem) {
769
                return $trashItem->id;
770
            },
771
            $searchResult->items
772
        );
773
774
        $this->assertEquals(4, $searchResult->count);
775
        $this->assertTrue(
776
            array_search($demoDesignLocationId, $foundIds) !== false
777
        );
778
    }
779
780
    /**
781
     * Test deleting a non existing trash item.
782
     *
783
     * @covers \eZ\Publish\API\Repository\TrashService::deleteTrashItem
784
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
785
     */
786
    public function testDeleteThrowsNotFoundExceptionForNonExistingTrashItem()
787
    {
788
        $repository = $this->getRepository();
789
        $trashService = $repository->getTrashService();
790
791
        $trashItem = new TrashItem(['id' => 123456]);
792
        $trashService->deleteTrashItem($trashItem);
793
    }
794
795
    /**
796
     * Returns an array with the remoteIds of all child locations of the
797
     * <b>Community</b> location. It is stored in a local variable named
798
     * <b>$remoteIds</b>.
799
     *
800
     * @return string[]
801
     */
802
    private function createRemoteIdList()
803
    {
804
        $repository = $this->getRepository();
805
806
        /* BEGIN: Inline */
807
        // remoteId of the "Community" location in an eZ Publish demo installation
808
        $mediaRemoteId = '75c715a51699d2d309a924eca6a95145';
809
810
        // Load the location service
811
        $locationService = $repository->getLocationService();
812
813
        $remoteIds = array();
814
        $children = $locationService->loadLocationChildren($locationService->loadLocationByRemoteId($mediaRemoteId));
815
        foreach ($children->locations as $child) {
816
            $remoteIds[] = $child->remoteId;
817
            foreach ($locationService->loadLocationChildren($child)->locations as $grandChild) {
818
                $remoteIds[] = $grandChild->remoteId;
819
            }
820
        }
821
        /* END: Inline */
822
823
        return $remoteIds;
824
    }
825
826
    /**
827
     * @param Repository $repository
828
     * @param int $parentLocationId
829
     *
830
     * @return \eZ\Publish\API\Repository\Values\Content\Content
831
     */
832
    protected function createNewContentInPlaceTrashedOne(Repository $repository, $parentLocationId)
833
    {
834
        $contentService = $repository->getContentService();
835
        $locationService = $repository->getLocationService();
836
        $contentTypeService = $repository->getContentTypeService();
837
838
        $contentType = $contentTypeService->loadContentTypeByIdentifier('forum');
839
        $newContent = $contentService->newContentCreateStruct($contentType, 'eng-US');
840
        $newContent->setField('name', 'Media');
841
842
        $location = $locationService->newLocationCreateStruct($parentLocationId);
843
844
        $draftContent = $contentService->createContent($newContent, [$location]);
845
846
        return $contentService->publishVersion($draftContent->versionInfo);
847
    }
848
849
    /**
850
     * @param URLAliasService $urlAliasService
851
     * @param string $urlPath Url alias path
852
     *
853
     * @return \eZ\Publish\API\Repository\Values\Content\URLAlias
854
     */
855
    private function assertAliasExists(URLAliasService $urlAliasService, $urlPath)
856
    {
857
        $urlAlias = $urlAliasService->lookup($urlPath);
858
859
        $this->assertInstanceOf('\eZ\Publish\API\Repository\Values\Content\URLAlias', $urlAlias);
860
861
        return $urlAlias;
862
    }
863
864
    /**
865
     * @param URLAliasService $urlAliasService
866
     * @param string $urlPath Url alias path
867
     */
868
    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...
869
    {
870
        try {
871
            $this->getRepository()->getURLAliasService()->lookup($urlPath);
872
            $this->fail(sprintf('Alias [%s] should not exists', $urlPath));
873
        } catch (\eZ\Publish\API\Repository\Exceptions\NotFoundException $e) {
874
            $this->assertTrue(true);
875
        }
876
    }
877
}
878