Completed
Push — EZP-31681 ( 54659b...e049ce )
by
unknown
18:38 queued 10s
created

LocationServiceTest   F

Complexity

Total Complexity 122

Size/Duplication

Total Lines 3165
Duplicated Lines 12.76 %

Coupling/Cohesion

Components 1
Dependencies 30

Importance

Changes 0
Metric Value
dl 404
loc 3165
rs 0.8
c 0
b 0
f 0
wmc 122
lcom 1
cbo 30

89 Methods

Rating   Name   Duplication   Size   Complexity  
A testNewLocationCreateStruct() 0 21 1
A testNewLocationCreateStructValues() 0 15 1
A testCreateLocation() 0 40 1
A testCreateLocationWithContentTypeSortingOptions() 0 31 1
A testCreateLocationStructValues() 0 24 1
A testCreateLocationThrowsInvalidArgumentExceptionPriorityIsOutOfRange() 29 29 1
A dataProviderForOutOfRangeLocationPriority() 0 4 1
A testCreateLocationInTransactionWithRollback() 0 43 3
A testLoadLocation() 0 20 1
A testLoadLocationRootStructValues() 0 8 1
A testLoadLocationRootStructValuesWithPrioritizedLanguages() 0 16 1
A assertRootLocationStructValues() 0 43 1
A testLoadLocationStructValues() 0 31 1
A testLoadLocationPrioritizedLanguagesFallback() 0 35 1
A testLoadLocationThrowsNotFoundExceptionForNotAvailableContent() 0 13 1
A testLoadLocationThrowsNotFoundException() 0 13 1
A testLoadLocationList() 14 14 1
A testLoadLocationListPrioritizedLanguagesFallback() 0 13 1
A testLoadLocationListPrioritizedLanguagesFallbackAndAlwaysAvailable() 0 16 1
A testLoadLocationListWithRootLocationId() 14 14 1
A testLoadLocationListInCorrectOrder() 0 16 1
A testLoadLocationByRemoteId() 17 17 1
A testLoadLocationByRemoteIdThrowsNotFoundException() 0 13 1
A testLoadLocations() 0 25 2
A testCreateLocationThrowsInvalidArgumentExceptionContentAlreadyBelowParent() 0 25 1
A testCreateLocationThrowsInvalidArgumentExceptionParentIsSubLocationOfContent() 0 25 1
A testCreateLocationThrowsInvalidArgumentExceptionRemoteIdExists() 0 25 1
A testLoadLocationsContent() 0 24 2
A testLoadLocationsLimitedSubtree() 0 38 1
A testLoadLocationsLimitedSubtreeContent() 0 9 1
A testLoadLocationsThrowsBadStateException() 21 21 1
A testLoadLocationsThrowsBadStateExceptionLimitedSubtree() 0 26 1
A testLoadLocationChildren() 0 26 2
A testLoadParentLocationsForDraftContent() 0 30 3
A testLoadParentLocationsForDraftContentThrowsBadStateException() 0 13 1
A testGetLocationChildCount() 0 12 1
A testLoadLocationChildrenData() 0 28 2
A testLoadLocationChildrenWithOffset() 20 20 1
A testLoadLocationChildrenDataWithOffset() 26 26 2
A testLoadLocationChildrenWithOffsetAndLimit() 20 20 1
A testLoadLocationChildrenDataWithOffsetAndLimit() 25 25 2
A testNewLocationUpdateStruct() 25 25 1
A testUpdateLocation() 0 31 1
A testUpdateLocationStructValues() 0 23 1
A testUpdateLocationWithSameRemoteId() 0 28 1
A testUpdateLocationThrowsInvalidArgumentException() 20 20 1
A testUpdateLocationThrowsInvalidArgumentExceptionPriorityIsOutOfRange() 0 20 1
A testUpdateLocationTwice() 0 23 1
A testSwapLocation() 0 52 1
A testSwapLocationForContentWithCustomUrlAliases() 0 33 1
A testSwapLocationForMainAndSecondaryLocation() 0 54 1
A assertContentHasExpectedLocations() 0 35 1
A testSwapLocationDoesNotCorruptSearchResults() 0 39 1
A testSwapLocationForSecondaryLocations() 0 42 1
A testSwapLocationUpdatesMainLocation() 0 31 1
A testBookmarksAreSwappedAfterSwapLocation() 0 29 1
A testHideLocation() 0 36 2
A assertSubtreeProperties() 0 20 4
A testUnhideLocation() 0 37 2
B testUnhideLocationNotUnhidesHiddenSubtree() 0 58 3
B testDeleteLocation() 0 42 6
A testDeleteLocationDecrementsChildCountOnParent() 0 38 1
A testDeleteContentObjectLastLocation() 0 36 1
A testDeleteLocationDeletesRelatedBookmarks() 0 26 2
B testDeleteUnusedLocationWhichPreviousHadContentWithRelativeAlias() 0 64 1
A testCopySubtree() 0 45 1
A testCopySubtreeWithAliases() 0 33 1
A assertDefaultContentStates() 0 19 3
B testCopySubtreeUpdatesSubtreeProperties() 0 59 3
A testCopySubtreeIncrementsChildCountOfNewParent() 0 38 1
A testCopySubtreeThrowsInvalidArgumentException() 27 27 1
A testMoveSubtree() 0 43 1
A testMoveSubtreeThrowsExceptionOnMoveNotIntoContainer() 0 26 1
A testMoveSubtreeThrowsExceptionOnMoveToSame() 22 22 1
A testMoveSubtreeHidden() 0 46 1
A testMoveSubtreeUpdatesSubtreeProperties() 0 54 2
B testMoveSubtreeUpdatesSubtreePropertiesHidden() 0 58 2
A testMoveSubtreeIncrementsChildCountOfNewParent() 51 51 1
A testMoveSubtreeDecrementsChildCountOfOldParent() 51 51 1
A testMoveInvisibleSubtree() 0 31 1
A testMoveSubtreeThrowsInvalidArgumentException() 0 30 1
A testMoveSubtreeUpdatesPathIdentificationString() 0 38 1
A loadSubtreeProperties() 0 12 2
A loadLocationProperties() 0 18 1
A assertGeneratedAliases() 0 7 2
A assertAliasesBeforeCopy() 0 11 3
A publishContentWithParentLocation() 22 22 1
A createForumStruct() 0 14 1
A assertAliasExists() 0 17 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like LocationServiceTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use LocationServiceTest, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
5
 * @license For full copyright and license information view LICENSE file distributed with this source code.
6
 */
7
namespace eZ\Publish\API\Repository\Tests;
8
9
use Exception;
10
use eZ\Publish\API\Repository\Exceptions\BadStateException;
11
use eZ\Publish\API\Repository\Exceptions\InvalidArgumentException;
12
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
13
use eZ\Publish\API\Repository\URLAliasService as URLAliasServiceInterface;
14
use eZ\Publish\API\Repository\Values\Content\Content;
15
use eZ\Publish\API\Repository\Values\Content\ContentCreateStruct;
16
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
17
use eZ\Publish\API\Repository\Values\Content\Location;
18
use eZ\Publish\API\Repository\Values\Content\LocationCreateStruct;
19
use eZ\Publish\API\Repository\Values\Content\LocationList;
20
use eZ\Publish\API\Repository\Values\Content\LocationUpdateStruct;
21
use eZ\Publish\API\Repository\Values\Content\Query;
22
use eZ\Publish\API\Repository\Values\Content\Search\SearchHit;
23
use eZ\Publish\API\Repository\Values\Content\URLAlias;
24
25
/**
26
 * Test case for operations in the LocationService using in memory storage.
27
 *
28
 * @see eZ\Publish\API\Repository\LocationService
29
 * @group location
30
 */
