Completed
Push — EZP-31681 ( e05106...aae569 )
by
unknown
17:43
created

testCreateLocationChecksContentVisibility()   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
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
5
 * @license For full copyright and license information view LICENSE file distributed with this source code.
6
 */
7
namespace eZ\Publish\API\Repository\Tests;
8
9
use Exception;
10
use eZ\Publish\API\Repository\Exceptions\BadStateException;
11
use eZ\Publish\API\Repository\Exceptions\InvalidArgumentException;
12
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
13
use eZ\Publish\API\Repository\URLAliasService as URLAliasServiceInterface;
14
use eZ\Publish\API\Repository\Values\Content\Content;
15
use eZ\Publish\API\Repository\Values\Content\ContentCreateStruct;
16
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
17
use eZ\Publish\API\Repository\Values\Content\Location;
18
use eZ\Publish\API\Repository\Values\Content\LocationCreateStruct;
19
use eZ\Publish\API\Repository\Values\Content\LocationList;
20
use eZ\Publish\API\Repository\Values\Content\LocationUpdateStruct;
21
use eZ\Publish\API\Repository\Values\Content\Query;
22
use eZ\Publish\API\Repository\Values\Content\Search\SearchHit;
23
use eZ\Publish\API\Repository\Values\Content\URLAlias;
24
25
/**
26
 * Test case for operations in the LocationService using in memory storage.
27
 *
28
 * @see eZ\Publish\API\Repository\LocationService
29
 * @group location
30
 */
