Completed
Push — 7.5 ( b433d9...a69cd3 )
by
unknown
20:17
created

LocationServiceTest   F

Complexity

Total Complexity 115

Size/Duplication

Total Lines 2925
Duplicated Lines 18.63 %

Coupling/Cohesion

Components 1
Dependencies 29

Importance

Changes 0
Metric Value
dl 545
loc 2925
rs 0.8
c 0
b 0
f 0
wmc 115
lcom 1
cbo 29

82 Methods

Rating   Name   Duplication   Size   Complexity  
A testNewLocationCreateStructValues() 0 15 1
A testCreateLocation() 0 40 1
A testCreateLocationStructValues() 0 24 1
A testCreateLocationThrowsInvalidArgumentExceptionContentAlreadyBelowParent() 25 25 1
A testCreateLocationThrowsInvalidArgumentExceptionParentIsSubLocationOfContent() 25 25 1
A testCreateLocationThrowsInvalidArgumentExceptionRemoteIdExists() 25 25 1
A testCreateLocationThrowsInvalidArgumentExceptionPriorityIsOutOfRange() 29 29 1
A dataProviderForOutOfRangeLocationPriority() 0 4 1
A testCreateLocationInTransactionWithRollback() 0 43 3
A testLoadLocation() 0 20 1
A testNewLocationCreateStruct() 21 21 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 testLoadLocationsContent() 0 30 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() 20 20 1
A testUpdateLocationTwice() 0 23 1
A testSwapLocation() 0 52 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
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 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() 29 29 1
A testMoveSubtreeUpdatesPathIdentificationString() 0 38 1
A loadSubtreeProperties() 0 12 2
A loadLocationProperties() 18 18 1
A assertGeneratedAliases() 0 7 2
A assertAliasesBeforeCopy() 0 11 3
A publishContentWithParentLocation() 22 22 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
 * File containing the LocationServiceTest class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\API\Repository\Tests;
10
11
use Exception;
12
use eZ\Publish\API\Repository\Exceptions\BadStateException;
13
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
14
use eZ\Publish\API\Repository\Values\Content\Content;
15
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
16
use eZ\Publish\API\Repository\Values\Content\Location;
17
use eZ\Publish\API\Repository\Values\Content\LocationCreateStruct;
18
use eZ\Publish\API\Repository\Values\Content\LocationList;
19
use eZ\Publish\API\Repository\Values\Content\LocationUpdateStruct;
20
use eZ\Publish\API\Repository\Values\Content\Query;
21
use eZ\Publish\API\Repository\Values\Content\Search\SearchHit;
22
23
/**
24
 * Test case for operations in the LocationService using in memory storage.
25
 *
26
 * @see eZ\Publish\API\Repository\LocationService
27
 * @group location
28
 */
