Completed
Push — master ( ace5fb...9c2de1 )
by
unknown
20:35 queued 07:41
created

testSwapLocationForContentWithCustomUrlAliases()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

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