31
class LocationServiceTest extends BaseTest
32
{
33
    /**
34
     * Test for the newLocationCreateStruct() method.
35
     *
36
     * @return \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct
37
     *
38
     * @see \eZ\Publish\API\Repository\LocationService::newLocationCreateStruct()
39
     */
40
    public function testNewLocationCreateStruct()
41
    {
42
        $repository = $this->getRepository();
43
44
        $parentLocationId = $this->generateId('location', 1);
45
        /* BEGIN: Use Case */
46
        // $parentLocationId is the ID of an existing location
47
        $locationService = $repository->getLocationService();
48
49
        $locationCreate = $locationService->newLocationCreateStruct(
50
            $parentLocationId
51
        );
52
        /* END: Use Case */
53
54
        $this->assertInstanceOf(
55
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\LocationCreateStruct',
56
            $locationCreate
57
        );
58
59
        return $locationCreate;
60
    }
61
62
    /**
63
     * Test for the newLocationCreateStruct() method.
64
     *
65
     * @param \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct $locationCreate
66
     *
67
     * @see \eZ\Publish\API\Repository\LocationService::newLocationCreateStruct()
68
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
69
     */
70
    public function testNewLocationCreateStructValues(LocationCreateStruct $locationCreate)
71
    {
72
        $this->assertPropertiesCorrect(
73
            [
74
                'priority' => 0,
75
                'hidden' => false,
76
                // remoteId should be initialized with a default value
77
                //'remoteId' => null,
78
                'sortField' => null,
79
                'sortOrder' => null,
80
                'parentLocationId' => $this->generateId('location', 1),
81
            ],
82
            $locationCreate
83
        );
84
    }
85
86
    /**
87
     * Test for the createLocation() method.
88
     *
89
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
90
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
91
     */
92
    public function testCreateLocation()
93
    {
94
        $repository = $this->getRepository();
95
96
        $contentId = $this->generateId('object', 41);
97
        $parentLocationId = $this->generateId('location', 5);
98
        /* BEGIN: Use Case */
99
        // $contentId is the ID of an existing content object
100
        // $parentLocationId is the ID of an existing location
101
        $contentService = $repository->getContentService();
102
        $locationService = $repository->getLocationService();
103
104
        // ContentInfo for "How to use eZ Publish"
105
        $contentInfo = $contentService->loadContentInfo($contentId);
106
107
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
108
        $locationCreate->priority = 23;
109
        $locationCreate->hidden = true;
110
        $locationCreate->remoteId = 'sindelfingen';
111
        $locationCreate->sortField = Location::SORT_FIELD_NODE_ID;
112
        $locationCreate->sortOrder = Location::SORT_ORDER_DESC;
113
114
        $location = $locationService->createLocation(
115
            $contentInfo,
116
            $locationCreate
117
        );
118
        /* END: Use Case */
119
120
        $this->assertInstanceOf(
121
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
122
            $location
123
        );
124
125
        return [
126
            'locationCreate' => $locationCreate,
127
            'createdLocation' => $location,
128
            'contentInfo' => $contentInfo,
129
            'parentLocation' => $locationService->loadLocation($this->generateId('location', 5)),
130
        ];
131
    }
132
133
    /**
134
     * Test for the createLocation() method with utilizing default ContentType sorting options.
135
     *
136
     * @covers \eZ\Publish\API\Repository\LocationService::createLocation
137
     */
138
    public function testCreateLocationWithContentTypeSortingOptions(): void
139
    {
140
        $repository = $this->getRepository();
141
142
        $contentId = $this->generateId('object', 41);
143
        $parentLocationId = $this->generateId('location', 5);
144
        // $contentId is the ID of an existing content object
145
        // $parentLocationId is the ID of an existing location
146
        $contentService = $repository->getContentService();
147
        $contentTypeService = $repository->getContentTypeService();
148
        $locationService = $repository->getLocationService();
149
150
        // ContentInfo for "How to use eZ Publish"
151
        $contentInfo = $contentService->loadContentInfo($contentId);
152
153
        // ContentType loading
154
        $contentType = $contentTypeService->loadContentType($contentInfo->contentTypeId);
155
156
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
157
        $locationCreate->priority = 23;
158
        $locationCreate->hidden = true;
159
        $locationCreate->remoteId = 'sindelfingen';
160
161
        $location = $locationService->createLocation(
162
            $contentInfo,
163
            $locationCreate
164
        );
165
166
        $this->assertEquals($contentType->defaultSortField, $location->sortField);
167
        $this->assertEquals($contentType->defaultSortOrder, $location->sortOrder);
168
    }
169
170
    /**
171
     * Test for the createLocation() method.
172
     *
173
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
174
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
175
     */
176
    public function testCreateLocationStructValues(array $data)
177
    {
178
        $locationCreate = $data['locationCreate'];
179
        $createdLocation = $data['createdLocation'];
180
        $contentInfo = $data['contentInfo'];
181
182
        $this->assertPropertiesCorrect(
183
            [
184
                'priority' => $locationCreate->priority,
185
                'hidden' => $locationCreate->hidden,
186
                'invisible' => $locationCreate->hidden,
187
                'remoteId' => $locationCreate->remoteId,
188
                'contentInfo' => $contentInfo,
189
                'parentLocationId' => $locationCreate->parentLocationId,
190
                'pathString' => '/1/5/' . $this->parseId('location', $createdLocation->id) . '/',
191
                'depth' => 2,
192
                'sortField' => $locationCreate->sortField,
193
                'sortOrder' => $locationCreate->sortOrder,
194
            ],
195
            $createdLocation
196
        );
197
198
        $this->assertNotNull($createdLocation->id);
199
    }
200
201
    /**
202
     * Test for the createLocation() method.
203
     *
204
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
205
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
206
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
207
     */
208
    public function testCreateLocationThrowsInvalidArgumentExceptionContentAlreadyBelowParent()
209
    {
210
        $repository = $this->getRepository();
211
212
        $contentId = $this->generateId('object', 11);
213
        $parentLocationId = $this->generateId('location', 5);
214
        /* BEGIN: Use Case */
215
        // $contentId is the ID of an existing content object
216
        // $parentLocationId is the ID of an existing location which already
217
        // has the content assigned to one of its descendant locations
218
        $contentService = $repository->getContentService();
219
        $locationService = $repository->getLocationService();
220
221
        // ContentInfo for "How to use eZ Publish"
222
        $contentInfo = $contentService->loadContentInfo($contentId);
223
224
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
225
226
        // Throws exception, since content is already located at "/1/2/107/110/"
227
        $locationService->createLocation(
228
            $contentInfo,
229
            $locationCreate
230
        );
231
        /* END: Use Case */
232
    }
233
234
    /**
235
     * Test for the createLocation() method.
236
     *
237
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
238
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
239
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
240
     */
241
    public function testCreateLocationThrowsInvalidArgumentExceptionParentIsSubLocationOfContent()
242
    {
243
        $repository = $this->getRepository();
244
245
        $contentId = $this->generateId('object', 4);
246
        $parentLocationId = $this->generateId('location', 12);
247
        /* BEGIN: Use Case */
248
        // $contentId is the ID of an existing content object
249
        // $parentLocationId is the ID of an existing location which is below a
250
        // location that is assigned to the content
251
        $contentService = $repository->getContentService();
252
        $locationService = $repository->getLocationService();
253
254
        // ContentInfo for "How to use eZ Publish"
255
        $contentInfo = $contentService->loadContentInfo($contentId);
256
257
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
258
259
        // Throws exception, since content is already located at "/1/2/"
260
        $locationService->createLocation(
261
            $contentInfo,
262
            $locationCreate
263
        );
264
        /* END: Use Case */
265
    }
266
267
    /**
268
     * Test for the createLocation() method.
269
     *
270
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
271
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
272
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
273
     */
274
    public function testCreateLocationThrowsInvalidArgumentExceptionRemoteIdExists()
275
    {
276
        $repository = $this->getRepository();
277
278
        $contentId = $this->generateId('object', 41);
279
        $parentLocationId = $this->generateId('location', 5);
280
        /* BEGIN: Use Case */
281
        // $contentId is the ID of an existing content object
282
        $contentService = $repository->getContentService();
283
        $locationService = $repository->getLocationService();
284
285
        // ContentInfo for "How to use eZ Publish"
286
        $contentInfo = $contentService->loadContentInfo($contentId);
287
288
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
289
        // This remote ID already exists
290
        $locationCreate->remoteId = 'f3e90596361e31d496d4026eb624c983';
291
292
        // Throws exception, since remote ID is already in use
293
        $locationService->createLocation(
294
            $contentInfo,
295
            $locationCreate
296
        );
297
        /* END: Use Case */
298
    }
299
300
    /**
301
     * Test for the createLocation() method.
302
     *
303
     * @covers \eZ\Publish\API\Repository\LocationService::createLocation()
304
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
305
     * @dataProvider dataProviderForOutOfRangeLocationPriority
306
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
307
     */
308 View Code Duplication
    public function testCreateLocationThrowsInvalidArgumentExceptionPriorityIsOutOfRange($priority)
309
    {
310
        $repository = $this->getRepository();
311
312
        $contentId = $this->generateId('object', 41);
313
        $parentLocationId = $this->generateId('location', 5);
314
        /* BEGIN: Use Case */
315
        // $contentId is the ID of an existing content object
316
        // $parentLocationId is the ID of an existing location
317
        $contentService = $repository->getContentService();
318
        $locationService = $repository->getLocationService();
319
320
        // ContentInfo for "How to use eZ Publish"
321
        $contentInfo = $contentService->loadContentInfo($contentId);
322
323
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
324
        $locationCreate->priority = $priority;
325
        $locationCreate->hidden = true;
326
        $locationCreate->remoteId = 'sindelfingen';
327
        $locationCreate->sortField = Location::SORT_FIELD_NODE_ID;
328
        $locationCreate->sortOrder = Location::SORT_ORDER_DESC;
329
330
        // Throws exception, since priority is out of range
331
        $locationService->createLocation(
332
            $contentInfo,
333
            $locationCreate
334
        );
335
        /* END: Use Case */
336
    }
337
338
    public function dataProviderForOutOfRangeLocationPriority()
339
    {
340
        return [[-2147483649], [2147483648]];
341
    }
342
343
    /**
344
     * Test for the createLocation() method.
345
     *
346
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
347
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
348
     */
349
    public function testCreateLocationInTransactionWithRollback()
350
    {
351
        $repository = $this->getRepository();
352
353
        $contentId = $this->generateId('object', 41);
354
        $parentLocationId = $this->generateId('location', 5);
355
        /* BEGIN: Use Case */
356
        // $contentId is the ID of an existing content object
357
        // $parentLocationId is the ID of an existing location
358
        $contentService = $repository->getContentService();
359
        $locationService = $repository->getLocationService();
360
361
        $repository->beginTransaction();
362
363
        try {
364
            // ContentInfo for "How to use eZ Publish"
365
            $contentInfo = $contentService->loadContentInfo($contentId);
366
367
            $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
368
            $locationCreate->remoteId = 'sindelfingen';
369
370
            $createdLocationId = $locationService->createLocation(
371
                $contentInfo,
372
                $locationCreate
373
            )->id;
374
        } catch (Exception $e) {
375
            // Cleanup hanging transaction on error
376
            $repository->rollback();
377
            throw $e;
378
        }
379
380
        $repository->rollback();
381
382
        try {
383
            // Throws exception since creation of location was rolled back
384
            $location = $locationService->loadLocation($createdLocationId);
0 ignored issues
show
Unused Code introduced by
$location is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
385
        } catch (NotFoundException $e) {
386
            return;
387
        }
388
        /* END: Use Case */
389
390
        $this->fail('Objects still exists after rollback.');
391
    }
392
393
    /**
394
     * Test for the loadLocation() method.
395
     *
396
     * @return \eZ\Publish\API\Repository\Values\Content\Location
397
     *
398
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocation
399
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
400
     */
401
    public function testLoadLocation()
402
    {
403
        $repository = $this->getRepository();
404
405
        $locationId = $this->generateId('location', 5);
406
        /* BEGIN: Use Case */
407
        // $locationId is the ID of an existing location
408
        $locationService = $repository->getLocationService();
409
410
        $location = $locationService->loadLocation($locationId);
411
        /* END: Use Case */
412
413
        $this->assertInstanceOf(
414
            Location::class,
415
            $location
416
        );
417
        self::assertEquals(5, $location->id);
418
419
        return $location;
420
    }
421
422
    /**
423
     * Test for the loadLocation() method.
424
     *
425
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
426
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
427
     */
428
    public function testLoadLocationRootStructValues()
429
    {
430
        $repository = $this->getRepository();
431
        $locationService = $repository->getLocationService();
432
        $location = $locationService->loadLocation($this->generateId('location', 1));
433
434
        $this->assertRootLocationStructValues($location);
435
    }
436
437
    public function testLoadLocationRootStructValuesWithPrioritizedLanguages(): void
438
    {
439
        $repository = $this->getRepository();
440
441
        $rootLocation = $repository
442
            ->getLocationService()
443
            ->loadLocation(
444
                $this->generateId('location', 1),
445
                [
446
                    'eng-GB',
447
                    'ger-DE',
448
                ]
449
            );
450
451
        $this->assertRootLocationStructValues($rootLocation);
452
    }
453
454
    private function assertRootLocationStructValues(Location $location): void
455
    {
456
        $legacyDateTime = new \DateTime();
457
        $legacyDateTime->setTimestamp(1030968000);
458
459
        $this->assertInstanceOf(Location::class, $location);
460
        $this->assertPropertiesCorrect(
461
            [
462
                'id' => $this->generateId('location', 1),
463
                'status' => 1,
464
                'priority' => 0,
465
                'hidden' => false,
466
                'invisible' => false,
467
                'remoteId' => '629709ba256fe317c3ddcee35453a96a',
468
                'parentLocationId' => $this->generateId('location', 1),
469
                'pathString' => '/1/',
470
                'depth' => 0,
471
                'sortField' => 1,
472
                'sortOrder' => 1,
473
            ],
474
            $location
475
        );
476
477
        $this->assertInstanceOf(ContentInfo::class, $location->contentInfo);
478
        $this->assertPropertiesCorrect(
479
            [
480
                'id' => $this->generateId('content', 0),
481
                'name' => 'Top Level Nodes',
482
                'sectionId' => 1,
483
                'mainLocationId' => 1,
484
                'contentTypeId' => 1,
485
                'currentVersionNo' => 1,
486
                'published' => 1,
487
                'ownerId' => 14,
488
                'modificationDate' => $legacyDateTime,
489
                'publishedDate' => $legacyDateTime,
490
                'alwaysAvailable' => 1,
491
                'remoteId' => null,
492
                'mainLanguageCode' => 'eng-GB',
493
            ],
494
            $location->contentInfo
495
        );
496
    }
497
498
    /**
499
     * Test for the loadLocation() method.
500
     *
501
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
502
     *
503
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
504
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
505
     */
506
    public function testLoadLocationStructValues(Location $location)
507
    {
508
        $this->assertPropertiesCorrect(
509
            [
510
                'id' => $this->generateId('location', 5),
511
                'priority' => 0,
512
                'hidden' => false,
513
                'invisible' => false,
514
                'remoteId' => '3f6d92f8044aed134f32153517850f5a',
515
                'parentLocationId' => $this->generateId('location', 1),
516
                'pathString' => '/1/5/',
517
                'depth' => 1,
518
                'sortField' => 1,
519
                'sortOrder' => 1,
520
            ],
521
            $location
522
        );
523
524
        $this->assertInstanceOf(
525
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\ContentInfo',
526
            $location->contentInfo
527
        );
528
        $this->assertEquals($this->generateId('object', 4), $location->contentInfo->id);
529
530
        // Check lazy loaded proxy on ->content
531
        $this->assertInstanceOf(
532
            Content::class,
533
            $content = $location->getContent()
534
        );
535
        $this->assertEquals(4, $content->contentInfo->id);
536
    }
537
538
    public function testLoadLocationPrioritizedLanguagesFallback()
539
    {
540
        $repository = $this->getRepository();
541
542
        // Add a language
543
        $this->createLanguage('nor-NO', 'Norsk');
544
545
        $locationService = $repository->getLocationService();
546
        $contentService = $repository->getContentService();
547
        $location = $locationService->loadLocation(5);
548
549
        // Translate "Users"
550
        $draft = $contentService->createContentDraft($location->contentInfo);
551
        $struct = $contentService->newContentUpdateStruct();
552
        $struct->setField('name', 'Brukere', 'nor-NO');
553
        $draft = $contentService->updateContent($draft->getVersionInfo(), $struct);
554
        $contentService->publishVersion($draft->getVersionInfo());
555
556
        // Load with priority language (fallback will be the old one)
557
        $location = $locationService->loadLocation(5, ['nor-NO']);
558
559
        $this->assertInstanceOf(
560
            Location::class,
561
            $location
562
        );
563
        self::assertEquals(5, $location->id);
564
        $this->assertInstanceOf(
565
            Content::class,
566
            $content = $location->getContent()
567
        );
568
        $this->assertEquals(4, $content->contentInfo->id);
569
570
        $this->assertEquals($content->getVersionInfo()->getName(), 'Brukere');
571
        $this->assertEquals($content->getVersionInfo()->getName('eng-US'), 'Users');
572
    }
573
574
    /**
575
     * Test that accessing lazy-loaded Content without a translation in the specific
576
     * not available language throws NotFoundException.
577
     */
578
    public function testLoadLocationThrowsNotFoundExceptionForNotAvailableContent(): void
579
    {
580
        $repository = $this->getRepository();
581
582
        $locationService = $repository->getLocationService();
583
584
        $this->createLanguage('pol-PL', 'Polski');
585
586
        $this->expectException(NotFoundException::class);
587
588
        // Note: relying on existing database fixtures to make test case more readable
589
        $locationService->loadLocation(60, ['pol-PL']);
590
    }
591
592
    /**
593
     * Test for the loadLocation() method.
594
     *
595
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
596
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
597
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
598
     */
599
    public function testLoadLocationThrowsNotFoundException()
600
    {
601
        $repository = $this->getRepository();
602
603
        $nonExistentLocationId = $this->generateId('location', 2342);
604
        /* BEGIN: Use Case */
605
        $locationService = $repository->getLocationService();
606
607
        // Throws exception, if Location with $nonExistentLocationId does not
608
        // exist
609
        $location = $locationService->loadLocation($nonExistentLocationId);
0 ignored issues
show
Unused Code introduced by
$location is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
610
        /* END: Use Case */
611
    }
612
613
    /**
614
     * Test for the loadLocationList() method.
615
     *
616
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
617
     */
618 View Code Duplication
    public function testLoadLocationList(): void
619
    {
620
        $repository = $this->getRepository();
621
622
        // 5 is the ID of an existing location, 442 is a non-existing id
623
        $locationService = $repository->getLocationService();
624
        $locations = $locationService->loadLocationList([5, 442]);
625
626
        self::assertInternalType('iterable', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
627
        self::assertCount(1, $locations);
0 ignored issues
show
Bug introduced by
It seems like $locations defined by $locationService->loadLocationList(array(5, 442)) on line 624 can also be of type array<integer,object<eZ\...lues\Content\Location>>; however, PHPUnit\Framework\Assert::assertCount() does only seem to accept object<Countable>|object...nit\Framework\iterable>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
628
        self::assertEquals([5], array_keys($locations));
629
        self::assertInstanceOf(Location::class, $locations[5]);
630
        self::assertEquals(5, $locations[5]->id);
631
    }
632
633
    /**
634
     * Test for the loadLocationList() method.
635
     *
636
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
637
     * @depends testLoadLocationList
638
     */
639
    public function testLoadLocationListPrioritizedLanguagesFallback(): void
640
    {
641
        $repository = $this->getRepository();
642
643
        $this->createLanguage('pol-PL', 'Polski');
644
645
        // 5 is the ID of an existing location, 442 is a non-existing id
646
        $locationService = $repository->getLocationService();
647
        $locations = $locationService->loadLocationList([5, 442], ['pol-PL'], false);
648
649
        self::assertInternalType('iterable', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
650
        self::assertCount(0, $locations);
0 ignored issues
show
Bug introduced by
It seems like $locations defined by $locationService->loadLo...array('pol-PL'), false) on line 647 can also be of type array<integer,object<eZ\...lues\Content\Location>>; however, PHPUnit\Framework\Assert::assertCount() does only seem to accept object<Countable>|object...nit\Framework\iterable>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
651
    }
652
653
    /**
654
     * Test for the loadLocationList() method.
655
     *
656
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
657
     * @depends testLoadLocationListPrioritizedLanguagesFallback
658
     */
659
    public function testLoadLocationListPrioritizedLanguagesFallbackAndAlwaysAvailable(): void
660
    {
661
        $repository = $this->getRepository();
662
663
        $this->createLanguage('pol-PL', 'Polski');
664
665
        // 5 is the ID of an existing location, 442 is a non-existing id
666
        $locationService = $repository->getLocationService();
667
        $locations = $locationService->loadLocationList([5, 442], ['pol-PL'], true);
668
669
        self::assertInternalType('iterable', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
670
        self::assertCount(1, $locations);
0 ignored issues
show
Bug introduced by
It seems like $locations defined by $locationService->loadLo... array('pol-PL'), true) on line 667 can also be of type array<integer,object<eZ\...lues\Content\Location>>; however, PHPUnit\Framework\Assert::assertCount() does only seem to accept object<Countable>|object...nit\Framework\iterable>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
671
        self::assertEquals([5], array_keys($locations));
672
        self::assertInstanceOf(Location::class, $locations[5]);
673
        self::assertEquals(5, $locations[5]->id);
674
    }
675
676
    /**
677
     * Test for the loadLocationList() method.
678
     *
679
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
680
     */
681 View Code Duplication
    public function testLoadLocationListWithRootLocationId()
682
    {
683
        $repository = $this->getRepository();
684
685
        // 1 is the ID of an root location
686
        $locationService = $repository->getLocationService();
687
        $locations = $locationService->loadLocationList([1]);
688
689
        self::assertInternalType('iterable', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
690
        self::assertCount(1, $locations);
0 ignored issues
show
Bug introduced by
It seems like $locations defined by $locationService->loadLocationList(array(1)) on line 687 can also be of type array<integer,object<eZ\...lues\Content\Location>>; however, PHPUnit\Framework\Assert::assertCount() does only seem to accept object<Countable>|object...nit\Framework\iterable>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
691
        self::assertEquals([1], array_keys($locations));
692
        self::assertInstanceOf(Location::class, $locations[1]);
693
        self::assertEquals(1, $locations[1]->id);
694
    }
695
696
    /**
697
     * Test for the loadLocationList() method.
698
     *
699
     * Ensures the list is returned in the same order as passed IDs array.
700
     *
701
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
702
     */
703
    public function testLoadLocationListInCorrectOrder()
704
    {
705
        $repository = $this->getRepository();
706
        $locationService = $repository->getLocationService();
707
708
        $cachedLocationId = 2;
709
        $locationIdsToLoad = [43, $cachedLocationId, 5];
710
711
        // Call loadLocation to cache it in memory as it might possibly affect list order
712
        $locationService->loadLocation($cachedLocationId);
713
714
        $locations = $locationService->loadLocationList($locationIdsToLoad);
715
        $locationIds = array_column($locations, 'id');
716
717
        self::assertEquals($locationIdsToLoad, $locationIds);
718
    }
719
720
    /**
721
     * Test for the loadLocationByRemoteId() method.
722
     *
723
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationByRemoteId()
724
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
725
     */
726 View Code Duplication
    public function testLoadLocationByRemoteId()
727
    {
728
        $repository = $this->getRepository();
729
730
        /* BEGIN: Use Case */
731
        $locationService = $repository->getLocationService();
732
733
        $location = $locationService->loadLocationByRemoteId(
734
            '3f6d92f8044aed134f32153517850f5a'
735
        );
736
        /* END: Use Case */
737
738
        $this->assertEquals(
739
            $locationService->loadLocation($this->generateId('location', 5)),
740
            $location
741
        );
742
    }
743
744
    /**
745
     * Test for the loadLocationByRemoteId() method.
746
     *
747
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationByRemoteId()
748
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
749
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
750
     */
751
    public function testLoadLocationByRemoteIdThrowsNotFoundException()
752
    {
753
        $repository = $this->getRepository();
754
755
        /* BEGIN: Use Case */
756
        $locationService = $repository->getLocationService();
757
758
        // Throws exception, since Location with remote ID does not exist
759
        $location = $locationService->loadLocationByRemoteId(
0 ignored issues
show
Unused Code introduced by
$location is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
760
            'not-exists'
761
        );
762
        /* END: Use Case */
763
    }
764
765
    /**
766
     * Test for the loadLocations() method.
767
     *
768
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
769
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
770
     */
771
    public function testLoadLocations()
772
    {
773
        $repository = $this->getRepository();
774
775
        $contentId = $this->generateId('object', 4);
776
        /* BEGIN: Use Case */
777
        // $contentId contains the ID of an existing content object
778
        $contentService = $repository->getContentService();
779
        $locationService = $repository->getLocationService();
780
781
        $contentInfo = $contentService->loadContentInfo($contentId);
782
783
        $locations = $locationService->loadLocations($contentInfo);
784
        /* END: Use Case */
785
786
        $this->assertInternalType('array', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
787
        self::assertNotEmpty($locations);
788
789
        foreach ($locations as $location) {
790
            self::assertInstanceOf(Location::class, $location);
791
            self::assertEquals($contentInfo->id, $location->getContentInfo()->id);
792
        }
793
794
        return $locations;
795
    }
796
797
    /**
798
     * Test for the loadLocations() method.
799
     *
800
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
801
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
802
     */
803
    public function testLoadLocationsContent(array $locations)
804
    {
805
        $this->assertEquals(1, count($locations));
806
        foreach ($locations as $loadedLocation) {
807
            self::assertInstanceOf(Location::class, $loadedLocation);
808
        }
809
810
        usort(
811
            $locations,
812
            static function ($a, $b) {
813
                return strcmp($a->id, $b->id);
814
            }
815
        );
816
817
        $this->assertEquals(
818
            [$this->generateId('location', 5)],
819
            array_map(
820
                static function (Location $location) {
821
                    return $location->id;
822
                },
823
                $locations
824
            )
825
        );
826
    }
827
828
    /**
829
     * Test for the loadLocations() method.
830
     *
831
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
832
     *
833
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations($contentInfo, $rootLocation)
834
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
835
     */
836
    public function testLoadLocationsLimitedSubtree()
837
    {
838
        $repository = $this->getRepository();
839
840
        $originalLocationId = $this->generateId('location', 54);
841
        $originalParentLocationId = $this->generateId('location', 48);
842
        $newParentLocationId = $this->generateId('location', 43);
843
        /* BEGIN: Use Case */
844
        // $originalLocationId is the ID of an existing location
845
        // $originalParentLocationId is the ID of the parent location of
846
        //     $originalLocationId
847
        // $newParentLocationId is the ID of an existing location outside the tree
848
        // of $originalLocationId and $originalParentLocationId
849
        $locationService = $repository->getLocationService();
850
851
        // Location at "/1/48/54"
852
        $originalLocation = $locationService->loadLocation($originalLocationId);
853
854
        // Create location under "/1/43/"
855
        $locationCreate = $locationService->newLocationCreateStruct($newParentLocationId);
856
        $locationService->createLocation(
857
            $originalLocation->contentInfo,
858
            $locationCreate
859
        );
860
861
        $findRootLocation = $locationService->loadLocation($originalParentLocationId);
862
863
        // Returns an array with only $originalLocation
864
        $locations = $locationService->loadLocations(
865
            $originalLocation->contentInfo,
866
            $findRootLocation
867
        );
868
        /* END: Use Case */
869
870
        $this->assertInternalType('array', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
871
872
        return $locations;
873
    }
874
875
    /**
876
     * Test for the loadLocations() method.
877
     *
878
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $locations
879
     *
880
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
881
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationsLimitedSubtree
882
     */
883
    public function testLoadLocationsLimitedSubtreeContent(array $locations)
884
    {
885
        $this->assertEquals(1, count($locations));
886
887
        $this->assertEquals(
888
            $this->generateId('location', 54),
889
            reset($locations)->id
890
        );
891
    }
892
893
    /**
894
     * Test for the loadLocations() method.
895
     *
896
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
897
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
898
     * @expectedException \eZ\Publish\API\Repository\Exceptions\BadStateException
899
     */
900 View Code Duplication
    public function testLoadLocationsThrowsBadStateException()
901
    {
902
        $repository = $this->getRepository();
903
904
        /* BEGIN: Use Case */
905
        $contentTypeService = $repository->getContentTypeService();
906
        $contentService = $repository->getContentService();
907
        $locationService = $repository->getLocationService();
908
909
        // Create new content, which is not published
910
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
911
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
912
        $contentCreate->setField('name', 'New Folder');
913
        $content = $contentService->createContent($contentCreate);
914
915
        // Throws Exception, since $content has no published version, yet
916
        $locationService->loadLocations(
917
            $content->contentInfo
918
        );
919
        /* END: Use Case */
920
    }
921
922
    /**
923
     * Test for the loadLocations() method.
924
     *
925
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations($contentInfo, $rootLocation)
926
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
927
     * @expectedException \eZ\Publish\API\Repository\Exceptions\BadStateException
928
     */
929
    public function testLoadLocationsThrowsBadStateExceptionLimitedSubtree()
930
    {
931
        $repository = $this->getRepository();
932
933
        $someLocationId = $this->generateId('location', 2);
934
        /* BEGIN: Use Case */
935
        // $someLocationId is the ID of an existing location
936
        $contentTypeService = $repository->getContentTypeService();
937
        $contentService = $repository->getContentService();
938
        $locationService = $repository->getLocationService();
939
940
        // Create new content, which is not published
941
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
942
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
943
        $contentCreate->setField('name', 'New Folder');
944
        $content = $contentService->createContent($contentCreate);
945
946
        $findRootLocation = $locationService->loadLocation($someLocationId);
947
948
        // Throws Exception, since $content has no published version, yet
949
        $locationService->loadLocations(
950
            $content->contentInfo,
951
            $findRootLocation
952
        );
953
        /* END: Use Case */
954
    }
955
956
    /**
957
     * Test for the loadLocationChildren() method.
958
     *
959
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationChildren
960
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
961
     */
962
    public function testLoadLocationChildren()
963
    {
964
        $repository = $this->getRepository();
965
966
        $locationId = $this->generateId('location', 5);
967
        /* BEGIN: Use Case */
968
        // $locationId is the ID of an existing location
969
        $locationService = $repository->getLocationService();
970
971
        $location = $locationService->loadLocation($locationId);
972
973
        $childLocations = $locationService->loadLocationChildren($location);
974
        /* END: Use Case */
975
976
        $this->assertInstanceOf(LocationList::class, $childLocations);
977
        $this->assertInternalType('array', $childLocations->locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
978
        $this->assertNotEmpty($childLocations->locations);
979
        $this->assertInternalType('int', $childLocations->totalCount);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
980
981
        foreach ($childLocations->locations as $childLocation) {
982
            $this->assertInstanceOf(Location::class, $childLocation);
983
            $this->assertEquals($location->id, $childLocation->parentLocationId);
984
        }
985
986
        return $childLocations;
987
    }
988
989
    /**
990
     * Test loading parent Locations for draft Content.
991
     *
992
     * @covers \eZ\Publish\API\Repository\LocationService::loadParentLocationsForDraftContent
993
     */
994
    public function testLoadParentLocationsForDraftContent()
995
    {
996
        $repository = $this->getRepository();
997
        $locationService = $repository->getLocationService();
998
        $contentService = $repository->getContentService();
999
        $contentTypeService = $repository->getContentTypeService();
1000
1001
        // prepare locations
1002
        $locationCreateStructs = [
1003
            $locationService->newLocationCreateStruct(2),
1004
            $locationService->newLocationCreateStruct(5),
1005
        ];
1006
1007
        // Create new content
1008
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
1009
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
1010
        $contentCreate->setField('name', 'New Folder');
1011
        $contentDraft = $contentService->createContent($contentCreate, $locationCreateStructs);
1012
1013
        // Test loading parent Locations
1014
        $locations = $locationService->loadParentLocationsForDraftContent($contentDraft->versionInfo);
1015
1016
        self::assertCount(2, $locations);
1017
        foreach ($locations as $location) {
1018
            // test it is one of the given parent locations
1019
            self::assertTrue($location->id === 2 || $location->id === 5);
1020
        }
1021
1022
        return $contentDraft;
1023
    }
1024
1025
    /**
1026
     * Test that trying to load parent Locations throws Exception if Content is not a draft.
1027
     *
1028
     * @depends testLoadParentLocationsForDraftContent
1029
     *
1030
     * @param \eZ\Publish\API\Repository\Values\Content\Content $contentDraft
1031
     */
1032
    public function testLoadParentLocationsForDraftContentThrowsBadStateException(Content $contentDraft)
1033
    {
1034
        $this->expectException(BadStateException::class);
1035
        $this->expectExceptionMessageRegExp('/has been already published/');
1036
1037
        $repository = $this->getRepository(false);
1038
        $locationService = $repository->getLocationService();
1039
        $contentService = $repository->getContentService();
1040
1041
        $content = $contentService->publishVersion($contentDraft->versionInfo);
1042
1043
        $locationService->loadParentLocationsForDraftContent($content->versionInfo);
1044
    }
1045
1046
    /**
1047
     * Test for the getLocationChildCount() method.
1048
     *
1049
     * @see \eZ\Publish\API\Repository\LocationService::getLocationChildCount()
1050
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1051
     */
1052
    public function testGetLocationChildCount()
1053
    {
1054
        // $locationId is the ID of an existing location
1055
        $locationService = $this->getRepository()->getLocationService();
1056
1057
        $this->assertSame(
1058
            5,
1059
            $locationService->getLocationChildCount(
1060
                $locationService->loadLocation($this->generateId('location', 5))
1061
            )
1062
        );
1063
    }
1064
1065
    /**
1066
     * Test for the loadLocationChildren() method.
1067
     *
1068
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren()
1069
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
1070
     */
1071
    public function testLoadLocationChildrenData(LocationList $locations)
1072
    {
1073
        $this->assertEquals(5, count($locations->locations));
1074
        $this->assertEquals(5, $locations->totalCount);
1075
1076
        foreach ($locations->locations as $location) {
1077
            $this->assertInstanceOf(
1078
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1079
                $location
1080
            );
1081
        }
1082
1083
        $this->assertEquals(
1084
            [
1085
                $this->generateId('location', 12),
1086
                $this->generateId('location', 13),
1087
                $this->generateId('location', 14),
1088
                $this->generateId('location', 44),
1089
                $this->generateId('location', 61),
1090
            ],
1091
            array_map(
1092
                function (Location $location) {
1093
                    return $location->id;
1094
                },
1095
                $locations->locations
1096
            )
1097
        );
1098
    }
1099
1100
    /**
1101
     * Test for the loadLocationChildren() method.
1102
     *
1103
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
1104
     *
1105
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset)
1106
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
1107
     */
1108 View Code Duplication
    public function testLoadLocationChildrenWithOffset()
1109
    {
1110
        $repository = $this->getRepository();
1111
1112
        $locationId = $this->generateId('location', 5);
1113
        /* BEGIN: Use Case */
1114
        // $locationId is the ID of an existing location
1115
        $locationService = $repository->getLocationService();
1116
1117
        $location = $locationService->loadLocation($locationId);
1118
1119
        $childLocations = $locationService->loadLocationChildren($location, 2);
1120
        /* END: Use Case */
1121
1122
        $this->assertInstanceOf('\\eZ\\Publish\\API\\Repository\\Values\\Content\\LocationList', $childLocations);
1123
        $this->assertInternalType('array', $childLocations->locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1124
        $this->assertInternalType('int', $childLocations->totalCount);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1125
1126
        return $childLocations;
1127
    }
1128
1129
    /**
1130
     * Test for the loadLocationChildren() method.
1131
     *
1132
     * @param \eZ\Publish\API\Repository\Values\Content\LocationList $locations
1133
     *
1134
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset)
1135
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildrenWithOffset
1136
     */
1137 View Code Duplication
    public function testLoadLocationChildrenDataWithOffset(LocationList $locations)
1138
    {
1139
        $this->assertEquals(3, count($locations->locations));
1140
        $this->assertEquals(5, $locations->totalCount);
1141
1142
        foreach ($locations->locations as $location) {
1143
            $this->assertInstanceOf(
1144
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1145
                $location
1146
            );
1147
        }
1148
1149
        $this->assertEquals(
1150
            [
1151
                $this->generateId('location', 14),
1152
                $this->generateId('location', 44),
1153
                $this->generateId('location', 61),
1154
            ],
1155
            array_map(
1156
                function (Location $location) {
1157
                    return $location->id;
1158
                },
1159
                $locations->locations
1160
            )
1161
        );
1162
    }
1163
1164
    /**
1165
     * Test for the loadLocationChildren() method.
1166
     *
1167
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
1168
     *
1169
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset, $limit)
1170
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
1171
     */
1172 View Code Duplication
    public function testLoadLocationChildrenWithOffsetAndLimit()
1173
    {
1174
        $repository = $this->getRepository();
1175
1176
        $locationId = $this->generateId('location', 5);
1177
        /* BEGIN: Use Case */
1178
        // $locationId is the ID of an existing location
1179
        $locationService = $repository->getLocationService();
1180
1181
        $location = $locationService->loadLocation($locationId);
1182
1183
        $childLocations = $locationService->loadLocationChildren($location, 2, 2);
1184
        /* END: Use Case */
1185
1186
        $this->assertInstanceOf('\\eZ\\Publish\\API\\Repository\\Values\\Content\\LocationList', $childLocations);
1187
        $this->assertInternalType('array', $childLocations->locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1188
        $this->assertInternalType('int', $childLocations->totalCount);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1189
1190
        return $childLocations;
1191
    }
1192
1193
    /**
1194
     * Test for the loadLocationChildren() method.
1195
     *
1196
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $locations
1197
     *
1198
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset, $limit)
1199
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildrenWithOffsetAndLimit
1200
     */
1201 View Code Duplication
    public function testLoadLocationChildrenDataWithOffsetAndLimit(LocationList $locations)
1202
    {
1203
        $this->assertEquals(2, count($locations->locations));
1204
        $this->assertEquals(5, $locations->totalCount);
1205
1206
        foreach ($locations->locations as $location) {
1207
            $this->assertInstanceOf(
1208
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1209
                $location
1210
            );
1211
        }
1212
1213
        $this->assertEquals(
1214
            [
1215
                $this->generateId('location', 14),
1216
                $this->generateId('location', 44),
1217
            ],
1218
            array_map(
1219
                function (Location $location) {
1220
                    return $location->id;
1221
                },
1222
                $locations->locations
1223
            )
1224
        );
1225
    }
1226
1227
    /**
1228
     * Test for the newLocationUpdateStruct() method.
1229
     *
1230
     * @covers \eZ\Publish\API\Repository\LocationService::newLocationUpdateStruct
1231
     */
1232 View Code Duplication
    public function testNewLocationUpdateStruct()
1233
    {
1234
        $repository = $this->getRepository();
1235
1236
        /* BEGIN: Use Case */
1237
        $locationService = $repository->getLocationService();
1238
1239
        $updateStruct = $locationService->newLocationUpdateStruct();
1240
        /* END: Use Case */
1241
1242
        $this->assertInstanceOf(
1243
            LocationUpdateStruct::class,
1244
            $updateStruct
1245
        );
1246
1247
        $this->assertPropertiesCorrect(
1248
            [
1249
                'priority' => null,
1250
                'remoteId' => null,
1251
                'sortField' => null,
1252
                'sortOrder' => null,
1253
            ],
1254
            $updateStruct
1255
        );
1256
    }
1257
1258
    /**
1259
     * Test for the updateLocation() method.
1260
     *
1261
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1262
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1263
     */
1264
    public function testUpdateLocation()
1265
    {
1266
        $repository = $this->getRepository();
1267
1268
        $originalLocationId = $this->generateId('location', 5);
1269
        /* BEGIN: Use Case */
1270
        // $originalLocationId is the ID of an existing location
1271
        $locationService = $repository->getLocationService();
1272
1273
        $originalLocation = $locationService->loadLocation($originalLocationId);
1274
1275
        $updateStruct = $locationService->newLocationUpdateStruct();
1276
        $updateStruct->priority = 3;
1277
        $updateStruct->remoteId = 'c7adcbf1e96bc29bca28c2d809d0c7ef69272651';
1278
        $updateStruct->sortField = Location::SORT_FIELD_PRIORITY;
1279
        $updateStruct->sortOrder = Location::SORT_ORDER_DESC;
1280
1281
        $updatedLocation = $locationService->updateLocation($originalLocation, $updateStruct);
1282
        /* END: Use Case */
1283
1284
        $this->assertInstanceOf(
1285
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1286
            $updatedLocation
1287
        );
1288
1289
        return [
1290
            'originalLocation' => $originalLocation,
1291
            'updateStruct' => $updateStruct,
1292
            'updatedLocation' => $updatedLocation,
1293
        ];
1294
    }
1295
1296
    /**
1297
     * Test for the updateLocation() method.
1298
     *
1299
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1300
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testUpdateLocation
1301
     */
1302
    public function testUpdateLocationStructValues(array $data)
1303
    {
1304
        $originalLocation = $data['originalLocation'];
1305
        $updateStruct = $data['updateStruct'];
1306
        $updatedLocation = $data['updatedLocation'];
1307
1308
        $this->assertPropertiesCorrect(
1309
            [
1310
                'id' => $originalLocation->id,
1311
                'priority' => $updateStruct->priority,
1312
                'hidden' => $originalLocation->hidden,
1313
                'invisible' => $originalLocation->invisible,
1314
                'remoteId' => $updateStruct->remoteId,
1315
                'contentInfo' => $originalLocation->contentInfo,
1316
                'parentLocationId' => $originalLocation->parentLocationId,
1317
                'pathString' => $originalLocation->pathString,
1318
                'depth' => $originalLocation->depth,
1319
                'sortField' => $updateStruct->sortField,
1320
                'sortOrder' => $updateStruct->sortOrder,
1321
            ],
1322
            $updatedLocation
1323
        );
1324
    }
1325
1326
    /**
1327
     * Test for the updateLocation() method.
1328
     *
1329
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1330
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1331
     */
1332
    public function testUpdateLocationWithSameRemoteId()
1333
    {
1334
        $repository = $this->getRepository();
1335
1336
        $locationId = $this->generateId('location', 5);
1337
        /* BEGIN: Use Case */
1338
        // $locationId and remote ID is the IDs of the same, existing location
1339
        $locationService = $repository->getLocationService();
1340
1341
        $originalLocation = $locationService->loadLocation($locationId);
1342
1343
        $updateStruct = $locationService->newLocationUpdateStruct();
1344
1345
        // Remote ID of an existing location with the same locationId
1346
        $updateStruct->remoteId = $originalLocation->remoteId;
1347
1348
        // Sets one of the properties to be able to confirm location gets updated, here: priority
1349
        $updateStruct->priority = 2;
1350
1351
        $location = $locationService->updateLocation($originalLocation, $updateStruct);
1352
1353
        // Checks that the location was updated
1354
        $this->assertEquals(2, $location->priority);
1355
1356
        // Checks that remoteId remains the same
1357
        $this->assertEquals($originalLocation->remoteId, $location->remoteId);
1358
        /* END: Use Case */
1359
    }
1360
1361
    /**
1362
     * Test for the updateLocation() method.
1363
     *
1364
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1365
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1366
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1367
     */
1368 View Code Duplication
    public function testUpdateLocationThrowsInvalidArgumentException()
1369
    {
1370
        $repository = $this->getRepository();
1371
1372
        $locationId = $this->generateId('location', 5);
1373
        /* BEGIN: Use Case */
1374
        // $locationId and remoteId is the IDs of an existing, but not the same, location
1375
        $locationService = $repository->getLocationService();
1376
1377
        $originalLocation = $locationService->loadLocation($locationId);
1378
1379
        $updateStruct = $locationService->newLocationUpdateStruct();
1380
1381
        // Remote ID of an existing location with a different locationId
1382
        $updateStruct->remoteId = 'f3e90596361e31d496d4026eb624c983';
1383
1384
        // Throws exception, since remote ID is already taken
1385
        $locationService->updateLocation($originalLocation, $updateStruct);
1386
        /* END: Use Case */
1387
    }
1388
1389
    /**
1390
     * Test for the updateLocation() method.
1391
     *
1392
     * @covers \eZ\Publish\API\Repository\LocationService::updateLocation()
1393
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1394
     * @dataProvider dataProviderForOutOfRangeLocationPriority
1395
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1396
     */
1397
    public function testUpdateLocationThrowsInvalidArgumentExceptionPriorityIsOutOfRange($priority)
1398
    {
1399
        $repository = $this->getRepository();
1400
1401
        $locationId = $this->generateId('location', 5);
1402
        /* BEGIN: Use Case */
1403
        // $locationId and remoteId is the IDs of an existing, but not the same, location
1404
        $locationService = $repository->getLocationService();
1405
1406
        $originalLocation = $locationService->loadLocation($locationId);
1407
1408
        $updateStruct = $locationService->newLocationUpdateStruct();
1409
1410
        // Priority value is out of range
1411
        $updateStruct->priority = $priority;
1412
1413
        // Throws exception, since remote ID is already taken
1414
        $locationService->updateLocation($originalLocation, $updateStruct);
1415
        /* END: Use Case */
1416
    }
1417
1418
    /**
1419
     * Test for the updateLocation() method.
1420
     * Ref EZP-23302: Update Location fails if no change is performed with the update.
1421
     *
1422
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1423
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1424
     */
1425
    public function testUpdateLocationTwice()
1426
    {
1427
        $repository = $this->getRepository();
1428
1429
        $locationId = $this->generateId('location', 5);
1430
        /* BEGIN: Use Case */
1431
        $locationService = $repository->getLocationService();
1432
        $repository->setCurrentUser($repository->getUserService()->loadUser(14));
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::setCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::setCurrentUserReference() instead. Sets the current user to the given $user.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1433
1434
        $originalLocation = $locationService->loadLocation($locationId);
1435
1436
        $updateStruct = $locationService->newLocationUpdateStruct();
1437
        $updateStruct->priority = 42;
1438
1439
        $updatedLocation = $locationService->updateLocation($originalLocation, $updateStruct);
1440
1441
        // Repeated update with the same, unchanged struct
1442
        $secondUpdatedLocation = $locationService->updateLocation($updatedLocation, $updateStruct);
1443
        /* END: Use Case */
1444
1445
        $this->assertEquals($updatedLocation->priority, 42);
1446
        $this->assertEquals($secondUpdatedLocation->priority, 42);
1447
    }
1448
1449
    /**
1450
     * Test for the swapLocation() method.
1451
     *
1452
     * @see \eZ\Publish\API\Repository\LocationService::swapLocation()
1453
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1454
     */
1455
    public function testSwapLocation()
1456
    {
1457
        $repository = $this->getRepository();
1458
        $locationService = $repository->getLocationService();
1459
1460
        $mediaLocationId = $this->generateId('location', 43);
1461
        $demoDesignLocationId = $this->generateId('location', 56);
1462
1463
        $mediaContentInfo = $locationService->loadLocation($mediaLocationId)->getContentInfo();
1464
        $demoDesignContentInfo = $locationService->loadLocation($demoDesignLocationId)->getContentInfo();
1465
1466
        /* BEGIN: Use Case */
1467
        // $mediaLocationId is the ID of the "Media" page location in
1468
        // an eZ Publish demo installation
1469
1470
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
1471
        // Publish demo installation
1472
1473
        // Load the location service
1474
        $locationService = $repository->getLocationService();
1475
1476
        $mediaLocation = $locationService->loadLocation($mediaLocationId);
1477
        $demoDesignLocation = $locationService->loadLocation($demoDesignLocationId);
1478
1479
        // Swaps the content referred to by the locations
1480
        $locationService->swapLocation($mediaLocation, $demoDesignLocation);
1481
        /* END: Use Case */
1482
1483
        // Reload Locations, IDs swapped
1484
        $demoDesignLocation = $locationService->loadLocation($mediaLocationId);
1485
        $mediaLocation = $locationService->loadLocation($demoDesignLocationId);
1486
1487
        // Assert Location's Content is updated
1488
        $this->assertEquals(
1489
            $mediaContentInfo->id,
1490
            $mediaLocation->getContentInfo()->id
1491
        );
1492
        $this->assertEquals(
1493
            $demoDesignContentInfo->id,
1494
            $demoDesignLocation->getContentInfo()->id
1495
        );
1496
1497
        // Assert URL aliases are updated
1498
        $this->assertEquals(
1499
            $mediaLocation->id,
1500
            $repository->getURLAliasService()->lookup('/Design/Media')->destination
1501
        );
1502
        $this->assertEquals(
1503
            $demoDesignLocation->id,
1504
            $repository->getURLAliasService()->lookup('/eZ-Publish-Demo-Design-without-demo-content')->destination
1505
        );
1506
    }
1507
1508
    /**
1509
     * Test for the swapLocation() method with custom aliases.
1510
     *
1511
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1512
     *
1513
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
1514
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
1515
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
1516
     */
1517
    public function testSwapLocationForContentWithCustomUrlAliases(): void
1518
    {
1519
        $repository = $this->getRepository();
1520
        $locationService = $repository->getLocationService();
1521
        $urlAliasService = $repository->getURLAliasService();
1522
        $this->createLanguage('pol-PL', 'Polski');
1523
1524
        $folder1 = $this->createFolder(['eng-GB' => 'Folder1', 'pol-PL' => 'Folder1'], 2);
1525
        $folder2 = $this->createFolder(['eng-GB' => 'Folder2'], 2);
1526
        $location1 = $locationService->loadLocation($folder1->contentInfo->mainLocationId);
1527
        $location2 = $locationService->loadLocation($folder2->contentInfo->mainLocationId);
1528
1529
        $urlAlias = $urlAliasService->createUrlAlias($location1, '/custom-location1', 'eng-GB', false, true);
1530
        $urlAliasService->createUrlAlias($location1, '/custom-location1', 'pol-PL', false, true);
1531
        $urlAliasService->createUrlAlias($location2, '/custom-location2', 'eng-GB', false, true);
1532
        $location1UrlAliases = $urlAliasService->listLocationAliases($location1);
1533
        $location2UrlAliases = $urlAliasService->listLocationAliases($location2);
1534
1535
        $locationService->swapLocation($location1, $location2);
1536
        $location1 = $locationService->loadLocation($location1->contentInfo->mainLocationId);
1537
        $location2 = $locationService->loadLocation($location2->contentInfo->mainLocationId);
1538
1539
        $location1UrlAliasesAfterSwap = $urlAliasService->listLocationAliases($location1);
1540
        $location2UrlAliasesAfterSwap = $urlAliasService->listLocationAliases($location2);
1541
1542
        $keyUrlAlias = array_search($urlAlias->id, array_column($location1UrlAliasesAfterSwap, 'id'));
1543
1544
        self::assertEquals($folder1->id, $location2->contentInfo->id);
1545
        self::assertEquals($folder2->id, $location1->contentInfo->id);
1546
        self::assertNotEquals($location1UrlAliases, $location1UrlAliasesAfterSwap);
1547
        self::assertEquals($location2UrlAliases, $location2UrlAliasesAfterSwap);
1548
        self::assertEquals(['eng-GB'], $location1UrlAliasesAfterSwap[$keyUrlAlias]->languageCodes);
1549
    }
1550
1551
    /**
1552
     * Test swapping secondary Location with main Location.
1553
     *
1554
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1555
     *
1556
     * @see https://jira.ez.no/browse/EZP-28663
1557
     *
1558
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
1559
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
1560
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
1561
     *
1562
     * @return int[]
1563
     */
1564
    public function testSwapLocationForMainAndSecondaryLocation(): array
1565
    {
1566
        $repository = $this->getRepository();
1567
        $locationService = $repository->getLocationService();
1568
        $contentService = $repository->getContentService();
1569
1570
        $folder1 = $this->createFolder(['eng-GB' => 'Folder1'], 2);
1571
        $folder2 = $this->createFolder(['eng-GB' => 'Folder2'], 2);
1572
        $folder3 = $this->createFolder(['eng-GB' => 'Folder3'], 2);
1573
1574
        $primaryLocation = $locationService->loadLocation($folder1->contentInfo->mainLocationId);
1575
        $parentLocation = $locationService->loadLocation($folder2->contentInfo->mainLocationId);
1576
        $secondaryLocation = $locationService->createLocation(
1577
            $folder1->contentInfo,
1578
            $locationService->newLocationCreateStruct($parentLocation->id)
1579
        );
1580
1581
        $targetLocation = $locationService->loadLocation($folder3->contentInfo->mainLocationId);
1582
1583
        // perform sanity checks
1584
        $this->assertContentHasExpectedLocations([$primaryLocation, $secondaryLocation], $folder1);
1585
1586
        // begin use case
1587
        $locationService->swapLocation($secondaryLocation, $targetLocation);
1588
1589
        // test results
1590
        $primaryLocation = $locationService->loadLocation($primaryLocation->id);
1591
        $secondaryLocation = $locationService->loadLocation($secondaryLocation->id);
1592
        $targetLocation = $locationService->loadLocation($targetLocation->id);
1593
1594
        self::assertEquals($folder1->id, $primaryLocation->contentInfo->id);
1595
        self::assertEquals($folder1->id, $targetLocation->contentInfo->id);
1596
        self::assertEquals($folder3->id, $secondaryLocation->contentInfo->id);
1597
1598
        $this->assertContentHasExpectedLocations([$primaryLocation, $targetLocation], $folder1);
1599
1600
        self::assertEquals(
1601
            $folder1,
1602
            $contentService->loadContent($folder1->id)
1603
        );
1604
1605
        self::assertEquals(
1606
            $folder2,
1607
            $contentService->loadContent($folder2->id)
1608
        );
1609
1610
        // only in case of Folder 3, main location id changed due to swap
1611
        self::assertEquals(
1612
            $secondaryLocation->id,
1613
            $contentService->loadContent($folder3->id)->contentInfo->mainLocationId
1614
        );
1615
1616
        return [$folder1, $folder2, $folder3];
1617
    }
1618
1619
    /**
1620
     * Compare Ids of expected and loaded Locations for the given Content.
1621
     *
1622
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $expectedLocations
1623
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1624
     *
1625
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
1626
     */
1627
    private function assertContentHasExpectedLocations(array $expectedLocations, Content $content)
1628
    {
1629
        $repository = $this->getRepository(false);
1630
        $locationService = $repository->getLocationService();
1631
1632
        $expectedLocationIds = array_map(
1633
            function (Location $location) {
1634
                return (int)$location->id;
1635
            },
1636
            $expectedLocations
1637
        );
1638
1639
        $actualLocationsIds = array_map(
1640
            function (Location $location) {
1641
                return $location->id;
1642
            },
1643
            $locationService->loadLocations($content->contentInfo)
1644
        );
1645
        self::assertCount(count($expectedLocations), $actualLocationsIds);
1646
1647
        // perform unordered equality assertion
1648
        self::assertEquals(
1649
            $expectedLocationIds,
1650
            $actualLocationsIds,
1651
            sprintf(
1652
                'Content %d contains Locations %s, but expected: %s',
1653
                $content->id,
1654
                implode(', ', $actualLocationsIds),
1655
                implode(', ', $expectedLocationIds)
1656
            ),
1657
            0.0,
1658
            10,
1659
            true
1660
        );
1661
    }
1662
1663
    /**
1664
     * @depends testSwapLocationForMainAndSecondaryLocation
1665
     *
1666
     * @param \eZ\Publish\API\Repository\Values\Content\Content[] $contentItems Content items created by testSwapLocationForSecondaryLocation
1667
     *
1668
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1669
     */
1670
    public function testSwapLocationDoesNotCorruptSearchResults(array $contentItems)
1671
    {
1672
        $repository = $this->getRepository(false);
1673
        $searchService = $repository->getSearchService();
1674
1675
        $this->refreshSearch($repository);
1676
1677
        $contentIds = array_map(
1678
            function (Content $content) {
1679
                return $content->id;
1680
            },
1681
            $contentItems
1682
        );
1683
1684
        $query = new Query();
1685
        $query->filter = new Query\Criterion\ContentId($contentIds);
1686
1687
        $searchResult = $searchService->findContent($query);
1688
1689
        self::assertEquals(count($contentItems), $searchResult->totalCount);
1690
        self::assertEquals(
1691
            $searchResult->totalCount,
1692
            count($searchResult->searchHits),
1693
            'Total count of search result hits does not match the actual number of found results'
1694
        );
1695
        $foundContentIds = array_map(
1696
            function (SearchHit $searchHit) {
1697
                return $searchHit->valueObject->id;
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read 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.");
        }
    }

}

If the property has read access only, you can use the @property-read 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...
1698
            },
1699
            $searchResult->searchHits
1700
        );
1701
        sort($contentIds);
1702
        sort($foundContentIds);
1703
        self::assertSame(
1704
            $contentIds,
1705
            $foundContentIds,
1706
            'Got different than expected Content item Ids'
1707
        );
1708
    }
1709
1710
    /**
1711
     * Test swapping two secondary (non-main) Locations.
1712
     *
1713
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1714
     *
1715
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
1716
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1717
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
1718
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
1719
     */
1720
    public function testSwapLocationForSecondaryLocations()
1721
    {
1722
        $repository = $this->getRepository();
1723
        $locationService = $repository->getLocationService();
1724
        $contentService = $repository->getContentService();
1725
1726
        $folder1 = $this->createFolder(['eng-GB' => 'Folder1'], 2);
1727
        $folder2 = $this->createFolder(['eng-GB' => 'Folder2'], 2);
1728
        $parentFolder1 = $this->createFolder(['eng-GB' => 'Parent1'], 2);
1729
        $parentFolder2 = $this->createFolder(['eng-GB' => 'Parent2'], 2);
1730
1731
        $parentLocation1 = $locationService->loadLocation($parentFolder1->contentInfo->mainLocationId);
1732
        $parentLocation2 = $locationService->loadLocation($parentFolder2->contentInfo->mainLocationId);
1733
        $secondaryLocation1 = $locationService->createLocation(
1734
            $folder1->contentInfo,
1735
            $locationService->newLocationCreateStruct($parentLocation1->id)
1736
        );
1737
        $secondaryLocation2 = $locationService->createLocation(
1738
            $folder2->contentInfo,
1739
            $locationService->newLocationCreateStruct($parentLocation2->id)
1740
        );
1741
1742
        // begin use case
1743
        $locationService->swapLocation($secondaryLocation1, $secondaryLocation2);
1744
1745
        // test results
1746
        $secondaryLocation1 = $locationService->loadLocation($secondaryLocation1->id);
1747
        $secondaryLocation2 = $locationService->loadLocation($secondaryLocation2->id);
1748
1749
        self::assertEquals($folder2->id, $secondaryLocation1->contentInfo->id);
1750
        self::assertEquals($folder1->id, $secondaryLocation2->contentInfo->id);
1751
1752
        self::assertEquals(
1753
            $folder1,
1754
            $contentService->loadContent($folder1->id)
1755
        );
1756
1757
        self::assertEquals(
1758
            $folder2,
1759
            $contentService->loadContent($folder2->id)
1760
        );
1761
    }
1762
1763
    /**
1764
     * Test swapping Main Location of a Content with another one updates Content item Main Location.
1765
     *
1766
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1767
     */
1768
    public function testSwapLocationUpdatesMainLocation()
1769
    {
1770
        $repository = $this->getRepository();
1771
        $locationService = $repository->getLocationService();
1772
        $contentService = $repository->getContentService();
1773
1774
        $mainLocationParentId = 60;
1775
        $secondaryLocationId = 43;
1776
1777
        $publishedContent = $this->publishContentWithParentLocation(
1778
            'Content for Swap Location Test', $mainLocationParentId
1779
        );
1780
1781
        // sanity check
1782
        $mainLocation = $locationService->loadLocation($publishedContent->contentInfo->mainLocationId);
1783
        self::assertEquals($mainLocationParentId, $mainLocation->parentLocationId);
1784
1785
        // load another pre-existing location
1786
        $secondaryLocation = $locationService->loadLocation($secondaryLocationId);
1787
1788
        // swap the Main Location with a secondary one
1789
        $locationService->swapLocation($mainLocation, $secondaryLocation);
1790
1791
        // check if Main Location has been updated
1792
        $mainLocation = $locationService->loadLocation($secondaryLocation->id);
1793
        self::assertEquals($publishedContent->contentInfo->id, $mainLocation->contentInfo->id);
1794
        self::assertEquals($mainLocation->id, $mainLocation->contentInfo->mainLocationId);
1795
1796
        $reloadedContent = $contentService->loadContentByContentInfo($publishedContent->contentInfo);
1797
        self::assertEquals($mainLocation->id, $reloadedContent->contentInfo->mainLocationId);
1798
    }
1799
1800
    /**
1801
     * Test if location swap affects related bookmarks.
1802
     *
1803
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1804
     */
1805
    public function testBookmarksAreSwappedAfterSwapLocation()
1806
    {
1807
        $repository = $this->getRepository();
1808
1809
        $mediaLocationId = $this->generateId('location', 43);
1810
        $demoDesignLocationId = $this->generateId('location', 56);
1811
1812
        /* BEGIN: Use Case */
1813
        $locationService = $repository->getLocationService();
1814
        $bookmarkService = $repository->getBookmarkService();
1815
1816
        $mediaLocation = $locationService->loadLocation($mediaLocationId);
1817
        $demoDesignLocation = $locationService->loadLocation($demoDesignLocationId);
1818
1819
        // Bookmark locations
1820
        $bookmarkService->createBookmark($mediaLocation);
1821
        $bookmarkService->createBookmark($demoDesignLocation);
1822
1823
        $beforeSwap = $bookmarkService->loadBookmarks();
1824
1825
        // Swaps the content referred to by the locations
1826
        $locationService->swapLocation($mediaLocation, $demoDesignLocation);
1827
1828
        $afterSwap = $bookmarkService->loadBookmarks();
1829
        /* END: Use Case */
1830
1831
        $this->assertEquals($beforeSwap->items[0]->id, $afterSwap->items[1]->id);
1832
        $this->assertEquals($beforeSwap->items[1]->id, $afterSwap->items[0]->id);
1833
    }
1834
1835
    /**
1836
     * Test for the hideLocation() method.
1837
     *
1838
     * @see \eZ\Publish\API\Repository\LocationService::hideLocation()
1839
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1840
     */
1841
    public function testHideLocation()
1842
    {
1843
        $repository = $this->getRepository();
1844
1845
        $locationId = $this->generateId('location', 5);
1846
        /* BEGIN: Use Case */
1847
        // $locationId is the ID of an existing location
1848
        $locationService = $repository->getLocationService();
1849
1850
        $visibleLocation = $locationService->loadLocation($locationId);
1851
1852
        $hiddenLocation = $locationService->hideLocation($visibleLocation);
1853
        /* END: Use Case */
1854
1855
        $this->assertInstanceOf(
1856
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1857
            $hiddenLocation
1858
        );
1859
1860
        $this->assertTrue(
1861
            $hiddenLocation->hidden,
1862
            sprintf(
1863
                'Location with ID "%s" not hidden.',
1864
                $hiddenLocation->id
1865
            )
1866
        );
1867
1868
        $this->refreshSearch($repository);
1869
1870
        foreach ($locationService->loadLocationChildren($hiddenLocation)->locations as $child) {
1871
            $this->assertSubtreeProperties(
1872
                ['invisible' => true],
1873
                $child
1874
            );
1875
        }
1876
    }
1877
1878
    /**
1879
     * Assert that $expectedValues are set in the subtree starting at $location.
1880
     *
1881
     * @param array $expectedValues
1882
     * @param Location $location
1883
     */
1884
    protected function assertSubtreeProperties(array $expectedValues, Location $location, $stopId = null)
1885
    {
1886
        $repository = $this->getRepository();
1887
        $locationService = $repository->getLocationService();
1888
1889
        if ($location->id === $stopId) {
1890
            return;
1891
        }
1892
1893
        foreach ($expectedValues as $propertyName => $propertyValue) {
1894
            $this->assertEquals(
1895
                $propertyValue,
1896
                $location->$propertyName
1897
            );
1898
1899
            foreach ($locationService->loadLocationChildren($location)->locations as $child) {
1900
                $this->assertSubtreeProperties($expectedValues, $child);
1901
            }
1902
        }
1903
    }
1904
1905
    /**
1906
     * Test for the unhideLocation() method.
1907
     *
1908
     * @see \eZ\Publish\API\Repository\LocationService::unhideLocation()
1909
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testHideLocation
1910
     */
1911
    public function testUnhideLocation()
1912
    {
1913
        $repository = $this->getRepository();
1914
1915
        $locationId = $this->generateId('location', 5);
1916
        /* BEGIN: Use Case */
1917
        // $locationId is the ID of an existing location
1918
        $locationService = $repository->getLocationService();
1919
1920
        $visibleLocation = $locationService->loadLocation($locationId);
1921
        $hiddenLocation = $locationService->hideLocation($visibleLocation);
1922
1923
        $unHiddenLocation = $locationService->unhideLocation($hiddenLocation);
1924
        /* END: Use Case */
1925
1926
        $this->assertInstanceOf(
1927
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1928
            $unHiddenLocation
1929
        );
1930
1931
        $this->assertFalse(
1932
            $unHiddenLocation->hidden,
1933
            sprintf(
1934
                'Location with ID "%s" not unhidden.',
1935
                $unHiddenLocation->id
1936
            )
1937
        );
1938
1939
        $this->refreshSearch($repository);
1940
1941
        foreach ($locationService->loadLocationChildren($unHiddenLocation)->locations as $child) {
1942
            $this->assertSubtreeProperties(
1943
                ['invisible' => false],
1944
                $child
1945
            );
1946
        }
1947
    }
1948
1949
    /**
1950
     * Test for the unhideLocation() method.
1951
     *
1952
     * @see \eZ\Publish\API\Repository\LocationService::unhideLocation()
1953
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testUnhideLocation
1954
     */
1955
    public function testUnhideLocationNotUnhidesHiddenSubtree()
1956
    {
1957
        $repository = $this->getRepository();
1958
1959
        $higherLocationId = $this->generateId('location', 5);
1960
        $lowerLocationId = $this->generateId('location', 13);
1961
        /* BEGIN: Use Case */
1962
        // $higherLocationId is the ID of a location
1963
        // $lowerLocationId is the ID of a location below $higherLocationId
1964
        $locationService = $repository->getLocationService();
1965
1966
        $higherLocation = $locationService->loadLocation($higherLocationId);
1967
        $hiddenHigherLocation = $locationService->hideLocation($higherLocation);
1968
1969
        $lowerLocation = $locationService->loadLocation($lowerLocationId);
1970
        $hiddenLowerLocation = $locationService->hideLocation($lowerLocation);
0 ignored issues
show
Unused Code introduced by
$hiddenLowerLocation is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1971
1972
        $unHiddenHigherLocation = $locationService->unhideLocation($hiddenHigherLocation);
1973
        /* END: Use Case */
1974
1975
        $this->assertInstanceOf(
1976
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1977
            $unHiddenHigherLocation
1978
        );
1979
1980
        $this->assertFalse(
1981
            $unHiddenHigherLocation->hidden,
1982
            sprintf(
1983
                'Location with ID "%s" not unhidden.',
1984
                $unHiddenHigherLocation->id
1985
            )
1986
        );
1987
1988
        $this->refreshSearch($repository);
1989
1990
        foreach ($locationService->loadLocationChildren($unHiddenHigherLocation)->locations as $child) {
1991
            $this->assertSubtreeProperties(
1992
                ['invisible' => false],
1993
                $child,
1994
                $this->generateId('location', 13)
1995
            );
1996
        }
1997
1998
        $stillHiddenLocation = $locationService->loadLocation($this->generateId('location', 13));
1999
        $this->assertTrue(
2000
            $stillHiddenLocation->hidden,
2001
            sprintf(
2002
                'Hidden sub-location with ID %s accidentally unhidden.',
2003
                $stillHiddenLocation->id
2004
            )
2005
        );
2006
        foreach ($locationService->loadLocationChildren($stillHiddenLocation)->locations as $child) {
2007
            $this->assertSubtreeProperties(
2008
                ['invisible' => true],
2009
                $child
2010
            );
2011
        }
2012
    }
2013
2014
    /**
2015
     * Test for the deleteLocation() method.
2016
     *
2017
     * @see \eZ\Publish\API\Repository\LocationService::deleteLocation()
2018
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2019
     */
2020
    public function testDeleteLocation()
2021
    {
2022
        $repository = $this->getRepository();
2023
2024
        $mediaLocationId = $this->generateId('location', 43);
2025
        /* BEGIN: Use Case */
2026
        // $mediaLocationId is the ID of the location of the
2027
        // "Media" location in an eZ Publish demo installation
2028
        $locationService = $repository->getLocationService();
2029
2030
        $location = $locationService->loadLocation($mediaLocationId);
2031
2032
        $locationService->deleteLocation($location);
2033
        /* END: Use Case */
2034
2035
        try {
2036
            $locationService->loadLocation($mediaLocationId);
2037
            $this->fail("Location $mediaLocationId not deleted.");
2038
        } catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
2039
        }
2040
2041
        // The following IDs are IDs of child locations of $mediaLocationId location
2042
        // ( Media/Images, Media/Files, Media/Multimedia respectively )
2043
        foreach ([51, 52, 53] as $childLocationId) {
2044
            try {
2045
                $locationService->loadLocation($this->generateId('location', $childLocationId));
2046
                $this->fail("Location $childLocationId not deleted.");
2047
            } catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
2048
            }
2049
        }
2050
2051
        // The following IDs are IDs of content below $mediaLocationId location
2052
        // ( Media/Images, Media/Files, Media/Multimedia respectively )
2053
        $contentService = $this->getRepository()->getContentService();
2054
        foreach ([49, 50, 51] as $childContentId) {
2055
            try {
2056
                $contentService->loadContentInfo($this->generateId('object', $childContentId));
2057
                $this->fail("Content $childContentId not deleted.");
2058
            } catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
2059
            }
2060
        }
2061
    }
2062
2063
    /**
2064
     * Test for the deleteLocation() method.
2065
     *
2066
     * @see \eZ\Publish\API\Repository\LocationService::deleteLocation()
2067
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testDeleteLocation
2068
     */
2069
    public function testDeleteLocationDecrementsChildCountOnParent()
2070
    {
2071
        $repository = $this->getRepository();
2072
2073
        $mediaLocationId = $this->generateId('location', 43);
2074
        /* BEGIN: Use Case */
2075
        // $mediaLocationId is the ID of the location of the
2076
        // "Media" location in an eZ Publish demo installation
2077
2078
        $locationService = $repository->getLocationService();
2079
2080
        // Load the current the user group location
2081
        $location = $locationService->loadLocation($mediaLocationId);
2082
2083
        // Load the parent location
2084
        $parentLocation = $locationService->loadLocation(
2085
            $location->parentLocationId
2086
        );
2087
2088
        // Get child count
2089
        $childCountBefore = $locationService->getLocationChildCount($parentLocation);
2090
2091
        // Delete the user group location
2092
        $locationService->deleteLocation($location);
2093
2094
        $this->refreshSearch($repository);
2095
2096
        // Reload parent location
2097
        $parentLocation = $locationService->loadLocation(
2098
            $location->parentLocationId
2099
        );
2100
2101
        // This will be $childCountBefore - 1
2102
        $childCountAfter = $locationService->getLocationChildCount($parentLocation);
2103
        /* END: Use Case */
2104
2105
        $this->assertEquals($childCountBefore - 1, $childCountAfter);
2106
    }
2107
2108
    /**
2109
     * Test for the deleteLocation() method.
2110
     *
2111
     * Related issue: EZP-21904
2112
     *
2113
     * @see \eZ\Publish\API\Repository\LocationService::deleteLocation()
2114
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
2115
     */
2116
    public function testDeleteContentObjectLastLocation()
2117
    {
2118
        $repository = $this->getRepository();
2119
2120
        /* BEGIN: Use case */
2121
        $contentService = $repository->getContentService();
2122
        $locationService = $repository->getLocationService();
2123
        $contentTypeService = $repository->getContentTypeService();
2124
        $urlAliasService = $repository->getURLAliasService();
2125
2126
        // prepare Content object
2127
        $createStruct = $contentService->newContentCreateStruct(
2128
            $contentTypeService->loadContentTypeByIdentifier('folder'),
2129
            'eng-GB'
2130
        );
2131
        $createStruct->setField('name', 'Test folder');
2132
2133
        // creata Content object
2134
        $content = $contentService->publishVersion(
2135
            $contentService->createContent(
2136
                $createStruct,
2137
                [$locationService->newLocationCreateStruct(2)]
2138
            )->versionInfo
2139
        );
2140
2141
        // delete location
2142
        $locationService->deleteLocation(
2143
            $locationService->loadLocation(
2144
                $urlAliasService->lookup('/Test-folder')->destination
2145
            )
2146
        );
2147
2148
        // this should throw a not found exception
2149
        $contentService->loadContent($content->versionInfo->contentInfo->id);
2150
        /* END: Use case*/
2151
    }
2152
2153
    /**
2154
     * Test for the deleteLocation() method.
2155
     *
2156
     * @covers  \eZ\Publish\API\Repository\LocationService::deleteLocation()
2157
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testDeleteLocation
2158
     */
2159
    public function testDeleteLocationDeletesRelatedBookmarks()
2160
    {
2161
        $repository = $this->getRepository();
2162
2163
        $parentLocationId = $this->generateId('location', 43);
2164
        $childLocationId = $this->generateId('location', 53);
2165
2166
        /* BEGIN: Use Case */
2167
        $locationService = $repository->getLocationService();
2168
        $bookmarkService = $repository->getBookmarkService();
2169
2170
        // Load location
2171
        $childLocation = $locationService->loadLocation($childLocationId);
2172
        // Add location to bookmarks
2173
        $bookmarkService->createBookmark($childLocation);
2174
        // Load parent location
2175
        $parentLocation = $locationService->loadLocation($parentLocationId);
2176
        // Delete parent location
2177
        $locationService->deleteLocation($parentLocation);
2178
        /* END: Use Case */
2179
2180
        // Location isn't bookmarked anymore
2181
        foreach ($bookmarkService->loadBookmarks(0, 9999) as $bookmarkedLocation) {
2182
            $this->assertNotEquals($childLocation->id, $bookmarkedLocation->id);
2183
        }
2184
    }
2185
2186
    /**
2187
     * @covers \eZ\Publish\API\Repository\LocationService::deleteLocation
2188
     */
2189
    public function testDeleteUnusedLocationWhichPreviousHadContentWithRelativeAlias(): void
2190
    {
2191
        $repository = $this->getRepository(false);
2192
2193
        $contentService = $repository->getContentService();
2194
        $locationService = $repository->getLocationService();
2195
        $urlAliasService = $repository->getURLAliasService();
2196
2197
        $originalFolder = $this->createFolder(['eng-GB' => 'Original folder'], 2);
2198
        $newFolder = $this->createFolder(['eng-GB' => 'New folder'], 2);
2199
        $originalFolderLocationId = $originalFolder->contentInfo->mainLocationId;
2200
2201
        $forum = $contentService->publishVersion(
2202
            $contentService->createContent(
2203
                $this->createForumStruct('Some forum'),
2204
                [
2205
                    $locationService->newLocationCreateStruct($originalFolderLocationId),
2206
                ]
2207
            )->versionInfo
2208
        );
2209
2210
        $forumMainLocation = $locationService->loadLocation(
2211
            $forum->contentInfo->mainLocationId
2212
        );
2213
2214
        $customRelativeAliasPath = '/Original-folder/some-forum-alias';
2215
2216
        $urlAliasService->createUrlAlias(
2217
            $forumMainLocation,
2218
            $customRelativeAliasPath,
2219
            'eng-GB',
2220
            true,
2221
            true
2222
        );
2223
2224
        $locationService->moveSubtree(
2225
            $forumMainLocation,
2226
            $locationService->loadLocation(
2227
                $newFolder->contentInfo->mainLocationId
2228
            )
2229
        );
2230
2231
        $this->assertAliasExists(
2232
            $customRelativeAliasPath,
2233
            $forumMainLocation,
2234
            $urlAliasService
2235
        );
2236
2237
        $urlAliasService->lookup($customRelativeAliasPath);
2238
2239
        $locationService->deleteLocation(
2240
            $locationService->loadLocation(
2241
                $originalFolder->contentInfo->mainLocationId
2242
            )
2243
        );
2244
2245
        $this->assertAliasExists(
2246
            $customRelativeAliasPath,
2247
            $forumMainLocation,
2248
            $urlAliasService
2249
        );
2250
2251
        $urlAliasService->lookup($customRelativeAliasPath);
2252
    }
2253
2254
    /**
2255
     * Test for the copySubtree() method.
2256
     *
2257
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2258
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2259
     */
2260
    public function testCopySubtree()
2261
    {
2262
        $repository = $this->getRepository();
2263
2264
        $mediaLocationId = $this->generateId('location', 43);
2265
        $demoDesignLocationId = $this->generateId('location', 56);
2266
        /* BEGIN: Use Case */
2267
        // $mediaLocationId is the ID of the "Media" page location in
2268
        // an eZ Publish demo installation
2269
2270
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2271
        // Publish demo installation
2272
2273
        // Load the location service
2274
        $locationService = $repository->getLocationService();
2275
2276
        // Load location to copy
2277
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2278
2279
        // Load new parent location
2280
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2281
2282
        // Copy location "Media" to "Demo Design"
2283
        $copiedLocation = $locationService->copySubtree(
2284
            $locationToCopy,
2285
            $newParentLocation
2286
        );
2287
        /* END: Use Case */
2288
2289
        $this->assertInstanceOf(
2290
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
2291
            $copiedLocation
2292
        );
2293
2294
        $this->assertPropertiesCorrect(
2295
            [
2296
                'depth' => $newParentLocation->depth + 1,
2297
                'parentLocationId' => $newParentLocation->id,
2298
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $copiedLocation->id) . '/',
2299
            ],
2300
            $copiedLocation
2301
        );
2302
2303
        $this->assertDefaultContentStates($copiedLocation->contentInfo);
2304
    }
2305
2306
    /**
2307
     * Test for the copySubtree() method.
2308
     *
2309
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2310
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2311
     */
2312
    public function testCopySubtreeWithAliases()
2313
    {
2314
        $repository = $this->getRepository();
2315
        $urlAliasService = $repository->getURLAliasService();
2316
2317
        // $mediaLocationId is the ID of the "Media" page location in
2318
        // an eZ Publish demo installation
2319
2320
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2321
        // Publish demo installation
2322
        $mediaLocationId = $this->generateId('location', 43);
2323
        $demoDesignLocationId = $this->generateId('location', 56);
2324
2325
        $locationService = $repository->getLocationService();
2326
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2327
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2328
2329
        $expectedSubItemAliases = [
2330
            '/Design/Plain-site/Media/Multimedia',
2331
            '/Design/Plain-site/Media/Images',
2332
            '/Design/Plain-site/Media/Files',
2333
        ];
2334
2335
        $this->assertAliasesBeforeCopy($urlAliasService, $expectedSubItemAliases);
2336
2337
        // Copy location "Media" to "Design"
2338
        $locationService->copySubtree(
2339
            $locationToCopy,
2340
            $newParentLocation
2341
        );
2342
2343
        $this->assertGeneratedAliases($urlAliasService, $expectedSubItemAliases);
2344
    }
2345
2346
    /**
2347
     * Asserts that given Content has default ContentStates.
2348
     *
2349
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
2350
     */
2351
    private function assertDefaultContentStates(ContentInfo $contentInfo)
2352
    {
2353
        $repository = $this->getRepository();
2354
        $objectStateService = $repository->getObjectStateService();
2355
2356
        $objectStateGroups = $objectStateService->loadObjectStateGroups();
2357
2358
        foreach ($objectStateGroups as $objectStateGroup) {
2359
            $contentState = $objectStateService->getContentState($contentInfo, $objectStateGroup);
2360
            foreach ($objectStateService->loadObjectStates($objectStateGroup) as $objectState) {
2361
                // Only check the first object state which is the default one.
2362
                $this->assertEquals(
2363
                    $objectState,
2364
                    $contentState
2365
                );
2366
                break;
2367
            }
2368
        }
2369
    }
2370
2371
    /**
2372
     * Test for the copySubtree() method.
2373
     *
2374
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2375
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCopySubtree
2376
     */
2377
    public function testCopySubtreeUpdatesSubtreeProperties()
2378
    {
2379
        $repository = $this->getRepository();
2380
        $locationService = $repository->getLocationService();
2381
2382
        $locationToCopy = $locationService->loadLocation($this->generateId('location', 43));
2383
2384
        // Load Subtree properties before copy
2385
        $expected = $this->loadSubtreeProperties($locationToCopy);
2386
2387
        $mediaLocationId = $this->generateId('location', 43);
2388
        $demoDesignLocationId = $this->generateId('location', 56);
2389
        /* BEGIN: Use Case */
2390
        // $mediaLocationId is the ID of the "Media" page location in
2391
        // an eZ Publish demo installation
2392
2393
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2394
        // Publish demo installation
2395
2396
        // Load the location service
2397
        $locationService = $repository->getLocationService();
2398
2399
        // Load location to copy
2400
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2401
2402
        // Load new parent location
2403
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2404
2405
        // Copy location "Media" to "Demo Design"
2406
        $copiedLocation = $locationService->copySubtree(
2407
            $locationToCopy,
2408
            $newParentLocation
2409
        );
2410
        /* END: Use Case */
2411
2412
        $beforeIds = [];
2413
        foreach ($expected as $properties) {
2414
            $beforeIds[] = $properties['id'];
2415
        }
2416
2417
        $this->refreshSearch($repository);
2418
2419
        // Load Subtree properties after copy
2420
        $actual = $this->loadSubtreeProperties($copiedLocation);
2421
2422
        $this->assertEquals(count($expected), count($actual));
2423
2424
        foreach ($actual as $properties) {
2425
            $this->assertNotContains($properties['id'], $beforeIds);
2426
            $this->assertStringStartsWith(
2427
                $newParentLocation->pathString . $this->parseId('location', $copiedLocation->id) . '/',
2428
                $properties['pathString']
2429
            );
2430
            $this->assertStringEndsWith(
2431
                '/' . $this->parseId('location', $properties['id']) . '/',
2432
                $properties['pathString']
2433
            );
2434
        }
2435
    }
2436
2437
    /**
2438
     * Test for the copySubtree() method.
2439
     *
2440
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2441
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCopySubtree
2442
     */
2443
    public function testCopySubtreeIncrementsChildCountOfNewParent()
2444
    {
2445
        $repository = $this->getRepository();
2446
        $locationService = $repository->getLocationService();
2447
2448
        $childCountBefore = $locationService->getLocationChildCount($locationService->loadLocation(56));
2449
2450
        $mediaLocationId = $this->generateId('location', 43);
2451
        $demoDesignLocationId = $this->generateId('location', 56);
2452
        /* BEGIN: Use Case */
2453
        // $mediaLocationId is the ID of the "Media" page location in
2454
        // an eZ Publish demo installation
2455
2456
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2457
        // Publish demo installation
2458
2459
        // Load the location service
2460
        $locationService = $repository->getLocationService();
2461
2462
        // Load location to copy
2463
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2464
2465
        // Load new parent location
2466
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2467
2468
        // Copy location "Media" to "Demo Design"
2469
        $copiedLocation = $locationService->copySubtree(
0 ignored issues
show
Unused Code introduced by
$copiedLocation is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2470
            $locationToCopy,
2471
            $newParentLocation
2472
        );
2473
        /* END: Use Case */
2474
2475
        $this->refreshSearch($repository);
2476
2477
        $childCountAfter = $locationService->getLocationChildCount($locationService->loadLocation($demoDesignLocationId));
2478
2479
        $this->assertEquals($childCountBefore + 1, $childCountAfter);
2480
    }
2481
2482
    /**
2483
     * Test for the copySubtree() method.
2484
     *
2485
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2486
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
2487
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCopySubtree
2488
     */
2489 View Code Duplication
    public function testCopySubtreeThrowsInvalidArgumentException()
2490
    {
2491
        $repository = $this->getRepository();
2492
2493
        $communityLocationId = $this->generateId('location', 5);
2494
        /* BEGIN: Use Case */
2495
        // $communityLocationId is the ID of the "Community" page location in
2496
        // an eZ Publish demo installation
2497
2498
        // Load the location service
2499
        $locationService = $repository->getLocationService();
2500
2501
        // Load location to copy
2502
        $locationToCopy = $locationService->loadLocation($communityLocationId);
2503
2504
        // Use a child as new parent
2505
        $childLocations = $locationService->loadLocationChildren($locationToCopy)->locations;
2506
        $newParentLocation = end($childLocations);
2507
2508
        // This call will fail with an "InvalidArgumentException", because the
2509
        // new parent is a child location of the subtree to copy.
2510
        $locationService->copySubtree(
2511
            $locationToCopy,
2512
            $newParentLocation
0 ignored issues
show
Security Bug introduced by
It seems like $newParentLocation defined by end($childLocations) on line 2506 can also be of type false; however, eZ\Publish\API\Repositor...nService::copySubtree() does only seem to accept object<eZ\Publish\API\Re...alues\Content\Location>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
2513
        );
2514
        /* END: Use Case */
2515
    }
2516
2517
    /**
2518
     * Test for the moveSubtree() method.
2519
     *
2520
     * @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
2521
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2522
     */
2523
    public function testMoveSubtree(): void
2524
    {
2525
        $repository = $this->getRepository();
2526
2527
        $mediaLocationId = $this->generateId('location', 43);
2528
        $demoDesignLocationId = $this->generateId('location', 56);
2529
        /* BEGIN: Use Case */
2530
        // $mediaLocationId is the ID of the "Media" page location in
2531
        // an eZ Publish demo installation
2532
2533
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2534
        // Publish demo installation
2535
2536
        // Load the location service
2537
        $locationService = $repository->getLocationService();
2538
2539
        // Load location to move
2540
        $locationToMove = $locationService->loadLocation($demoDesignLocationId);
2541
2542
        // Load new parent location
2543
        $newParentLocation = $locationService->loadLocation($mediaLocationId);
2544
2545
        // Move location from "Home" to "Media"
2546
        $locationService->moveSubtree(
2547
            $locationToMove,
2548
            $newParentLocation
2549
        );
2550
2551
        // Load moved location
2552
        $movedLocation = $locationService->loadLocation($demoDesignLocationId);
2553
        /* END: Use Case */
2554
2555
        $this->assertPropertiesCorrect(
2556
            [
2557
                'hidden' => false,
2558
                'invisible' => false,
2559
                'depth' => $newParentLocation->depth + 1,
2560
                'parentLocationId' => $newParentLocation->id,
2561
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $movedLocation->id) . '/',
2562
            ],
2563
            $movedLocation
2564
        );
2565
    }