29
class LocationServiceTest extends BaseTest
30
{
31
    /**
32
     * Test for the newLocationCreateStruct() method.
33
     *
34
     * @return \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct
35
     *
36
     * @see \eZ\Publish\API\Repository\LocationService::newLocationCreateStruct()
37
     */
38 View Code Duplication
    public function testNewLocationCreateStruct()
39
    {
40
        $repository = $this->getRepository();
41
42
        $parentLocationId = $this->generateId('location', 1);
43
        /* BEGIN: Use Case */
44
        // $parentLocationId is the ID of an existing location
45
        $locationService = $repository->getLocationService();
46
47
        $locationCreate = $locationService->newLocationCreateStruct(
48
            $parentLocationId
49
        );
50
        /* END: Use Case */
51
52
        $this->assertInstanceOf(
53
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\LocationCreateStruct',
54
            $locationCreate
55
        );
56
57
        return $locationCreate;
58
    }
59
60
    /**
61
     * Test for the newLocationCreateStruct() method.
62
     *
63
     * @param \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct $locationCreate
64
     *
65
     * @see \eZ\Publish\API\Repository\LocationService::newLocationCreateStruct()
66
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
67
     */
68
    public function testNewLocationCreateStructValues(LocationCreateStruct $locationCreate)
69
    {
70
        $this->assertPropertiesCorrect(
71
            [
72
                'priority' => 0,
73
                'hidden' => false,
74
                // remoteId should be initialized with a default value
75
                //'remoteId' => null,
76
                'sortField' => Location::SORT_FIELD_NAME,
77
                'sortOrder' => Location::SORT_ORDER_ASC,
78
                'parentLocationId' => $this->generateId('location', 1),
79
            ],
80
            $locationCreate
81
        );
82
    }
83
84
    /**
85
     * Test for the createLocation() method.
86
     *
87
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
88
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
89
     */
90
    public function testCreateLocation()
91
    {
92
        $repository = $this->getRepository();
93
94
        $contentId = $this->generateId('object', 41);
95
        $parentLocationId = $this->generateId('location', 5);
96
        /* BEGIN: Use Case */
97
        // $contentId is the ID of an existing content object
98
        // $parentLocationId is the ID of an existing location
99
        $contentService = $repository->getContentService();
100
        $locationService = $repository->getLocationService();
101
102
        // ContentInfo for "How to use eZ Publish"
103
        $contentInfo = $contentService->loadContentInfo($contentId);
104
105
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
106
        $locationCreate->priority = 23;
107
        $locationCreate->hidden = true;
108
        $locationCreate->remoteId = 'sindelfingen';
109
        $locationCreate->sortField = Location::SORT_FIELD_NODE_ID;
110
        $locationCreate->sortOrder = Location::SORT_ORDER_DESC;
111
112
        $location = $locationService->createLocation(
113
            $contentInfo,
114
            $locationCreate
115
        );
116
        /* END: Use Case */
117
118
        $this->assertInstanceOf(
119
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
120
            $location
121
        );
122
123
        return [
124
            'locationCreate' => $locationCreate,
125
            'createdLocation' => $location,
126
            'contentInfo' => $contentInfo,
127
            'parentLocation' => $locationService->loadLocation($this->generateId('location', 5)),
128
        ];
129
    }
130
131
    /**
132
     * Test for the createLocation() method.
133
     *
134
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
135
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
136
     */
137
    public function testCreateLocationStructValues(array $data)
138
    {
139
        $locationCreate = $data['locationCreate'];
140
        $createdLocation = $data['createdLocation'];
141
        $contentInfo = $data['contentInfo'];
142
143
        $this->assertPropertiesCorrect(
144
            [
145
                'priority' => $locationCreate->priority,
146
                'hidden' => $locationCreate->hidden,
147
                'invisible' => $locationCreate->hidden,
148
                'remoteId' => $locationCreate->remoteId,
149
                'contentInfo' => $contentInfo,
150
                'parentLocationId' => $locationCreate->parentLocationId,
151
                'pathString' => '/1/5/' . $this->parseId('location', $createdLocation->id) . '/',
152
                'depth' => 2,
153
                'sortField' => $locationCreate->sortField,
154
                'sortOrder' => $locationCreate->sortOrder,
155
            ],
156
            $createdLocation
157
        );
158
159
        $this->assertNotNull($createdLocation->id);
160
    }
161
162
    /**
163
     * Test for the createLocation() method.
164
     *
165
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
166
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
167
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
168
     */
169 View Code Duplication
    public function testCreateLocationThrowsInvalidArgumentExceptionContentAlreadyBelowParent()
170
    {
171
        $repository = $this->getRepository();
172
173
        $contentId = $this->generateId('object', 11);
174
        $parentLocationId = $this->generateId('location', 5);
175
        /* BEGIN: Use Case */
176
        // $contentId is the ID of an existing content object
177
        // $parentLocationId is the ID of an existing location which already
178
        // has the content assigned to one of its descendant locations
179
        $contentService = $repository->getContentService();
180
        $locationService = $repository->getLocationService();
181
182
        // ContentInfo for "How to use eZ Publish"
183
        $contentInfo = $contentService->loadContentInfo($contentId);
184
185
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
186
187
        // Throws exception, since content is already located at "/1/2/107/110/"
188
        $locationService->createLocation(
189
            $contentInfo,
190
            $locationCreate
191
        );
192
        /* END: Use Case */
193
    }
194
195
    /**
196
     * Test for the createLocation() method.
197
     *
198
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
199
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
200
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
201
     */
202 View Code Duplication
    public function testCreateLocationThrowsInvalidArgumentExceptionParentIsSubLocationOfContent()
203
    {
204
        $repository = $this->getRepository();
205
206
        $contentId = $this->generateId('object', 4);
207
        $parentLocationId = $this->generateId('location', 12);
208
        /* BEGIN: Use Case */
209
        // $contentId is the ID of an existing content object
210
        // $parentLocationId is the ID of an existing location which is below a
211
        // location that is assigned to the content
212
        $contentService = $repository->getContentService();
213
        $locationService = $repository->getLocationService();
214
215
        // ContentInfo for "How to use eZ Publish"
216
        $contentInfo = $contentService->loadContentInfo($contentId);
217
218
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
219
220
        // Throws exception, since content is already located at "/1/2/"
221
        $locationService->createLocation(
222
            $contentInfo,
223
            $locationCreate
224
        );
225
        /* END: Use Case */
226
    }
227
228
    /**
229
     * Test for the createLocation() method.
230
     *
231
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
232
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
233
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
234
     */
235 View Code Duplication
    public function testCreateLocationThrowsInvalidArgumentExceptionRemoteIdExists()
236
    {
237
        $repository = $this->getRepository();
238
239
        $contentId = $this->generateId('object', 41);
240
        $parentLocationId = $this->generateId('location', 5);
241
        /* BEGIN: Use Case */
242
        // $contentId is the ID of an existing content object
243
        $contentService = $repository->getContentService();
244
        $locationService = $repository->getLocationService();
245
246
        // ContentInfo for "How to use eZ Publish"
247
        $contentInfo = $contentService->loadContentInfo($contentId);
248
249
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
250
        // This remote ID already exists
251
        $locationCreate->remoteId = 'f3e90596361e31d496d4026eb624c983';
252
253
        // Throws exception, since remote ID is already in use
254
        $locationService->createLocation(
255
            $contentInfo,
256
            $locationCreate
257
        );
258
        /* END: Use Case */
259
    }
260
261
    /**
262
     * Test for the createLocation() method.
263
     *
264
     * @covers \eZ\Publish\API\Repository\LocationService::createLocation()
265
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
266
     * @dataProvider dataProviderForOutOfRangeLocationPriority
267
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
268
     */
269 View Code Duplication
    public function testCreateLocationThrowsInvalidArgumentExceptionPriorityIsOutOfRange($priority)
270
    {
271
        $repository = $this->getRepository();
272
273
        $contentId = $this->generateId('object', 41);
274
        $parentLocationId = $this->generateId('location', 5);
275
        /* BEGIN: Use Case */
276
        // $contentId is the ID of an existing content object
277
        // $parentLocationId is the ID of an existing location
278
        $contentService = $repository->getContentService();
279
        $locationService = $repository->getLocationService();
280
281
        // ContentInfo for "How to use eZ Publish"
282
        $contentInfo = $contentService->loadContentInfo($contentId);
283
284
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
285
        $locationCreate->priority = $priority;
286
        $locationCreate->hidden = true;
287
        $locationCreate->remoteId = 'sindelfingen';
288
        $locationCreate->sortField = Location::SORT_FIELD_NODE_ID;
289
        $locationCreate->sortOrder = Location::SORT_ORDER_DESC;
290
291
        // Throws exception, since priority is out of range
292
        $locationService->createLocation(
293
            $contentInfo,
294
            $locationCreate
295
        );
296
        /* END: Use Case */
297
    }
298
299
    public function dataProviderForOutOfRangeLocationPriority()
300
    {
301
        return [[-2147483649], [2147483648]];
302
    }
303
304
    /**
305
     * Test for the createLocation() method.
306
     *
307
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
308
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
309
     */
310
    public function testCreateLocationInTransactionWithRollback()
311
    {
312
        $repository = $this->getRepository();
313
314
        $contentId = $this->generateId('object', 41);
315
        $parentLocationId = $this->generateId('location', 5);
316
        /* BEGIN: Use Case */
317
        // $contentId is the ID of an existing content object
318
        // $parentLocationId is the ID of an existing location
319
        $contentService = $repository->getContentService();
320
        $locationService = $repository->getLocationService();
321
322
        $repository->beginTransaction();
323
324
        try {
325
            // ContentInfo for "How to use eZ Publish"
326
            $contentInfo = $contentService->loadContentInfo($contentId);
327
328
            $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
329
            $locationCreate->remoteId = 'sindelfingen';
330
331
            $createdLocationId = $locationService->createLocation(
332
                $contentInfo,
333
                $locationCreate
334
            )->id;
335
        } catch (Exception $e) {
336
            // Cleanup hanging transaction on error
337
            $repository->rollback();
338
            throw $e;
339
        }
340
341
        $repository->rollback();
342
343
        try {
344
            // Throws exception since creation of location was rolled back
345
            $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...
346
        } catch (NotFoundException $e) {
347
            return;
348
        }
349
        /* END: Use Case */
350
351
        $this->fail('Objects still exists after rollback.');
352
    }
353
354
    /**
355
     * Test for the loadLocation() method.
356
     *
357
     * @return \eZ\Publish\API\Repository\Values\Content\Location
358
     *
359
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocation
360
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
361
     */
362
    public function testLoadLocation()
363
    {
364
        $repository = $this->getRepository();
365
366
        $locationId = $this->generateId('location', 5);
367
        /* BEGIN: Use Case */
368
        // $locationId is the ID of an existing location
369
        $locationService = $repository->getLocationService();
370
371
        $location = $locationService->loadLocation($locationId);
372
        /* END: Use Case */
373
374
        $this->assertInstanceOf(
375
            Location::class,
376
            $location
377
        );
378
        self::assertEquals(5, $location->id);
379
380
        return $location;
381
    }
382
383
    /**
384
     * Test for the loadLocation() method.
385
     *
386
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
387
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
388
     */
389
    public function testLoadLocationRootStructValues()
390
    {
391
        $repository = $this->getRepository();
392
        $locationService = $repository->getLocationService();
393
        $location = $locationService->loadLocation($this->generateId('location', 1));
394
395
        $this->assertRootLocationStructValues($location);
396
    }
397
398
    public function testLoadLocationRootStructValuesWithPrioritizedLanguages(): void
399
    {
400
        $repository = $this->getRepository();
401
402
        $rootLocation = $repository
403
            ->getLocationService()
404
            ->loadLocation(
405
                $this->generateId('location', 1),
406
                [
407
                    'eng-GB',
408
                    'ger-DE',
409
                ]
410
            );
411
412
        $this->assertRootLocationStructValues($rootLocation);
413
    }
414
415
    private function assertRootLocationStructValues(Location $location): void
416
    {
417
        $legacyDateTime = new \DateTime();
418
        $legacyDateTime->setTimestamp(1030968000);
419
420
        $this->assertInstanceOf(Location::class, $location);
421
        $this->assertPropertiesCorrect(
422
            [
423
                'id' => $this->generateId('location', 1),
424
                'status' => 1,
425
                'priority' => 0,
426
                'hidden' => false,
427
                'invisible' => false,
428
                'remoteId' => '629709ba256fe317c3ddcee35453a96a',
429
                'parentLocationId' => $this->generateId('location', 1),
430
                'pathString' => '/1/',
431
                'depth' => 0,
432
                'sortField' => 1,
433
                'sortOrder' => 1,
434
            ],
435
            $location
436
        );
437
438
        $this->assertInstanceOf(ContentInfo::class, $location->contentInfo);
439
        $this->assertPropertiesCorrect(
440
            [
441
                'id' => $this->generateId('content', 0),
442
                'name' => 'Top Level Nodes',
443
                'sectionId' => 1,
444
                'mainLocationId' => 1,
445
                'contentTypeId' => 1,
446
                'currentVersionNo' => 1,
447
                'published' => 1,
448
                'ownerId' => 14,
449
                'modificationDate' => $legacyDateTime,
450
                'publishedDate' => $legacyDateTime,
451
                'alwaysAvailable' => 1,
452
                'remoteId' => null,
453
                'mainLanguageCode' => 'eng-GB',
454
            ],
455
            $location->contentInfo
456
        );
457
    }
458
459
    /**
460
     * Test for the loadLocation() method.
461
     *
462
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
463
     *
464
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
465
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
466
     */
467
    public function testLoadLocationStructValues(Location $location)
468
    {
469
        $this->assertPropertiesCorrect(
470
            [
471
                'id' => $this->generateId('location', 5),
472
                'priority' => 0,
473
                'hidden' => false,
474
                'invisible' => false,
475
                'remoteId' => '3f6d92f8044aed134f32153517850f5a',
476
                'parentLocationId' => $this->generateId('location', 1),
477
                'pathString' => '/1/5/',
478
                'depth' => 1,
479
                'sortField' => 1,
480
                'sortOrder' => 1,
481
            ],
482
            $location
483
        );
484
485
        $this->assertInstanceOf(
486
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\ContentInfo',
487
            $location->contentInfo
488
        );
489
        $this->assertEquals($this->generateId('object', 4), $location->contentInfo->id);
490
491
        // Check lazy loaded proxy on ->content
492
        $this->assertInstanceOf(
493
            Content::class,
494
            $content = $location->getContent()
495
        );
496
        $this->assertEquals(4, $content->contentInfo->id);
497
    }
498
499
    public function testLoadLocationPrioritizedLanguagesFallback()
500
    {
501
        $repository = $this->getRepository();
502
503
        // Add a language
504
        $this->createLanguage('nor-NO', 'Norsk');
505
506
        $locationService = $repository->getLocationService();
507
        $contentService = $repository->getContentService();
508
        $location = $locationService->loadLocation(5);
509
510
        // Translate "Users"
511
        $draft = $contentService->createContentDraft($location->contentInfo);
512
        $struct = $contentService->newContentUpdateStruct();
513
        $struct->setField('name', 'Brukere', 'nor-NO');
514
        $draft = $contentService->updateContent($draft->getVersionInfo(), $struct);
515
        $contentService->publishVersion($draft->getVersionInfo());
516
517
        // Load with priority language (fallback will be the old one)
518
        $location = $locationService->loadLocation(5, ['nor-NO']);
519
520
        $this->assertInstanceOf(
521
            Location::class,
522
            $location
523
        );
524
        self::assertEquals(5, $location->id);
525
        $this->assertInstanceOf(
526
            Content::class,
527
            $content = $location->getContent()
528
        );
529
        $this->assertEquals(4, $content->contentInfo->id);
530
531
        $this->assertEquals($content->getVersionInfo()->getName(), 'Brukere');
532
        $this->assertEquals($content->getVersionInfo()->getName('eng-US'), 'Users');
533
    }
534
535
    /**
536
     * Test that accessing lazy-loaded Content without a translation in the specific
537
     * not available language throws NotFoundException.
538
     */
539
    public function testLoadLocationThrowsNotFoundExceptionForNotAvailableContent(): void
540
    {
541
        $repository = $this->getRepository();
542
543
        $locationService = $repository->getLocationService();
544
545
        $this->createLanguage('pol-PL', 'Polski');
546
547
        $this->expectException(NotFoundException::class);
548
549
        // Note: relying on existing database fixtures to make test case more readable
550
        $locationService->loadLocation(60, ['pol-PL']);
551
    }
552
553
    /**
554
     * Test for the loadLocation() method.
555
     *
556
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
557
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
558
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
559
     */
560
    public function testLoadLocationThrowsNotFoundException()
561
    {
562
        $repository = $this->getRepository();
563
564
        $nonExistentLocationId = $this->generateId('location', 2342);
565
        /* BEGIN: Use Case */
566
        $locationService = $repository->getLocationService();
567
568
        // Throws exception, if Location with $nonExistentLocationId does not
569
        // exist
570
        $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...
571
        /* END: Use Case */
572
    }
573
574
    /**
575
     * Test for the loadLocationList() method.
576
     *
577
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
578
     */
579 View Code Duplication
    public function testLoadLocationList(): void
580
    {
581
        $repository = $this->getRepository();
582
583
        // 5 is the ID of an existing location, 442 is a non-existing id
584
        $locationService = $repository->getLocationService();
585
        $locations = $locationService->loadLocationList([5, 442]);
586
587
        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...
588
        self::assertCount(1, $locations);
0 ignored issues
show
Bug introduced by
It seems like $locations defined by $locationService->loadLocationList(array(5, 442)) on line 585 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...
589
        self::assertEquals([5], array_keys($locations));
590
        self::assertInstanceOf(Location::class, $locations[5]);
591
        self::assertEquals(5, $locations[5]->id);
592
    }
593
594
    /**
595
     * Test for the loadLocationList() method.
596
     *
597
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
598
     * @depends testLoadLocationList
599
     */
600
    public function testLoadLocationListPrioritizedLanguagesFallback(): void
601
    {
602
        $repository = $this->getRepository();
603
604
        $this->createLanguage('pol-PL', 'Polski');
605
606
        // 5 is the ID of an existing location, 442 is a non-existing id
607
        $locationService = $repository->getLocationService();
608
        $locations = $locationService->loadLocationList([5, 442], ['pol-PL'], false);
609
610
        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...
611
        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 608 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...
612
    }
613
614
    /**
615
     * Test for the loadLocationList() method.
616
     *
617
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
618
     * @depends testLoadLocationListPrioritizedLanguagesFallback
619
     */
620
    public function testLoadLocationListPrioritizedLanguagesFallbackAndAlwaysAvailable(): void
621
    {
622
        $repository = $this->getRepository();
623
624
        $this->createLanguage('pol-PL', 'Polski');
625
626
        // 5 is the ID of an existing location, 442 is a non-existing id
627
        $locationService = $repository->getLocationService();
628
        $locations = $locationService->loadLocationList([5, 442], ['pol-PL'], true);
629
630
        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...
631
        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 628 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...
632
        self::assertEquals([5], array_keys($locations));
633
        self::assertInstanceOf(Location::class, $locations[5]);
634
        self::assertEquals(5, $locations[5]->id);
635
    }
636
637
    /**
638
     * Test for the loadLocationList() method.
639
     *
640
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
641
     */
642 View Code Duplication
    public function testLoadLocationListWithRootLocationId()
643
    {
644
        $repository = $this->getRepository();
645
646
        // 1 is the ID of an root location
647
        $locationService = $repository->getLocationService();
648
        $locations = $locationService->loadLocationList([1]);
649
650
        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...
651
        self::assertCount(1, $locations);
0 ignored issues
show
Bug introduced by
It seems like $locations defined by $locationService->loadLocationList(array(1)) on line 648 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...
652
        self::assertEquals([1], array_keys($locations));
653
        self::assertInstanceOf(Location::class, $locations[1]);
654
        self::assertEquals(1, $locations[1]->id);
655
    }
656
657
    /**
658
     * Test for the loadLocationList() method.
659
     *
660
     * Ensures the list is returned in the same order as passed IDs array.
661
     *
662
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
663
     */
664
    public function testLoadLocationListInCorrectOrder()
665
    {
666
        $repository = $this->getRepository();
667
        $locationService = $repository->getLocationService();
668
669
        $cachedLocationId = 2;
670
        $locationIdsToLoad = [43, $cachedLocationId, 5];
671
672
        // Call loadLocation to cache it in memory as it might possibly affect list order
673
        $locationService->loadLocation($cachedLocationId);
674
675
        $locations = $locationService->loadLocationList($locationIdsToLoad);
676
        $locationIds = array_column($locations, 'id');
677
678
        self::assertEquals($locationIdsToLoad, $locationIds);
679
    }
680
681
    /**
682
     * Test for the loadLocationByRemoteId() method.
683
     *
684
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationByRemoteId()
685
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
686
     */
687 View Code Duplication
    public function testLoadLocationByRemoteId()
688
    {
689
        $repository = $this->getRepository();
690
691
        /* BEGIN: Use Case */
692
        $locationService = $repository->getLocationService();
693
694
        $location = $locationService->loadLocationByRemoteId(
695
            '3f6d92f8044aed134f32153517850f5a'
696
        );
697
        /* END: Use Case */
698
699
        $this->assertEquals(
700
            $locationService->loadLocation($this->generateId('location', 5)),
701
            $location
702
        );
703
    }
704
705
    /**
706
     * Test for the loadLocationByRemoteId() method.
707
     *
708
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationByRemoteId()
709
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
710
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
711
     */
712
    public function testLoadLocationByRemoteIdThrowsNotFoundException()
713
    {
714
        $repository = $this->getRepository();
715
716
        /* BEGIN: Use Case */
717
        $locationService = $repository->getLocationService();
718
719
        // Throws exception, since Location with remote ID does not exist
720
        $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...
721
            'not-exists'
722
        );
723
        /* END: Use Case */
724
    }
725
726
    /**
727
     * Test for the loadLocations() method.
728
     *
729
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
730
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
731
     */
732
    public function testLoadLocations()
