testMoveSubtreeDecrementsChildCountOfOldParent()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 51

Duplication

Lines 51
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 51
loc 51
rs 9.069
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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