2566
2567
    /**
2568
     * Test for the moveSubtree() method.
2569
     *
2570
     * @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
2571
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2572
     */
2573
    public function testMoveSubtreeThrowsExceptionOnMoveNotIntoContainer(): void
2574
    {
2575
        $repository = $this->getRepository();
2576
2577
        $mediaLocationId = $this->generateId('location', 43);
2578
        $demoDesignLocationId = $this->generateId('location', 56);
2579
        /* BEGIN: Use Case */
2580
        // $mediaLocationId is the ID of the "Media" page location in
2581
        // an eZ Publish demo installation
2582
2583
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2584
        // Publish demo installation
2585
2586
        // Load the location service
2587
        $locationService = $repository->getLocationService();
2588
2589
        // Load location to move
2590
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2591
2592
        // Load new parent location
2593
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2594
2595
        // Move location from "Home" to "Demo Design" (not container)
2596
        $this->expectException(InvalidArgumentException::class);
2597
        $locationService->moveSubtree($locationToMove, $newParentLocation);
2598
    }
2599
2600
    /**
2601
     * Test for the moveSubtree() method.
2602
     *
2603
     * @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
2604
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2605
     */
2606 View Code Duplication
    public function testMoveSubtreeThrowsExceptionOnMoveToSame(): void