733
    {
734
        $repository = $this->getRepository();
735
736
        $contentId = $this->generateId('object', 4);
737
        /* BEGIN: Use Case */
738
        // $contentId contains the ID of an existing content object
739
        $contentService = $repository->getContentService();
740
        $locationService = $repository->getLocationService();
741
742
        $contentInfo = $contentService->loadContentInfo($contentId);
743
744
        $locations = $locationService->loadLocations($contentInfo);
745
        /* END: Use Case */
746
747
        $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...
748
        self::assertNotEmpty($locations);
749
750
        foreach ($locations as $location) {
751
            self::assertInstanceOf(Location::class, $location);
752
            self::assertEquals($contentInfo->id, $location->getContentInfo()->id);
753
        }
754
755
        return $locations;
756
    }
757
758
    /**
759
     * Test for the loadLocations() method.
760
     *
761
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
762
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
763
     */
764
    public function testLoadLocationsContent(array $locations)
765
    {
766
        $repository = $this->getRepository();
767
        $locationService = $repository->getLocationService();
0 ignored issues
show
Unused Code introduced by
$locationService 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...
768
769
        $this->assertEquals(1, count($locations));
770
        foreach ($locations as $loadedLocation) {
771
            $this->assertInstanceOf(
772
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
773
                $loadedLocation
774
            );
775
        }
776
777
        usort(
778
            $locations,
779
            function ($a, $b) {
780
                strcmp($a->id, $b->id);
781
            }
782
        );
783
784
        $this->assertEquals(
785
            [$this->generateId('location', 5)],
786
            array_map(
787
                function (Location $location) {
788
                    return $location->id;
789
                },
790
                $locations
791
            )
792
        );
793
    }
794
795
    /**
796
     * Test for the loadLocations() method.
797
     *
798
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
799
     *
800
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations($contentInfo, $rootLocation)
801
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
802
     */
803
    public function testLoadLocationsLimitedSubtree()
804
    {
805
        $repository = $this->getRepository();
806
807
        $originalLocationId = $this->generateId('location', 54);
808
        $originalParentLocationId = $this->generateId('location', 48);
809
        $newParentLocationId = $this->generateId('location', 43);
810
        /* BEGIN: Use Case */
811
        // $originalLocationId is the ID of an existing location
812
        // $originalParentLocationId is the ID of the parent location of
813
        //     $originalLocationId
814
        // $newParentLocationId is the ID of an existing location outside the tree
815
        // of $originalLocationId and $originalParentLocationId
816
        $locationService = $repository->getLocationService();
817
818
        // Location at "/1/48/54"
819
        $originalLocation = $locationService->loadLocation($originalLocationId);
820
821
        // Create location under "/1/43/"
822
        $locationCreate = $locationService->newLocationCreateStruct($newParentLocationId);
823
        $locationService->createLocation(
824
            $originalLocation->contentInfo,
825
            $locationCreate
826
        );
827
828
        $findRootLocation = $locationService->loadLocation($originalParentLocationId);
829
830
        // Returns an array with only $originalLocation
831
        $locations = $locationService->loadLocations(
832
            $originalLocation->contentInfo,
833
            $findRootLocation
834
        );
835
        /* END: Use Case */
836
837
        $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...
838
839
        return $locations;
840
    }
841
842
    /**
843
     * Test for the loadLocations() method.
844
     *
845
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $locations
846
     *
847
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
848
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationsLimitedSubtree
849
     */
850
    public function testLoadLocationsLimitedSubtreeContent(array $locations)
851
    {
852
        $this->assertEquals(1, count($locations));
853
854
        $this->assertEquals(
855
            $this->generateId('location', 54),
856
            reset($locations)->id
857
        );
858
    }
859
860
    /**
861
     * Test for the loadLocations() method.
862
     *
863
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
864
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
865
     * @expectedException \eZ\Publish\API\Repository\Exceptions\BadStateException
866
     */
867 View Code Duplication
    public function testLoadLocationsThrowsBadStateException()
868
    {
869
        $repository = $this->getRepository();
870
871
        /* BEGIN: Use Case */
872
        $contentTypeService = $repository->getContentTypeService();
873
        $contentService = $repository->getContentService();
874
        $locationService = $repository->getLocationService();
875
876
        // Create new content, which is not published
877
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
878
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
879
        $contentCreate->setField('name', 'New Folder');
880
        $content = $contentService->createContent($contentCreate);
881
882
        // Throws Exception, since $content has no published version, yet
883
        $locationService->loadLocations(
884
            $content->contentInfo
885
        );
886
        /* END: Use Case */
887
    }
888
889
    /**
890
     * Test for the loadLocations() method.
891
     *
892
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations($contentInfo, $rootLocation)
893
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
894
     * @expectedException \eZ\Publish\API\Repository\Exceptions\BadStateException
895
     */
896
    public function testLoadLocationsThrowsBadStateExceptionLimitedSubtree()
897
    {
898
        $repository = $this->getRepository();
899
900
        $someLocationId = $this->generateId('location', 2);
901
        /* BEGIN: Use Case */
902
        // $someLocationId is the ID of an existing location
903
        $contentTypeService = $repository->getContentTypeService();
904
        $contentService = $repository->getContentService();
905
        $locationService = $repository->getLocationService();
906
907
        // Create new content, which is not published
908
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
909
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
910
        $contentCreate->setField('name', 'New Folder');
911
        $content = $contentService->createContent($contentCreate);
912
913
        $findRootLocation = $locationService->loadLocation($someLocationId);
914
915
        // Throws Exception, since $content has no published version, yet
916
        $locationService->loadLocations(
917
            $content->contentInfo,
918
            $findRootLocation
919
        );
920
        /* END: Use Case */
921
    }
922
923
    /**
924
     * Test for the loadLocationChildren() method.
925
     *
926
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationChildren
927
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
928
     */
929
    public function testLoadLocationChildren()
930
    {
931
        $repository = $this->getRepository();
932
933
        $locationId = $this->generateId('location', 5);
934
        /* BEGIN: Use Case */
935
        // $locationId is the ID of an existing location
936
        $locationService = $repository->getLocationService();
937
938
        $location = $locationService->loadLocation($locationId);
939
940
        $childLocations = $locationService->loadLocationChildren($location);
941
        /* END: Use Case */
942
943
        $this->assertInstanceOf(LocationList::class, $childLocations);
944
        $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...
945
        $this->assertNotEmpty($childLocations->locations);
946
        $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...
947
948
        foreach ($childLocations->locations as $childLocation) {
949
            $this->assertInstanceOf(Location::class, $childLocation);
950
            $this->assertEquals($location->id, $childLocation->parentLocationId);
951
        }
952
953
        return $childLocations;
954
    }
955
956
    /**
957
     * Test loading parent Locations for draft Content.
958
     *
959
     * @covers \eZ\Publish\API\Repository\LocationService::loadParentLocationsForDraftContent
960
     */
961
    public function testLoadParentLocationsForDraftContent()
962
    {
963
        $repository = $this->getRepository();
964
        $locationService = $repository->getLocationService();
965
        $contentService = $repository->getContentService();
966
        $contentTypeService = $repository->getContentTypeService();
967
968
        // prepare locations
969
        $locationCreateStructs = [
970
            $locationService->newLocationCreateStruct(2),
971
            $locationService->newLocationCreateStruct(5),
972
        ];
973
974
        // Create new content
975
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
976
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
977
        $contentCreate->setField('name', 'New Folder');
978
        $contentDraft = $contentService->createContent($contentCreate, $locationCreateStructs);
979
980
        // Test loading parent Locations
981
        $locations = $locationService->loadParentLocationsForDraftContent($contentDraft->versionInfo);
982
983
        self::assertCount(2, $locations);
984
        foreach ($locations as $location) {
985
            // test it is one of the given parent locations
986
            self::assertTrue($location->id === 2 || $location->id === 5);
987
        }
988
989
        return $contentDraft;
990
    }
991
992
    /**
993
     * Test that trying to load parent Locations throws Exception if Content is not a draft.
994
     *
995
     * @depends testLoadParentLocationsForDraftContent
996
     *
997
     * @param \eZ\Publish\API\Repository\Values\Content\Content $contentDraft
998
     */
999
    public function testLoadParentLocationsForDraftContentThrowsBadStateException(Content $contentDraft)
1000
    {
1001
        $this->expectException(BadStateException::class);
1002
        $this->expectExceptionMessageRegExp('/has been already published/');
1003
1004
        $repository = $this->getRepository(false);
1005
        $locationService = $repository->getLocationService();
1006
        $contentService = $repository->getContentService();
1007
1008
        $content = $contentService->publishVersion($contentDraft->versionInfo);
1009
1010
        $locationService->loadParentLocationsForDraftContent($content->versionInfo);
1011
    }
1012
1013
    /**
1014
     * Test for the getLocationChildCount() method.
1015
     *
1016
     * @see \eZ\Publish\API\Repository\LocationService::getLocationChildCount()
1017
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1018
     */
1019
    public function testGetLocationChildCount()
1020
    {
1021
        // $locationId is the ID of an existing location
1022
        $locationService = $this->getRepository()->getLocationService();
1023
1024
        $this->assertSame(
1025
            5,
1026
            $locationService->getLocationChildCount(
1027
                $locationService->loadLocation($this->generateId('location', 5))
1028
            )
1029
        );
1030
    }
1031
1032
    /**
1033
     * Test for the loadLocationChildren() method.
1034
     *
1035
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren()
1036
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
1037
     */
1038
    public function testLoadLocationChildrenData(LocationList $locations)
1039
    {
1040
        $this->assertEquals(5, count($locations->locations));
1041
        $this->assertEquals(5, $locations->totalCount);
1042
1043
        foreach ($locations->locations as $location) {
1044
            $this->assertInstanceOf(
1045
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1046
                $location
1047
            );
1048
        }
1049
1050
        $this->assertEquals(
1051
            [
1052
                $this->generateId('location', 12),
1053
                $this->generateId('location', 13),
1054
                $this->generateId('location', 14),
1055
                $this->generateId('location', 44),
1056
                $this->generateId('location', 61),
1057
            ],
1058
            array_map(
1059
                function (Location $location) {
1060
                    return $location->id;
1061
                },
1062
                $locations->locations
1063
            )
1064
        );
1065
    }
1066
1067
    /**
1068
     * Test for the loadLocationChildren() method.
1069
     *
1070
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
1071
     *
1072
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset)
1073
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
1074
     */
1075 View Code Duplication
    public function testLoadLocationChildrenWithOffset()
1076
    {
1077
        $repository = $this->getRepository();
1078
1079
        $locationId = $this->generateId('location', 5);
1080
        /* BEGIN: Use Case */
1081
        // $locationId is the ID of an existing location
1082
        $locationService = $repository->getLocationService();
1083
1084
        $location = $locationService->loadLocation($locationId);
1085
1086
        $childLocations = $locationService->loadLocationChildren($location, 2);
1087
        /* END: Use Case */
1088
1089
        $this->assertInstanceOf('\\eZ\\Publish\\API\\Repository\\Values\\Content\\LocationList', $childLocations);
1090
        $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...
1091
        $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...
1092
1093
        return $childLocations;
1094
    }
1095
1096
    /**
1097
     * Test for the loadLocationChildren() method.
1098
     *
1099
     * @param \eZ\Publish\API\Repository\Values\Content\LocationList $locations
1100
     *
1101
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset)
1102
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildrenWithOffset
1103
     */
1104 View Code Duplication
    public function testLoadLocationChildrenDataWithOffset(LocationList $locations)
1105
    {
1106
        $this->assertEquals(3, count($locations->locations));
1107
        $this->assertEquals(5, $locations->totalCount);
1108
1109
        foreach ($locations->locations as $location) {
1110
            $this->assertInstanceOf(
1111
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1112
                $location
1113
            );
1114
        }
1115
1116
        $this->assertEquals(
1117
            [
1118
                $this->generateId('location', 14),
1119
                $this->generateId('location', 44),
1120
                $this->generateId('location', 61),
1121
            ],
1122
            array_map(
1123
                function (Location $location) {
1124
                    return $location->id;
1125
                },
1126
                $locations->locations
1127
            )
1128
        );
1129
    }
1130
1131
    /**
1132
     * Test for the loadLocationChildren() method.
1133
     *
1134
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
1135
     *
1136
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset, $limit)
1137
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
1138
     */
1139 View Code Duplication
    public function testLoadLocationChildrenWithOffsetAndLimit()
1140
    {
1141
        $repository = $this->getRepository();
1142
1143
        $locationId = $this->generateId('location', 5);
1144
        /* BEGIN: Use Case */
1145
        // $locationId is the ID of an existing location
1146
        $locationService = $repository->getLocationService();
1147
1148
        $location = $locationService->loadLocation($locationId);
1149
1150
        $childLocations = $locationService->loadLocationChildren($location, 2, 2);
1151
        /* END: Use Case */
1152
1153
        $this->assertInstanceOf('\\eZ\\Publish\\API\\Repository\\Values\\Content\\LocationList', $childLocations);
1154
        $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...
1155
        $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...
1156
1157
        return $childLocations;
1158
    }