31
class LocationServiceTest extends BaseTest
32
{
33
    /**
34
     * Test for the newLocationCreateStruct() method.
35
     *
36
     * @return \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct
37
     *
38
     * @see \eZ\Publish\API\Repository\LocationService::newLocationCreateStruct()
39
     */
40
    public function testNewLocationCreateStruct()
41
    {
42
        $repository = $this->getRepository();
43
44
        $parentLocationId = $this->generateId('location', 1);
45
        /* BEGIN: Use Case */
46
        // $parentLocationId is the ID of an existing location
47
        $locationService = $repository->getLocationService();
48
49
        $locationCreate = $locationService->newLocationCreateStruct(
50
            $parentLocationId
51
        );
52
        /* END: Use Case */
53
54
        $this->assertInstanceOf(
55
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\LocationCreateStruct',
56
            $locationCreate
57
        );
58
59
        return $locationCreate;
60
    }
61
62
    /**
63
     * Test for the newLocationCreateStruct() method.
64
     *
65
     * @param \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct $locationCreate
66
     *
67
     * @see \eZ\Publish\API\Repository\LocationService::newLocationCreateStruct()
68
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
69
     */
70
    public function testNewLocationCreateStructValues(LocationCreateStruct $locationCreate)
71
    {
72
        $this->assertPropertiesCorrect(
73
            [
74
                'priority' => 0,
75
                'hidden' => false,
76
                // remoteId should be initialized with a default value
77
                //'remoteId' => null,
78
                'sortField' => null,
79
                'sortOrder' => null,
80
                'parentLocationId' => $this->generateId('location', 1),
81
            ],
82
            $locationCreate
83
        );
84
    }
85
86
    /**
87
     * Test for the createLocation() method.
88
     *
89
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
90
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
91
     */
92
    public function testCreateLocation()
93
    {
94
        $repository = $this->getRepository();
95
96
        $contentId = $this->generateId('object', 41);
97
        $parentLocationId = $this->generateId('location', 5);
98
        /* BEGIN: Use Case */
99
        // $contentId is the ID of an existing content object
100
        // $parentLocationId is the ID of an existing location
101
        $contentService = $repository->getContentService();
102
        $locationService = $repository->getLocationService();
103
104
        // ContentInfo for "How to use eZ Publish"
105
        $contentInfo = $contentService->loadContentInfo($contentId);
106
107
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
108
        $locationCreate->priority = 23;
109
        $locationCreate->hidden = true;
110
        $locationCreate->remoteId = 'sindelfingen';
111
        $locationCreate->sortField = Location::SORT_FIELD_NODE_ID;
112
        $locationCreate->sortOrder = Location::SORT_ORDER_DESC;
113
114
        $location = $locationService->createLocation(
115
            $contentInfo,
116
            $locationCreate
117
        );
118
        /* END: Use Case */
119
120
        $this->assertInstanceOf(
121
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
122
            $location
123
        );
124
125
        return [
126
            'locationCreate' => $locationCreate,
127
            'createdLocation' => $location,
128
            'contentInfo' => $contentInfo,
129
            'parentLocation' => $locationService->loadLocation($this->generateId('location', 5)),
130
        ];
131
    }
132
133
    /**
134
     * Test for the createLocation() method.
135
     *
136
     * @covers \eZ\Publish\API\Repository\LocationService::createLocation
137
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
138
     * @depends eZ\Publish\API\Repository\Tests\ContentServiceTest::testHideContent
139
     */
140
    public function testCreateLocationChecksContentVisibility(): void
141
    {
142
        $repository = $this->getRepository();
143
144
        $contentId = $this->generateId('object', 41);
145
        $parentLocationId = $this->generateId('location', 5);
146
        /* BEGIN: Use Case */
147
        // $contentId is the ID of an existing content object
148
        // $parentLocationId is the ID of an existing location
149
        $contentService = $repository->getContentService();
150
        $locationService = $repository->getLocationService();
151
152
        // ContentInfo for "How to use eZ Publish"
153
        $contentInfo = $contentService->loadContentInfo($contentId);
154
        $contentService->hideContent($contentInfo);
155
156
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
157
        $locationCreate->priority = 23;
158
        $locationCreate->hidden = false;
159
        $locationCreate->remoteId = 'sindelfingen';
160
        $locationCreate->sortField = Location::SORT_FIELD_NODE_ID;
161
        $locationCreate->sortOrder = Location::SORT_ORDER_DESC;
162
163
        $location = $locationService->createLocation(
164
            $contentInfo,
165
            $locationCreate
166
        );
167
        /* END: Use Case */
168
169
        self::assertInstanceOf(Location::class, $location);
170
171
        self::assertTrue($location->invisible);
172
    }
173
174
    /**
175
     * Test for the createLocation() method with utilizing default ContentType sorting options.
176
     *
177
     * @covers \eZ\Publish\API\Repository\LocationService::createLocation
178
     */
179
    public function testCreateLocationWithContentTypeSortingOptions(): void
180
    {
181
        $repository = $this->getRepository();
182
183
        $contentId = $this->generateId('object', 41);
184
        $parentLocationId = $this->generateId('location', 5);
185
        // $contentId is the ID of an existing content object
186
        // $parentLocationId is the ID of an existing location
187
        $contentService = $repository->getContentService();
188
        $contentTypeService = $repository->getContentTypeService();
189
        $locationService = $repository->getLocationService();
190
191
        // ContentInfo for "How to use eZ Publish"
192
        $contentInfo = $contentService->loadContentInfo($contentId);
193
194
        // ContentType loading
195
        $contentType = $contentTypeService->loadContentType($contentInfo->contentTypeId);
196
197
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
198
        $locationCreate->priority = 23;
199
        $locationCreate->hidden = true;
200
        $locationCreate->remoteId = 'sindelfingen';
201
202
        $location = $locationService->createLocation(
203
            $contentInfo,
204
            $locationCreate
205
        );
206
207
        $this->assertEquals($contentType->defaultSortField, $location->sortField);
208
        $this->assertEquals($contentType->defaultSortOrder, $location->sortOrder);
209
    }
210
211
    /**
212
     * Test for the createLocation() method.
213
     *
214
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
215
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
216
     */
217
    public function testCreateLocationStructValues(array $data)
218
    {
219
        $locationCreate = $data['locationCreate'];
220
        $createdLocation = $data['createdLocation'];
221
        $contentInfo = $data['contentInfo'];
222
223
        $this->assertPropertiesCorrect(
224
            [
225
                'priority' => $locationCreate->priority,
226
                'hidden' => $locationCreate->hidden,
227
                'invisible' => $locationCreate->hidden,
228
                'remoteId' => $locationCreate->remoteId,
229
                'contentInfo' => $contentInfo,
230
                'parentLocationId' => $locationCreate->parentLocationId,
231
                'pathString' => '/1/5/' . $this->parseId('location', $createdLocation->id) . '/',
232
                'depth' => 2,
233
                'sortField' => $locationCreate->sortField,
234
                'sortOrder' => $locationCreate->sortOrder,
235
            ],
236
            $createdLocation
237
        );
238
239
        $this->assertNotNull($createdLocation->id);
240
    }
241
242
    /**
243
     * Test for the createLocation() method.
244
     *
245
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
246
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
247
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
248
     */
249 View Code Duplication
    public function testCreateLocationThrowsInvalidArgumentExceptionContentAlreadyBelowParent()
250
    {
251
        $repository = $this->getRepository();
252
253
        $contentId = $this->generateId('object', 11);
254
        $parentLocationId = $this->generateId('location', 5);
255
        /* BEGIN: Use Case */
256
        // $contentId is the ID of an existing content object
257
        // $parentLocationId is the ID of an existing location which already
258
        // has the content assigned to one of its descendant locations
259
        $contentService = $repository->getContentService();
260
        $locationService = $repository->getLocationService();
261
262
        // ContentInfo for "How to use eZ Publish"
263
        $contentInfo = $contentService->loadContentInfo($contentId);
264
265
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
266
267
        // Throws exception, since content is already located at "/1/2/107/110/"
268
        $locationService->createLocation(
269
            $contentInfo,
270
            $locationCreate
271
        );
272
        /* END: Use Case */
273
    }
274
275
    /**
276
     * Test for the createLocation() method.
277
     *
278
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
279
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
280
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
281
     */
282 View Code Duplication
    public function testCreateLocationThrowsInvalidArgumentExceptionParentIsSubLocationOfContent()
283
    {
284
        $repository = $this->getRepository();
285
286
        $contentId = $this->generateId('object', 4);
287
        $parentLocationId = $this->generateId('location', 12);
288
        /* BEGIN: Use Case */
289
        // $contentId is the ID of an existing content object
290
        // $parentLocationId is the ID of an existing location which is below a
291
        // location that is assigned to the content
292
        $contentService = $repository->getContentService();
293
        $locationService = $repository->getLocationService();
294
295
        // ContentInfo for "How to use eZ Publish"
296
        $contentInfo = $contentService->loadContentInfo($contentId);
297
298
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
299
300
        // Throws exception, since content is already located at "/1/2/"
301
        $locationService->createLocation(
302
            $contentInfo,
303
            $locationCreate
304
        );
305
        /* END: Use Case */
306
    }
307
308
    /**
309
     * Test for the createLocation() method.
310
     *
311
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
312
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
313
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
314
     */
315 View Code Duplication
    public function testCreateLocationThrowsInvalidArgumentExceptionRemoteIdExists()
316
    {
317
        $repository = $this->getRepository();
318
319
        $contentId = $this->generateId('object', 41);
320
        $parentLocationId = $this->generateId('location', 5);
321
        /* BEGIN: Use Case */
322
        // $contentId is the ID of an existing content object
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
        // This remote ID already exists
331
        $locationCreate->remoteId = 'f3e90596361e31d496d4026eb624c983';
332
333
        // Throws exception, since remote ID is already in use
334
        $locationService->createLocation(
335
            $contentInfo,
336
            $locationCreate
337
        );
338
        /* END: Use Case */
339
    }
340
341
    /**
342
     * Test for the createLocation() method.
343
     *
344
     * @covers \eZ\Publish\API\Repository\LocationService::createLocation()
345
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
346
     * @dataProvider dataProviderForOutOfRangeLocationPriority
347
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
348
     */
349 View Code Duplication
    public function testCreateLocationThrowsInvalidArgumentExceptionPriorityIsOutOfRange($priority)
350
    {
351
        $repository = $this->getRepository();
352
353
        $contentId = $this->generateId('object', 41);
354
        $parentLocationId = $this->generateId('location', 5);
355
        /* BEGIN: Use Case */
356
        // $contentId is the ID of an existing content object
357
        // $parentLocationId is the ID of an existing location
358
        $contentService = $repository->getContentService();
359
        $locationService = $repository->getLocationService();
360
361
        // ContentInfo for "How to use eZ Publish"
362
        $contentInfo = $contentService->loadContentInfo($contentId);
363
364
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
365
        $locationCreate->priority = $priority;
366
        $locationCreate->hidden = true;
367
        $locationCreate->remoteId = 'sindelfingen';
368
        $locationCreate->sortField = Location::SORT_FIELD_NODE_ID;
369
        $locationCreate->sortOrder = Location::SORT_ORDER_DESC;
370
371
        // Throws exception, since priority is out of range
372
        $locationService->createLocation(
373
            $contentInfo,
374
            $locationCreate
375
        );
376
        /* END: Use Case */
377
    }
378
379
    public function dataProviderForOutOfRangeLocationPriority()
380
    {
381
        return [[-2147483649], [2147483648]];
382
    }
383
384
    /**
385
     * Test for the createLocation() method.
386
     *
387
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
388
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
389
     */
390
    public function testCreateLocationInTransactionWithRollback()
391
    {
392
        $repository = $this->getRepository();
393
394
        $contentId = $this->generateId('object', 41);
395
        $parentLocationId = $this->generateId('location', 5);
396
        /* BEGIN: Use Case */
397
        // $contentId is the ID of an existing content object
398
        // $parentLocationId is the ID of an existing location
399
        $contentService = $repository->getContentService();
400
        $locationService = $repository->getLocationService();
401
402
        $repository->beginTransaction();
403
404
        try {
405
            // ContentInfo for "How to use eZ Publish"
406
            $contentInfo = $contentService->loadContentInfo($contentId);
407
408
            $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
409
            $locationCreate->remoteId = 'sindelfingen';
410
411
            $createdLocationId = $locationService->createLocation(
412
                $contentInfo,
413
                $locationCreate
414
            )->id;
415
        } catch (Exception $e) {
416
            // Cleanup hanging transaction on error
417
            $repository->rollback();
418
            throw $e;
419
        }
420
421
        $repository->rollback();
422
423
        try {
424
            // Throws exception since creation of location was rolled back
425
            $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...
426
        } catch (NotFoundException $e) {
427
            return;
428
        }
429
        /* END: Use Case */
430
431
        $this->fail('Objects still exists after rollback.');
432
    }
433
434
    /**
435
     * Test for the loadLocation() method.
436
     *
437
     * @return \eZ\Publish\API\Repository\Values\Content\Location
438
     *
439
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocation
440
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
441
     */
442
    public function testLoadLocation()
443
    {
444
        $repository = $this->getRepository();
445
446
        $locationId = $this->generateId('location', 5);
447
        /* BEGIN: Use Case */
448
        // $locationId is the ID of an existing location
449
        $locationService = $repository->getLocationService();
450
451
        $location = $locationService->loadLocation($locationId);
452
        /* END: Use Case */
453
454
        $this->assertInstanceOf(
455
            Location::class,
456
            $location
457
        );
458
        self::assertEquals(5, $location->id);
459
460
        return $location;
461
    }
462
463
    /**
464
     * Test for the loadLocation() method.
465
     *
466
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
467
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
468
     */
469
    public function testLoadLocationRootStructValues()
470
    {
471
        $repository = $this->getRepository();
472
        $locationService = $repository->getLocationService();
473
        $location = $locationService->loadLocation($this->generateId('location', 1));
474
475
        $this->assertRootLocationStructValues($location);
476
    }
477
478
    public function testLoadLocationRootStructValuesWithPrioritizedLanguages(): void
479
    {
480
        $repository = $this->getRepository();
481
482
        $rootLocation = $repository
483
            ->getLocationService()
484
            ->loadLocation(
485
                $this->generateId('location', 1),
486
                [
487
                    'eng-GB',
488
                    'ger-DE',
489
                ]
490
            );
491
492
        $this->assertRootLocationStructValues($rootLocation);
493
    }
494
495
    private function assertRootLocationStructValues(Location $location): void
496
    {
497
        $legacyDateTime = new \DateTime();
498
        $legacyDateTime->setTimestamp(1030968000);
499
500
        $this->assertInstanceOf(Location::class, $location);
501
        $this->assertPropertiesCorrect(
502
            [
503
                'id' => $this->generateId('location', 1),
504
                'status' => 1,
505
                'priority' => 0,
506
                'hidden' => false,
507
                'invisible' => false,
508
                'remoteId' => '629709ba256fe317c3ddcee35453a96a',
509
                'parentLocationId' => $this->generateId('location', 1),
510
                'pathString' => '/1/',
511
                'depth' => 0,
512
                'sortField' => 1,
513
                'sortOrder' => 1,
514
            ],
515
            $location
516
        );
517
518
        $this->assertInstanceOf(ContentInfo::class, $location->contentInfo);
519
        $this->assertPropertiesCorrect(
520
            [
521
                'id' => $this->generateId('content', 0),
522
                'name' => 'Top Level Nodes',
523
                'sectionId' => 1,
524
                'mainLocationId' => 1,
525
                'contentTypeId' => 1,
526
                'currentVersionNo' => 1,
527
                'published' => 1,
528
                'ownerId' => 14,
529
                'modificationDate' => $legacyDateTime,
530
                'publishedDate' => $legacyDateTime,
531
                'alwaysAvailable' => 1,
532
                'remoteId' => null,
533
                'mainLanguageCode' => 'eng-GB',
534
            ],
535
            $location->contentInfo
536
        );
537
    }
538
539
    /**
540
     * Test for the loadLocation() method.
541
     *
542
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
543
     *
544
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
545
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
546
     */
547
    public function testLoadLocationStructValues(Location $location)
548
    {
549
        $this->assertPropertiesCorrect(
550
            [
551
                'id' => $this->generateId('location', 5),
552
                'priority' => 0,
553
                'hidden' => false,
554
                'invisible' => false,
555
                'remoteId' => '3f6d92f8044aed134f32153517850f5a',
556
                'parentLocationId' => $this->generateId('location', 1),
557
                'pathString' => '/1/5/',
558
                'depth' => 1,
559
                'sortField' => 1,
560
                'sortOrder' => 1,
561
            ],
562
            $location
563
        );
564
565
        $this->assertInstanceOf(
566
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\ContentInfo',
567
            $location->contentInfo
568
        );
569
        $this->assertEquals($this->generateId('object', 4), $location->contentInfo->id);
570
571
        // Check lazy loaded proxy on ->content
572
        $this->assertInstanceOf(
573
            Content::class,
574
            $content = $location->getContent()
575
        );
576
        $this->assertEquals(4, $content->contentInfo->id);
577
    }
578
579
    public function testLoadLocationPrioritizedLanguagesFallback()
580
    {
581
        $repository = $this->getRepository();
582
583
        // Add a language
584
        $this->createLanguage('nor-NO', 'Norsk');
585
586
        $locationService = $repository->getLocationService();
587
        $contentService = $repository->getContentService();
588
        $location = $locationService->loadLocation(5);
589
590
        // Translate "Users"
591
        $draft = $contentService->createContentDraft($location->contentInfo);
592
        $struct = $contentService->newContentUpdateStruct();
593
        $struct->setField('name', 'Brukere', 'nor-NO');
594
        $draft = $contentService->updateContent($draft->getVersionInfo(), $struct);
595
        $contentService->publishVersion($draft->getVersionInfo());
596
597
        // Load with priority language (fallback will be the old one)
598
        $location = $locationService->loadLocation(5, ['nor-NO']);
599
600
        $this->assertInstanceOf(
601
            Location::class,
602
            $location
603
        );
604
        self::assertEquals(5, $location->id);
605
        $this->assertInstanceOf(
606
            Content::class,
607
            $content = $location->getContent()
608
        );
609
        $this->assertEquals(4, $content->contentInfo->id);
610
611
        $this->assertEquals($content->getVersionInfo()->getName(), 'Brukere');
612
        $this->assertEquals($content->getVersionInfo()->getName('eng-US'), 'Users');
613
    }
614
615
    /**
616
     * Test that accessing lazy-loaded Content without a translation in the specific
617
     * not available language throws NotFoundException.
618
     */
619
    public function testLoadLocationThrowsNotFoundExceptionForNotAvailableContent(): void
620
    {
621
        $repository = $this->getRepository();
622
623
        $locationService = $repository->getLocationService();
624
625
        $this->createLanguage('pol-PL', 'Polski');
626
627
        $this->expectException(NotFoundException::class);
628
629
        // Note: relying on existing database fixtures to make test case more readable
630
        $locationService->loadLocation(60, ['pol-PL']);
631
    }
632
633
    /**
634
     * Test for the loadLocation() method.
635
     *
636
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
637
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
638
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
639
     */
640
    public function testLoadLocationThrowsNotFoundException()
641
    {
642
        $repository = $this->getRepository();
643
644
        $nonExistentLocationId = $this->generateId('location', 2342);
645
        /* BEGIN: Use Case */
646
        $locationService = $repository->getLocationService();
647
648
        // Throws exception, if Location with $nonExistentLocationId does not
649
        // exist
650
        $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...
651
        /* END: Use Case */
652
    }
653
654
    /**
655
     * Test for the loadLocationList() method.
656
     *
657
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
658
     */
659 View Code Duplication
    public function testLoadLocationList(): void
660
    {
661
        $repository = $this->getRepository();
662
663
        // 5 is the ID of an existing location, 442 is a non-existing id
664
        $locationService = $repository->getLocationService();
665
        $locations = $locationService->loadLocationList([5, 442]);
666
667
        self::assertInternalType('iterable', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

Loading history...
668
        self::assertCount(1, $locations);
0 ignored issues
show
Bug introduced by
It seems like $locations defined by $locationService->loadLocationList(array(5, 442)) on line 665 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...
669
        self::assertEquals([5], array_keys($locations));
670
        self::assertInstanceOf(Location::class, $locations[5]);
671
        self::assertEquals(5, $locations[5]->id);
672
    }
673
674
    /**
675
     * Test for the loadLocationList() method.
676
     *
677
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
678
     * @depends testLoadLocationList
679
     */
680
    public function testLoadLocationListPrioritizedLanguagesFallback(): void
681
    {
682
        $repository = $this->getRepository();
683
684
        $this->createLanguage('pol-PL', 'Polski');
685
686
        // 5 is the ID of an existing location, 442 is a non-existing id
687
        $locationService = $repository->getLocationService();
688
        $locations = $locationService->loadLocationList([5, 442], ['pol-PL'], false);
689
690
        self::assertInternalType('iterable', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

Loading history...
691
        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 688 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...
692
    }
693
694
    /**
695
     * Test for the loadLocationList() method.
696
     *
697
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
698
     * @depends testLoadLocationListPrioritizedLanguagesFallback
699
     */
700
    public function testLoadLocationListPrioritizedLanguagesFallbackAndAlwaysAvailable(): void
701
    {
702
        $repository = $this->getRepository();
703
704
        $this->createLanguage('pol-PL', 'Polski');
705
706
        // 5 is the ID of an existing location, 442 is a non-existing id
707
        $locationService = $repository->getLocationService();
708
        $locations = $locationService->loadLocationList([5, 442], ['pol-PL'], true);
709
710
        self::assertInternalType('iterable', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

Loading history...
711
        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 708 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...
712
        self::assertEquals([5], array_keys($locations));
713
        self::assertInstanceOf(Location::class, $locations[5]);
714
        self::assertEquals(5, $locations[5]->id);
715
    }
716
717
    /**
718
     * Test for the loadLocationList() method.
719
     *
720
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
721
     */
722 View Code Duplication
    public function testLoadLocationListWithRootLocationId()
723
    {
724
        $repository = $this->getRepository();
725
726
        // 1 is the ID of an root location
727
        $locationService = $repository->getLocationService();
728
        $locations = $locationService->loadLocationList([1]);
729
730
        self::assertInternalType('iterable', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

Loading history...
731
        self::assertCount(1, $locations);
0 ignored issues
show
Bug introduced by
It seems like $locations defined by $locationService->loadLocationList(array(1)) on line 728 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...
732
        self::assertEquals([1], array_keys($locations));
733
        self::assertInstanceOf(Location::class, $locations[1]);
734
        self::assertEquals(1, $locations[1]->id);
735
    }
736
737
    /**
738
     * Test for the loadLocationList() method.
739
     *
740
     * Ensures the list is returned in the same order as passed IDs array.
741
     *
742
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
743
     */
744
    public function testLoadLocationListInCorrectOrder()
745
    {
746
        $repository = $this->getRepository();
747
        $locationService = $repository->getLocationService();
748
749
        $cachedLocationId = 2;
750
        $locationIdsToLoad = [43, $cachedLocationId, 5];
751
752
        // Call loadLocation to cache it in memory as it might possibly affect list order
753
        $locationService->loadLocation($cachedLocationId);
754
755
        $locations = $locationService->loadLocationList($locationIdsToLoad);
756
        $locationIds = array_column($locations, 'id');
757
758
        self::assertEquals($locationIdsToLoad, $locationIds);
759
    }
760
761
    /**
762
     * Test for the loadLocationByRemoteId() method.
763
     *
764
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationByRemoteId()
765
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
766
     */
767 View Code Duplication
    public function testLoadLocationByRemoteId()
768
    {
769
        $repository = $this->getRepository();
770
771
        /* BEGIN: Use Case */
772
        $locationService = $repository->getLocationService();
773
774
        $location = $locationService->loadLocationByRemoteId(
775
            '3f6d92f8044aed134f32153517850f5a'
776
        );
777
        /* END: Use Case */
778
779
        $this->assertEquals(
780
            $locationService->loadLocation($this->generateId('location', 5)),
781
            $location
782
        );
783
    }
784
785
    /**
786
     * Test for the loadLocationByRemoteId() method.
787
     *
788
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationByRemoteId()
789
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
790
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
791
     */
792
    public function testLoadLocationByRemoteIdThrowsNotFoundException()
793
    {
794
        $repository = $this->getRepository();
795
796
        /* BEGIN: Use Case */
797
        $locationService = $repository->getLocationService();
798
799
        // Throws exception, since Location with remote ID does not exist
800
        $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...
801
            'not-exists'
802
        );
803
        /* END: Use Case */
804
    }
805
806
    /**
807
     * Test for the loadLocations() method.
808
     *
809
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
810
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
811
     */
812
    public function testLoadLocations()
813
    {
814
        $repository = $this->getRepository();
815
816
        $contentId = $this->generateId('object', 4);
817
        /* BEGIN: Use Case */
818
        // $contentId contains the ID of an existing content object
819
        $contentService = $repository->getContentService();
820
        $locationService = $repository->getLocationService();
821
822
        $contentInfo = $contentService->loadContentInfo($contentId);
823
824
        $locations = $locationService->loadLocations($contentInfo);
825
        /* END: Use Case */
826
827
        $this->assertInternalType('array', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

Loading history...
828
        self::assertNotEmpty($locations);
829
830
        foreach ($locations as $location) {
831
            self::assertInstanceOf(Location::class, $location);
832
            self::assertEquals($contentInfo->id, $location->getContentInfo()->id);
833
        }
834
835
        return $locations;
836
    }
837
838
    /**
839
     * Test for the loadLocations() method.
840
     *
841
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
842
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
843
     */
844
    public function testLoadLocationsContent(array $locations)
845
    {
846
        $this->assertEquals(1, count($locations));
847
        foreach ($locations as $loadedLocation) {
848
            self::assertInstanceOf(Location::class, $loadedLocation);
849
        }
850
851
        usort(
852
            $locations,
853
            static function ($a, $b) {
854
                return strcmp($a->id, $b->id);
855
            }
856
        );
857
858
        $this->assertEquals(
859
            [$this->generateId('location', 5)],
860
            array_map(
861
                static function (Location $location) {
862
                    return $location->id;
863
                },
864
                $locations
865
            )
866
        );
867
    }
868
869
    /**
870
     * Test for the loadLocations() method.
871
     *
872
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
873
     *
874
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations($contentInfo, $rootLocation)
875
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
876
     */
877
    public function testLoadLocationsLimitedSubtree()
878
    {
879
        $repository = $this->getRepository();
880
881
        $originalLocationId = $this->generateId('location', 54);
882
        $originalParentLocationId = $this->generateId('location', 48);
883
        $newParentLocationId = $this->generateId('location', 43);
884
        /* BEGIN: Use Case */
885
        // $originalLocationId is the ID of an existing location
886
        // $originalParentLocationId is the ID of the parent location of
887
        //     $originalLocationId
888
        // $newParentLocationId is the ID of an existing location outside the tree
889
        // of $originalLocationId and $originalParentLocationId
890
        $locationService = $repository->getLocationService();
891
892
        // Location at "/1/48/54"
893
        $originalLocation = $locationService->loadLocation($originalLocationId);
894
895
        // Create location under "/1/43/"
896
        $locationCreate = $locationService->newLocationCreateStruct($newParentLocationId);
897
        $locationService->createLocation(
898
            $originalLocation->contentInfo,
899
            $locationCreate
900
        );
901
902
        $findRootLocation = $locationService->loadLocation($originalParentLocationId);
903
904
        // Returns an array with only $originalLocation
905
        $locations = $locationService->loadLocations(
906
            $originalLocation->contentInfo,
907
            $findRootLocation
908
        );
909
        /* END: Use Case */
910
911
        $this->assertInternalType('array', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

Loading history...
912
913
        return $locations;
914
    }
915
916
    /**
917
     * Test for the loadLocations() method.
918
     *
919
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $locations
920
     *
921
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
922
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationsLimitedSubtree
923
     */
924
    public function testLoadLocationsLimitedSubtreeContent(array $locations)
925
    {
926
        $this->assertEquals(1, count($locations));
927
928
        $this->assertEquals(
929
            $this->generateId('location', 54),
930
            reset($locations)->id
931
        );
932
    }
933
934
    /**
935
     * Test for the loadLocations() method.
936
     *
937
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
938
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
939
     * @expectedException \eZ\Publish\API\Repository\Exceptions\BadStateException
940
     */
941
    public function testLoadLocationsThrowsBadStateException()
942
    {
943
        $repository = $this->getRepository();
944
945
        /* BEGIN: Use Case */
946
        $contentTypeService = $repository->getContentTypeService();
947
        $contentService = $repository->getContentService();
948
        $locationService = $repository->getLocationService();
949
950
        // Create new content, which is not published
951
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
952
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
953
        $contentCreate->setField('name', 'New Folder');
954
        $content = $contentService->createContent($contentCreate);
955
956
        // Throws Exception, since $content has no published version, yet
957
        $locationService->loadLocations(
958
            $content->contentInfo
959
        );
960
        /* END: Use Case */
961
    }
962
963
    /**
964
     * Test for the loadLocations() method.
965
     *
966
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations($contentInfo, $rootLocation)
967
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
968
     * @expectedException \eZ\Publish\API\Repository\Exceptions\BadStateException
969
     */
970
    public function testLoadLocationsThrowsBadStateExceptionLimitedSubtree()
971
    {
972
        $repository = $this->getRepository();
973
974
        $someLocationId = $this->generateId('location', 2);
975
        /* BEGIN: Use Case */
976
        // $someLocationId is the ID of an existing location
977
        $contentTypeService = $repository->getContentTypeService();
978
        $contentService = $repository->getContentService();
979
        $locationService = $repository->getLocationService();
980
981
        // Create new content, which is not published
982
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
983
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
984
        $contentCreate->setField('name', 'New Folder');
985
        $content = $contentService->createContent($contentCreate);
986
987
        $findRootLocation = $locationService->loadLocation($someLocationId);
988
989
        // Throws Exception, since $content has no published version, yet
990
        $locationService->loadLocations(
991
            $content->contentInfo,
992
            $findRootLocation
993
        );
994
        /* END: Use Case */
995
    }
996
997
    /**
998
     * Test for the loadLocationChildren() method.
999
     *
1000
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationChildren
1001
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1002
     */
1003
    public function testLoadLocationChildren()
1004
    {
1005
        $repository = $this->getRepository();
1006
1007
        $locationId = $this->generateId('location', 5);
1008
        /* BEGIN: Use Case */
1009
        // $locationId is the ID of an existing location
1010
        $locationService = $repository->getLocationService();
1011
1012
        $location = $locationService->loadLocation($locationId);
1013
1014
        $childLocations = $locationService->loadLocationChildren($location);
1015
        /* END: Use Case */
1016
1017
        $this->assertInstanceOf(LocationList::class, $childLocations);
1018
        $this->assertInternalType('array', $childLocations->locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

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

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

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

Loading history...
1021
1022
        foreach ($childLocations->locations as $childLocation) {
1023
            $this->assertInstanceOf(Location::class, $childLocation);
1024
            $this->assertEquals($location->id, $childLocation->parentLocationId);
1025
        }
1026
1027
        return $childLocations;
1028
    }
1029
1030
    /**
1031
     * Test loading parent Locations for draft Content.
1032
     *
1033
     * @covers \eZ\Publish\API\Repository\LocationService::loadParentLocationsForDraftContent
1034
     */
1035
    public function testLoadParentLocationsForDraftContent()
1036
    {
1037
        $repository = $this->getRepository();
1038
        $locationService = $repository->getLocationService();
1039
        $contentService = $repository->getContentService();
1040
        $contentTypeService = $repository->getContentTypeService();
1041
1042
        // prepare locations
1043
        $locationCreateStructs = [
1044
            $locationService->newLocationCreateStruct(2),
1045
            $locationService->newLocationCreateStruct(5),
1046
        ];
1047
1048
        // Create new content
1049
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
1050
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
1051
        $contentCreate->setField('name', 'New Folder');
1052
        $contentDraft = $contentService->createContent($contentCreate, $locationCreateStructs);
1053
1054
        // Test loading parent Locations
1055
        $locations = $locationService->loadParentLocationsForDraftContent($contentDraft->versionInfo);
1056
1057
        self::assertCount(2, $locations);
1058
        foreach ($locations as $location) {
1059
            // test it is one of the given parent locations
1060
            self::assertTrue($location->id === 2 || $location->id === 5);
1061
        }
1062
1063
        return $contentDraft;
1064
    }
1065
1066
    /**
1067
     * Test that trying to load parent Locations throws Exception if Content is not a draft.
1068
     *
1069
     * @depends testLoadParentLocationsForDraftContent
1070
     *
1071
     * @param \eZ\Publish\API\Repository\Values\Content\Content $contentDraft
1072
     */
1073
    public function testLoadParentLocationsForDraftContentThrowsBadStateException(Content $contentDraft)
1074
    {
1075
        $this->expectException(BadStateException::class);
1076
        $this->expectExceptionMessageRegExp('/has been already published/');
1077
1078
        $repository = $this->getRepository(false);
1079
        $locationService = $repository->getLocationService();
1080
        $contentService = $repository->getContentService();
1081
1082
        $content = $contentService->publishVersion($contentDraft->versionInfo);
1083
1084
        $locationService->loadParentLocationsForDraftContent($content->versionInfo);
1085
    }
1086
1087
    /**
1088
     * Test for the getLocationChildCount() method.
1089
     *
1090
     * @see \eZ\Publish\API\Repository\LocationService::getLocationChildCount()
1091
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1092
     */
1093
    public function testGetLocationChildCount()
1094
    {
1095
        // $locationId is the ID of an existing location
1096
        $locationService = $this->getRepository()->getLocationService();
1097
1098
        $this->assertSame(
1099
            5,
1100
            $locationService->getLocationChildCount(
1101
                $locationService->loadLocation($this->generateId('location', 5))
1102
            )
1103
        );
1104
    }
1105
1106
    /**
1107
     * Test for the loadLocationChildren() method.
1108
     *
1109
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren()
1110
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
1111
     */
1112
    public function testLoadLocationChildrenData(LocationList $locations)
1113
    {
1114
        $this->assertEquals(5, count($locations->locations));
1115
        $this->assertEquals(5, $locations->totalCount);
1116
1117
        foreach ($locations->locations as $location) {
1118
            $this->assertInstanceOf(
1119
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1120
                $location
1121
            );
1122
        }
1123
1124
        $this->assertEquals(
1125
            [
1126
                $this->generateId('location', 12),
1127
                $this->generateId('location', 13),
1128
                $this->generateId('location', 14),
1129
                $this->generateId('location', 44),
1130
                $this->generateId('location', 61),
1131
            ],
1132
            array_map(
1133
                function (Location $location) {
1134
                    return $location->id;
1135
                },
1136
                $locations->locations
1137
            )
1138
        );
1139
    }
1140
1141
    /**
1142
     * Test for the loadLocationChildren() method.
1143
     *
1144
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
1145
     *
1146
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset)
1147
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
1148
     */
1149 View Code Duplication
    public function testLoadLocationChildrenWithOffset()
1150
    {
1151
        $repository = $this->getRepository();
1152
1153
        $locationId = $this->generateId('location', 5);
1154
        /* BEGIN: Use Case */
1155
        // $locationId is the ID of an existing location
1156
        $locationService = $repository->getLocationService();
1157
1158
        $location = $locationService->loadLocation($locationId);
1159
1160
        $childLocations = $locationService->loadLocationChildren($location, 2);
1161
        /* END: Use Case */
1162
1163
        $this->assertInstanceOf('\\eZ\\Publish\\API\\Repository\\Values\\Content\\LocationList', $childLocations);
1164
        $this->assertInternalType('array', $childLocations->locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

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

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

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

Loading history...
1166
1167
        return $childLocations;
1168
    }
1169
1170
    /**
1171
     * Test for the loadLocationChildren() method.
1172
     *
1173
     * @param \eZ\Publish\API\Repository\Values\Content\LocationList $locations
1174
     *
1175
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset)
1176
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildrenWithOffset
1177
     */
1178 View Code Duplication
    public function testLoadLocationChildrenDataWithOffset(LocationList $locations)
1179
    {
1180
        $this->assertEquals(3, count($locations->locations));
1181
        $this->assertEquals(5, $locations->totalCount);
1182
1183
        foreach ($locations->locations as $location) {
1184
            $this->assertInstanceOf(
1185
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1186
                $location
1187
            );
1188
        }
1189
1190
        $this->assertEquals(
1191
            [
1192
                $this->generateId('location', 14),
1193
                $this->generateId('location', 44),
1194
                $this->generateId('location', 61),
1195
            ],
1196
            array_map(
1197
                function (Location $location) {
1198
                    return $location->id;
1199
                },
1200
                $locations->locations
1201
            )
1202
        );
1203
    }
1204
1205
    /**
1206
     * Test for the loadLocationChildren() method.
1207
     *
1208
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
1209
     *
1210
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset, $limit)
1211
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
1212
     */
1213 View Code Duplication
    public function testLoadLocationChildrenWithOffsetAndLimit()
1214
    {
1215
        $repository = $this->getRepository();
1216
1217
        $locationId = $this->generateId('location', 5);
1218
        /* BEGIN: Use Case */
1219
        // $locationId is the ID of an existing location
1220
        $locationService = $repository->getLocationService();
1221
1222
        $location = $locationService->loadLocation($locationId);
1223
1224
        $childLocations = $locationService->loadLocationChildren($location, 2, 2);
1225
        /* END: Use Case */
1226
1227
        $this->assertInstanceOf('\\eZ\\Publish\\API\\Repository\\Values\\Content\\LocationList', $childLocations);
1228
        $this->assertInternalType('array', $childLocations->locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

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

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

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

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

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

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

Loading history...
1474
1475
        $originalLocation = $locationService->loadLocation($locationId);
1476
1477
        $updateStruct = $locationService->newLocationUpdateStruct();
1478
        $updateStruct->priority = 42;
1479
1480
        $updatedLocation = $locationService->updateLocation($originalLocation, $updateStruct);
1481
1482
        // Repeated update with the same, unchanged struct
1483
        $secondUpdatedLocation = $locationService->updateLocation($updatedLocation, $updateStruct);
1484
        /* END: Use Case */
1485
1486
        $this->assertEquals($updatedLocation->priority, 42);
1487
        $this->assertEquals($secondUpdatedLocation->priority, 42);
1488
    }
1489
1490
    /**
1491
     * Test for the swapLocation() method.
1492
     *
1493
     * @see \eZ\Publish\API\Repository\LocationService::swapLocation()
1494
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1495
     */
1496
    public function testSwapLocation()
1497
    {
1498
        $repository = $this->getRepository();
1499
        $locationService = $repository->getLocationService();
1500
1501
        $mediaLocationId = $this->generateId('location', 43);
1502
        $demoDesignLocationId = $this->generateId('location', 56);
1503
1504
        $mediaContentInfo = $locationService->loadLocation($mediaLocationId)->getContentInfo();
1505
        $demoDesignContentInfo = $locationService->loadLocation($demoDesignLocationId)->getContentInfo();
1506
1507
        /* BEGIN: Use Case */
1508
        // $mediaLocationId is the ID of the "Media" page location in
1509
        // an eZ Publish demo installation
1510
1511
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
1512
        // Publish demo installation
1513
1514
        // Load the location service
1515
        $locationService = $repository->getLocationService();
1516
1517
        $mediaLocation = $locationService->loadLocation($mediaLocationId);
1518
        $demoDesignLocation = $locationService->loadLocation($demoDesignLocationId);
1519
1520
        // Swaps the content referred to by the locations
1521
        $locationService->swapLocation($mediaLocation, $demoDesignLocation);
1522
        /* END: Use Case */
1523
1524
        // Reload Locations, IDs swapped
1525
        $demoDesignLocation = $locationService->loadLocation($mediaLocationId);
1526
        $mediaLocation = $locationService->loadLocation($demoDesignLocationId);
1527
1528
        // Assert Location's Content is updated
1529
        $this->assertEquals(
1530
            $mediaContentInfo->id,
1531
            $mediaLocation->getContentInfo()->id
1532
        );
1533
        $this->assertEquals(
1534
            $demoDesignContentInfo->id,
1535
            $demoDesignLocation->getContentInfo()->id
1536
        );
1537
1538
        // Assert URL aliases are updated
1539
        $this->assertEquals(
1540
            $mediaLocation->id,
1541
            $repository->getURLAliasService()->lookup('/Design/Media')->destination
1542
        );
1543
        $this->assertEquals(
1544
            $demoDesignLocation->id,
1545
            $repository->getURLAliasService()->lookup('/eZ-Publish-Demo-Design-without-demo-content')->destination
1546
        );
1547
    }
1548
1549
    /**
1550
     * Test for the swapLocation() method with custom aliases.
1551
     *
1552
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1553
     *
1554
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
1555
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
1556
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
1557
     */
1558
    public function testSwapLocationForContentWithCustomUrlAliases(): void
1559
    {
1560
        $repository = $this->getRepository();
1561
        $locationService = $repository->getLocationService();
1562
        $urlAliasService = $repository->getURLAliasService();
1563
        $this->createLanguage('pol-PL', 'Polski');
1564
1565
        $folder1 = $this->createFolder(['eng-GB' => 'Folder1', 'pol-PL' => 'Folder1'], 2);
1566
        $folder2 = $this->createFolder(['eng-GB' => 'Folder2'], 2);
1567
        $location1 = $locationService->loadLocation($folder1->contentInfo->mainLocationId);
1568
        $location2 = $locationService->loadLocation($folder2->contentInfo->mainLocationId);
1569
1570
        $urlAlias = $urlAliasService->createUrlAlias($location1, '/custom-location1', 'eng-GB', false, true);
1571
        $urlAliasService->createUrlAlias($location1, '/custom-location1', 'pol-PL', false, true);
1572
        $urlAliasService->createUrlAlias($location2, '/custom-location2', 'eng-GB', false, true);
1573
        $location1UrlAliases = $urlAliasService->listLocationAliases($location1);
1574
        $location2UrlAliases = $urlAliasService->listLocationAliases($location2);
1575
1576
        $locationService->swapLocation($location1, $location2);
1577
        $location1 = $locationService->loadLocation($location1->contentInfo->mainLocationId);
1578
        $location2 = $locationService->loadLocation($location2->contentInfo->mainLocationId);
1579
1580
        $location1UrlAliasesAfterSwap = $urlAliasService->listLocationAliases($location1);
1581
        $location2UrlAliasesAfterSwap = $urlAliasService->listLocationAliases($location2);
1582
1583
        $keyUrlAlias = array_search($urlAlias->id, array_column($location1UrlAliasesAfterSwap, 'id'));
1584
1585
        self::assertEquals($folder1->id, $location2->contentInfo->id);
1586
        self::assertEquals($folder2->id, $location1->contentInfo->id);
1587
        self::assertNotEquals($location1UrlAliases, $location1UrlAliasesAfterSwap);
1588
        self::assertEquals($location2UrlAliases, $location2UrlAliasesAfterSwap);
1589
        self::assertEquals(['eng-GB'], $location1UrlAliasesAfterSwap[$keyUrlAlias]->languageCodes);
1590
    }
1591
1592
    /**
1593
     * Test swapping secondary Location with main Location.
1594
     *
1595
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1596
     *
1597
     * @see https://jira.ez.no/browse/EZP-28663
1598
     *
1599
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
1600
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
1601
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
1602
     *
1603
     * @return int[]
1604
     */
1605
    public function testSwapLocationForMainAndSecondaryLocation(): array
1606
    {
1607
        $repository = $this->getRepository();
1608
        $locationService = $repository->getLocationService();
1609
        $contentService = $repository->getContentService();
1610
1611
        $folder1 = $this->createFolder(['eng-GB' => 'Folder1'], 2);
1612
        $folder2 = $this->createFolder(['eng-GB' => 'Folder2'], 2);
1613
        $folder3 = $this->createFolder(['eng-GB' => 'Folder3'], 2);
1614
1615
        $primaryLocation = $locationService->loadLocation($folder1->contentInfo->mainLocationId);
1616
        $parentLocation = $locationService->loadLocation($folder2->contentInfo->mainLocationId);
1617
        $secondaryLocation = $locationService->createLocation(
1618
            $folder1->contentInfo,
1619
            $locationService->newLocationCreateStruct($parentLocation->id)
1620
        );
1621
1622
        $targetLocation = $locationService->loadLocation($folder3->contentInfo->mainLocationId);
1623
1624
        // perform sanity checks
1625
        $this->assertContentHasExpectedLocations([$primaryLocation, $secondaryLocation], $folder1);
1626
1627
        // begin use case
1628
        $locationService->swapLocation($secondaryLocation, $targetLocation);
1629
1630
        // test results
1631
        $primaryLocation = $locationService->loadLocation($primaryLocation->id);
1632
        $secondaryLocation = $locationService->loadLocation($secondaryLocation->id);
1633
        $targetLocation = $locationService->loadLocation($targetLocation->id);
1634
1635
        self::assertEquals($folder1->id, $primaryLocation->contentInfo->id);
1636
        self::assertEquals($folder1->id, $targetLocation->contentInfo->id);
1637
        self::assertEquals($folder3->id, $secondaryLocation->contentInfo->id);
1638
1639
        $this->assertContentHasExpectedLocations([$primaryLocation, $targetLocation], $folder1);
1640
1641
        self::assertEquals(
1642
            $folder1,
1643
            $contentService->loadContent($folder1->id)
1644
        );
1645
1646
        self::assertEquals(
1647
            $folder2,
1648
            $contentService->loadContent($folder2->id)
1649
        );
1650
1651
        // only in case of Folder 3, main location id changed due to swap
1652
        self::assertEquals(
1653
            $secondaryLocation->id,
1654
            $contentService->loadContent($folder3->id)->contentInfo->mainLocationId
1655
        );
1656
1657
        return [$folder1, $folder2, $folder3];
1658
    }
1659
1660
    /**
1661
     * Compare Ids of expected and loaded Locations for the given Content.
1662
     *
1663
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $expectedLocations
1664
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1665
     *
1666
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
1667
     */
1668
    private function assertContentHasExpectedLocations(array $expectedLocations, Content $content)
1669
    {
1670
        $repository = $this->getRepository(false);
1671
        $locationService = $repository->getLocationService();
1672
1673
        $expectedLocationIds = array_map(
1674
            function (Location $location) {
1675
                return (int)$location->id;
1676
            },
1677
            $expectedLocations
1678
        );
1679
1680
        $actualLocationsIds = array_map(
1681
            function (Location $location) {
1682
                return $location->id;
1683
            },
1684
            $locationService->loadLocations($content->contentInfo)
1685
        );
1686
        self::assertCount(count($expectedLocations), $actualLocationsIds);
1687
1688
        // perform unordered equality assertion
1689
        self::assertEquals(
1690
            $expectedLocationIds,
1691
            $actualLocationsIds,
1692
            sprintf(
1693
                'Content %d contains Locations %s, but expected: %s',
1694
                $content->id,
1695
                implode(', ', $actualLocationsIds),
1696
                implode(', ', $expectedLocationIds)
1697
            ),
1698
            0.0,
1699
            10,
1700
            true
1701
        );
1702
    }
1703
1704
    /**
1705
     * @depends testSwapLocationForMainAndSecondaryLocation
1706
     *
1707
     * @param \eZ\Publish\API\Repository\Values\Content\Content[] $contentItems Content items created by testSwapLocationForSecondaryLocation
1708
     *
1709
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1710
     */
1711
    public function testSwapLocationDoesNotCorruptSearchResults(array $contentItems)
1712
    {
1713
        $repository = $this->getRepository(false);
1714
        $searchService = $repository->getSearchService();
1715
1716
        $this->refreshSearch($repository);
1717
1718
        $contentIds = array_map(
1719
            function (Content $content) {
1720
                return $content->id;
1721
            },
1722
            $contentItems
1723
        );
1724
1725
        $query = new Query();
1726
        $query->filter = new Query\Criterion\ContentId($contentIds);
1727
1728
        $searchResult = $searchService->findContent($query);
1729
1730
        self::assertEquals(count($contentItems), $searchResult->totalCount);
1731
        self::assertEquals(
1732
            $searchResult->totalCount,
1733
            count($searchResult->searchHits),
1734
            'Total count of search result hits does not match the actual number of found results'
1735
        );
1736
        $foundContentIds = array_map(
1737
            function (SearchHit $searchHit) {
1738
                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...
1739
            },
1740
            $searchResult->searchHits
1741
        );
1742
        sort($contentIds);
1743
        sort($foundContentIds);
1744
        self::assertSame(
1745
            $contentIds,
1746
            $foundContentIds,
1747
            'Got different than expected Content item Ids'
1748
        );
1749
    }
1750
1751
    /**
1752
     * Test swapping two secondary (non-main) Locations.
1753
     *
1754
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1755
     *
1756
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
1757
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1758
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
1759
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
1760
     */
1761
    public function testSwapLocationForSecondaryLocations()
1762
    {
1763
        $repository = $this->getRepository();
1764
        $locationService = $repository->getLocationService();
1765
        $contentService = $repository->getContentService();
1766
1767
        $folder1 = $this->createFolder(['eng-GB' => 'Folder1'], 2);
1768
        $folder2 = $this->createFolder(['eng-GB' => 'Folder2'], 2);
1769
        $parentFolder1 = $this->createFolder(['eng-GB' => 'Parent1'], 2);
1770
        $parentFolder2 = $this->createFolder(['eng-GB' => 'Parent2'], 2);
1771
1772
        $parentLocation1 = $locationService->loadLocation($parentFolder1->contentInfo->mainLocationId);
1773
        $parentLocation2 = $locationService->loadLocation($parentFolder2->contentInfo->mainLocationId);
1774
        $secondaryLocation1 = $locationService->createLocation(
1775
            $folder1->contentInfo,
1776
            $locationService->newLocationCreateStruct($parentLocation1->id)
1777
        );
1778
        $secondaryLocation2 = $locationService->createLocation(
1779
            $folder2->contentInfo,
1780
            $locationService->newLocationCreateStruct($parentLocation2->id)
1781
        );
1782
1783
        // begin use case
1784
        $locationService->swapLocation($secondaryLocation1, $secondaryLocation2);
1785
1786
        // test results
1787
        $secondaryLocation1 = $locationService->loadLocation($secondaryLocation1->id);
1788
        $secondaryLocation2 = $locationService->loadLocation($secondaryLocation2->id);
1789
1790
        self::assertEquals($folder2->id, $secondaryLocation1->contentInfo->id);
1791
        self::assertEquals($folder1->id, $secondaryLocation2->contentInfo->id);
1792
1793
        self::assertEquals(
1794
            $folder1,
1795
            $contentService->loadContent($folder1->id)
1796
        );
1797
1798
        self::assertEquals(
1799
            $folder2,
1800
            $contentService->loadContent($folder2->id)
1801
        );
1802
    }
1803
1804
    /**
1805
     * Test swapping Main Location of a Content with another one updates Content item Main Location.
1806
     *
1807
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1808
     */
1809
    public function testSwapLocationUpdatesMainLocation()
1810
    {
1811
        $repository = $this->getRepository();
1812
        $locationService = $repository->getLocationService();
1813
        $contentService = $repository->getContentService();
1814
1815
        $mainLocationParentId = 60;
1816
        $secondaryLocationId = 43;
1817
1818
        $publishedContent = $this->publishContentWithParentLocation(
1819
            'Content for Swap Location Test', $mainLocationParentId
1820
        );
1821
1822
        // sanity check
1823
        $mainLocation = $locationService->loadLocation($publishedContent->contentInfo->mainLocationId);
1824
        self::assertEquals($mainLocationParentId, $mainLocation->parentLocationId);
1825
1826
        // load another pre-existing location
1827
        $secondaryLocation = $locationService->loadLocation($secondaryLocationId);
1828
1829
        // swap the Main Location with a secondary one
1830
        $locationService->swapLocation($mainLocation, $secondaryLocation);
1831
1832
        // check if Main Location has been updated
1833
        $mainLocation = $locationService->loadLocation($secondaryLocation->id);
1834
        self::assertEquals($publishedContent->contentInfo->id, $mainLocation->contentInfo->id);
1835
        self::assertEquals($mainLocation->id, $mainLocation->contentInfo->mainLocationId);
1836
1837
        $reloadedContent = $contentService->loadContentByContentInfo($publishedContent->contentInfo);
1838
        self::assertEquals($mainLocation->id, $reloadedContent->contentInfo->mainLocationId);
1839
    }
1840
1841
    /**
1842
     * Test if location swap affects related bookmarks.
1843
     *
1844
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1845
     */
1846
    public function testBookmarksAreSwappedAfterSwapLocation()
1847
    {
1848
        $repository = $this->getRepository();
1849
1850
        $mediaLocationId = $this->generateId('location', 43);
1851
        $demoDesignLocationId = $this->generateId('location', 56);
1852
1853
        /* BEGIN: Use Case */
1854
        $locationService = $repository->getLocationService();
1855
        $bookmarkService = $repository->getBookmarkService();
1856
1857
        $mediaLocation = $locationService->loadLocation($mediaLocationId);
1858
        $demoDesignLocation = $locationService->loadLocation($demoDesignLocationId);
1859
1860
        // Bookmark locations
1861
        $bookmarkService->createBookmark($mediaLocation);
1862
        $bookmarkService->createBookmark($demoDesignLocation);
1863
1864
        $beforeSwap = $bookmarkService->loadBookmarks();
1865
1866
        // Swaps the content referred to by the locations
1867
        $locationService->swapLocation($mediaLocation, $demoDesignLocation);
1868
1869
        $afterSwap = $bookmarkService->loadBookmarks();
1870
        /* END: Use Case */
1871
1872
        $this->assertEquals($beforeSwap->items[0]->id, $afterSwap->items[1]->id);
1873
        $this->assertEquals($beforeSwap->items[1]->id, $afterSwap->items[0]->id);
1874
    }
1875
1876
    /**
1877
     * Test for the hideLocation() method.
1878
     *
1879
     * @see \eZ\Publish\API\Repository\LocationService::hideLocation()
1880
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1881
     */
1882
    public function testHideLocation()
1883
    {
1884
        $repository = $this->getRepository();
1885
1886
        $locationId = $this->generateId('location', 5);
1887
        /* BEGIN: Use Case */
1888
        // $locationId is the ID of an existing location
1889
        $locationService = $repository->getLocationService();
1890
1891
        $visibleLocation = $locationService->loadLocation($locationId);
1892
1893
        $hiddenLocation = $locationService->hideLocation($visibleLocation);
1894
        /* END: Use Case */
1895
1896
        $this->assertInstanceOf(
1897
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1898
            $hiddenLocation
1899
        );
1900
1901
        $this->assertTrue(
1902
            $hiddenLocation->hidden,
1903
            sprintf(
1904
                'Location with ID "%s" not hidden.',
1905
                $hiddenLocation->id
1906
            )
1907
        );
1908
1909
        $this->refreshSearch($repository);
1910
1911
        foreach ($locationService->loadLocationChildren($hiddenLocation)->locations as $child) {
1912
            $this->assertSubtreeProperties(
1913
                ['invisible' => true],
1914
                $child
1915
            );
1916
        }
1917
    }
1918
1919
    /**
1920
     * Assert that $expectedValues are set in the subtree starting at $location.
1921
     *
1922
     * @param array $expectedValues
1923
     * @param Location $location
1924
     */
1925
    protected function assertSubtreeProperties(array $expectedValues, Location $location, $stopId = null)
1926
    {
1927
        $repository = $this->getRepository();
1928
        $locationService = $repository->getLocationService();
1929
1930
        if ($location->id === $stopId) {
1931
            return;
1932
        }
1933
1934
        foreach ($expectedValues as $propertyName => $propertyValue) {
1935
            $this->assertEquals(
1936
                $propertyValue,
1937
                $location->$propertyName
1938
            );
1939
1940
            foreach ($locationService->loadLocationChildren($location)->locations as $child) {
1941
                $this->assertSubtreeProperties($expectedValues, $child);
1942
            }
1943
        }
1944
    }
1945
1946
    /**
1947
     * Test for the unhideLocation() method.
1948
     *
1949
     * @see \eZ\Publish\API\Repository\LocationService::unhideLocation()
1950
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testHideLocation
1951
     */
1952
    public function testUnhideLocation()
1953
    {
1954
        $repository = $this->getRepository();
1955
1956
        $locationId = $this->generateId('location', 5);
1957
        /* BEGIN: Use Case */
1958
        // $locationId is the ID of an existing location
1959
        $locationService = $repository->getLocationService();
1960
1961
        $visibleLocation = $locationService->loadLocation($locationId);
1962
        $hiddenLocation = $locationService->hideLocation($visibleLocation);
1963
1964
        $unHiddenLocation = $locationService->unhideLocation($hiddenLocation);
1965
        /* END: Use Case */
1966
1967
        $this->assertInstanceOf(
1968
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1969
            $unHiddenLocation
1970
        );
1971
1972
        $this->assertFalse(
1973
            $unHiddenLocation->hidden,
1974
            sprintf(
1975
                'Location with ID "%s" not unhidden.',
1976
                $unHiddenLocation->id
1977
            )
1978
        );
1979
1980
        $this->refreshSearch($repository);
1981
1982
        foreach ($locationService->loadLocationChildren($unHiddenLocation)->locations as $child) {
1983
            $this->assertSubtreeProperties(
1984
                ['invisible' => false],
1985
                $child
1986
            );
1987
        }
1988
    }
1989
1990
    /**
1991
     * Test for the unhideLocation() method.
1992
     *
1993
     * @see \eZ\Publish\API\Repository\LocationService::unhideLocation()
1994
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testUnhideLocation
1995
     */
1996
    public function testUnhideLocationNotUnhidesHiddenSubtree()
1997
    {
1998
        $repository = $this->getRepository();
1999
2000
        $higherLocationId = $this->generateId('location', 5);
2001
        $lowerLocationId = $this->generateId('location', 13);
2002
        /* BEGIN: Use Case */
2003
        // $higherLocationId is the ID of a location
2004
        // $lowerLocationId is the ID of a location below $higherLocationId
2005
        $locationService = $repository->getLocationService();
2006
2007
        $higherLocation = $locationService->loadLocation($higherLocationId);
2008
        $hiddenHigherLocation = $locationService->hideLocation($higherLocation);
2009
2010
        $lowerLocation = $locationService->loadLocation($lowerLocationId);
2011
        $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...
2012
2013
        $unHiddenHigherLocation = $locationService->unhideLocation($hiddenHigherLocation);
2014
        /* END: Use Case */
2015
2016
        $this->assertInstanceOf(
2017
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
2018
            $unHiddenHigherLocation
2019
        );
2020
2021
        $this->assertFalse(
2022
            $unHiddenHigherLocation->hidden,
2023
            sprintf(
2024
                'Location with ID "%s" not unhidden.',
2025
                $unHiddenHigherLocation->id
2026
            )
2027
        );
2028
2029
        $this->refreshSearch($repository);
2030
2031
        foreach ($locationService->loadLocationChildren($unHiddenHigherLocation)->locations as $child) {
2032
            $this->assertSubtreeProperties(
2033
                ['invisible' => false],
2034
                $child,
2035
                $this->generateId('location', 13)
2036
            );
2037
        }
2038
2039
        $stillHiddenLocation = $locationService->loadLocation($this->generateId('location', 13));
2040
        $this->assertTrue(
2041
            $stillHiddenLocation->hidden,
2042
            sprintf(
2043
                'Hidden sub-location with ID %s accidentally unhidden.',
2044
                $stillHiddenLocation->id
2045
            )
2046
        );
2047
        foreach ($locationService->loadLocationChildren($stillHiddenLocation)->locations as $child) {
2048
            $this->assertSubtreeProperties(
2049
                ['invisible' => true],
2050
                $child
2051
            );
2052
        }
2053
    }
2054
2055
    /**
2056
     * Test for the deleteLocation() method.
2057
     *
2058
     * @see \eZ\Publish\API\Repository\LocationService::deleteLocation()
2059
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2060
     */
2061
    public function testDeleteLocation()
2062
    {
2063
        $repository = $this->getRepository();
2064
2065
        $mediaLocationId = $this->generateId('location', 43);
2066
        /* BEGIN: Use Case */
2067
        // $mediaLocationId is the ID of the location of the
2068
        // "Media" location in an eZ Publish demo installation
2069
        $locationService = $repository->getLocationService();
2070
2071
        $location = $locationService->loadLocation($mediaLocationId);
2072
2073
        $locationService->deleteLocation($location);
2074
        /* END: Use Case */
2075
2076
        try {
2077
            $locationService->loadLocation($mediaLocationId);
2078
            $this->fail("Location $mediaLocationId not deleted.");
2079
        } catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
2080
        }
2081
2082
        // The following IDs are IDs of child locations of $mediaLocationId location
2083
        // ( Media/Images, Media/Files, Media/Multimedia respectively )
2084
        foreach ([51, 52, 53] as $childLocationId) {
2085
            try {
2086
                $locationService->loadLocation($this->generateId('location', $childLocationId));
2087
                $this->fail("Location $childLocationId not deleted.");
2088
            } catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
2089
            }
2090
        }
2091
2092
        // The following IDs are IDs of content below $mediaLocationId location
2093
        // ( Media/Images, Media/Files, Media/Multimedia respectively )
2094
        $contentService = $this->getRepository()->getContentService();
2095
        foreach ([49, 50, 51] as $childContentId) {
2096
            try {
2097
                $contentService->loadContentInfo($this->generateId('object', $childContentId));
2098
                $this->fail("Content $childContentId not deleted.");
2099
            } catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
2100
            }
2101
        }
2102
    }
2103
2104
    /**
2105
     * Test for the deleteLocation() method.
2106
     *
2107
     * @see \eZ\Publish\API\Repository\LocationService::deleteLocation()
2108
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testDeleteLocation
2109
     */
2110
    public function testDeleteLocationDecrementsChildCountOnParent()
2111
    {
2112
        $repository = $this->getRepository();
2113
2114
        $mediaLocationId = $this->generateId('location', 43);
2115
        /* BEGIN: Use Case */
2116
        // $mediaLocationId is the ID of the location of the
2117
        // "Media" location in an eZ Publish demo installation
2118
2119
        $locationService = $repository->getLocationService();
2120
2121
        // Load the current the user group location
2122
        $location = $locationService->loadLocation($mediaLocationId);
2123
2124
        // Load the parent location
2125
        $parentLocation = $locationService->loadLocation(
2126
            $location->parentLocationId
2127
        );
2128
2129
        // Get child count
2130
        $childCountBefore = $locationService->getLocationChildCount($parentLocation);
2131
2132
        // Delete the user group location
2133
        $locationService->deleteLocation($location);
2134
2135
        $this->refreshSearch($repository);
2136
2137
        // Reload parent location
2138
        $parentLocation = $locationService->loadLocation(
2139
            $location->parentLocationId
2140
        );
2141
2142
        // This will be $childCountBefore - 1
2143
        $childCountAfter = $locationService->getLocationChildCount($parentLocation);
2144
        /* END: Use Case */
2145
2146
        $this->assertEquals($childCountBefore - 1, $childCountAfter);
2147
    }
2148
2149
    /**
2150
     * Test for the deleteLocation() method.
2151
     *
2152
     * Related issue: EZP-21904
2153
     *
2154
     * @see \eZ\Publish\API\Repository\LocationService::deleteLocation()
2155
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
2156
     */
2157
    public function testDeleteContentObjectLastLocation()
2158
    {
2159
        $repository = $this->getRepository();
2160
2161
        /* BEGIN: Use case */
2162
        $contentService = $repository->getContentService();
2163
        $locationService = $repository->getLocationService();
2164
        $contentTypeService = $repository->getContentTypeService();
2165
        $urlAliasService = $repository->getURLAliasService();
2166
2167
        // prepare Content object
2168
        $createStruct = $contentService->newContentCreateStruct(
2169
            $contentTypeService->loadContentTypeByIdentifier('folder'),
2170
            'eng-GB'
2171
        );
2172
        $createStruct->setField('name', 'Test folder');
2173
2174
        // creata Content object
2175
        $content = $contentService->publishVersion(
2176
            $contentService->createContent(
2177
                $createStruct,
2178
                [$locationService->newLocationCreateStruct(2)]
2179
            )->versionInfo
2180
        );
2181
2182
        // delete location
2183
        $locationService->deleteLocation(
2184
            $locationService->loadLocation(
2185
                $urlAliasService->lookup('/Test-folder')->destination
2186
            )
2187
        );
2188
2189
        // this should throw a not found exception
2190
        $contentService->loadContent($content->versionInfo->contentInfo->id);
2191
        /* END: Use case*/
2192
    }
2193
2194
    /**
2195
     * Test for the deleteLocation() method.
2196
     *
2197
     * @covers  \eZ\Publish\API\Repository\LocationService::deleteLocation()
2198
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testDeleteLocation
2199
     */
2200
    public function testDeleteLocationDeletesRelatedBookmarks()
2201
    {
2202
        $repository = $this->getRepository();
2203
2204
        $parentLocationId = $this->generateId('location', 43);
2205
        $childLocationId = $this->generateId('location', 53);
2206
2207
        /* BEGIN: Use Case */
2208
        $locationService = $repository->getLocationService();
2209
        $bookmarkService = $repository->getBookmarkService();
2210
2211
        // Load location
2212
        $childLocation = $locationService->loadLocation($childLocationId);
2213
        // Add location to bookmarks
2214
        $bookmarkService->createBookmark($childLocation);
2215
        // Load parent location
2216
        $parentLocation = $locationService->loadLocation($parentLocationId);
2217
        // Delete parent location
2218
        $locationService->deleteLocation($parentLocation);
2219
        /* END: Use Case */
2220
2221
        // Location isn't bookmarked anymore
2222
        foreach ($bookmarkService->loadBookmarks(0, 9999) as $bookmarkedLocation) {
2223
            $this->assertNotEquals($childLocation->id, $bookmarkedLocation->id);
2224
        }
2225
    }
2226
2227
    /**
2228
     * @covers \eZ\Publish\API\Repository\LocationService::deleteLocation
2229
     */
2230
    public function testDeleteUnusedLocationWhichPreviousHadContentWithRelativeAlias(): void
2231
    {
2232
        $repository = $this->getRepository(false);
2233
2234
        $contentService = $repository->getContentService();
2235
        $locationService = $repository->getLocationService();
2236
        $urlAliasService = $repository->getURLAliasService();
2237
2238
        $originalFolder = $this->createFolder(['eng-GB' => 'Original folder'], 2);
2239
        $newFolder = $this->createFolder(['eng-GB' => 'New folder'], 2);
2240
        $originalFolderLocationId = $originalFolder->contentInfo->mainLocationId;
2241
2242
        $forum = $contentService->publishVersion(
2243
            $contentService->createContent(
2244
                $this->createForumStruct('Some forum'),
2245
                [
2246
                    $locationService->newLocationCreateStruct($originalFolderLocationId),
2247
                ]
2248
            )->versionInfo
2249
        );
2250
2251
        $forumMainLocation = $locationService->loadLocation(
2252
            $forum->contentInfo->mainLocationId
2253
        );
2254
2255
        $customRelativeAliasPath = '/Original-folder/some-forum-alias';
2256
2257
        $urlAliasService->createUrlAlias(
2258
            $forumMainLocation,
2259
            $customRelativeAliasPath,
2260
            'eng-GB',
2261
            true,
2262
            true
2263
        );
2264
2265
        $locationService->moveSubtree(
2266
            $forumMainLocation,
2267
            $locationService->loadLocation(
2268
                $newFolder->contentInfo->mainLocationId
2269
            )
2270
        );
2271
2272
        $this->assertAliasExists(
2273
            $customRelativeAliasPath,
2274
            $forumMainLocation,
2275
            $urlAliasService
2276
        );
2277
2278
        $urlAliasService->lookup($customRelativeAliasPath);
2279
2280
        $locationService->deleteLocation(
2281
            $locationService->loadLocation(
2282
                $originalFolder->contentInfo->mainLocationId
2283
            )
2284
        );
2285
2286
        $this->assertAliasExists(
2287
            $customRelativeAliasPath,
2288
            $forumMainLocation,
2289
            $urlAliasService
2290
        );
2291
2292
        $urlAliasService->lookup($customRelativeAliasPath);
2293
    }
2294
2295
    /**
2296
     * Test for the copySubtree() method.
2297
     *
2298
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2299
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2300
     */
2301
    public function testCopySubtree()
2302
    {
2303
        $repository = $this->getRepository();
2304
2305
        $mediaLocationId = $this->generateId('location', 43);
2306
        $demoDesignLocationId = $this->generateId('location', 56);
2307
        /* BEGIN: Use Case */
2308
        // $mediaLocationId is the ID of the "Media" page location in
2309
        // an eZ Publish demo installation
2310
2311
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2312
        // Publish demo installation
2313
2314
        // Load the location service
2315
        $locationService = $repository->getLocationService();
2316
2317
        // Load location to copy
2318
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2319
2320
        // Load new parent location
2321
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2322
2323
        // Copy location "Media" to "Demo Design"
2324
        $copiedLocation = $locationService->copySubtree(
2325
            $locationToCopy,
2326
            $newParentLocation
2327
        );
2328
        /* END: Use Case */
2329
2330
        $this->assertInstanceOf(
2331
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
2332
            $copiedLocation
2333
        );
2334
2335
        $this->assertPropertiesCorrect(
2336
            [
2337
                'depth' => $newParentLocation->depth + 1,
2338
                'parentLocationId' => $newParentLocation->id,
2339
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $copiedLocation->id) . '/',
2340
            ],
2341
            $copiedLocation
2342
        );
2343
2344
        $this->assertDefaultContentStates($copiedLocation->contentInfo);
2345
    }
2346
2347
    /**
2348
     * Test for the copySubtree() method.
2349
     *
2350
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2351
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2352
     */
2353
    public function testCopySubtreeWithAliases()
2354
    {
2355
        $repository = $this->getRepository();
2356
        $urlAliasService = $repository->getURLAliasService();
2357
2358
        // $mediaLocationId is the ID of the "Media" page location in
2359
        // an eZ Publish demo installation
2360
2361
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2362
        // Publish demo installation
2363
        $mediaLocationId = $this->generateId('location', 43);
2364
        $demoDesignLocationId = $this->generateId('location', 56);
2365
2366
        $locationService = $repository->getLocationService();
2367
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2368
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2369
2370
        $expectedSubItemAliases = [
2371
            '/Design/Plain-site/Media/Multimedia',
2372
            '/Design/Plain-site/Media/Images',
2373
            '/Design/Plain-site/Media/Files',
2374
        ];
2375
2376
        $this->assertAliasesBeforeCopy($urlAliasService, $expectedSubItemAliases);
2377
2378
        // Copy location "Media" to "Design"
2379
        $locationService->copySubtree(
2380
            $locationToCopy,
2381
            $newParentLocation
2382
        );
2383
2384
        $this->assertGeneratedAliases($urlAliasService, $expectedSubItemAliases);
2385
    }
2386
2387
    /**
2388
     * Asserts that given Content has default ContentStates.
2389
     *
2390
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
2391
     */
2392
    private function assertDefaultContentStates(ContentInfo $contentInfo)
2393
    {
2394
        $repository = $this->getRepository();
2395
        $objectStateService = $repository->getObjectStateService();
2396
2397
        $objectStateGroups = $objectStateService->loadObjectStateGroups();
2398
2399
        foreach ($objectStateGroups as $objectStateGroup) {
2400
            $contentState = $objectStateService->getContentState($contentInfo, $objectStateGroup);
2401
            foreach ($objectStateService->loadObjectStates($objectStateGroup) as $objectState) {
2402
                // Only check the first object state which is the default one.
2403
                $this->assertEquals(
2404
                    $objectState,
2405
                    $contentState
2406
                );
2407
                break;
2408
            }
2409
        }
2410
    }
2411
2412
    /**
2413
     * Test for the copySubtree() method.
2414
     *
2415
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2416
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCopySubtree
2417
     */
2418
    public function testCopySubtreeUpdatesSubtreeProperties()
2419
    {
2420
        $repository = $this->getRepository();
2421
        $locationService = $repository->getLocationService();
2422
2423
        $locationToCopy = $locationService->loadLocation($this->generateId('location', 43));
2424
2425
        // Load Subtree properties before copy
2426
        $expected = $this->loadSubtreeProperties($locationToCopy);
2427
2428
        $mediaLocationId = $this->generateId('location', 43);
2429
        $demoDesignLocationId = $this->generateId('location', 56);
2430
        /* BEGIN: Use Case */
2431
        // $mediaLocationId is the ID of the "Media" page location in
2432
        // an eZ Publish demo installation
2433
2434
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2435
        // Publish demo installation
2436
2437
        // Load the location service
2438
        $locationService = $repository->getLocationService();
2439
2440
        // Load location to copy
2441
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2442
2443
        // Load new parent location
2444
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2445
2446
        // Copy location "Media" to "Demo Design"
2447
        $copiedLocation = $locationService->copySubtree(
2448
            $locationToCopy,
2449
            $newParentLocation
2450
        );
2451
        /* END: Use Case */
2452
2453
        $beforeIds = [];
2454
        foreach ($expected as $properties) {
2455
            $beforeIds[] = $properties['id'];
2456
        }
2457
2458
        $this->refreshSearch($repository);
2459
2460
        // Load Subtree properties after copy
2461
        $actual = $this->loadSubtreeProperties($copiedLocation);
2462
2463
        $this->assertEquals(count($expected), count($actual));
2464
2465
        foreach ($actual as $properties) {
2466
            $this->assertNotContains($properties['id'], $beforeIds);
2467
            $this->assertStringStartsWith(
2468
                $newParentLocation->pathString . $this->parseId('location', $copiedLocation->id) . '/',
2469
                $properties['pathString']
2470
            );
2471
            $this->assertStringEndsWith(
2472
                '/' . $this->parseId('location', $properties['id']) . '/',
2473
                $properties['pathString']
2474
            );
2475
        }
2476
    }
2477
2478
    /**
2479
     * Test for the copySubtree() method.
2480
     *
2481
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2482
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCopySubtree
2483
     */
2484
    public function testCopySubtreeIncrementsChildCountOfNewParent()
2485
    {
2486
        $repository = $this->getRepository();
2487
        $locationService = $repository->getLocationService();
2488
2489
        $childCountBefore = $locationService->getLocationChildCount($locationService->loadLocation(56));
2490
2491
        $mediaLocationId = $this->generateId('location', 43);
2492
        $demoDesignLocationId = $this->generateId('location', 56);
2493
        /* BEGIN: Use Case */
2494
        // $mediaLocationId is the ID of the "Media" page location in
2495
        // an eZ Publish demo installation
2496
2497
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2498
        // Publish demo installation
2499
2500
        // Load the location service
2501
        $locationService = $repository->getLocationService();
2502
2503
        // Load location to copy
2504
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2505
2506
        // Load new parent location
2507
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2508
2509
        // Copy location "Media" to "Demo Design"
2510
        $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...
2511
            $locationToCopy,
2512
            $newParentLocation
2513
        );
2514
        /* END: Use Case */
2515
2516
        $this->refreshSearch($repository);
2517
2518
        $childCountAfter = $locationService->getLocationChildCount($locationService->loadLocation($demoDesignLocationId));
2519
2520
        $this->assertEquals($childCountBefore + 1, $childCountAfter);
2521
    }
2522
2523
    /**
2524
     * Test for the copySubtree() method.
2525
     *
2526
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2527
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
2528
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCopySubtree
2529
     */
2530
    public function testCopySubtreeThrowsInvalidArgumentException()
2531
    {
2532
        $repository = $this->getRepository();
2533
2534
        $communityLocationId = $this->generateId('location', 5);
2535
        /* BEGIN: Use Case */
2536
        // $communityLocationId is the ID of the "Community" page location in
2537
        // an eZ Publish demo installation
2538
2539
        // Load the location service
2540
        $locationService = $repository->getLocationService();
2541
2542
        // Load location to copy
2543
        $locationToCopy = $locationService->loadLocation($communityLocationId);
2544
2545
        // Use a child as new parent
2546
        $childLocations = $locationService->loadLocationChildren($locationToCopy)->locations;
2547
        $newParentLocation = end($childLocations);
2548
2549
        // This call will fail with an "InvalidArgumentException", because the
2550
        // new parent is a child location of the subtree to copy.
2551
        $locationService->copySubtree(
2552
            $locationToCopy,
2553
            $newParentLocation
0 ignored issues
show
Security Bug introduced by
It seems like $newParentLocation defined by end($childLocations) on line 2547 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...
2554
        );
2555
        /* END: Use Case */
2556
    }
2557
2558
    /**
2559
     * Test for the moveSubtree() method.
2560
     *
2561
     * @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
2562
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2563
     */
2564
    public function testMoveSubtree(): void
2565
    {
2566
        $repository = $this->getRepository();
2567
2568
        $mediaLocationId = $this->generateId('location', 43);
2569
        $demoDesignLocationId = $this->generateId('location', 56);
2570
        /* BEGIN: Use Case */
2571
        // $mediaLocationId is the ID of the "Media" page location in
2572
        // an eZ Publish demo installation
2573
2574
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2575
        // Publish demo installation
2576
2577
        // Load the location service
2578
        $locationService = $repository->getLocationService();
2579
2580
        // Load location to move
2581
        $locationToMove = $locationService->loadLocation($demoDesignLocationId);
2582
2583
        // Load new parent location
2584
        $newParentLocation = $locationService->loadLocation($mediaLocationId);
2585
2586
        // Move location from "Home" to "Media"
2587
        $locationService->moveSubtree(
2588
            $locationToMove,
2589
            $newParentLocation
2590
        );
2591
2592
        // Load moved location
2593
        $movedLocation = $locationService->loadLocation($demoDesignLocationId);
2594
        /* END: Use Case */
2595
2596
        $this->assertPropertiesCorrect(
2597
            [
2598
                'hidden' => false,
2599
                'invisible' => false,
2600
                'depth' => $newParentLocation->depth + 1,
2601
                'parentLocationId' => $newParentLocation->id,
2602
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $movedLocation->id) . '/',
2603
            ],
2604
            $movedLocation
2605
        );
2606
    }
2607
2608
    /**
2609
     * Test for the moveSubtree() method.
2610
     *
2611
     * @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
2612
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2613
     */
2614 View Code Duplication
    public function testMoveSubtreeThrowsExceptionOnMoveNotIntoContainer(): void
2615
    {
2616
        $repository = $this->getRepository();
2617
2618
        $mediaLocationId = $this->generateId('location', 43);
2619
        $demoDesignLocationId = $this->generateId('location', 56);
2620
        /* BEGIN: Use Case */
2621
        // $mediaLocationId is the ID of the "Media" page location in
2622
        // an eZ Publish demo installation
2623
2624
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2625
        // Publish demo installation
2626
2627
        // Load the location service
2628
        $locationService = $repository->getLocationService();
2629
2630
        // Load location to move
2631
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2632
2633
        // Load new parent location
2634
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2635
2636
        // Move location from "Home" to "Demo Design" (not container)
2637
        $this->expectException(InvalidArgumentException::class);
2638
        $locationService->moveSubtree($locationToMove, $newParentLocation);
2639
    }
2640
2641
    /**
2642
     * Test for the moveSubtree() method.
2643
     *
2644
     * @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
2645
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2646
     */
2647 View Code Duplication
    public function testMoveSubtreeThrowsExceptionOnMoveToSame(): void
2648
    {
2649
        $repository = $this->getRepository();
2650
2651
        $mediaLocationId = $this->generateId('location', 43);
2652
        /* BEGIN: Use Case */
2653
        // $mediaLocationId is the ID of the "Media" page location in
2654
        // an eZ Publish demo installation
2655
2656
        // Load the location service
2657
        $locationService = $repository->getLocationService();
2658
2659
        // Load location to move
2660
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2661
2662
        // Load parent location
2663
        $newParentLocation = $locationService->loadLocation($locationToMove->parentLocationId);
2664
2665
        // Move location from "Home" to "Home"
2666
        $this->expectException(InvalidArgumentException::class);
2667
        $locationService->moveSubtree($locationToMove, $newParentLocation);
2668
    }
2669
2670
    /**
2671
     * Test for the moveSubtree() method.
2672
     *
2673
     * @covers \eZ\Publish\API\Repository\LocationService::moveSubtree
2674
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2675
     */
2676
    public function testMoveSubtreeHidden(): void
2677
    {
2678
        $repository = $this->getRepository();
2679
2680
        $mediaLocationId = $this->generateId('location', 43);
2681
        $demoDesignLocationId = $this->generateId('location', 56);
2682
        /* BEGIN: Use Case */
2683
        // $mediaLocationId is the ID of the "Media" page location in
2684
        // an eZ Publish demo installation
2685
2686
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2687
        // Publish demo installation
2688
2689
        // Load the location service
2690
        $locationService = $repository->getLocationService();
2691
2692
        // Load location to move
2693
        $locationToMove = $locationService->loadLocation($demoDesignLocationId);
2694
2695
        // Load new parent location
2696
        $newParentLocation = $locationService->loadLocation($mediaLocationId);
2697
2698
        // Hide the target location before we move
2699
        $newParentLocation = $locationService->hideLocation($newParentLocation);
2700
2701
        // Move location from "Demo Design" to "Home"
2702
        $locationService->moveSubtree(
2703
            $locationToMove,
2704
            $newParentLocation
2705
        );
2706
2707
        // Load moved location
2708
        $movedLocation = $locationService->loadLocation($demoDesignLocationId);
2709
        /* END: Use Case */
2710
2711
        $this->assertPropertiesCorrect(
2712
            [
2713
                'hidden' => false,
2714
                'invisible' => true,
2715
                'depth' => $newParentLocation->depth + 1,
2716
                'parentLocationId' => $newParentLocation->id,
2717
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $movedLocation->id) . '/',
2718
            ],
2719
            $movedLocation
2720
        );
2721
    }
2722
2723
    /**
2724
     * Test for the moveSubtree() method.
2725
     *
2726
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2727
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2728
     */
2729
    public function testMoveSubtreeUpdatesSubtreeProperties()
2730
    {
2731
        $repository = $this->getRepository();
2732
        $locationService = $repository->getLocationService();
2733
2734
        $locationToMove = $locationService->loadLocation($this->generateId('location', 56));
2735
        $newParentLocation = $locationService->loadLocation($this->generateId('location', 43));
2736
2737
        // Load Subtree properties before move
2738
        $expected = $this->loadSubtreeProperties($locationToMove);
2739
        foreach ($expected as $id => $properties) {
2740
            $expected[$id]['depth'] = $properties['depth'] + 2;
2741
            $expected[$id]['pathString'] = str_replace(
2742
                $locationToMove->pathString,
2743
                $newParentLocation->pathString . $this->parseId('location', $locationToMove->id) . '/',
2744
                $properties['pathString']
2745
            );
2746
        }
2747
2748
        $mediaLocationId = $this->generateId('location', 43);
2749
        $demoDesignLocationId = $this->generateId('location', 56);
2750
        /* BEGIN: Use Case */
2751
        // $mediaLocationId is the ID of the "Media" page location in
2752
        // an eZ Publish demo installation
2753
2754
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2755
        // Publish demo installation
2756
2757
        // Load the location service
2758
        $locationService = $repository->getLocationService();
2759
2760
        // Load location to move
2761
        $locationToMove = $locationService->loadLocation($demoDesignLocationId);
2762
2763
        // Load new parent location
2764
        $newParentLocation = $locationService->loadLocation($mediaLocationId);
2765
2766
        // Move location from "Demo Design" to "Home"
2767
        $locationService->moveSubtree(
2768
            $locationToMove,
2769
            $newParentLocation
2770
        );
2771
2772
        // Load moved location
2773
        $movedLocation = $locationService->loadLocation($demoDesignLocationId);
2774
        /* END: Use Case */
2775
2776
        $this->refreshSearch($repository);
2777
2778
        // Load Subtree properties after move
2779
        $actual = $this->loadSubtreeProperties($movedLocation);
2780
2781
        $this->assertEquals($expected, $actual);
2782
    }
2783
2784
    /**
2785
     * Test for the moveSubtree() method.
2786
     *
2787
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2788
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtreeUpdatesSubtreeProperties
2789
     */
2790
    public function testMoveSubtreeUpdatesSubtreePropertiesHidden()
2791
    {
2792
        $repository = $this->getRepository();
2793
        $locationService = $repository->getLocationService();
2794
2795
        $locationToMove = $locationService->loadLocation($this->generateId('location', 2));
2796
        $newParentLocation = $locationService->loadLocation($this->generateId('location', 43));
2797
2798
        // Hide the target location before we move
2799
        $newParentLocation = $locationService->hideLocation($newParentLocation);
2800
2801
        // Load Subtree properties before move
2802
        $expected = $this->loadSubtreeProperties($locationToMove);
2803
        foreach ($expected as $id => $properties) {
2804
            $expected[$id]['invisible'] = true;
2805
            $expected[$id]['depth'] = $properties['depth'] + 1;
2806
            $expected[$id]['pathString'] = str_replace(
2807
                $locationToMove->pathString,
2808
                $newParentLocation->pathString . $this->parseId('location', $locationToMove->id) . '/',
2809
                $properties['pathString']
2810
            );
2811
        }
2812
2813
        $homeLocationId = $this->generateId('location', 2);
2814
        $mediaLocationId = $this->generateId('location', 43);
2815
        /* BEGIN: Use Case */
2816
        // $mediaLocationId is the ID of the "Media" page location in
2817
        // an eZ Publish demo installation
2818
2819
        // $homeLocationId is the ID of the "Home" page location in an eZ
2820
        // Publish demo installation
2821
2822
        // Load the location service
2823
        $locationService = $repository->getLocationService();
2824
2825
        // Load location to move
2826
        $locationToMove = $locationService->loadLocation($homeLocationId);
2827
2828
        // Load new parent location
2829
        $newParentLocation = $locationService->loadLocation($mediaLocationId);
2830
2831
        // Move location from "Home" to "Demo Design"
2832
        $locationService->moveSubtree(
2833
            $locationToMove,
2834
            $newParentLocation
2835
        );
2836
2837
        // Load moved location
2838
        $movedLocation = $locationService->loadLocation($homeLocationId);
2839
        /* END: Use Case */
2840
2841
        $this->refreshSearch($repository);
2842
2843
        // Load Subtree properties after move
2844
        $actual = $this->loadSubtreeProperties($movedLocation);
2845
2846
        $this->assertEquals($expected, $actual);
2847
    }
2848
2849
    /**
2850
     * Test for the moveSubtree() method.
2851
     *
2852
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2853
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2854
     */
2855 View Code Duplication
    public function testMoveSubtreeIncrementsChildCountOfNewParent()
2856
    {
2857
        $repository = $this->getRepository();
2858
        $locationService = $repository->getLocationService();
2859
2860
        $newParentLocation = $locationService->loadLocation($this->generateId('location', 43));
2861
2862
        // Load expected properties before move
2863
        $expected = $this->loadLocationProperties($newParentLocation);
2864
        $childCountBefore = $locationService->getLocationChildCount($newParentLocation);
2865
2866
        $mediaLocationId = $this->generateId('location', 43);
2867
        $demoDesignLocationId = $this->generateId('location', 56);
2868
        /* BEGIN: Use Case */
2869
        // $mediaLocationId is the ID of the "Media" page location in
2870
        // an eZ Publish demo installation
2871
2872
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2873
        // Publish demo installation
2874
2875
        // Load the location service
2876
        $locationService = $repository->getLocationService();
2877
2878
        // Load location to move
2879
        $locationToMove = $locationService->loadLocation($demoDesignLocationId);
2880
2881
        // Load new parent location
2882
        $newParentLocation = $locationService->loadLocation($mediaLocationId);
2883
2884
        // Move location from "Demo Design" to "Home"
2885
        $locationService->moveSubtree(
2886
            $locationToMove,
2887
            $newParentLocation
2888
        );
2889
2890
        // Load moved location
2891
        $movedLocation = $locationService->loadLocation($demoDesignLocationId);
0 ignored issues
show
Unused Code introduced by
$movedLocation is not used, you could remove the assignment.

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

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

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

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

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