2607
    {
2608
        $repository = $this->getRepository();
2609
2610
        $mediaLocationId = $this->generateId('location', 43);
2611
        /* BEGIN: Use Case */
2612
        // $mediaLocationId is the ID of the "Media" page location in
2613
        // an eZ Publish demo installation
2614
2615
        // Load the location service
2616
        $locationService = $repository->getLocationService();
2617
2618
        // Load location to move
2619
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2620
2621
        // Load parent location
2622
        $newParentLocation = $locationService->loadLocation($locationToMove->parentLocationId);
2623
2624
        // Move location from "Home" to "Home"
2625
        $this->expectException(InvalidArgumentException::class);
2626
        $locationService->moveSubtree($locationToMove, $newParentLocation);
2627
    }
2628
2629
    /**
2630
     * Test for the moveSubtree() method.
2631
     *
2632
     * @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
2633
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2634
     */
2635
    public function testMoveSubtreeHidden(): void
2636
    {
2637
        $repository = $this->getRepository();
2638
2639
        $mediaLocationId = $this->generateId('location', 43);
2640
        $demoDesignLocationId = $this->generateId('location', 56);
2641
        /* BEGIN: Use Case */
2642
        // $mediaLocationId is the ID of the "Media" page location in
2643
        // an eZ Publish demo installation
2644
2645
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2646
        // Publish demo installation
2647
2648
        // Load the location service
2649
        $locationService = $repository->getLocationService();
2650
2651
        // Load location to move
2652
        $locationToMove = $locationService->loadLocation($demoDesignLocationId);
2653
2654
        // Load new parent location
2655
        $newParentLocation = $locationService->loadLocation($mediaLocationId);
2656
2657
        // Hide the target location before we move
2658
        $newParentLocation = $locationService->hideLocation($newParentLocation);
2659
2660
        // Move location from "Demo Design" to "Home"
2661
        $locationService->moveSubtree(
2662
            $locationToMove,
2663
            $newParentLocation
2664
        );
2665
2666
        // Load moved location
2667
        $movedLocation = $locationService->loadLocation($demoDesignLocationId);
2668
        /* END: Use Case */
2669
2670
        $this->assertPropertiesCorrect(
2671
            [
2672
                'hidden' => false,
2673
                'invisible' => true,
2674
                'depth' => $newParentLocation->depth + 1,
2675
                'parentLocationId' => $newParentLocation->id,
2676
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $movedLocation->id) . '/',
2677
            ],
2678
            $movedLocation
2679
        );