1159
1160
    /**
1161
     * Test for the loadLocationChildren() method.
1162
     *
1163
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $locations
1164
     *
1165
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset, $limit)
1166
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildrenWithOffsetAndLimit
1167
     */
1168 View Code Duplication
    public function testLoadLocationChildrenDataWithOffsetAndLimit(LocationList $locations)
1169
    {
1170
        $this->assertEquals(2, count($locations->locations));
1171
        $this->assertEquals(5, $locations->totalCount);
1172
1173
        foreach ($locations->locations as $location) {
1174
            $this->assertInstanceOf(
1175
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1176
                $location
1177
            );
1178
        }
1179
1180
        $this->assertEquals(
1181
            [
1182
                $this->generateId('location', 14),
1183
                $this->generateId('location', 44),
1184
            ],
1185
            array_map(
1186
                function (Location $location) {
1187
                    return $location->id;
1188
                },
1189
                $locations->locations
1190
            )
1191
        );
1192
    }
1193
1194
    /**
1195
     * Test for the newLocationUpdateStruct() method.
1196
     *
1197
     * @covers \eZ\Publish\API\Repository\LocationService::newLocationUpdateStruct
1198
     */
1199 View Code Duplication
    public function testNewLocationUpdateStruct()
1200
    {
1201
        $repository = $this->getRepository();
1202
1203
        /* BEGIN: Use Case */
1204
        $locationService = $repository->getLocationService();
1205
1206
        $updateStruct = $locationService->newLocationUpdateStruct();
1207
        /* END: Use Case */
1208
1209
        $this->assertInstanceOf(
1210
            LocationUpdateStruct::class,
1211
            $updateStruct
1212
        );
1213
1214
        $this->assertPropertiesCorrect(
1215
            [
1216
                'priority' => null,
1217
                'remoteId' => null,
1218
                'sortField' => null,
1219
                'sortOrder' => null,
1220
            ],
1221
            $updateStruct
1222
        );
1223
    }
1224
1225
    /**
1226
     * Test for the updateLocation() method.
1227
     *
1228
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1229
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1230
     */
1231
    public function testUpdateLocation()
1232
    {
1233
        $repository = $this->getRepository();
1234
1235
        $originalLocationId = $this->generateId('location', 5);
1236
        /* BEGIN: Use Case */
1237
        // $originalLocationId is the ID of an existing location
1238
        $locationService = $repository->getLocationService();
1239
1240
        $originalLocation = $locationService->loadLocation($originalLocationId);
1241
1242
        $updateStruct = $locationService->newLocationUpdateStruct();
1243
        $updateStruct->priority = 3;
1244
        $updateStruct->remoteId = 'c7adcbf1e96bc29bca28c2d809d0c7ef69272651';
1245
        $updateStruct->sortField = Location::SORT_FIELD_PRIORITY;
1246
        $updateStruct->sortOrder = Location::SORT_ORDER_DESC;
1247
1248
        $updatedLocation = $locationService->updateLocation($originalLocation, $updateStruct);
1249
        /* END: Use Case */
1250
1251
        $this->assertInstanceOf(
1252
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1253
            $updatedLocation
1254
        );
1255
1256
        return [
1257
            'originalLocation' => $originalLocation,
1258
            'updateStruct' => $updateStruct,
1259
            'updatedLocation' => $updatedLocation,
1260
        ];
1261
    }
1262
1263
    /**
1264
     * Test for the updateLocation() method.
1265
     *
1266
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1267
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testUpdateLocation
1268
     */
1269
    public function testUpdateLocationStructValues(array $data)
1270
    {
1271
        $originalLocation = $data['originalLocation'];
1272
        $updateStruct = $data['updateStruct'];
1273
        $updatedLocation = $data['updatedLocation'];
1274
1275
        $this->assertPropertiesCorrect(
1276
            [
1277
                'id' => $originalLocation->id,
1278
                'priority' => $updateStruct->priority,
1279
                'hidden' => $originalLocation->hidden,
1280
                'invisible' => $originalLocation->invisible,
1281
                'remoteId' => $updateStruct->remoteId,
1282
                'contentInfo' => $originalLocation->contentInfo,
1283
                'parentLocationId' => $originalLocation->parentLocationId,
1284
                'pathString' => $originalLocation->pathString,
1285
                'depth' => $originalLocation->depth,
1286
                'sortField' => $updateStruct->sortField,
1287
                'sortOrder' => $updateStruct->sortOrder,
1288
            ],
1289
            $updatedLocation
1290
        );
1291
    }
1292
1293
    /**
1294
     * Test for the updateLocation() method.
1295
     *
1296
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1297
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1298
     */
1299
    public function testUpdateLocationWithSameRemoteId()
1300
    {
1301
        $repository = $this->getRepository();
1302
1303
        $locationId = $this->generateId('location', 5);
1304
        /* BEGIN: Use Case */
1305
        // $locationId and remote ID is the IDs of the same, existing location
1306
        $locationService = $repository->getLocationService();
1307
1308
        $originalLocation = $locationService->loadLocation($locationId);
1309
1310
        $updateStruct = $locationService->newLocationUpdateStruct();
1311
1312
        // Remote ID of an existing location with the same locationId
1313
        $updateStruct->remoteId = $originalLocation->remoteId;
1314
1315
        // Sets one of the properties to be able to confirm location gets updated, here: priority
1316
        $updateStruct->priority = 2;
1317
1318
        $location = $locationService->updateLocation($originalLocation, $updateStruct);
1319
1320
        // Checks that the location was updated
1321
        $this->assertEquals(2, $location->priority);
1322
1323
        // Checks that remoteId remains the same
1324
        $this->assertEquals($originalLocation->remoteId, $location->remoteId);
1325
        /* END: Use Case */
1326
    }
1327
1328
    /**
1329
     * Test for the updateLocation() method.
1330
     *
1331
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1332
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1333
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1334
     */
1335 View Code Duplication
    public function testUpdateLocationThrowsInvalidArgumentException()
1336
    {
1337
        $repository = $this->getRepository();
1338
1339
        $locationId = $this->generateId('location', 5);
1340
        /* BEGIN: Use Case */
1341
        // $locationId and remoteId is the IDs of an existing, but not the same, location
1342
        $locationService = $repository->getLocationService();
1343
1344
        $originalLocation = $locationService->loadLocation($locationId);
1345
1346
        $updateStruct = $locationService->newLocationUpdateStruct();
1347
1348
        // Remote ID of an existing location with a different locationId
1349
        $updateStruct->remoteId = 'f3e90596361e31d496d4026eb624c983';
1350
1351
        // Throws exception, since remote ID is already taken
1352
        $locationService->updateLocation($originalLocation, $updateStruct);
1353
        /* END: Use Case */
1354
    }
1355
1356
    /**
1357
     * Test for the updateLocation() method.
1358
     *
1359
     * @covers \eZ\Publish\API\Repository\LocationService::updateLocation()
1360
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1361
     * @dataProvider dataProviderForOutOfRangeLocationPriority
1362
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1363
     */
1364 View Code Duplication
    public function testUpdateLocationThrowsInvalidArgumentExceptionPriorityIsOutOfRange($priority)
1365
    {
1366
        $repository = $this->getRepository();
1367
1368
        $locationId = $this->generateId('location', 5);
1369
        /* BEGIN: Use Case */
1370
        // $locationId and remoteId is the IDs of an existing, but not the same, location
1371
        $locationService = $repository->getLocationService();
1372
1373
        $originalLocation = $locationService->loadLocation($locationId);
1374
1375
        $updateStruct = $locationService->newLocationUpdateStruct();
1376
1377
        // Priority value is out of range
1378
        $updateStruct->priority = $priority;
1379
1380
        // Throws exception, since remote ID is already taken
1381
        $locationService->updateLocation($originalLocation, $updateStruct);
1382
        /* END: Use Case */
1383
    }
1384
1385
    /**
1386
     * Test for the updateLocation() method.
1387
     * Ref EZP-23302: Update Location fails if no change is performed with the update.
1388
     *
1389
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1390
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1391
     */
1392
    public function testUpdateLocationTwice()
1393
    {
1394
        $repository = $this->getRepository();
1395
1396
        $locationId = $this->generateId('location', 5);
1397
        /* BEGIN: Use Case */
1398
        $locationService = $repository->getLocationService();
1399
        $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...
1400
1401
        $originalLocation = $locationService->loadLocation($locationId);
1402
1403
        $updateStruct = $locationService->newLocationUpdateStruct();
1404
        $updateStruct->priority = 42;
1405
1406
        $updatedLocation = $locationService->updateLocation($originalLocation, $updateStruct);
1407
1408
        // Repeated update with the same, unchanged struct
1409
        $secondUpdatedLocation = $locationService->updateLocation($updatedLocation, $updateStruct);
1410
        /* END: Use Case */
1411
1412
        $this->assertEquals($updatedLocation->priority, 42);
1413
        $this->assertEquals($secondUpdatedLocation->priority, 42);
1414
    }
1415
1416
    /**
1417
     * Test for the swapLocation() method.
1418
     *
1419
     * @see \eZ\Publish\API\Repository\LocationService::swapLocation()
1420
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1421
     */
1422
    public function testSwapLocation()
1423
    {
1424
        $repository = $this->getRepository();
1425
        $locationService = $repository->getLocationService();
1426
1427
        $mediaLocationId = $this->generateId('location', 43);
1428
        $demoDesignLocationId = $this->generateId('location', 56);
1429
1430
        $mediaContentInfo = $locationService->loadLocation($mediaLocationId)->getContentInfo();
1431
        $demoDesignContentInfo = $locationService->loadLocation($demoDesignLocationId)->getContentInfo();
1432
1433
        /* BEGIN: Use Case */
1434
        // $mediaLocationId is the ID of the "Media" page location in
1435
        // an eZ Publish demo installation
1436
1437
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
1438
        // Publish demo installation
1439
1440
        // Load the location service
1441
        $locationService = $repository->getLocationService();
1442
1443
        $mediaLocation = $locationService->loadLocation($mediaLocationId);
1444
        $demoDesignLocation = $locationService->loadLocation($demoDesignLocationId);
1445
1446
        // Swaps the content referred to by the locations
1447
        $locationService->swapLocation($mediaLocation, $demoDesignLocation);
1448
        /* END: Use Case */
1449
1450
        // Reload Locations, IDs swapped
1451
        $demoDesignLocation = $locationService->loadLocation($mediaLocationId);
1452
        $mediaLocation = $locationService->loadLocation($demoDesignLocationId);
1453
1454
        // Assert Location's Content is updated
1455
        $this->assertEquals(
1456
            $mediaContentInfo->id,
1457
            $mediaLocation->getContentInfo()->id
1458
        );
1459
        $this->assertEquals(
1460
            $demoDesignContentInfo->id,
1461
            $demoDesignLocation->getContentInfo()->id
1462
        );
1463
1464
        // Assert URL aliases are updated
1465
        $this->assertEquals(
1466
            $mediaLocation->id,
1467
            $repository->getURLAliasService()->lookup('/Design/Media')->destination
1468
        );
1469
        $this->assertEquals(
1470
            $demoDesignLocation->id,
1471
            $repository->getURLAliasService()->lookup('/eZ-Publish-Demo-Design-without-demo-content')->destination
1472
        );
1473
    }
1474
1475
    /**
1476
     * Test swapping secondary Location with main Location.
1477
     *
1478
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1479
     *
1480
     * @see https://jira.ez.no/browse/EZP-28663
1481
     *
1482
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
1483
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
1484
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
1485
     *
1486
     * @return int[]
1487
     */
1488
    public function testSwapLocationForMainAndSecondaryLocation(): array
1489
    {
1490
        $repository = $this->getRepository();
1491
        $locationService = $repository->getLocationService();
1492
        $contentService = $repository->getContentService();
1493
1494
        $folder1 = $this->createFolder(['eng-GB' => 'Folder1'], 2);
1495
        $folder2 = $this->createFolder(['eng-GB' => 'Folder2'], 2);
1496
        $folder3 = $this->createFolder(['eng-GB' => 'Folder3'], 2);
1497
1498
        $primaryLocation = $locationService->loadLocation($folder1->contentInfo->mainLocationId);
1499
        $parentLocation = $locationService->loadLocation($folder2->contentInfo->mainLocationId);
1500
        $secondaryLocation = $locationService->createLocation(
1501
            $folder1->contentInfo,
1502
            $locationService->newLocationCreateStruct($parentLocation->id)
1503
        );
1504
1505
        $targetLocation = $locationService->loadLocation($folder3->contentInfo->mainLocationId);
1506
1507
        // perform sanity checks
1508
        $this->assertContentHasExpectedLocations([$primaryLocation, $secondaryLocation], $folder1);
1509
1510
        // begin use case
1511
        $locationService->swapLocation($secondaryLocation, $targetLocation);
1512
1513
        // test results
1514
        $primaryLocation = $locationService->loadLocation($primaryLocation->id);
1515
        $secondaryLocation = $locationService->loadLocation($secondaryLocation->id);
1516
        $targetLocation = $locationService->loadLocation($targetLocation->id);
1517
1518
        self::assertEquals($folder1->id, $primaryLocation->contentInfo->id);
1519
        self::assertEquals($folder1->id, $targetLocation->contentInfo->id);
1520
        self::assertEquals($folder3->id, $secondaryLocation->contentInfo->id);
1521
1522
        $this->assertContentHasExpectedLocations([$primaryLocation, $targetLocation], $folder1);
1523
1524
        self::assertEquals(
1525
            $folder1,
1526
            $contentService->loadContent($folder1->id)
1527
        );
1528
1529
        self::assertEquals(
1530
            $folder2,
1531
            $contentService->loadContent($folder2->id)
1532
        );
1533
1534
        // only in case of Folder 3, main location id changed due to swap
1535
        self::assertEquals(
1536
            $secondaryLocation->id,
1537
            $contentService->loadContent($folder3->id)->contentInfo->mainLocationId
1538
        );
1539
1540
        return [$folder1, $folder2, $folder3];
1541
    }
1542
1543
    /**
1544
     * Compare Ids of expected and loaded Locations for the given Content.
1545
     *
1546
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $expectedLocations
1547
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1548
     *
1549
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
1550
     */
1551
    private function assertContentHasExpectedLocations(array $expectedLocations, Content $content)
1552
    {
1553
        $repository = $this->getRepository(false);
1554
        $locationService = $repository->getLocationService();
1555
1556
        $expectedLocationIds = array_map(
1557
            function (Location $location) {
1558
                return (int)$location->id;
1559
            },
1560
            $expectedLocations
1561
        );
1562
1563
        $actualLocationsIds = array_map(
1564
            function (Location $location) {
1565
                return $location->id;
1566
            },
1567
            $locationService->loadLocations($content->contentInfo)
1568
        );
1569
        self::assertCount(count($expectedLocations), $actualLocationsIds);
1570
1571
        // perform unordered equality assertion
1572
        self::assertEquals(
1573
            $expectedLocationIds,
1574
            $actualLocationsIds,
1575
            sprintf(
1576
                'Content %d contains Locations %s, but expected: %s',
1577
                $content->id,
1578
                implode(', ', $actualLocationsIds),
1579
                implode(', ', $expectedLocationIds)
1580
            ),
1581
            0.0,
1582
            10,
1583
            true
1584
        );
1585
    }
1586
1587
    /**
1588
     * @depends testSwapLocationForMainAndSecondaryLocation
1589
     *
1590
     * @param \eZ\Publish\API\Repository\Values\Content\Content[] $contentItems Content items created by testSwapLocationForSecondaryLocation
1591
     *
1592
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1593
     */
1594
    public function testSwapLocationDoesNotCorruptSearchResults(array $contentItems)
1595
    {
1596
        $repository = $this->getRepository(false);
1597
        $searchService = $repository->getSearchService();
1598
1599
        $this->refreshSearch($repository);
1600
1601
        $contentIds = array_map(
1602
            function (Content $content) {
1603
                return $content->id;
1604
            },
1605
            $contentItems
1606
        );
1607
1608
        $query = new Query();
1609
        $query->filter = new Query\Criterion\ContentId($contentIds);
1610
1611
        $searchResult = $searchService->findContent($query);
1612
1613
        self::assertEquals(count($contentItems), $searchResult->totalCount);
1614
        self::assertEquals(
1615
            $searchResult->totalCount,
1616
            count($searchResult->searchHits),
1617
            'Total count of search result hits does not match the actual number of found results'
1618
        );
1619
        $foundContentIds = array_map(
1620
            function (SearchHit $searchHit) {
1621
                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...
1622
            },
1623
            $searchResult->searchHits
1624
        );
1625
        sort($contentIds);
1626
        sort($foundContentIds);
1627
        self::assertSame(
1628
            $contentIds,
1629
            $foundContentIds,
1630
            'Got different than expected Content item Ids'
1631
        );
1632
    }
1633
1634
    /**
1635
     * Test swapping two secondary (non-main) Locations.
1636
     *
1637
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1638
     *
1639
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
1640
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1641
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
1642
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
1643
     */
1644
    public function testSwapLocationForSecondaryLocations()
1645
    {
1646
        $repository = $this->getRepository();
1647
        $locationService = $repository->getLocationService();
1648
        $contentService = $repository->getContentService();
1649
1650
        $folder1 = $this->createFolder(['eng-GB' => 'Folder1'], 2);
1651
        $folder2 = $this->createFolder(['eng-GB' => 'Folder2'], 2);
1652
        $parentFolder1 = $this->createFolder(['eng-GB' => 'Parent1'], 2);
1653
        $parentFolder2 = $this->createFolder(['eng-GB' => 'Parent2'], 2);
1654
1655
        $parentLocation1 = $locationService->loadLocation($parentFolder1->contentInfo->mainLocationId);
1656
        $parentLocation2 = $locationService->loadLocation($parentFolder2->contentInfo->mainLocationId);
1657
        $secondaryLocation1 = $locationService->createLocation(
1658
            $folder1->contentInfo,
1659
            $locationService->newLocationCreateStruct($parentLocation1->id)
1660
        );
1661
        $secondaryLocation2 = $locationService->createLocation(
1662
            $folder2->contentInfo,
1663
            $locationService->newLocationCreateStruct($parentLocation2->id)
1664
        );
1665
1666
        // begin use case
1667
        $locationService->swapLocation($secondaryLocation1, $secondaryLocation2);
1668
1669
        // test results
1670
        $secondaryLocation1 = $locationService->loadLocation($secondaryLocation1->id);
1671
        $secondaryLocation2 = $locationService->loadLocation($secondaryLocation2->id);
1672
1673
        self::assertEquals($folder2->id, $secondaryLocation1->contentInfo->id);
1674
        self::assertEquals($folder1->id, $secondaryLocation2->contentInfo->id);
1675
1676
        self::assertEquals(
1677
            $folder1,
1678
            $contentService->loadContent($folder1->id)
1679
        );
1680
1681
        self::assertEquals(
1682
            $folder2,
1683
            $contentService->loadContent($folder2->id)
1684
        );
1685
    }
1686
1687
    /**
1688
     * Test swapping Main Location of a Content with another one updates Content item Main Location.
1689
     *
1690
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1691
     */
1692
    public function testSwapLocationUpdatesMainLocation()
1693
    {
1694
        $repository = $this->getRepository();
1695
        $locationService = $repository->getLocationService();
1696
        $contentService = $repository->getContentService();
1697
1698
        $mainLocationParentId = 60;
1699
        $secondaryLocationId = 43;
1700
1701
        $publishedContent = $this->publishContentWithParentLocation(
1702
            'Content for Swap Location Test', $mainLocationParentId
1703
        );
1704
1705
        // sanity check
1706
        $mainLocation = $locationService->loadLocation($publishedContent->contentInfo->mainLocationId);
1707
        self::assertEquals($mainLocationParentId, $mainLocation->parentLocationId);
1708
1709
        // load another pre-existing location
1710
        $secondaryLocation = $locationService->loadLocation($secondaryLocationId);
1711
1712
        // swap the Main Location with a secondary one
1713
        $locationService->swapLocation($mainLocation, $secondaryLocation);
1714
1715
        // check if Main Location has been updated
1716
        $mainLocation = $locationService->loadLocation($secondaryLocation->id);
1717
        self::assertEquals($publishedContent->contentInfo->id, $mainLocation->contentInfo->id);
1718
        self::assertEquals($mainLocation->id, $mainLocation->contentInfo->mainLocationId);
1719
1720
        $reloadedContent = $contentService->loadContentByContentInfo($publishedContent->contentInfo);
1721
        self::assertEquals($mainLocation->id, $reloadedContent->contentInfo->mainLocationId);
1722
    }
1723
1724
    /**
1725
     * Test if location swap affects related bookmarks.
1726
     *
1727
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1728
     */
1729
    public function testBookmarksAreSwappedAfterSwapLocation()
1730
    {
1731
        $repository = $this->getRepository();
1732
1733
        $mediaLocationId = $this->generateId('location', 43);
1734
        $demoDesignLocationId = $this->generateId('location', 56);
1735
1736
        /* BEGIN: Use Case */
1737
        $locationService = $repository->getLocationService();
1738
        $bookmarkService = $repository->getBookmarkService();
1739
1740
        $mediaLocation = $locationService->loadLocation($mediaLocationId);
1741
        $demoDesignLocation = $locationService->loadLocation($demoDesignLocationId);
1742
1743
        // Bookmark locations
1744
        $bookmarkService->createBookmark($mediaLocation);
1745
        $bookmarkService->createBookmark($demoDesignLocation);
1746
1747
        $beforeSwap = $bookmarkService->loadBookmarks();
1748
1749
        // Swaps the content referred to by the locations
1750
        $locationService->swapLocation($mediaLocation, $demoDesignLocation);
1751
1752
        $afterSwap = $bookmarkService->loadBookmarks();
1753
        /* END: Use Case */
1754
1755
        $this->assertEquals($beforeSwap->items[0]->id, $afterSwap->items[1]->id);
1756
        $this->assertEquals($beforeSwap->items[1]->id, $afterSwap->items[0]->id);
1757
    }
1758
1759
    /**
1760
     * Test for the hideLocation() method.
1761
     *
1762
     * @see \eZ\Publish\API\Repository\LocationService::hideLocation()
1763
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1764
     */
1765
    public function testHideLocation()
1766
    {
1767
        $repository = $this->getRepository();
1768
1769
        $locationId = $this->generateId('location', 5);
1770
        /* BEGIN: Use Case */
1771
        // $locationId is the ID of an existing location
1772
        $locationService = $repository->getLocationService();
1773
1774
        $visibleLocation = $locationService->loadLocation($locationId);
1775
1776
        $hiddenLocation = $locationService->hideLocation($visibleLocation);
1777
        /* END: Use Case */
1778
1779
        $this->assertInstanceOf(
1780
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1781
            $hiddenLocation
1782
        );
1783
1784
        $this->assertTrue(
1785
            $hiddenLocation->hidden,
1786
            sprintf(
1787
                'Location with ID "%s" not hidden.',
1788
                $hiddenLocation->id
1789
            )
1790
        );
1791
1792
        $this->refreshSearch($repository);
1793
1794
        foreach ($locationService->loadLocationChildren($hiddenLocation)->locations as $child) {
1795
            $this->assertSubtreeProperties(
1796
                ['invisible' => true],
1797
                $child
1798
            );
1799
        }
1800
    }
1801
1802
    /**
1803
     * Assert that $expectedValues are set in the subtree starting at $location.
1804
     *
1805
     * @param array $expectedValues
1806
     * @param Location $location
1807
     */
1808
    protected function assertSubtreeProperties(array $expectedValues, Location $location, $stopId = null)
1809
    {
1810
        $repository = $this->getRepository();
1811
        $locationService = $repository->getLocationService();
1812
1813
        if ($location->id === $stopId) {
1814
            return;
1815
        }
1816
1817
        foreach ($expectedValues as $propertyName => $propertyValue) {
1818
            $this->assertEquals(
1819
                $propertyValue,
1820
                $location->$propertyName
1821
            );
1822
1823
            foreach ($locationService->loadLocationChildren($location)->locations as $child) {
1824
                $this->assertSubtreeProperties($expectedValues, $child);
1825
            }
1826
        }
1827
    }
1828
1829
    /**
1830
     * Test for the unhideLocation() method.
1831
     *
1832
     * @see \eZ\Publish\API\Repository\LocationService::unhideLocation()
1833
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testHideLocation
1834
     */
1835
    public function testUnhideLocation()