2680
    }
2681
2682
    /**
2683
     * Test for the moveSubtree() method.
2684
     *
2685
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2686
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2687
     */
2688
    public function testMoveSubtreeUpdatesSubtreeProperties()
2689
    {
2690
        $repository = $this->getRepository();
2691
        $locationService = $repository->getLocationService();
2692
2693
        $locationToMove = $locationService->loadLocation($this->generateId('location', 56));
2694
        $newParentLocation = $locationService->loadLocation($this->generateId('location', 43));
2695
2696
        // Load Subtree properties before move
2697
        $expected = $this->loadSubtreeProperties($locationToMove);
2698
        foreach ($expected as $id => $properties) {
2699
            $expected[$id]['depth'] = $properties['depth'] + 2;
2700
            $expected[$id]['pathString'] = str_replace(
2701
                $locationToMove->pathString,
2702
                $newParentLocation->pathString . $this->parseId('location', $locationToMove->id) . '/',
2703
                $properties['pathString']
2704
            );
2705
        }
2706
2707
        $mediaLocationId = $this->generateId('location', 43);
2708
        $demoDesignLocationId = $this->generateId('location', 56);
2709
        /* BEGIN: Use Case */
2710
        // $mediaLocationId is the ID of the "Media" page location in
2711
        // an eZ Publish demo installation
2712
2713
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2714
        // Publish demo installation
2715
2716
        // Load the location service
2717
        $locationService = $repository->getLocationService();
2718
2719
        // Load location to move
2720
        $locationToMove = $locationService->loadLocation($demoDesignLocationId);
2721
2722
        // Load new parent location
2723
        $newParentLocation = $locationService->loadLocation($mediaLocationId);
2724
2725
        // Move location from "Demo Design" to "Home"
2726
        $locationService->moveSubtree(
2727
            $locationToMove,
2728
            $newParentLocation
2729
        );
2730
2731
        // Load moved location
2732
        $movedLocation = $locationService->loadLocation($demoDesignLocationId);
2733
        /* END: Use Case */
2734
2735
        $this->refreshSearch($repository);
2736
2737
        // Load Subtree properties after move
2738
        $actual = $this->loadSubtreeProperties($movedLocation);
2739
2740
        $this->assertEquals($expected, $actual);
2741
    }