1836
    {
1837
        $repository = $this->getRepository();
1838
1839
        $locationId = $this->generateId('location', 5);
1840
        /* BEGIN: Use Case */
1841
        // $locationId is the ID of an existing location
1842
        $locationService = $repository->getLocationService();
1843
1844
        $visibleLocation = $locationService->loadLocation($locationId);
1845
        $hiddenLocation = $locationService->hideLocation($visibleLocation);
1846
1847
        $unHiddenLocation = $locationService->unhideLocation($hiddenLocation);
1848
        /* END: Use Case */
1849
1850
        $this->assertInstanceOf(
1851
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1852
            $unHiddenLocation
1853
        );
1854
1855
        $this->assertFalse(
1856
            $unHiddenLocation->hidden,
1857
            sprintf(
1858
                'Location with ID "%s" not unhidden.',
1859
                $unHiddenLocation->id
1860
            )
1861
        );
1862
1863
        $this->refreshSearch($repository);
1864
1865
        foreach ($locationService->loadLocationChildren($unHiddenLocation)->locations as $child) {
1866
            $this->assertSubtreeProperties(
1867
                ['invisible' => false],
1868
                $child
1869
            );
1870
        }
1871
    }
1872
1873
    /**
1874
     * Test for the unhideLocation() method.
1875
     *
1876
     * @see \eZ\Publish\API\Repository\LocationService::unhideLocation()
1877
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testUnhideLocation
1878
     */
1879
    public function testUnhideLocationNotUnhidesHiddenSubtree()
1880
    {
1881
        $repository = $this->getRepository();
1882
1883
        $higherLocationId = $this->generateId('location', 5);
1884
        $lowerLocationId = $this->generateId('location', 13);
1885
        /* BEGIN: Use Case */
1886
        // $higherLocationId is the ID of a location
1887
        // $lowerLocationId is the ID of a location below $higherLocationId
1888
        $locationService = $repository->getLocationService();
1889
1890
        $higherLocation = $locationService->loadLocation($higherLocationId);
1891
        $hiddenHigherLocation = $locationService->hideLocation($higherLocation);
1892
1893
        $lowerLocation = $locationService->loadLocation($lowerLocationId);
1894
        $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...
1895
1896
        $unHiddenHigherLocation = $locationService->unhideLocation($hiddenHigherLocation);
1897
        /* END: Use Case */
1898
1899
        $this->assertInstanceOf(
1900
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1901
            $unHiddenHigherLocation
1902
        );
1903
1904
        $this->assertFalse(
1905
            $unHiddenHigherLocation->hidden,
1906
            sprintf(
1907
                'Location with ID "%s" not unhidden.',
1908
                $unHiddenHigherLocation->id
1909
            )
1910
        );
1911
1912
        $this->refreshSearch($repository);
1913
1914
        foreach ($locationService->loadLocationChildren($unHiddenHigherLocation)->locations as $child) {
1915
            $this->assertSubtreeProperties(
1916
                ['invisible' => false],
1917
                $child,
1918
                $this->generateId('location', 13)
1919
            );
1920
        }
1921
1922
        $stillHiddenLocation = $locationService->loadLocation($this->generateId('location', 13));
1923
        $this->assertTrue(
1924
            $stillHiddenLocation->hidden,
1925
            sprintf(
1926
                'Hidden sub-location with ID %s accidentally unhidden.',
1927
                $stillHiddenLocation->id
1928
            )
1929
        );
1930
        foreach ($locationService->loadLocationChildren($stillHiddenLocation)->locations as $child) {
1931
            $this->assertSubtreeProperties(
1932
                ['invisible' => true],
1933
                $child
1934
            );
1935
        }
1936
    }
1937
1938
    /**
1939
     * Test for the deleteLocation() method.
1940
     *
1941
     * @see \eZ\Publish\API\Repository\LocationService::deleteLocation()
1942
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1943
     */
1944
    public function testDeleteLocation()
1945
    {
1946
        $repository = $this->getRepository();
1947
1948
        $mediaLocationId = $this->generateId('location', 43);
1949
        /* BEGIN: Use Case */
1950
        // $mediaLocationId is the ID of the location of the
1951
        // "Media" location in an eZ Publish demo installation
1952
        $locationService = $repository->getLocationService();
1953
1954
        $location = $locationService->loadLocation($mediaLocationId);
1955
1956
        $locationService->deleteLocation($location);
1957
        /* END: Use Case */
1958
1959
        try {
1960
            $locationService->loadLocation($mediaLocationId);
1961
            $this->fail("Location $mediaLocationId not deleted.");
1962
        } catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1963
        }
1964
1965
        // The following IDs are IDs of child locations of $mediaLocationId location
1966
        // ( Media/Images, Media/Files, Media/Multimedia respectively )
1967
        foreach ([51, 52, 53] as $childLocationId) {
1968
            try {
1969
                $locationService->loadLocation($this->generateId('location', $childLocationId));
1970
                $this->fail("Location $childLocationId not deleted.");
1971
            } catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1972
            }
1973
        }
1974
1975
        // The following IDs are IDs of content below $mediaLocationId location
1976
        // ( Media/Images, Media/Files, Media/Multimedia respectively )
1977
        $contentService = $this->getRepository()->getContentService();
1978
        foreach ([49, 50, 51] as $childContentId) {
1979
            try {
1980
                $contentService->loadContentInfo($this->generateId('object', $childContentId));
1981
                $this->fail("Content $childContentId not deleted.");
1982
            } catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
1983
            }
1984
        }
1985
    }
1986
1987
    /**
1988
     * Test for the deleteLocation() method.
1989
     *
1990
     * @see \eZ\Publish\API\Repository\LocationService::deleteLocation()
1991
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testDeleteLocation
1992
     */
1993
    public function testDeleteLocationDecrementsChildCountOnParent()
1994
    {
1995
        $repository = $this->getRepository();
1996
1997
        $mediaLocationId = $this->generateId('location', 43);
1998
        /* BEGIN: Use Case */
1999
        // $mediaLocationId is the ID of the location of the
2000
        // "Media" location in an eZ Publish demo installation
2001
2002
        $locationService = $repository->getLocationService();
2003
2004
        // Load the current the user group location
2005
        $location = $locationService->loadLocation($mediaLocationId);
2006
2007
        // Load the parent location
2008
        $parentLocation = $locationService->loadLocation(
2009
            $location->parentLocationId
2010
        );
2011
2012
        // Get child count
2013
        $childCountBefore = $locationService->getLocationChildCount($parentLocation);
2014
2015
        // Delete the user group location
2016
        $locationService->deleteLocation($location);
2017
2018
        $this->refreshSearch($repository);
2019
2020
        // Reload parent location
2021
        $parentLocation = $locationService->loadLocation(
2022
            $location->parentLocationId
2023
        );
2024
2025
        // This will be $childCountBefore - 1
2026
        $childCountAfter = $locationService->getLocationChildCount($parentLocation);
2027
        /* END: Use Case */
2028
2029
        $this->assertEquals($childCountBefore - 1, $childCountAfter);
2030
    }
2031
2032
    /**
2033
     * Test for the deleteLocation() method.
2034
     *
2035
     * Related issue: EZP-21904
2036
     *
2037
     * @see \eZ\Publish\API\Repository\LocationService::deleteLocation()
2038
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
2039
     */
2040
    public function testDeleteContentObjectLastLocation()
2041
    {
2042
        $repository = $this->getRepository();
2043
2044
        /* BEGIN: Use case */
2045
        $contentService = $repository->getContentService();
2046
        $locationService = $repository->getLocationService();
2047
        $contentTypeService = $repository->getContentTypeService();
2048
        $urlAliasService = $repository->getURLAliasService();
2049
2050
        // prepare Content object
2051
        $createStruct = $contentService->newContentCreateStruct(
2052
            $contentTypeService->loadContentTypeByIdentifier('folder'),
2053
            'eng-GB'
2054
        );
2055
        $createStruct->setField('name', 'Test folder');
2056
2057
        // creata Content object
2058
        $content = $contentService->publishVersion(
2059
            $contentService->createContent(
2060
                $createStruct,
2061
                [$locationService->newLocationCreateStruct(2)]
2062
            )->versionInfo
2063
        );
2064
2065
        // delete location
2066
        $locationService->deleteLocation(
2067
            $locationService->loadLocation(
2068
                $urlAliasService->lookup('/Test-folder')->destination
2069
            )
2070
        );
2071
2072
        // this should throw a not found exception
2073
        $contentService->loadContent($content->versionInfo->contentInfo->id);
2074
        /* END: Use case*/
2075
    }
2076
2077
    /**
2078
     * Test for the deleteLocation() method.
2079
     *
2080
     * @covers  \eZ\Publish\API\Repository\LocationService::deleteLocation()
2081
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testDeleteLocation
2082
     */
2083
    public function testDeleteLocationDeletesRelatedBookmarks()
2084
    {
2085
        $repository = $this->getRepository();
2086
2087
        $parentLocationId = $this->generateId('location', 43);
2088
        $childLocationId = $this->generateId('location', 53);
2089
2090
        /* BEGIN: Use Case */
2091
        $locationService = $repository->getLocationService();
2092
        $bookmarkService = $repository->getBookmarkService();
2093
2094
        // Load location
2095
        $childLocation = $locationService->loadLocation($childLocationId);
2096
        // Add location to bookmarks
2097
        $bookmarkService->createBookmark($childLocation);
2098
        // Load parent location
2099
        $parentLocation = $locationService->loadLocation($parentLocationId);
2100
        // Delete parent location
2101
        $locationService->deleteLocation($parentLocation);
2102
        /* END: Use Case */
2103
2104
        // Location isn't bookmarked anymore
2105
        foreach ($bookmarkService->loadBookmarks(0, 9999) as $bookmarkedLocation) {
2106
            $this->assertNotEquals($childLocation->id, $bookmarkedLocation->id);
2107
        }
2108
    }
2109
2110
    /**
2111
     * Test for the copySubtree() method.
2112
     *
2113
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2114
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2115
     */
2116
    public function testCopySubtree()
2117
    {
2118
        $repository = $this->getRepository();
2119
2120
        $mediaLocationId = $this->generateId('location', 43);
2121
        $demoDesignLocationId = $this->generateId('location', 56);
2122
        /* BEGIN: Use Case */
2123
        // $mediaLocationId is the ID of the "Media" page location in
2124
        // an eZ Publish demo installation
2125
2126
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2127
        // Publish demo installation
2128
2129
        // Load the location service
2130
        $locationService = $repository->getLocationService();
2131
2132
        // Load location to copy
2133
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2134
2135
        // Load new parent location
2136
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2137
2138
        // Copy location "Media" to "Demo Design"
2139
        $copiedLocation = $locationService->copySubtree(
2140
            $locationToCopy,
2141
            $newParentLocation
2142
        );
2143
        /* END: Use Case */
2144
2145
        $this->assertInstanceOf(
2146
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
2147
            $copiedLocation
2148
        );
2149
2150
        $this->assertPropertiesCorrect(
2151
            [
2152
                'depth' => $newParentLocation->depth + 1,
2153
                'parentLocationId' => $newParentLocation->id,
2154
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $copiedLocation->id) . '/',
2155
            ],
2156
            $copiedLocation
2157
        );
2158
2159
        $this->assertDefaultContentStates($copiedLocation->contentInfo);
2160
    }
2161
2162
    /**
2163
     * Test for the copySubtree() method.
2164
     *
2165
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2166
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2167
     */
2168
    public function testCopySubtreeWithAliases()
2169
    {
2170
        $repository = $this->getRepository();
2171
        $urlAliasService = $repository->getURLAliasService();
2172
2173
        // $mediaLocationId is the ID of the "Media" page location in
2174
        // an eZ Publish demo installation
2175
2176
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2177
        // Publish demo installation
2178
        $mediaLocationId = $this->generateId('location', 43);
2179
        $demoDesignLocationId = $this->generateId('location', 56);
2180
2181
        $locationService = $repository->getLocationService();
2182
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2183
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2184
2185
        $expectedSubItemAliases = [
2186
            '/Design/Plain-site/Media/Multimedia',
2187
            '/Design/Plain-site/Media/Images',
2188
            '/Design/Plain-site/Media/Files',
2189
        ];
2190
2191
        $this->assertAliasesBeforeCopy($urlAliasService, $expectedSubItemAliases);
2192
2193
        // Copy location "Media" to "Design"
2194
        $locationService->copySubtree(
2195
            $locationToCopy,
2196
            $newParentLocation
2197
        );
2198
2199
        $this->assertGeneratedAliases($urlAliasService, $expectedSubItemAliases);
2200
    }
2201
2202
    /**
2203
     * Asserts that given Content has default ContentStates.
2204
     *
2205
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
2206
     */
2207
    private function assertDefaultContentStates(ContentInfo $contentInfo)
2208
    {
2209
        $repository = $this->getRepository();
2210
        $objectStateService = $repository->getObjectStateService();
2211
2212
        $objectStateGroups = $objectStateService->loadObjectStateGroups();
2213
2214
        foreach ($objectStateGroups as $objectStateGroup) {
2215
            $contentState = $objectStateService->getContentState($contentInfo, $objectStateGroup);
2216
            foreach ($objectStateService->loadObjectStates($objectStateGroup) as $objectState) {
2217
                // Only check the first object state which is the default one.
2218
                $this->assertEquals(
2219
                    $objectState,
2220
                    $contentState
2221
                );
2222
                break;
2223
            }
2224
        }
2225
    }
2226
2227
    /**
2228
     * Test for the copySubtree() method.
2229
     *
2230
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2231
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCopySubtree
2232
     */
2233
    public function testCopySubtreeUpdatesSubtreeProperties()
2234
    {
2235
        $repository = $this->getRepository();
2236
        $locationService = $repository->getLocationService();
2237
2238
        $locationToCopy = $locationService->loadLocation($this->generateId('location', 43));
2239
2240
        // Load Subtree properties before copy
2241
        $expected = $this->loadSubtreeProperties($locationToCopy);
2242
2243
        $mediaLocationId = $this->generateId('location', 43);
2244
        $demoDesignLocationId = $this->generateId('location', 56);
2245
        /* BEGIN: Use Case */
2246
        // $mediaLocationId is the ID of the "Media" page location in
2247
        // an eZ Publish demo installation
2248
2249
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2250
        // Publish demo installation
2251
2252
        // Load the location service
2253
        $locationService = $repository->getLocationService();
2254
2255
        // Load location to copy
2256
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2257
2258
        // Load new parent location
2259
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2260
2261
        // Copy location "Media" to "Demo Design"
2262
        $copiedLocation = $locationService->copySubtree(
2263
            $locationToCopy,
2264
            $newParentLocation
2265
        );
2266
        /* END: Use Case */
2267
2268
        $beforeIds = [];
2269
        foreach ($expected as $properties) {
2270
            $beforeIds[] = $properties['id'];
2271
        }
2272
2273
        $this->refreshSearch($repository);
2274
2275
        // Load Subtree properties after copy
2276
        $actual = $this->loadSubtreeProperties($copiedLocation);
2277
2278
        $this->assertEquals(count($expected), count($actual));
2279
2280
        foreach ($actual as $properties) {
2281
            $this->assertNotContains($properties['id'], $beforeIds);
2282
            $this->assertStringStartsWith(
2283
                $newParentLocation->pathString . $this->parseId('location', $copiedLocation->id) . '/',
2284
                $properties['pathString']
2285
            );
2286
            $this->assertStringEndsWith(
2287
                '/' . $this->parseId('location', $properties['id']) . '/',
2288
                $properties['pathString']
2289
            );
2290
        }
2291
    }
2292
2293
    /**
2294
     * Test for the copySubtree() method.
2295
     *
2296
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2297
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCopySubtree
2298
     */
2299
    public function testCopySubtreeIncrementsChildCountOfNewParent()
2300
    {
2301
        $repository = $this->getRepository();
2302
        $locationService = $repository->getLocationService();
2303
2304
        $childCountBefore = $locationService->getLocationChildCount($locationService->loadLocation(56));
2305
2306
        $mediaLocationId = $this->generateId('location', 43);
2307
        $demoDesignLocationId = $this->generateId('location', 56);
2308
        /* BEGIN: Use Case */
2309
        // $mediaLocationId is the ID of the "Media" page location in
2310
        // an eZ Publish demo installation
2311
2312
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2313
        // Publish demo installation
2314
2315
        // Load the location service
2316
        $locationService = $repository->getLocationService();
2317
2318
        // Load location to copy
2319
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2320
2321
        // Load new parent location
2322
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2323
2324
        // Copy location "Media" to "Demo Design"
2325
        $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...
2326
            $locationToCopy,
2327
            $newParentLocation
2328
        );
2329
        /* END: Use Case */
2330
2331
        $this->refreshSearch($repository);
2332
2333
        $childCountAfter = $locationService->getLocationChildCount($locationService->loadLocation($demoDesignLocationId));
2334
2335
        $this->assertEquals($childCountBefore + 1, $childCountAfter);
2336
    }
2337
2338
    /**
2339
     * Test for the copySubtree() method.
2340
     *
2341
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2342
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
2343
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCopySubtree
2344
     */
2345 View Code Duplication
    public function testCopySubtreeThrowsInvalidArgumentException()
2346
    {
2347
        $repository = $this->getRepository();
2348
2349
        $communityLocationId = $this->generateId('location', 5);
2350
        /* BEGIN: Use Case */
2351
        // $communityLocationId is the ID of the "Community" page location in
2352
        // an eZ Publish demo installation
2353
2354
        // Load the location service
2355
        $locationService = $repository->getLocationService();
2356
2357
        // Load location to copy
2358
        $locationToCopy = $locationService->loadLocation($communityLocationId);
2359
2360
        // Use a child as new parent
2361
        $childLocations = $locationService->loadLocationChildren($locationToCopy)->locations;
2362
        $newParentLocation = end($childLocations);
2363
2364
        // This call will fail with an "InvalidArgumentException", because the
2365
        // new parent is a child location of the subtree to copy.
2366
        $locationService->copySubtree(
2367
            $locationToCopy,
2368
            $newParentLocation
0 ignored issues
show
Security Bug introduced by
It seems like $newParentLocation defined by end($childLocations) on line 2362 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...
2369
        );
2370
        /* END: Use Case */
2371
    }
2372
2373
    /**
2374
     * Test for the moveSubtree() method.
2375
     *
2376
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2377
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2378
     */
2379
    public function testMoveSubtree()
2380
    {
2381
        $repository = $this->getRepository();
2382
2383
        $mediaLocationId = $this->generateId('location', 43);
2384
        $demoDesignLocationId = $this->generateId('location', 56);
2385
        /* BEGIN: Use Case */
2386
        // $mediaLocationId is the ID of the "Media" page location in
2387
        // an eZ Publish demo installation
2388
2389
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2390
        // Publish demo installation
2391
2392
        // Load the location service
2393
        $locationService = $repository->getLocationService();
2394
2395
        // Load location to move
2396
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2397
2398
        // Load new parent location
2399
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2400
2401
        // Move location from "Home" to "Demo Design"
2402
        $locationService->moveSubtree(
2403
            $locationToMove,
2404
            $newParentLocation
2405
        );
2406
2407
        // Load moved location
2408
        $movedLocation = $locationService->loadLocation($mediaLocationId);
2409
        /* END: Use Case */
2410
2411
        $this->assertPropertiesCorrect(
2412
            [
2413
                'hidden' => false,
2414
                'invisible' => false,
2415
                'depth' => $newParentLocation->depth + 1,
2416
                'parentLocationId' => $newParentLocation->id,
2417
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $movedLocation->id) . '/',
2418
            ],
2419
            $movedLocation
2420
        );
2421
    }
2422
2423
    /**
2424
     * Test for the moveSubtree() method.
2425
     *
2426
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2427
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2428
     */
2429
    public function testMoveSubtreeHidden()
2430
    {
2431
        $repository = $this->getRepository();
2432
2433
        $mediaLocationId = $this->generateId('location', 43);
2434
        $demoDesignLocationId = $this->generateId('location', 56);
2435
        /* BEGIN: Use Case */
2436
        // $mediaLocationId is the ID of the "Media" page location in
2437
        // an eZ Publish demo installation
2438
2439
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2440
        // Publish demo installation
2441
2442
        // Load the location service
2443
        $locationService = $repository->getLocationService();
2444
2445
        // Load location to move
2446
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2447
2448
        // Load new parent location
2449
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2450
2451
        // Hide the target location before we move
2452
        $newParentLocation = $locationService->hideLocation($newParentLocation);
2453
2454
        // Move location from "Home" to "Demo Design"
2455
        $locationService->moveSubtree(
2456
            $locationToMove,
2457
            $newParentLocation
2458
        );
2459
2460
        // Load moved location
2461
        $movedLocation = $locationService->loadLocation($mediaLocationId);
2462
        /* END: Use Case */
2463
2464
        $this->assertPropertiesCorrect(
2465
            [
2466
                'hidden' => false,
2467
                'invisible' => true,
2468
                'depth' => $newParentLocation->depth + 1,
2469
                'parentLocationId' => $newParentLocation->id,
2470
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $movedLocation->id) . '/',
2471
            ],
2472
            $movedLocation
2473
        );
2474
    }
2475
2476
    /**
2477
     * Test for the moveSubtree() method.
2478
     *
2479
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2480
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2481
     */
2482
    public function testMoveSubtreeUpdatesSubtreeProperties()
2483
    {
2484
        $repository = $this->getRepository();
2485
        $locationService = $repository->getLocationService();
2486
2487
        $locationToMove = $locationService->loadLocation($this->generateId('location', 43));
2488
        $newParentLocation = $locationService->loadLocation($this->generateId('location', 56));
2489
2490
        // Load Subtree properties before move
2491
        $expected = $this->loadSubtreeProperties($locationToMove);
2492
        foreach ($expected as $id => $properties) {
2493
            $expected[$id]['depth'] = $properties['depth'] + 2;
2494
            $expected[$id]['pathString'] = str_replace(
2495
                $locationToMove->pathString,
2496
                $newParentLocation->pathString . $this->parseId('location', $locationToMove->id) . '/',
2497
                $properties['pathString']
2498
            );
2499
        }
2500
2501
        $mediaLocationId = $this->generateId('location', 43);
2502
        $demoDesignLocationId = $this->generateId('location', 56);
2503
        /* BEGIN: Use Case */
2504
        // $mediaLocationId is the ID of the "Media" page location in
2505
        // an eZ Publish demo installation
2506
2507
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2508
        // Publish demo installation
2509
2510
        // Load the location service
2511
        $locationService = $repository->getLocationService();
2512
2513
        // Load location to move
2514
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2515
2516
        // Load new parent location
2517
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2518
2519
        // Move location from "Home" to "Demo Design"
2520
        $locationService->moveSubtree(
2521
            $locationToMove,
2522
            $newParentLocation
2523
        );
2524
2525
        // Load moved location
2526
        $movedLocation = $locationService->loadLocation($mediaLocationId);
2527
        /* END: Use Case */
2528
2529
        $this->refreshSearch($repository);
2530
2531
        // Load Subtree properties after move
2532
        $actual = $this->loadSubtreeProperties($movedLocation);
2533
2534
        $this->assertEquals($expected, $actual);
2535
    }
2536
2537
    /**
2538
     * Test for the moveSubtree() method.
2539
     *
2540
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2541
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtreeUpdatesSubtreeProperties
2542
     */
2543
    public function testMoveSubtreeUpdatesSubtreePropertiesHidden()
2544
    {
2545
        $repository = $this->getRepository();
2546
        $locationService = $repository->getLocationService();
2547
2548
        $locationToMove = $locationService->loadLocation($this->generateId('location', 43));
2549
        $newParentLocation = $locationService->loadLocation($this->generateId('location', 56));
2550
2551
        // Hide the target location before we move
2552
        $newParentLocation = $locationService->hideLocation($newParentLocation);
2553
2554
        // Load Subtree properties before move
2555
        $expected = $this->loadSubtreeProperties($locationToMove);
2556
        foreach ($expected as $id => $properties) {
2557
            $expected[$id]['invisible'] = true;
2558
            $expected[$id]['depth'] = $properties['depth'] + 2;
2559
            $expected[$id]['pathString'] = str_replace(
2560
                $locationToMove->pathString,
2561
                $newParentLocation->pathString . $this->parseId('location', $locationToMove->id) . '/',
2562
                $properties['pathString']
2563
            );
2564
        }
2565
2566
        $mediaLocationId = $this->generateId('location', 43);
2567
        $demoDesignLocationId = $this->generateId('location', 56);
2568
        /* BEGIN: Use Case */
2569
        // $mediaLocationId is the ID of the "Media" page location in
2570
        // an eZ Publish demo installation
2571
2572
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2573
        // Publish demo installation
2574
2575
        // Load the location service
2576
        $locationService = $repository->getLocationService();
2577
2578
        // Load location to move
2579
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2580
2581
        // Load new parent location
2582
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2583
2584
        // Move location from "Home" to "Demo Design"
2585
        $locationService->moveSubtree(
2586
            $locationToMove,
2587
            $newParentLocation
2588
        );
2589
2590
        // Load moved location
2591
        $movedLocation = $locationService->loadLocation($mediaLocationId);
2592
        /* END: Use Case */
2593
2594
        $this->refreshSearch($repository);
2595
2596
        // Load Subtree properties after move
2597
        $actual = $this->loadSubtreeProperties($movedLocation);
2598
2599
        $this->assertEquals($expected, $actual);
2600
    }