2742
2743
    /**
2744
     * Test for the moveSubtree() method.
2745
     *
2746
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2747
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtreeUpdatesSubtreeProperties
2748
     */
2749
    public function testMoveSubtreeUpdatesSubtreePropertiesHidden()
2750
    {
2751
        $repository = $this->getRepository();
2752
        $locationService = $repository->getLocationService();
2753
2754
        $locationToMove = $locationService->loadLocation($this->generateId('location', 2));
2755
        $newParentLocation = $locationService->loadLocation($this->generateId('location', 43));
2756
2757
        // Hide the target location before we move
2758
        $newParentLocation = $locationService->hideLocation($newParentLocation);
2759
2760
        // Load Subtree properties before move
2761
        $expected = $this->loadSubtreeProperties($locationToMove);
2762
        foreach ($expected as $id => $properties) {
2763
            $expected[$id]['invisible'] = true;
2764
            $expected[$id]['depth'] = $properties['depth'] + 1;
2765
            $expected[$id]['pathString'] = str_replace(
2766
                $locationToMove->pathString,
2767
                $newParentLocation->pathString . $this->parseId('location', $locationToMove->id) . '/',
2768
                $properties['pathString']
2769
            );
2770
        }
2771
2772
        $homeLocationId = $this->generateId('location', 2);
2773
        $mediaLocationId = $this->generateId('location', 43);
2774
        /* BEGIN: Use Case */
2775
        // $mediaLocationId is the ID of the "Media" page location in
2776
        // an eZ Publish demo installation
2777
2778
        // $homeLocationId is the ID of the "Home" page location in an eZ
2779
        // Publish demo installation
2780
2781
        // Load the location service
2782
        $locationService = $repository->getLocationService();
2783
2784
        // Load location to move
2785
        $locationToMove = $locationService->loadLocation($homeLocationId);
2786
2787
        // Load new parent location
2788
        $newParentLocation = $locationService->loadLocation($mediaLocationId);
2789
2790
        // Move location from "Home" to "Demo Design"
2791
        $locationService->moveSubtree(
2792
            $locationToMove,
2793
            $newParentLocation
2794
        );
2795
2796
        // Load moved location
2797
        $movedLocation = $locationService->loadLocation($homeLocationId);
2798
        /* END: Use Case */
2799
2800
        $this->refreshSearch($repository);
2801
2802
        // Load Subtree properties after move
2803
        $actual = $this->loadSubtreeProperties($movedLocation);
2804
2805
        $this->assertEquals($expected, $actual);
2806
    }