2601
2602
    /**
2603
     * Test for the moveSubtree() method.
2604
     *
2605
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2606
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2607
     */
2608 View Code Duplication
    public function testMoveSubtreeIncrementsChildCountOfNewParent()
2609
    {
2610
        $repository = $this->getRepository();
2611
        $locationService = $repository->getLocationService();
2612
2613
        $newParentLocation = $locationService->loadLocation($this->generateId('location', 56));
2614
2615
        // Load expected properties before move
2616
        $expected = $this->loadLocationProperties($newParentLocation);
2617
        $childCountBefore = $locationService->getLocationChildCount($newParentLocation);
2618
2619
        $mediaLocationId = $this->generateId('location', 43);
2620
        $demoDesignLocationId = $this->generateId('location', 56);
2621
        /* BEGIN: Use Case */
2622
        // $mediaLocationId is the ID of the "Media" page location in
2623
        // an eZ Publish demo installation
2624
2625
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2626
        // Publish demo installation
2627
2628
        // Load the location service
2629
        $locationService = $repository->getLocationService();
2630
2631
        // Load location to move
2632
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2633
2634
        // Load new parent location
2635
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2636
2637
        // Move location from "Home" to "Demo Design"
2638
        $locationService->moveSubtree(
2639
            $locationToMove,
2640
            $newParentLocation
2641
        );
2642
2643
        // Load moved location
2644
        $movedLocation = $locationService->loadLocation($mediaLocationId);
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...
2645
2646
        // Reload new parent location
2647
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2648
        /* END: Use Case */
2649
2650
        $this->refreshSearch($repository);
2651
2652
        // Load Subtree properties after move
2653
        $actual = $this->loadLocationProperties($newParentLocation);
2654
        $childCountAfter = $locationService->getLocationChildCount($newParentLocation);
2655
2656
        $this->assertEquals($expected, $actual);
2657
        $this->assertEquals($childCountBefore + 1, $childCountAfter);
2658
    }
2659
2660
    /**
2661
     * Test for the moveSubtree() method.
2662
     *
2663
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2664
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2665
     */
2666 View Code Duplication
    public function testMoveSubtreeDecrementsChildCountOfOldParent()
2667
    {
2668
        $repository = $this->getRepository();
2669
        $locationService = $repository->getLocationService();
2670
2671
        $oldParentLocation = $locationService->loadLocation($this->generateId('location', 1));
2672
2673
        // Load expected properties before move
2674
        $expected = $this->loadLocationProperties($oldParentLocation);
2675
        $childCountBefore = $locationService->getLocationChildCount($oldParentLocation);
2676
2677
        $mediaLocationId = $this->generateId('location', 43);
2678
        $demoDesignLocationId = $this->generateId('location', 56);
2679
        /* BEGIN: Use Case */
2680
        // $mediaLocationId is the ID of the "Media" page location in
2681
        // an eZ Publish demo installation
2682
2683
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2684
        // Publish demo installation
2685
2686
        // Load the location service
2687
        $locationService = $repository->getLocationService();
2688
2689
        // Load location to move
2690
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2691
2692
        // Get the location id of the old parent
2693
        $oldParentLocationId = $locationToMove->parentLocationId;
2694
2695
        // Load new parent location
2696
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2697
2698
        // Move location from "Home" to "Demo Design"
2699
        $locationService->moveSubtree(
2700
            $locationToMove,
2701
            $newParentLocation
2702
        );
2703
2704
        // Reload old parent location
2705
        $oldParentLocation = $locationService->loadLocation($oldParentLocationId);
2706
        /* END: Use Case */
2707
2708
        $this->refreshSearch($repository);
2709
2710
        // Load Subtree properties after move
2711
        $actual = $this->loadLocationProperties($oldParentLocation);
2712
        $childCountAfter = $locationService->getLocationChildCount($oldParentLocation);
2713
2714
        $this->assertEquals($expected, $actual);
2715
        $this->assertEquals($childCountBefore - 1, $childCountAfter);
2716
    }
2717
2718
    /**
2719
     * Test moving invisible (hidden by parent) subtree.
2720
     *
2721
     * @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
2722
     *
2723
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
2724
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
2725
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
2726
     */
2727
    public function testMoveInvisibleSubtree()
2728
    {
2729
        $repository = $this->getRepository();
2730
        $locationService = $repository->getLocationService();
2731
2732
        $rootLocationId = 2;
2733
2734
        $folder = $this->createFolder(['eng-GB' => 'Folder'], $rootLocationId);
2735
        $child = $this->createFolder(['eng-GB' => 'Child'], $folder->contentInfo->mainLocationId);
2736
        $locationService->hideLocation(
2737
            $locationService->loadLocation($folder->contentInfo->mainLocationId)
2738
        );
2739
        // sanity check
2740
        $childLocation = $locationService->loadLocation($child->contentInfo->mainLocationId);
2741
        self::assertFalse($childLocation->hidden);
2742
        self::assertTrue($childLocation->invisible);
2743
        self::assertEquals($folder->contentInfo->mainLocationId, $childLocation->parentLocationId);
2744
2745
        $destination = $this->createFolder(['eng-GB' => 'Destination'], $rootLocationId);
2746
        $destinationLocation = $locationService->loadLocation(
2747
            $destination->contentInfo->mainLocationId
2748
        );
2749
2750
        $locationService->moveSubtree($childLocation, $destinationLocation);
2751
2752
        $childLocation = $locationService->loadLocation($child->contentInfo->mainLocationId);
2753
        // Business logic - Location moved to visible parent becomes visible
2754
        self::assertFalse($childLocation->hidden);
2755
        self::assertFalse($childLocation->invisible);
2756
        self::assertEquals($destinationLocation->id, $childLocation->parentLocationId);
2757
    }
2758
2759
    /**
2760
     * Test for the moveSubtree() method.
2761
     *
2762
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2763
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
2764
     */
2765 View Code Duplication
    public function testMoveSubtreeThrowsInvalidArgumentException()
2766
    {
2767
        $repository = $this->getRepository();
2768
        $mediaLocationId = $this->generateId('location', 43);
2769
        $multimediaLocationId = $this->generateId('location', 53);
2770
2771
        /* BEGIN: Use Case */
2772
        // $mediaLocationId is the ID of the "Media" page location in
2773
        // an eZ Publish demo installation
2774
2775
        // $multimediaLocationId is the ID of the "Multimedia" page location in an eZ
2776
        // Publish demo installation
2777
2778
        // Load the location service
2779
        $locationService = $repository->getLocationService();
2780
2781
        // Load location to move
2782
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2783
2784
        // Load new parent location
2785
        $newParentLocation = $locationService->loadLocation($multimediaLocationId);
2786
2787
        // Throws an exception because new parent location is placed below location to move
2788
        $locationService->moveSubtree(
2789
            $locationToMove,
2790
            $newParentLocation
2791
        );
2792
        /* END: Use Case */
2793
    }
2794
2795
    /**
2796
     * Test that Legacy ezcontentobject_tree.path_identification_string field is correctly updated
2797
     * after moving subtree.
2798
     *
2799
     * @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
2800
     *
2801
     * @throws \ErrorException
2802
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
2803
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
2804
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
2805
     */
2806
    public function testMoveSubtreeUpdatesPathIdentificationString(): void
2807
    {
2808
        $repository = $this->getRepository();
2809
        $locationService = $repository->getLocationService();
2810
2811
        $topNode = $this->createFolder(['eng-US' => 'top_node'], 2);
2812
2813
        $newParentLocation = $locationService->loadLocation(
2814
            $this
2815
                ->createFolder(['eng-US' => 'Parent'], $topNode->contentInfo->mainLocationId)
2816
                ->contentInfo
2817
                ->mainLocationId
2818
        );
2819
        $location = $locationService->loadLocation(
2820
            $this
2821
                ->createFolder(['eng-US' => 'Move Me'], $topNode->contentInfo->mainLocationId)
2822
                ->contentInfo
2823
                ->mainLocationId
2824
        );
2825
2826
        $locationService->moveSubtree($location, $newParentLocation);
2827
2828
        // path location string is not present on API level, so we need to query database
2829
        $serviceContainer = $this->getSetupFactory()->getServiceContainer();
2830
        /** @var \Doctrine\DBAL\Connection $connection */
2831
        $connection = $serviceContainer->get('ezpublish.persistence.connection');
2832
        $query = $connection->createQueryBuilder();
2833
        $query
2834
            ->select('path_identification_string')
2835
            ->from('ezcontentobject_tree')
2836
            ->where('node_id = :nodeId')
2837
            ->setParameter('nodeId', $location->id);
2838
2839
        self::assertEquals(
2840
            'top_node/parent/move_me',
2841
            $query->execute()->fetchColumn()
2842
        );
2843
    }
2844
2845
    /**
2846
     * Loads properties from all locations in the $location's subtree.
2847
     *
2848
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
2849
     * @param array $properties
2850
     *
2851
     * @return array
2852
     */
2853
    private function loadSubtreeProperties(Location $location, array $properties = [])
2854
    {
2855
        $locationService = $this->getRepository()->getLocationService();
2856
2857
        foreach ($locationService->loadLocationChildren($location)->locations as $childLocation) {
2858
            $properties[] = $this->loadLocationProperties($childLocation);
2859
2860
            $properties = $this->loadSubtreeProperties($childLocation, $properties);
2861
        }
2862
2863
        return $properties;
2864
    }
2865
2866
    /**
2867
     * Loads assertable properties from the given location.
2868
     *
2869
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
2870
     * @param mixed[] $overwrite
2871
     *
2872
     * @return array
2873
     */
2874 View Code Duplication
    private function loadLocationProperties(Location $location, array $overwrite = [])
2875
    {
2876
        return array_merge(
2877
            [
2878
                'id' => $location->id,
2879
                'depth' => $location->depth,
2880
                'parentLocationId' => $location->parentLocationId,
2881
                'pathString' => $location->pathString,
2882
                'remoteId' => $location->remoteId,
2883
                'hidden' => $location->hidden,
2884
                'invisible' => $location->invisible,
2885
                'priority' => $location->priority,
2886
                'sortField' => $location->sortField,
2887
                'sortOrder' => $location->sortOrder,
2888
            ],
2889
            $overwrite
2890
        );
2891
    }
2892
2893
    /**
2894
     * Assert generated aliases to expected alias return.
2895
     *
2896
     * @param \eZ\Publish\API\Repository\URLAliasService $urlAliasService
2897
     * @param array $expectedAliases
2898
     */
2899
    protected function assertGeneratedAliases($urlAliasService, array $expectedAliases)
2900
    {
2901
        foreach ($expectedAliases as $expectedAlias) {
2902
            $urlAlias = $urlAliasService->lookup($expectedAlias);
2903
            $this->assertPropertiesCorrect(['type' => 0], $urlAlias);
2904
        }
2905
    }
2906
2907
    /**
2908
     * @param \eZ\Publish\API\Repository\URLAliasService $urlAliasService
2909
     * @param array $expectedSubItemAliases
2910
     */
2911
    private function assertAliasesBeforeCopy($urlAliasService, array $expectedSubItemAliases)
2912
    {
2913
        foreach ($expectedSubItemAliases as $aliasUrl) {
2914
            try {
2915
                $urlAliasService->lookup($aliasUrl);
2916
                $this->fail('We didn\'t expect to find alias, but it was found');
2917
            } catch (\Exception $e) {
2918
                $this->assertTrue(true); // OK - alias was not found
2919
            }
2920
        }
2921
    }
2922
2923
    /**
2924
     * Create and publish Content with the given parent Location.
2925
     *
2926
     * @param string $contentName
2927
     * @param int $parentLocationId
2928
     *
2929
     * @return \eZ\Publish\API\Repository\Values\Content\Content published Content
2930
     */
2931 View Code Duplication
    private function publishContentWithParentLocation($contentName, $parentLocationId)
2932
    {
2933
        $repository = $this->getRepository(false);
2934
        $locationService = $repository->getLocationService();
2935
2936
        $contentService = $repository->getContentService();
2937
        $contentTypeService = $repository->getContentTypeService();
2938
2939
        $contentCreateStruct = $contentService->newContentCreateStruct(
2940
            $contentTypeService->loadContentTypeByIdentifier('folder'),
2941
            'eng-US'
2942
        );
2943
        $contentCreateStruct->setField('name', $contentName);
2944
        $contentDraft = $contentService->createContent(
2945
            $contentCreateStruct,
2946
            [
2947
                $locationService->newLocationCreateStruct($parentLocationId),
2948
            ]
2949
        );
2950
2951
        return $contentService->publishVersion($contentDraft->versionInfo);
2952
    }
2953
}
2954