2807
2808
    /**
2809
     * Test for the moveSubtree() method.
2810
     *
2811
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2812
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2813
     */
2814 View Code Duplication
    public function testMoveSubtreeIncrementsChildCountOfNewParent()
2815
    {
2816
        $repository = $this->getRepository();
2817
        $locationService = $repository->getLocationService();
2818
2819
        $newParentLocation = $locationService->loadLocation($this->generateId('location', 43));
2820
2821
        // Load expected properties before move
2822
        $expected = $this->loadLocationProperties($newParentLocation);
2823
        $childCountBefore = $locationService->getLocationChildCount($newParentLocation);
2824
2825
        $mediaLocationId = $this->generateId('location', 43);
2826
        $demoDesignLocationId = $this->generateId('location', 56);
2827
        /* BEGIN: Use Case */
2828
        // $mediaLocationId is the ID of the "Media" page location in
2829
        // an eZ Publish demo installation
2830
2831
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2832
        // Publish demo installation
2833
2834
        // Load the location service
2835
        $locationService = $repository->getLocationService();
2836
2837
        // Load location to move
2838
        $locationToMove = $locationService->loadLocation($demoDesignLocationId);
2839
2840
        // Load new parent location
2841
        $newParentLocation = $locationService->loadLocation($mediaLocationId);
2842
2843
        // Move location from "Demo Design" to "Home"
2844
        $locationService->moveSubtree(
2845
            $locationToMove,
2846
            $newParentLocation
2847
        );
2848
2849
        // Load moved location
2850
        $movedLocation = $locationService->loadLocation($demoDesignLocationId);
0 ignored issues
show
Unused Code introduced by
$movedLocation is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2851
2852
        // Reload new parent location
2853
        $newParentLocation = $locationService->loadLocation($mediaLocationId);
2854
        /* END: Use Case */
2855
2856
        $this->refreshSearch($repository);
2857
2858
        // Load Subtree properties after move
2859
        $actual = $this->loadLocationProperties($newParentLocation);
2860
        $childCountAfter = $locationService->getLocationChildCount($newParentLocation);
2861
2862
        $this->assertEquals($expected, $actual);
2863
        $this->assertEquals($childCountBefore + 1, $childCountAfter);
2864
    }
2865
2866
    /**
2867
     * Test for the moveSubtree() method.
2868
     *
2869
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2870
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2871
     */
2872 View Code Duplication
    public function testMoveSubtreeDecrementsChildCountOfOldParent()
2873
    {
2874
        $repository = $this->getRepository();
2875
        $locationService = $repository->getLocationService();
2876
2877
        $oldParentLocation = $locationService->loadLocation($this->generateId('location', 1));
2878
2879
        // Load expected properties before move
2880
        $expected = $this->loadLocationProperties($oldParentLocation);
2881
        $childCountBefore = $locationService->getLocationChildCount($oldParentLocation);
2882
2883
        $homeLocationId = $this->generateId('location', 2);
2884
        $mediaLocationId = $this->generateId('location', 43);
2885
        /* BEGIN: Use Case */
2886
        // $homeLocationId is the ID of the "Home" page location in
2887
        // an eZ Publish demo installation
2888
2889
        // $mediaLocationId is the ID of the "Media" page location in an eZ
2890
        // Publish demo installation
2891
2892
        // Load the location service
2893
        $locationService = $repository->getLocationService();
2894
2895
        // Load location to move
2896
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2897
2898
        // Get the location id of the old parent
2899
        $oldParentLocationId = $locationToMove->parentLocationId;
2900
2901
        // Load new parent location
2902
        $newParentLocation = $locationService->loadLocation($homeLocationId);
2903
2904
        // Move location from "Demo Design" to "Home"
2905
        $locationService->moveSubtree(
2906
            $locationToMove,
2907
            $newParentLocation
2908
        );
2909
2910
        // Reload old parent location
2911
        $oldParentLocation = $locationService->loadLocation($oldParentLocationId);
2912
        /* END: Use Case */
2913
2914
        $this->refreshSearch($repository);
2915
2916
        // Load Subtree properties after move
2917
        $actual = $this->loadLocationProperties($oldParentLocation);
2918
        $childCountAfter = $locationService->getLocationChildCount($oldParentLocation);
2919
2920
        $this->assertEquals($expected, $actual);
2921
        $this->assertEquals($childCountBefore - 1, $childCountAfter);
2922
    }
2923
2924
    /**
2925
     * Test moving invisible (hidden by parent) subtree.
2926
     *
2927
     * @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
2928
     *
2929
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
2930
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
2931
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
2932
     */
2933
    public function testMoveInvisibleSubtree()
2934
    {
2935
        $repository = $this->getRepository();
2936
        $locationService = $repository->getLocationService();
2937
2938
        $rootLocationId = 2;
2939
2940
        $folder = $this->createFolder(['eng-GB' => 'Folder'], $rootLocationId);
2941
        $child = $this->createFolder(['eng-GB' => 'Child'], $folder->contentInfo->mainLocationId);
2942
        $locationService->hideLocation(
2943
            $locationService->loadLocation($folder->contentInfo->mainLocationId)
2944
        );
2945
        // sanity check
2946
        $childLocation = $locationService->loadLocation($child->contentInfo->mainLocationId);
2947
        self::assertFalse($childLocation->hidden);
2948
        self::assertTrue($childLocation->invisible);
2949
        self::assertEquals($folder->contentInfo->mainLocationId, $childLocation->parentLocationId);
2950
2951
        $destination = $this->createFolder(['eng-GB' => 'Destination'], $rootLocationId);
2952
        $destinationLocation = $locationService->loadLocation(
2953
            $destination->contentInfo->mainLocationId
2954
        );
2955
2956
        $locationService->moveSubtree($childLocation, $destinationLocation);
2957
2958
        $childLocation = $locationService->loadLocation($child->contentInfo->mainLocationId);
2959
        // Business logic - Location moved to visible parent becomes visible
2960
        self::assertFalse($childLocation->hidden);
2961
        self::assertFalse($childLocation->invisible);
2962
        self::assertEquals($destinationLocation->id, $childLocation->parentLocationId);
2963
    }
2964
2965
    /**
2966
     * Test for the moveSubtree() method.
2967
     *
2968
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2969
     */
2970
    public function testMoveSubtreeThrowsInvalidArgumentException(): void
2971
    {
2972
        $repository = $this->getRepository();
2973
        $mediaLocationId = $this->generateId('location', 43);
2974
        $multimediaLocationId = $this->generateId('location', 53);
2975
2976
        /* BEGIN: Use Case */
2977
        // $mediaLocationId is the ID of the "Media" page location in
2978
        // an eZ Publish demo installation
2979
2980
        // $multimediaLocationId is the ID of the "Multimedia" page location in an eZ
2981
        // Publish demo installation
2982
2983
        // Load the location service
2984
        $locationService = $repository->getLocationService();
2985
2986
        // Load location to move
2987
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2988
2989
        // Load new parent location
2990
        $newParentLocation = $locationService->loadLocation($multimediaLocationId);
2991
2992
        // Throws an exception because new parent location is placed below location to move
2993
        $this->expectException(InvalidArgumentException::class);
2994
        $locationService->moveSubtree(
2995
            $locationToMove,
2996
            $newParentLocation
2997
        );
2998
        /* END: Use Case */
2999
    }
3000
3001
    /**
3002
     * Test that Legacy ezcontentobject_tree.path_identification_string field is correctly updated
3003
     * after moving subtree.
3004
     *
3005
     * @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
3006
     *
3007
     * @throws \ErrorException
3008
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
3009
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
3010
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
3011
     */
3012
    public function testMoveSubtreeUpdatesPathIdentificationString(): void
3013
    {
3014
        $repository = $this->getRepository();
3015
        $locationService = $repository->getLocationService();
3016
3017
        $topNode = $this->createFolder(['eng-US' => 'top_node'], 2);
3018
3019
        $newParentLocation = $locationService->loadLocation(
3020
            $this
3021
                ->createFolder(['eng-US' => 'Parent'], $topNode->contentInfo->mainLocationId)
3022
                ->contentInfo
3023
                ->mainLocationId
3024
        );
3025
        $location = $locationService->loadLocation(
3026
            $this
3027
                ->createFolder(['eng-US' => 'Move Me'], $topNode->contentInfo->mainLocationId)
3028
                ->contentInfo
3029
                ->mainLocationId
3030
        );
3031
3032
        $locationService->moveSubtree($location, $newParentLocation);
3033
3034
        // path location string is not present on API level, so we need to query database
3035
        $serviceContainer = $this->getSetupFactory()->getServiceContainer();
3036
        /** @var \Doctrine\DBAL\Connection $connection */
3037
        $connection = $serviceContainer->get('ezpublish.persistence.connection');
3038
        $query = $connection->createQueryBuilder();
3039
        $query
3040
            ->select('path_identification_string')
3041
            ->from('ezcontentobject_tree')
3042
            ->where('node_id = :nodeId')
3043
            ->setParameter('nodeId', $location->id);
3044
3045
        self::assertEquals(
3046
            'top_node/parent/move_me',
3047
            $query->execute()->fetchColumn()
3048
        );
3049
    }
3050
3051
    /**
3052
     * Loads properties from all locations in the $location's subtree.
3053
     *
3054
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
3055
     * @param array $properties
3056
     *
3057
     * @return array
3058
     */
3059
    private function loadSubtreeProperties(Location $location, array $properties = [])
3060
    {
3061
        $locationService = $this->getRepository()->getLocationService();
3062
3063
        foreach ($locationService->loadLocationChildren($location)->locations as $childLocation) {
3064
            $properties[] = $this->loadLocationProperties($childLocation);
3065
3066
            $properties = $this->loadSubtreeProperties($childLocation, $properties);
3067
        }
3068
3069
        return $properties;
3070
    }
3071
3072
    /**
3073
     * Loads assertable properties from the given location.
3074
     *
3075
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
3076
     * @param mixed[] $overwrite
3077
     *
3078
     * @return array
3079
     */
3080
    private function loadLocationProperties(Location $location, array $overwrite = [])
3081
    {
3082
        return array_merge(
3083
            [
3084
                'id' => $location->id,
3085
                'depth' => $location->depth,
3086
                'parentLocationId' => $location->parentLocationId,
3087
                'pathString' => $location->pathString,
3088
                'remoteId' => $location->remoteId,
3089
                'hidden' => $location->hidden,
3090
                'invisible' => $location->invisible,
3091
                'priority' => $location->priority,
3092
                'sortField' => $location->sortField,
3093
                'sortOrder' => $location->sortOrder,
3094
            ],
3095
            $overwrite
3096
        );
3097
    }
3098
3099
    /**
3100
     * Assert generated aliases to expected alias return.
3101
     *
3102
     * @param \eZ\Publish\API\Repository\URLAliasService $urlAliasService
3103
     * @param array $expectedAliases
3104
     */
3105
    protected function assertGeneratedAliases($urlAliasService, array $expectedAliases)
3106
    {
3107
        foreach ($expectedAliases as $expectedAlias) {
3108
            $urlAlias = $urlAliasService->lookup($expectedAlias);
3109
            $this->assertPropertiesCorrect(['type' => 0], $urlAlias);
3110
        }
3111
    }
3112
3113
    /**
3114
     * @param \eZ\Publish\API\Repository\URLAliasService $urlAliasService
3115
     * @param array $expectedSubItemAliases
3116
     */
3117
    private function assertAliasesBeforeCopy($urlAliasService, array $expectedSubItemAliases)
3118
    {
3119
        foreach ($expectedSubItemAliases as $aliasUrl) {
3120
            try {
3121
                $urlAliasService->lookup($aliasUrl);
3122
                $this->fail('We didn\'t expect to find alias, but it was found');
3123
            } catch (\Exception $e) {
3124
                $this->assertTrue(true); // OK - alias was not found
3125
            }
3126
        }
3127
    }
3128
3129
    /**
3130
     * Create and publish Content with the given parent Location.
3131
     *
3132
     * @param string $contentName
3133
     * @param int $parentLocationId
3134
     *
3135
     * @return \eZ\Publish\API\Repository\Values\Content\Content published Content
3136
     */
3137 View Code Duplication
    private function publishContentWithParentLocation($contentName, $parentLocationId)
3138
    {
3139
        $repository = $this->getRepository(false);
3140
        $locationService = $repository->getLocationService();
3141
3142
        $contentService = $repository->getContentService();
3143
        $contentTypeService = $repository->getContentTypeService();
3144
3145
        $contentCreateStruct = $contentService->newContentCreateStruct(
3146
            $contentTypeService->loadContentTypeByIdentifier('folder'),
3147
            'eng-US'
3148
        );
3149
        $contentCreateStruct->setField('name', $contentName);
3150
        $contentDraft = $contentService->createContent(
3151
            $contentCreateStruct,
3152
            [
3153
                $locationService->newLocationCreateStruct($parentLocationId),
3154
            ]
3155
        );
3156
3157
        return $contentService->publishVersion($contentDraft->versionInfo);
3158
    }
3159
3160
    /**
3161
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
3162
     */
3163
    private function createForumStruct(string $name): ContentCreateStruct
3164
    {
3165
        $repository = $this->getRepository(false);
3166
3167
        $contentTypeForum = $repository->getContentTypeService()
3168
            ->loadContentTypeByIdentifier('forum');
3169
3170
        $forum = $repository->getContentService()
3171
            ->newContentCreateStruct($contentTypeForum, 'eng-GB');
3172
3173
        $forum->setField('name', $name);
3174
3175
        return $forum;
3176
    }
3177
3178
    private function assertAliasExists(
3179
        string $expectedAliasPath,
3180
        Location $location,
3181
        URLAliasServiceInterface $urlAliasService
3182
    ): void {
3183
        $articleAliasesBeforeDelete = $urlAliasService
3184
            ->listLocationAliases($location);
3185
3186
        $this->assertNotEmpty(
3187
            array_filter(
3188
                $articleAliasesBeforeDelete,
3189
                static function (URLAlias $alias) use ($expectedAliasPath) {
3190
                    return $alias->path === $expectedAliasPath;
3191
                }
3192
            )
3193
        );
3194
    }
3195
}
3196