Completed
Push — EZP-31112-custom-aliases-gone-... ( 7e52f9...5caa2f )
by
unknown
18:51
created

testDeleteUnusedLocationWhichPreviousHadContentWithRelativeAlias()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 64

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 64
rs 8.7853
c 0
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

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

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

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

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

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

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

    return array();
}

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

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

Loading history...
652
    }
653
654
    /**
655
     * Test for the loadLocationList() method.
656
     *
657
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
658
     * @depends testLoadLocationListPrioritizedLanguagesFallback
659
     */
660
    public function testLoadLocationListPrioritizedLanguagesFallbackAndAlwaysAvailable(): void
661
    {
662
        $repository = $this->getRepository();
663
664
        $this->createLanguage('pol-PL', 'Polski');
665
666
        // 5 is the ID of an existing location, 442 is a non-existing id
667
        $locationService = $repository->getLocationService();
668
        $locations = $locationService->loadLocationList([5, 442], ['pol-PL'], true);
669
670
        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...
671
        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 668 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...
672
        self::assertEquals([5], array_keys($locations));
673
        self::assertInstanceOf(Location::class, $locations[5]);
674
        self::assertEquals(5, $locations[5]->id);
675
    }
676
677
    /**
678
     * Test for the loadLocationList() method.
679
     *
680
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
681
     */
682 View Code Duplication
    public function testLoadLocationListWithRootLocationId()
683
    {
684
        $repository = $this->getRepository();
685
686
        // 1 is the ID of an root location
687
        $locationService = $repository->getLocationService();
688
        $locations = $locationService->loadLocationList([1]);
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(1, $locations);
0 ignored issues
show
Bug introduced by
It seems like $locations defined by $locationService->loadLocationList(array(1)) 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
        self::assertEquals([1], array_keys($locations));
693
        self::assertInstanceOf(Location::class, $locations[1]);
694
        self::assertEquals(1, $locations[1]->id);
695
    }
696
697
    /**
698
     * Test for the loadLocationList() method.
699
     *
700
     * Ensures the list is returned in the same order as passed IDs array.
701
     *
702
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
703
     */
704
    public function testLoadLocationListInCorrectOrder()
705
    {
706
        $repository = $this->getRepository();
707
        $locationService = $repository->getLocationService();
708
709
        $cachedLocationId = 2;
710
        $locationIdsToLoad = [43, $cachedLocationId, 5];
711
712
        // Call loadLocation to cache it in memory as it might possibly affect list order
713
        $locationService->loadLocation($cachedLocationId);
714
715
        $locations = $locationService->loadLocationList($locationIdsToLoad);
716
        $locationIds = array_column($locations, 'id');
717
718
        self::assertEquals($locationIdsToLoad, $locationIds);
719
    }
720
721
    /**
722
     * Test for the loadLocationByRemoteId() method.
723
     *
724
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationByRemoteId()
725
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
726
     */
727 View Code Duplication
    public function testLoadLocationByRemoteId()
728
    {
729
        $repository = $this->getRepository();
730
731
        /* BEGIN: Use Case */
732
        $locationService = $repository->getLocationService();
733
734
        $location = $locationService->loadLocationByRemoteId(
735
            '3f6d92f8044aed134f32153517850f5a'
736
        );
737
        /* END: Use Case */
738
739
        $this->assertEquals(
740
            $locationService->loadLocation($this->generateId('location', 5)),
741
            $location
742
        );
743
    }
744
745
    /**
746
     * Test for the loadLocationByRemoteId() method.
747
     *
748
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationByRemoteId()
749
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
750
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
751
     */
752
    public function testLoadLocationByRemoteIdThrowsNotFoundException()
753
    {
754
        $repository = $this->getRepository();
755
756
        /* BEGIN: Use Case */
757
        $locationService = $repository->getLocationService();
758
759
        // Throws exception, since Location with remote ID does not exist
760
        $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...
761
            'not-exists'
762
        );
763
        /* END: Use Case */
764
    }
765
766
    /**
767
     * Test for the loadLocations() method.
768
     *
769
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
770
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
771
     */
772
    public function testLoadLocations()
773
    {
774
        $repository = $this->getRepository();
775
776
        $contentId = $this->generateId('object', 4);
777
        /* BEGIN: Use Case */
778
        // $contentId contains the ID of an existing content object
779
        $contentService = $repository->getContentService();
780
        $locationService = $repository->getLocationService();
781
782
        $contentInfo = $contentService->loadContentInfo($contentId);
783
784
        $locations = $locationService->loadLocations($contentInfo);
785
        /* END: Use Case */
786
787
        $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...
788
        self::assertNotEmpty($locations);
789
790
        foreach ($locations as $location) {
791
            self::assertInstanceOf(Location::class, $location);
792
            self::assertEquals($contentInfo->id, $location->getContentInfo()->id);
793
        }
794
795
        return $locations;
796
    }
797
798
    /**
799
     * Test for the loadLocations() method.
800
     *
801
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
802
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
803
     */
804
    public function testLoadLocationsContent(array $locations)
805
    {
806
        $repository = $this->getRepository();
807
        $locationService = $repository->getLocationService();
0 ignored issues
show
Unused Code introduced by
$locationService is not used, you could remove the assignment.

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

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

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

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

Loading history...
808
809
        $this->assertEquals(1, count($locations));
810
        foreach ($locations as $loadedLocation) {
811
            $this->assertInstanceOf(
812
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
813
                $loadedLocation
814
            );
815
        }
816
817
        usort(
818
            $locations,
819
            function ($a, $b) {
820
                strcmp($a->id, $b->id);
821
            }
822
        );
823
824
        $this->assertEquals(
825
            [$this->generateId('location', 5)],
826
            array_map(
827
                function (Location $location) {
828
                    return $location->id;
829
                },
830
                $locations
831
            )
832
        );
833
    }
834
835
    /**
836
     * Test for the loadLocations() method.
837
     *
838
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
839
     *
840
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations($contentInfo, $rootLocation)
841
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
842
     */
843
    public function testLoadLocationsLimitedSubtree()
844
    {
845
        $repository = $this->getRepository();
846
847
        $originalLocationId = $this->generateId('location', 54);
848
        $originalParentLocationId = $this->generateId('location', 48);
849
        $newParentLocationId = $this->generateId('location', 43);
850
        /* BEGIN: Use Case */
851
        // $originalLocationId is the ID of an existing location
852
        // $originalParentLocationId is the ID of the parent location of
853
        //     $originalLocationId
854
        // $newParentLocationId is the ID of an existing location outside the tree
855
        // of $originalLocationId and $originalParentLocationId
856
        $locationService = $repository->getLocationService();
857
858
        // Location at "/1/48/54"
859
        $originalLocation = $locationService->loadLocation($originalLocationId);
860
861
        // Create location under "/1/43/"
862
        $locationCreate = $locationService->newLocationCreateStruct($newParentLocationId);
863
        $locationService->createLocation(
864
            $originalLocation->contentInfo,
865
            $locationCreate
866
        );
867
868
        $findRootLocation = $locationService->loadLocation($originalParentLocationId);
869
870
        // Returns an array with only $originalLocation
871
        $locations = $locationService->loadLocations(
872
            $originalLocation->contentInfo,
873
            $findRootLocation
874
        );
875
        /* END: Use Case */
876
877
        $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...
878
879
        return $locations;
880
    }
881
882
    /**
883
     * Test for the loadLocations() method.
884
     *
885
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $locations
886
     *
887
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
888
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationsLimitedSubtree
889
     */
890
    public function testLoadLocationsLimitedSubtreeContent(array $locations)
891
    {
892
        $this->assertEquals(1, count($locations));
893
894
        $this->assertEquals(
895
            $this->generateId('location', 54),
896
            reset($locations)->id
897
        );
898
    }
899
900
    /**
901
     * Test for the loadLocations() method.
902
     *
903
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
904
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
905
     * @expectedException \eZ\Publish\API\Repository\Exceptions\BadStateException
906
     */
907 View Code Duplication
    public function testLoadLocationsThrowsBadStateException()
908
    {
909
        $repository = $this->getRepository();
910
911
        /* BEGIN: Use Case */
912
        $contentTypeService = $repository->getContentTypeService();
913
        $contentService = $repository->getContentService();
914
        $locationService = $repository->getLocationService();
915
916
        // Create new content, which is not published
917
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
918
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
919
        $contentCreate->setField('name', 'New Folder');
920
        $content = $contentService->createContent($contentCreate);
921
922
        // Throws Exception, since $content has no published version, yet
923
        $locationService->loadLocations(
924
            $content->contentInfo
925
        );
926
        /* END: Use Case */
927
    }
928
929
    /**
930
     * Test for the loadLocations() method.
931
     *
932
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations($contentInfo, $rootLocation)
933
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
934
     * @expectedException \eZ\Publish\API\Repository\Exceptions\BadStateException
935
     */
936
    public function testLoadLocationsThrowsBadStateExceptionLimitedSubtree()
937
    {
938
        $repository = $this->getRepository();
939
940
        $someLocationId = $this->generateId('location', 2);
941
        /* BEGIN: Use Case */
942
        // $someLocationId is the ID of an existing location
943
        $contentTypeService = $repository->getContentTypeService();
944
        $contentService = $repository->getContentService();
945
        $locationService = $repository->getLocationService();
946
947
        // Create new content, which is not published
948
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
949
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
950
        $contentCreate->setField('name', 'New Folder');
951
        $content = $contentService->createContent($contentCreate);
952
953
        $findRootLocation = $locationService->loadLocation($someLocationId);
954
955
        // Throws Exception, since $content has no published version, yet
956
        $locationService->loadLocations(
957
            $content->contentInfo,
958
            $findRootLocation
959
        );
960
        /* END: Use Case */
961
    }
962
963
    /**
964
     * Test for the loadLocationChildren() method.
965
     *
966
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationChildren
967
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
968
     */
969
    public function testLoadLocationChildren()
970
    {
971
        $repository = $this->getRepository();
972
973
        $locationId = $this->generateId('location', 5);
974
        /* BEGIN: Use Case */
975
        // $locationId is the ID of an existing location
976
        $locationService = $repository->getLocationService();
977
978
        $location = $locationService->loadLocation($locationId);
979
980
        $childLocations = $locationService->loadLocationChildren($location);
981
        /* END: Use Case */
982
983
        $this->assertInstanceOf(LocationList::class, $childLocations);
984
        $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...
985
        $this->assertNotEmpty($childLocations->locations);
986
        $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...
987
988
        foreach ($childLocations->locations as $childLocation) {
989
            $this->assertInstanceOf(Location::class, $childLocation);
990
            $this->assertEquals($location->id, $childLocation->parentLocationId);
991
        }
992
993
        return $childLocations;
994
    }
995
996
    /**
997
     * Test loading parent Locations for draft Content.
998
     *
999
     * @covers \eZ\Publish\API\Repository\LocationService::loadParentLocationsForDraftContent
1000
     */
1001
    public function testLoadParentLocationsForDraftContent()
1002
    {
1003
        $repository = $this->getRepository();
1004
        $locationService = $repository->getLocationService();
1005
        $contentService = $repository->getContentService();
1006
        $contentTypeService = $repository->getContentTypeService();
1007
1008
        // prepare locations
1009
        $locationCreateStructs = [
1010
            $locationService->newLocationCreateStruct(2),
1011
            $locationService->newLocationCreateStruct(5),
1012
        ];
1013
1014
        // Create new content
1015
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
1016
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
1017
        $contentCreate->setField('name', 'New Folder');
1018
        $contentDraft = $contentService->createContent($contentCreate, $locationCreateStructs);
1019
1020
        // Test loading parent Locations
1021
        $locations = $locationService->loadParentLocationsForDraftContent($contentDraft->versionInfo);
1022
1023
        self::assertCount(2, $locations);
1024
        foreach ($locations as $location) {
1025
            // test it is one of the given parent locations
1026
            self::assertTrue($location->id === 2 || $location->id === 5);
1027
        }
1028
1029
        return $contentDraft;
1030
    }
1031
1032
    /**
1033
     * Test that trying to load parent Locations throws Exception if Content is not a draft.
1034
     *
1035
     * @depends testLoadParentLocationsForDraftContent
1036
     *
1037
     * @param \eZ\Publish\API\Repository\Values\Content\Content $contentDraft
1038
     */
1039
    public function testLoadParentLocationsForDraftContentThrowsBadStateException(Content $contentDraft)
1040
    {
1041
        $this->expectException(BadStateException::class);
1042
        $this->expectExceptionMessageRegExp('/has been already published/');
1043
1044
        $repository = $this->getRepository(false);
1045
        $locationService = $repository->getLocationService();
1046
        $contentService = $repository->getContentService();
1047
1048
        $content = $contentService->publishVersion($contentDraft->versionInfo);
1049
1050
        $locationService->loadParentLocationsForDraftContent($content->versionInfo);
1051
    }
1052
1053
    /**
1054
     * Test for the getLocationChildCount() method.
1055
     *
1056
     * @see \eZ\Publish\API\Repository\LocationService::getLocationChildCount()
1057
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1058
     */
1059
    public function testGetLocationChildCount()
1060
    {
1061
        // $locationId is the ID of an existing location
1062
        $locationService = $this->getRepository()->getLocationService();
1063
1064
        $this->assertSame(
1065
            5,
1066
            $locationService->getLocationChildCount(
1067
                $locationService->loadLocation($this->generateId('location', 5))
1068
            )
1069
        );
1070
    }
1071
1072
    /**
1073
     * Test for the loadLocationChildren() method.
1074
     *
1075
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren()
1076
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
1077
     */
1078
    public function testLoadLocationChildrenData(LocationList $locations)
1079
    {
1080
        $this->assertEquals(5, count($locations->locations));
1081
        $this->assertEquals(5, $locations->totalCount);
1082
1083
        foreach ($locations->locations as $location) {
1084
            $this->assertInstanceOf(
1085
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1086
                $location
1087
            );
1088
        }
1089
1090
        $this->assertEquals(
1091
            [
1092
                $this->generateId('location', 12),
1093
                $this->generateId('location', 13),
1094
                $this->generateId('location', 14),
1095
                $this->generateId('location', 44),
1096
                $this->generateId('location', 61),
1097
            ],
1098
            array_map(
1099
                function (Location $location) {
1100
                    return $location->id;
1101
                },
1102
                $locations->locations
1103
            )
1104
        );
1105
    }
1106
1107
    /**
1108
     * Test for the loadLocationChildren() method.
1109
     *
1110
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
1111
     *
1112
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset)
1113
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
1114
     */
1115 View Code Duplication
    public function testLoadLocationChildrenWithOffset()
1116
    {
1117
        $repository = $this->getRepository();
1118
1119
        $locationId = $this->generateId('location', 5);
1120
        /* BEGIN: Use Case */
1121
        // $locationId is the ID of an existing location
1122
        $locationService = $repository->getLocationService();
1123
1124
        $location = $locationService->loadLocation($locationId);
1125
1126
        $childLocations = $locationService->loadLocationChildren($location, 2);
1127
        /* END: Use Case */
1128
1129
        $this->assertInstanceOf('\\eZ\\Publish\\API\\Repository\\Values\\Content\\LocationList', $childLocations);
1130
        $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...
1131
        $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...
1132
1133
        return $childLocations;
1134
    }
1135
1136
    /**
1137
     * Test for the loadLocationChildren() method.
1138
     *
1139
     * @param \eZ\Publish\API\Repository\Values\Content\LocationList $locations
1140
     *
1141
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset)
1142
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildrenWithOffset
1143
     */
1144 View Code Duplication
    public function testLoadLocationChildrenDataWithOffset(LocationList $locations)
1145
    {
1146
        $this->assertEquals(3, count($locations->locations));
1147
        $this->assertEquals(5, $locations->totalCount);
1148
1149
        foreach ($locations->locations as $location) {
1150
            $this->assertInstanceOf(
1151
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1152
                $location
1153
            );
1154
        }
1155
1156
        $this->assertEquals(
1157
            [
1158
                $this->generateId('location', 14),
1159
                $this->generateId('location', 44),
1160
                $this->generateId('location', 61),
1161
            ],
1162
            array_map(
1163
                function (Location $location) {
1164
                    return $location->id;
1165
                },
1166
                $locations->locations
1167
            )
1168
        );
1169
    }
1170
1171
    /**
1172
     * Test for the loadLocationChildren() method.
1173
     *
1174
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
1175
     *
1176
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset, $limit)
1177
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
1178
     */
1179 View Code Duplication
    public function testLoadLocationChildrenWithOffsetAndLimit()
1180
    {
1181
        $repository = $this->getRepository();
1182
1183
        $locationId = $this->generateId('location', 5);
1184
        /* BEGIN: Use Case */
1185
        // $locationId is the ID of an existing location
1186
        $locationService = $repository->getLocationService();
1187
1188
        $location = $locationService->loadLocation($locationId);
1189
1190
        $childLocations = $locationService->loadLocationChildren($location, 2, 2);
1191
        /* END: Use Case */
1192
1193
        $this->assertInstanceOf('\\eZ\\Publish\\API\\Repository\\Values\\Content\\LocationList', $childLocations);
1194
        $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...
1195
        $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...
1196
1197
        return $childLocations;
1198
    }
1199
1200
    /**
1201
     * Test for the loadLocationChildren() method.
1202
     *
1203
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $locations
1204
     *
1205
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset, $limit)
1206
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildrenWithOffsetAndLimit
1207
     */
1208 View Code Duplication
    public function testLoadLocationChildrenDataWithOffsetAndLimit(LocationList $locations)
1209
    {
1210
        $this->assertEquals(2, count($locations->locations));
1211
        $this->assertEquals(5, $locations->totalCount);
1212
1213
        foreach ($locations->locations as $location) {
1214
            $this->assertInstanceOf(
1215
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1216
                $location
1217
            );
1218
        }
1219
1220
        $this->assertEquals(
1221
            [
1222
                $this->generateId('location', 14),
1223
                $this->generateId('location', 44),
1224
            ],
1225
            array_map(
1226
                function (Location $location) {
1227
                    return $location->id;
1228
                },
1229
                $locations->locations
1230
            )
1231
        );
1232
    }
1233
1234
    /**
1235
     * Test for the newLocationUpdateStruct() method.
1236
     *
1237
     * @covers \eZ\Publish\API\Repository\LocationService::newLocationUpdateStruct
1238
     */
1239 View Code Duplication
    public function testNewLocationUpdateStruct()
1240
    {
1241
        $repository = $this->getRepository();
1242
1243
        /* BEGIN: Use Case */
1244
        $locationService = $repository->getLocationService();
1245
1246
        $updateStruct = $locationService->newLocationUpdateStruct();
1247
        /* END: Use Case */
1248
1249
        $this->assertInstanceOf(
1250
            LocationUpdateStruct::class,
1251
            $updateStruct
1252
        );
1253
1254
        $this->assertPropertiesCorrect(
1255
            [
1256
                'priority' => null,
1257
                'remoteId' => null,
1258
                'sortField' => null,
1259
                'sortOrder' => null,
1260
            ],
1261
            $updateStruct
1262
        );
1263
    }
1264
1265
    /**
1266
     * Test for the updateLocation() method.
1267
     *
1268
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1269
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1270
     */
1271
    public function testUpdateLocation()
1272
    {
1273
        $repository = $this->getRepository();
1274
1275
        $originalLocationId = $this->generateId('location', 5);
1276
        /* BEGIN: Use Case */
1277
        // $originalLocationId is the ID of an existing location
1278
        $locationService = $repository->getLocationService();
1279
1280
        $originalLocation = $locationService->loadLocation($originalLocationId);
1281
1282
        $updateStruct = $locationService->newLocationUpdateStruct();
1283
        $updateStruct->priority = 3;
1284
        $updateStruct->remoteId = 'c7adcbf1e96bc29bca28c2d809d0c7ef69272651';
1285
        $updateStruct->sortField = Location::SORT_FIELD_PRIORITY;
1286
        $updateStruct->sortOrder = Location::SORT_ORDER_DESC;
1287
1288
        $updatedLocation = $locationService->updateLocation($originalLocation, $updateStruct);
1289
        /* END: Use Case */
1290
1291
        $this->assertInstanceOf(
1292
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1293
            $updatedLocation
1294
        );
1295
1296
        return [
1297
            'originalLocation' => $originalLocation,
1298
            'updateStruct' => $updateStruct,
1299
            'updatedLocation' => $updatedLocation,
1300
        ];
1301
    }
1302
1303
    /**
1304
     * Test for the updateLocation() method.
1305
     *
1306
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1307
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testUpdateLocation
1308
     */
1309
    public function testUpdateLocationStructValues(array $data)
1310
    {
1311
        $originalLocation = $data['originalLocation'];
1312
        $updateStruct = $data['updateStruct'];
1313
        $updatedLocation = $data['updatedLocation'];
1314
1315
        $this->assertPropertiesCorrect(
1316
            [
1317
                'id' => $originalLocation->id,
1318
                'priority' => $updateStruct->priority,
1319
                'hidden' => $originalLocation->hidden,
1320
                'invisible' => $originalLocation->invisible,
1321
                'remoteId' => $updateStruct->remoteId,
1322
                'contentInfo' => $originalLocation->contentInfo,
1323
                'parentLocationId' => $originalLocation->parentLocationId,
1324
                'pathString' => $originalLocation->pathString,
1325
                'depth' => $originalLocation->depth,
1326
                'sortField' => $updateStruct->sortField,
1327
                'sortOrder' => $updateStruct->sortOrder,
1328
            ],
1329
            $updatedLocation
1330
        );
1331
    }
1332
1333
    /**
1334
     * Test for the updateLocation() method.
1335
     *
1336
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1337
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1338
     */
1339
    public function testUpdateLocationWithSameRemoteId()
1340
    {
1341
        $repository = $this->getRepository();
1342
1343
        $locationId = $this->generateId('location', 5);
1344
        /* BEGIN: Use Case */
1345
        // $locationId and remote ID is the IDs of the same, existing location
1346
        $locationService = $repository->getLocationService();
1347
1348
        $originalLocation = $locationService->loadLocation($locationId);
1349
1350
        $updateStruct = $locationService->newLocationUpdateStruct();
1351
1352
        // Remote ID of an existing location with the same locationId
1353
        $updateStruct->remoteId = $originalLocation->remoteId;
1354
1355
        // Sets one of the properties to be able to confirm location gets updated, here: priority
1356
        $updateStruct->priority = 2;
1357
1358
        $location = $locationService->updateLocation($originalLocation, $updateStruct);
1359
1360
        // Checks that the location was updated
1361
        $this->assertEquals(2, $location->priority);
1362
1363
        // Checks that remoteId remains the same
1364
        $this->assertEquals($originalLocation->remoteId, $location->remoteId);
1365
        /* END: Use Case */
1366
    }
1367
1368
    /**
1369
     * Test for the updateLocation() method.
1370
     *
1371
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1372
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1373
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1374
     */
1375 View Code Duplication
    public function testUpdateLocationThrowsInvalidArgumentException()
1376
    {
1377
        $repository = $this->getRepository();
1378
1379
        $locationId = $this->generateId('location', 5);
1380
        /* BEGIN: Use Case */
1381
        // $locationId and remoteId is the IDs of an existing, but not the same, location
1382
        $locationService = $repository->getLocationService();
1383
1384
        $originalLocation = $locationService->loadLocation($locationId);
1385
1386
        $updateStruct = $locationService->newLocationUpdateStruct();
1387
1388
        // Remote ID of an existing location with a different locationId
1389
        $updateStruct->remoteId = 'f3e90596361e31d496d4026eb624c983';
1390
1391
        // Throws exception, since remote ID is already taken
1392
        $locationService->updateLocation($originalLocation, $updateStruct);
1393
        /* END: Use Case */
1394
    }
1395
1396
    /**
1397
     * Test for the updateLocation() method.
1398
     *
1399
     * @covers \eZ\Publish\API\Repository\LocationService::updateLocation()
1400
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1401
     * @dataProvider dataProviderForOutOfRangeLocationPriority
1402
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1403
     */
1404 View Code Duplication
    public function testUpdateLocationThrowsInvalidArgumentExceptionPriorityIsOutOfRange($priority)
1405
    {
1406
        $repository = $this->getRepository();
1407
1408
        $locationId = $this->generateId('location', 5);
1409
        /* BEGIN: Use Case */
1410
        // $locationId and remoteId is the IDs of an existing, but not the same, location
1411
        $locationService = $repository->getLocationService();
1412
1413
        $originalLocation = $locationService->loadLocation($locationId);
1414
1415
        $updateStruct = $locationService->newLocationUpdateStruct();
1416
1417
        // Priority value is out of range
1418
        $updateStruct->priority = $priority;
1419
1420
        // Throws exception, since remote ID is already taken
1421
        $locationService->updateLocation($originalLocation, $updateStruct);
1422
        /* END: Use Case */
1423
    }
1424
1425
    /**
1426
     * Test for the updateLocation() method.
1427
     * Ref EZP-23302: Update Location fails if no change is performed with the update.
1428
     *
1429
     * @see \eZ\Publish\API\Repository\LocationService::updateLocation()
1430
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1431
     */
1432
    public function testUpdateLocationTwice()
1433
    {
1434
        $repository = $this->getRepository();
1435
1436
        $locationId = $this->generateId('location', 5);
1437
        /* BEGIN: Use Case */
1438
        $locationService = $repository->getLocationService();
1439
        $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...
1440
1441
        $originalLocation = $locationService->loadLocation($locationId);
1442
1443
        $updateStruct = $locationService->newLocationUpdateStruct();
1444
        $updateStruct->priority = 42;
1445
1446
        $updatedLocation = $locationService->updateLocation($originalLocation, $updateStruct);
1447
1448
        // Repeated update with the same, unchanged struct
1449
        $secondUpdatedLocation = $locationService->updateLocation($updatedLocation, $updateStruct);
1450
        /* END: Use Case */
1451
1452
        $this->assertEquals($updatedLocation->priority, 42);
1453
        $this->assertEquals($secondUpdatedLocation->priority, 42);
1454
    }
1455
1456
    /**
1457
     * Test for the swapLocation() method.
1458
     *
1459
     * @see \eZ\Publish\API\Repository\LocationService::swapLocation()
1460
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1461
     */
1462
    public function testSwapLocation()
1463
    {
1464
        $repository = $this->getRepository();
1465
        $locationService = $repository->getLocationService();
1466
1467
        $mediaLocationId = $this->generateId('location', 43);
1468
        $demoDesignLocationId = $this->generateId('location', 56);
1469
1470
        $mediaContentInfo = $locationService->loadLocation($mediaLocationId)->getContentInfo();
1471
        $demoDesignContentInfo = $locationService->loadLocation($demoDesignLocationId)->getContentInfo();
1472
1473
        /* BEGIN: Use Case */
1474
        // $mediaLocationId is the ID of the "Media" page location in
1475
        // an eZ Publish demo installation
1476
1477
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
1478
        // Publish demo installation
1479
1480
        // Load the location service
1481
        $locationService = $repository->getLocationService();
1482
1483
        $mediaLocation = $locationService->loadLocation($mediaLocationId);
1484
        $demoDesignLocation = $locationService->loadLocation($demoDesignLocationId);
1485
1486
        // Swaps the content referred to by the locations
1487
        $locationService->swapLocation($mediaLocation, $demoDesignLocation);
1488
        /* END: Use Case */
1489
1490
        // Reload Locations, IDs swapped
1491
        $demoDesignLocation = $locationService->loadLocation($mediaLocationId);
1492
        $mediaLocation = $locationService->loadLocation($demoDesignLocationId);
1493
1494
        // Assert Location's Content is updated
1495
        $this->assertEquals(
1496
            $mediaContentInfo->id,
1497
            $mediaLocation->getContentInfo()->id
1498
        );
1499
        $this->assertEquals(
1500
            $demoDesignContentInfo->id,
1501
            $demoDesignLocation->getContentInfo()->id
1502
        );
1503
1504
        // Assert URL aliases are updated
1505
        $this->assertEquals(
1506
            $mediaLocation->id,
1507
            $repository->getURLAliasService()->lookup('/Design/Media')->destination
1508
        );
1509
        $this->assertEquals(
1510
            $demoDesignLocation->id,
1511
            $repository->getURLAliasService()->lookup('/eZ-Publish-Demo-Design-without-demo-content')->destination
1512
        );
1513
    }
1514
1515
    /**
1516
     * Test for the swapLocation() method with custom aliases.
1517
     *
1518
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1519
     *
1520
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
1521
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
1522
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
1523
     */
1524
    public function testSwapLocationForContentWithCustomUrlAliases(): void
1525
    {
1526
        $repository = $this->getRepository();
1527
        $locationService = $repository->getLocationService();
1528
        $urlAliasService = $repository->getURLAliasService();
1529
        $this->createLanguage('pol-PL', 'Polski');
1530
1531
        $folder1 = $this->createFolder(['eng-GB' => 'Folder1', 'pol-PL' => 'Folder1'], 2);
1532
        $folder2 = $this->createFolder(['eng-GB' => 'Folder2'], 2);
1533
        $location1 = $locationService->loadLocation($folder1->contentInfo->mainLocationId);
1534
        $location2 = $locationService->loadLocation($folder2->contentInfo->mainLocationId);
1535
1536
        $urlAlias = $urlAliasService->createUrlAlias($location1, '/custom-location1', 'eng-GB', false, true);
1537
        $urlAliasService->createUrlAlias($location1, '/custom-location1', 'pol-PL', false, true);
1538
        $urlAliasService->createUrlAlias($location2, '/custom-location2', 'eng-GB', false, true);
1539
        $location1UrlAliases = $urlAliasService->listLocationAliases($location1);
1540
        $location2UrlAliases = $urlAliasService->listLocationAliases($location2);
1541
1542
        $locationService->swapLocation($location1, $location2);
1543
        $location1 = $locationService->loadLocation($location1->contentInfo->mainLocationId);
1544
        $location2 = $locationService->loadLocation($location2->contentInfo->mainLocationId);
1545
1546
        $location1UrlAliasesAfterSwap = $urlAliasService->listLocationAliases($location1);
1547
        $location2UrlAliasesAfterSwap = $urlAliasService->listLocationAliases($location2);
1548
1549
        $keyUrlAlias = array_search($urlAlias->id, array_column($location1UrlAliasesAfterSwap, 'id'));
1550
1551
        self::assertEquals($folder1->id, $location2->contentInfo->id);
1552
        self::assertEquals($folder2->id, $location1->contentInfo->id);
1553
        self::assertNotEquals($location1UrlAliases, $location1UrlAliasesAfterSwap);
1554
        self::assertEquals($location2UrlAliases, $location2UrlAliasesAfterSwap);
1555
        self::assertEquals(['eng-GB'], $location1UrlAliasesAfterSwap[$keyUrlAlias]->languageCodes);
1556
    }
1557
1558
    /**
1559
     * Test swapping secondary Location with main Location.
1560
     *
1561
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1562
     *
1563
     * @see https://jira.ez.no/browse/EZP-28663
1564
     *
1565
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
1566
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
1567
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
1568
     *
1569
     * @return int[]
1570
     */
1571
    public function testSwapLocationForMainAndSecondaryLocation(): array
1572
    {
1573
        $repository = $this->getRepository();
1574
        $locationService = $repository->getLocationService();
1575
        $contentService = $repository->getContentService();
1576
1577
        $folder1 = $this->createFolder(['eng-GB' => 'Folder1'], 2);
1578
        $folder2 = $this->createFolder(['eng-GB' => 'Folder2'], 2);
1579
        $folder3 = $this->createFolder(['eng-GB' => 'Folder3'], 2);
1580
1581
        $primaryLocation = $locationService->loadLocation($folder1->contentInfo->mainLocationId);
1582
        $parentLocation = $locationService->loadLocation($folder2->contentInfo->mainLocationId);
1583
        $secondaryLocation = $locationService->createLocation(
1584
            $folder1->contentInfo,
1585
            $locationService->newLocationCreateStruct($parentLocation->id)
1586
        );
1587
1588
        $targetLocation = $locationService->loadLocation($folder3->contentInfo->mainLocationId);
1589
1590
        // perform sanity checks
1591
        $this->assertContentHasExpectedLocations([$primaryLocation, $secondaryLocation], $folder1);
1592
1593
        // begin use case
1594
        $locationService->swapLocation($secondaryLocation, $targetLocation);
1595
1596
        // test results
1597
        $primaryLocation = $locationService->loadLocation($primaryLocation->id);
1598
        $secondaryLocation = $locationService->loadLocation($secondaryLocation->id);
1599
        $targetLocation = $locationService->loadLocation($targetLocation->id);
1600
1601
        self::assertEquals($folder1->id, $primaryLocation->contentInfo->id);
1602
        self::assertEquals($folder1->id, $targetLocation->contentInfo->id);
1603
        self::assertEquals($folder3->id, $secondaryLocation->contentInfo->id);
1604
1605
        $this->assertContentHasExpectedLocations([$primaryLocation, $targetLocation], $folder1);
1606
1607
        self::assertEquals(
1608
            $folder1,
1609
            $contentService->loadContent($folder1->id)
1610
        );
1611
1612
        self::assertEquals(
1613
            $folder2,
1614
            $contentService->loadContent($folder2->id)
1615
        );
1616
1617
        // only in case of Folder 3, main location id changed due to swap
1618
        self::assertEquals(
1619
            $secondaryLocation->id,
1620
            $contentService->loadContent($folder3->id)->contentInfo->mainLocationId
1621
        );
1622
1623
        return [$folder1, $folder2, $folder3];
1624
    }
1625
1626
    /**
1627
     * Compare Ids of expected and loaded Locations for the given Content.
1628
     *
1629
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $expectedLocations
1630
     * @param \eZ\Publish\API\Repository\Values\Content\Content $content
1631
     *
1632
     * @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
1633
     */
1634
    private function assertContentHasExpectedLocations(array $expectedLocations, Content $content)
1635
    {
1636
        $repository = $this->getRepository(false);
1637
        $locationService = $repository->getLocationService();
1638
1639
        $expectedLocationIds = array_map(
1640
            function (Location $location) {
1641
                return (int)$location->id;
1642
            },
1643
            $expectedLocations
1644
        );
1645
1646
        $actualLocationsIds = array_map(
1647
            function (Location $location) {
1648
                return $location->id;
1649
            },
1650
            $locationService->loadLocations($content->contentInfo)
1651
        );
1652
        self::assertCount(count($expectedLocations), $actualLocationsIds);
1653
1654
        // perform unordered equality assertion
1655
        self::assertEquals(
1656
            $expectedLocationIds,
1657
            $actualLocationsIds,
1658
            sprintf(
1659
                'Content %d contains Locations %s, but expected: %s',
1660
                $content->id,
1661
                implode(', ', $actualLocationsIds),
1662
                implode(', ', $expectedLocationIds)
1663
            ),
1664
            0.0,
1665
            10,
1666
            true
1667
        );
1668
    }
1669
1670
    /**
1671
     * @depends testSwapLocationForMainAndSecondaryLocation
1672
     *
1673
     * @param \eZ\Publish\API\Repository\Values\Content\Content[] $contentItems Content items created by testSwapLocationForSecondaryLocation
1674
     *
1675
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1676
     */
1677
    public function testSwapLocationDoesNotCorruptSearchResults(array $contentItems)
1678
    {
1679
        $repository = $this->getRepository(false);
1680
        $searchService = $repository->getSearchService();
1681
1682
        $this->refreshSearch($repository);
1683
1684
        $contentIds = array_map(
1685
            function (Content $content) {
1686
                return $content->id;
1687
            },
1688
            $contentItems
1689
        );
1690
1691
        $query = new Query();
1692
        $query->filter = new Query\Criterion\ContentId($contentIds);
1693
1694
        $searchResult = $searchService->findContent($query);
1695
1696
        self::assertEquals(count($contentItems), $searchResult->totalCount);
1697
        self::assertEquals(
1698
            $searchResult->totalCount,
1699
            count($searchResult->searchHits),
1700
            'Total count of search result hits does not match the actual number of found results'
1701
        );
1702
        $foundContentIds = array_map(
1703
            function (SearchHit $searchHit) {
1704
                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...
1705
            },
1706
            $searchResult->searchHits
1707
        );
1708
        sort($contentIds);
1709
        sort($foundContentIds);
1710
        self::assertSame(
1711
            $contentIds,
1712
            $foundContentIds,
1713
            'Got different than expected Content item Ids'
1714
        );
1715
    }
1716
1717
    /**
1718
     * Test swapping two secondary (non-main) Locations.
1719
     *
1720
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1721
     *
1722
     * @throws \eZ\Publish\API\Repository\Exceptions\ForbiddenException
1723
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1724
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
1725
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
1726
     */
1727
    public function testSwapLocationForSecondaryLocations()
1728
    {
1729
        $repository = $this->getRepository();
1730
        $locationService = $repository->getLocationService();
1731
        $contentService = $repository->getContentService();
1732
1733
        $folder1 = $this->createFolder(['eng-GB' => 'Folder1'], 2);
1734
        $folder2 = $this->createFolder(['eng-GB' => 'Folder2'], 2);
1735
        $parentFolder1 = $this->createFolder(['eng-GB' => 'Parent1'], 2);
1736
        $parentFolder2 = $this->createFolder(['eng-GB' => 'Parent2'], 2);
1737
1738
        $parentLocation1 = $locationService->loadLocation($parentFolder1->contentInfo->mainLocationId);
1739
        $parentLocation2 = $locationService->loadLocation($parentFolder2->contentInfo->mainLocationId);
1740
        $secondaryLocation1 = $locationService->createLocation(
1741
            $folder1->contentInfo,
1742
            $locationService->newLocationCreateStruct($parentLocation1->id)
1743
        );
1744
        $secondaryLocation2 = $locationService->createLocation(
1745
            $folder2->contentInfo,
1746
            $locationService->newLocationCreateStruct($parentLocation2->id)
1747
        );
1748
1749
        // begin use case
1750
        $locationService->swapLocation($secondaryLocation1, $secondaryLocation2);
1751
1752
        // test results
1753
        $secondaryLocation1 = $locationService->loadLocation($secondaryLocation1->id);
1754
        $secondaryLocation2 = $locationService->loadLocation($secondaryLocation2->id);
1755
1756
        self::assertEquals($folder2->id, $secondaryLocation1->contentInfo->id);
1757
        self::assertEquals($folder1->id, $secondaryLocation2->contentInfo->id);
1758
1759
        self::assertEquals(
1760
            $folder1,
1761
            $contentService->loadContent($folder1->id)
1762
        );
1763
1764
        self::assertEquals(
1765
            $folder2,
1766
            $contentService->loadContent($folder2->id)
1767
        );
1768
    }
1769
1770
    /**
1771
     * Test swapping Main Location of a Content with another one updates Content item Main Location.
1772
     *
1773
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1774
     */
1775
    public function testSwapLocationUpdatesMainLocation()
1776
    {
1777
        $repository = $this->getRepository();
1778
        $locationService = $repository->getLocationService();
1779
        $contentService = $repository->getContentService();
1780
1781
        $mainLocationParentId = 60;
1782
        $secondaryLocationId = 43;
1783
1784
        $publishedContent = $this->publishContentWithParentLocation(
1785
            'Content for Swap Location Test', $mainLocationParentId
1786
        );
1787
1788
        // sanity check
1789
        $mainLocation = $locationService->loadLocation($publishedContent->contentInfo->mainLocationId);
1790
        self::assertEquals($mainLocationParentId, $mainLocation->parentLocationId);
1791
1792
        // load another pre-existing location
1793
        $secondaryLocation = $locationService->loadLocation($secondaryLocationId);
1794
1795
        // swap the Main Location with a secondary one
1796
        $locationService->swapLocation($mainLocation, $secondaryLocation);
1797
1798
        // check if Main Location has been updated
1799
        $mainLocation = $locationService->loadLocation($secondaryLocation->id);
1800
        self::assertEquals($publishedContent->contentInfo->id, $mainLocation->contentInfo->id);
1801
        self::assertEquals($mainLocation->id, $mainLocation->contentInfo->mainLocationId);
1802
1803
        $reloadedContent = $contentService->loadContentByContentInfo($publishedContent->contentInfo);
1804
        self::assertEquals($mainLocation->id, $reloadedContent->contentInfo->mainLocationId);
1805
    }
1806
1807
    /**
1808
     * Test if location swap affects related bookmarks.
1809
     *
1810
     * @covers \eZ\Publish\API\Repository\LocationService::swapLocation
1811
     */
1812
    public function testBookmarksAreSwappedAfterSwapLocation()
1813
    {
1814
        $repository = $this->getRepository();
1815
1816
        $mediaLocationId = $this->generateId('location', 43);
1817
        $demoDesignLocationId = $this->generateId('location', 56);
1818
1819
        /* BEGIN: Use Case */
1820
        $locationService = $repository->getLocationService();
1821
        $bookmarkService = $repository->getBookmarkService();
1822
1823
        $mediaLocation = $locationService->loadLocation($mediaLocationId);
1824
        $demoDesignLocation = $locationService->loadLocation($demoDesignLocationId);
1825
1826
        // Bookmark locations
1827
        $bookmarkService->createBookmark($mediaLocation);
1828
        $bookmarkService->createBookmark($demoDesignLocation);
1829
1830
        $beforeSwap = $bookmarkService->loadBookmarks();
1831
1832
        // Swaps the content referred to by the locations
1833
        $locationService->swapLocation($mediaLocation, $demoDesignLocation);
1834
1835
        $afterSwap = $bookmarkService->loadBookmarks();
1836
        /* END: Use Case */
1837
1838
        $this->assertEquals($beforeSwap->items[0]->id, $afterSwap->items[1]->id);
1839
        $this->assertEquals($beforeSwap->items[1]->id, $afterSwap->items[0]->id);
1840
    }
1841
1842
    /**
1843
     * Test for the hideLocation() method.
1844
     *
1845
     * @see \eZ\Publish\API\Repository\LocationService::hideLocation()
1846
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
1847
     */
1848
    public function testHideLocation()
1849
    {
1850
        $repository = $this->getRepository();
1851
1852
        $locationId = $this->generateId('location', 5);
1853
        /* BEGIN: Use Case */
1854
        // $locationId is the ID of an existing location
1855
        $locationService = $repository->getLocationService();
1856
1857
        $visibleLocation = $locationService->loadLocation($locationId);
1858
1859
        $hiddenLocation = $locationService->hideLocation($visibleLocation);
1860
        /* END: Use Case */
1861
1862
        $this->assertInstanceOf(
1863
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1864
            $hiddenLocation
1865
        );
1866
1867
        $this->assertTrue(
1868
            $hiddenLocation->hidden,
1869
            sprintf(
1870
                'Location with ID "%s" not hidden.',
1871
                $hiddenLocation->id
1872
            )
1873
        );
1874
1875
        $this->refreshSearch($repository);
1876
1877
        foreach ($locationService->loadLocationChildren($hiddenLocation)->locations as $child) {
1878
            $this->assertSubtreeProperties(
1879
                ['invisible' => true],
1880
                $child
1881
            );
1882
        }
1883
    }
1884
1885
    /**
1886
     * Assert that $expectedValues are set in the subtree starting at $location.
1887
     *
1888
     * @param array $expectedValues
1889
     * @param Location $location
1890
     */
1891
    protected function assertSubtreeProperties(array $expectedValues, Location $location, $stopId = null)
1892
    {
1893
        $repository = $this->getRepository();
1894
        $locationService = $repository->getLocationService();
1895
1896
        if ($location->id === $stopId) {
1897
            return;
1898
        }
1899
1900
        foreach ($expectedValues as $propertyName => $propertyValue) {
1901
            $this->assertEquals(
1902
                $propertyValue,
1903
                $location->$propertyName
1904
            );
1905
1906
            foreach ($locationService->loadLocationChildren($location)->locations as $child) {
1907
                $this->assertSubtreeProperties($expectedValues, $child);
1908
            }
1909
        }
1910
    }
1911
1912
    /**
1913
     * Test for the unhideLocation() method.
1914
     *
1915
     * @see \eZ\Publish\API\Repository\LocationService::unhideLocation()
1916
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testHideLocation
1917
     */
1918
    public function testUnhideLocation()
1919
    {
1920
        $repository = $this->getRepository();
1921
1922
        $locationId = $this->generateId('location', 5);
1923
        /* BEGIN: Use Case */
1924
        // $locationId is the ID of an existing location
1925
        $locationService = $repository->getLocationService();
1926
1927
        $visibleLocation = $locationService->loadLocation($locationId);
1928
        $hiddenLocation = $locationService->hideLocation($visibleLocation);
1929
1930
        $unHiddenLocation = $locationService->unhideLocation($hiddenLocation);
1931
        /* END: Use Case */
1932
1933
        $this->assertInstanceOf(
1934
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1935
            $unHiddenLocation
1936
        );
1937
1938
        $this->assertFalse(
1939
            $unHiddenLocation->hidden,
1940
            sprintf(
1941
                'Location with ID "%s" not unhidden.',
1942
                $unHiddenLocation->id
1943
            )
1944
        );
1945
1946
        $this->refreshSearch($repository);
1947
1948
        foreach ($locationService->loadLocationChildren($unHiddenLocation)->locations as $child) {
1949
            $this->assertSubtreeProperties(
1950
                ['invisible' => false],
1951
                $child
1952
            );
1953
        }
1954
    }
1955
1956
    /**
1957
     * Test for the unhideLocation() method.
1958
     *
1959
     * @see \eZ\Publish\API\Repository\LocationService::unhideLocation()
1960
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testUnhideLocation
1961
     */
1962
    public function testUnhideLocationNotUnhidesHiddenSubtree()
1963
    {
1964
        $repository = $this->getRepository();
1965
1966
        $higherLocationId = $this->generateId('location', 5);
1967
        $lowerLocationId = $this->generateId('location', 13);
1968
        /* BEGIN: Use Case */
1969
        // $higherLocationId is the ID of a location
1970
        // $lowerLocationId is the ID of a location below $higherLocationId
1971
        $locationService = $repository->getLocationService();
1972
1973
        $higherLocation = $locationService->loadLocation($higherLocationId);
1974
        $hiddenHigherLocation = $locationService->hideLocation($higherLocation);
1975
1976
        $lowerLocation = $locationService->loadLocation($lowerLocationId);
1977
        $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...
1978
1979
        $unHiddenHigherLocation = $locationService->unhideLocation($hiddenHigherLocation);
1980
        /* END: Use Case */
1981
1982
        $this->assertInstanceOf(
1983
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1984
            $unHiddenHigherLocation
1985
        );
1986
1987
        $this->assertFalse(
1988
            $unHiddenHigherLocation->hidden,
1989
            sprintf(
1990
                'Location with ID "%s" not unhidden.',
1991
                $unHiddenHigherLocation->id
1992
            )
1993
        );
1994
1995
        $this->refreshSearch($repository);
1996
1997
        foreach ($locationService->loadLocationChildren($unHiddenHigherLocation)->locations as $child) {
1998
            $this->assertSubtreeProperties(
1999
                ['invisible' => false],
2000
                $child,
2001
                $this->generateId('location', 13)
2002
            );
2003
        }
2004
2005
        $stillHiddenLocation = $locationService->loadLocation($this->generateId('location', 13));
2006
        $this->assertTrue(
2007
            $stillHiddenLocation->hidden,
2008
            sprintf(
2009
                'Hidden sub-location with ID %s accidentally unhidden.',
2010
                $stillHiddenLocation->id
2011
            )
2012
        );
2013
        foreach ($locationService->loadLocationChildren($stillHiddenLocation)->locations as $child) {
2014
            $this->assertSubtreeProperties(
2015
                ['invisible' => true],
2016
                $child
2017
            );
2018
        }
2019
    }
2020
2021
    /**
2022
     * Test for the deleteLocation() method.
2023
     *
2024
     * @see \eZ\Publish\API\Repository\LocationService::deleteLocation()
2025
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2026
     */
2027
    public function testDeleteLocation()
2028
    {
2029
        $repository = $this->getRepository();
2030
2031
        $mediaLocationId = $this->generateId('location', 43);
2032
        /* BEGIN: Use Case */
2033
        // $mediaLocationId is the ID of the location of the
2034
        // "Media" location in an eZ Publish demo installation
2035
        $locationService = $repository->getLocationService();
2036
2037
        $location = $locationService->loadLocation($mediaLocationId);
2038
2039
        $locationService->deleteLocation($location);
2040
        /* END: Use Case */
2041
2042
        try {
2043
            $locationService->loadLocation($mediaLocationId);
2044
            $this->fail("Location $mediaLocationId not deleted.");
2045
        } catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
2046
        }
2047
2048
        // The following IDs are IDs of child locations of $mediaLocationId location
2049
        // ( Media/Images, Media/Files, Media/Multimedia respectively )
2050
        foreach ([51, 52, 53] as $childLocationId) {
2051
            try {
2052
                $locationService->loadLocation($this->generateId('location', $childLocationId));
2053
                $this->fail("Location $childLocationId not deleted.");
2054
            } catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
2055
            }
2056
        }
2057
2058
        // The following IDs are IDs of content below $mediaLocationId location
2059
        // ( Media/Images, Media/Files, Media/Multimedia respectively )
2060
        $contentService = $this->getRepository()->getContentService();
2061
        foreach ([49, 50, 51] as $childContentId) {
2062
            try {
2063
                $contentService->loadContentInfo($this->generateId('object', $childContentId));
2064
                $this->fail("Content $childContentId not deleted.");
2065
            } catch (NotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
2066
            }
2067
        }
2068
    }
2069
2070
    /**
2071
     * Test for the deleteLocation() method.
2072
     *
2073
     * @see \eZ\Publish\API\Repository\LocationService::deleteLocation()
2074
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testDeleteLocation
2075
     */
2076
    public function testDeleteLocationDecrementsChildCountOnParent()
2077
    {
2078
        $repository = $this->getRepository();
2079
2080
        $mediaLocationId = $this->generateId('location', 43);
2081
        /* BEGIN: Use Case */
2082
        // $mediaLocationId is the ID of the location of the
2083
        // "Media" location in an eZ Publish demo installation
2084
2085
        $locationService = $repository->getLocationService();
2086
2087
        // Load the current the user group location
2088
        $location = $locationService->loadLocation($mediaLocationId);
2089
2090
        // Load the parent location
2091
        $parentLocation = $locationService->loadLocation(
2092
            $location->parentLocationId
2093
        );
2094
2095
        // Get child count
2096
        $childCountBefore = $locationService->getLocationChildCount($parentLocation);
2097
2098
        // Delete the user group location
2099
        $locationService->deleteLocation($location);
2100
2101
        $this->refreshSearch($repository);
2102
2103
        // Reload parent location
2104
        $parentLocation = $locationService->loadLocation(
2105
            $location->parentLocationId
2106
        );
2107
2108
        // This will be $childCountBefore - 1
2109
        $childCountAfter = $locationService->getLocationChildCount($parentLocation);
2110
        /* END: Use Case */
2111
2112
        $this->assertEquals($childCountBefore - 1, $childCountAfter);
2113
    }
2114
2115
    /**
2116
     * Test for the deleteLocation() method.
2117
     *
2118
     * Related issue: EZP-21904
2119
     *
2120
     * @see \eZ\Publish\API\Repository\LocationService::deleteLocation()
2121
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
2122
     */
2123
    public function testDeleteContentObjectLastLocation()
2124
    {
2125
        $repository = $this->getRepository();
2126
2127
        /* BEGIN: Use case */
2128
        $contentService = $repository->getContentService();
2129
        $locationService = $repository->getLocationService();
2130
        $contentTypeService = $repository->getContentTypeService();
2131
        $urlAliasService = $repository->getURLAliasService();
2132
2133
        // prepare Content object
2134
        $createStruct = $contentService->newContentCreateStruct(
2135
            $contentTypeService->loadContentTypeByIdentifier('folder'),
2136
            'eng-GB'
2137
        );
2138
        $createStruct->setField('name', 'Test folder');
2139
2140
        // creata Content object
2141
        $content = $contentService->publishVersion(
2142
            $contentService->createContent(
2143
                $createStruct,
2144
                [$locationService->newLocationCreateStruct(2)]
2145
            )->versionInfo
2146
        );
2147
2148
        // delete location
2149
        $locationService->deleteLocation(
2150
            $locationService->loadLocation(
2151
                $urlAliasService->lookup('/Test-folder')->destination
2152
            )
2153
        );
2154
2155
        // this should throw a not found exception
2156
        $contentService->loadContent($content->versionInfo->contentInfo->id);
2157
        /* END: Use case*/
2158
    }
2159
2160
    /**
2161
     * Test for the deleteLocation() method.
2162
     *
2163
     * @covers  \eZ\Publish\API\Repository\LocationService::deleteLocation()
2164
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testDeleteLocation
2165
     */
2166
    public function testDeleteLocationDeletesRelatedBookmarks()
2167
    {
2168
        $repository = $this->getRepository();
2169
2170
        $parentLocationId = $this->generateId('location', 43);
2171
        $childLocationId = $this->generateId('location', 53);
2172
2173
        /* BEGIN: Use Case */
2174
        $locationService = $repository->getLocationService();
2175
        $bookmarkService = $repository->getBookmarkService();
2176
2177
        // Load location
2178
        $childLocation = $locationService->loadLocation($childLocationId);
2179
        // Add location to bookmarks
2180
        $bookmarkService->createBookmark($childLocation);
2181
        // Load parent location
2182
        $parentLocation = $locationService->loadLocation($parentLocationId);
2183
        // Delete parent location
2184
        $locationService->deleteLocation($parentLocation);
2185
        /* END: Use Case */
2186
2187
        // Location isn't bookmarked anymore
2188
        foreach ($bookmarkService->loadBookmarks(0, 9999) as $bookmarkedLocation) {
2189
            $this->assertNotEquals($childLocation->id, $bookmarkedLocation->id);
2190
        }
2191
    }
2192
2193
    /**
2194
     * @covers \eZ\Publish\API\Repository\LocationService::deleteLocation
2195
     */
2196
    public function testDeleteUnusedLocationWhichPreviousHadContentWithRelativeAlias(): void
2197
    {
2198
        $repository = $this->getRepository(false);
2199
2200
        $contentService = $repository->getContentService();
2201
        $locationService = $repository->getLocationService();
2202
        $urlAliasService = $repository->getURLAliasService();
2203
2204
        $originalFolder = $this->createFolder(['eng-GB' => 'Original folder'], 2);
2205
        $newFolder = $this->createFolder(['eng-GB' => 'New folder'], 2);
2206
        $originalFolderLocationId = $originalFolder->contentInfo->mainLocationId;
2207
2208
        $forum = $contentService->publishVersion(
2209
            $contentService->createContent(
2210
                $this->createForumStruct('Some forum'),
2211
                [
2212
                    $locationService->newLocationCreateStruct($originalFolderLocationId),
2213
                ]
2214
            )->versionInfo
2215
        );
2216
2217
        $forumMainLocation = $locationService->loadLocation(
2218
            $forum->contentInfo->mainLocationId
2219
        );
2220
2221
        $customRelativeAliasPath = '/Original-folder/some-forum-alias';
2222
2223
        $urlAliasService->createUrlAlias(
2224
            $forumMainLocation,
2225
            $customRelativeAliasPath,
2226
            'eng-GB',
2227
            true,
2228
            true
2229
        );
2230
2231
        $locationService->moveSubtree(
2232
            $forumMainLocation,
2233
            $locationService->loadLocation(
2234
                $newFolder->contentInfo->mainLocationId
2235
            )
2236
        );
2237
2238
        $this->assertAliasExists(
2239
            $customRelativeAliasPath,
2240
            $forumMainLocation,
2241
            $urlAliasService
2242
        );
2243
2244
        $urlAliasService->lookup($customRelativeAliasPath);
2245
2246
        $locationService->deleteLocation(
2247
            $locationService->loadLocation(
2248
                $originalFolder->contentInfo->mainLocationId
2249
            )
2250
        );
2251
2252
        $this->assertAliasExists(
2253
            $customRelativeAliasPath,
2254
            $forumMainLocation,
2255
            $urlAliasService
2256
        );
2257
2258
        $urlAliasService->lookup($customRelativeAliasPath);
2259
    }
2260
2261
    /**
2262
     * Test for the copySubtree() method.
2263
     *
2264
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2265
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2266
     */
2267
    public function testCopySubtree()
2268
    {
2269
        $repository = $this->getRepository();
2270
2271
        $mediaLocationId = $this->generateId('location', 43);
2272
        $demoDesignLocationId = $this->generateId('location', 56);
2273
        /* BEGIN: Use Case */
2274
        // $mediaLocationId is the ID of the "Media" page location in
2275
        // an eZ Publish demo installation
2276
2277
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2278
        // Publish demo installation
2279
2280
        // Load the location service
2281
        $locationService = $repository->getLocationService();
2282
2283
        // Load location to copy
2284
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2285
2286
        // Load new parent location
2287
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2288
2289
        // Copy location "Media" to "Demo Design"
2290
        $copiedLocation = $locationService->copySubtree(
2291
            $locationToCopy,
2292
            $newParentLocation
2293
        );
2294
        /* END: Use Case */
2295
2296
        $this->assertInstanceOf(
2297
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
2298
            $copiedLocation
2299
        );
2300
2301
        $this->assertPropertiesCorrect(
2302
            [
2303
                'depth' => $newParentLocation->depth + 1,
2304
                'parentLocationId' => $newParentLocation->id,
2305
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $copiedLocation->id) . '/',
2306
            ],
2307
            $copiedLocation
2308
        );
2309
2310
        $this->assertDefaultContentStates($copiedLocation->contentInfo);
2311
    }
2312
2313
    /**
2314
     * Test for the copySubtree() method.
2315
     *
2316
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2317
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2318
     */
2319
    public function testCopySubtreeWithAliases()
2320
    {
2321
        $repository = $this->getRepository();
2322
        $urlAliasService = $repository->getURLAliasService();
2323
2324
        // $mediaLocationId is the ID of the "Media" page location in
2325
        // an eZ Publish demo installation
2326
2327
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2328
        // Publish demo installation
2329
        $mediaLocationId = $this->generateId('location', 43);
2330
        $demoDesignLocationId = $this->generateId('location', 56);
2331
2332
        $locationService = $repository->getLocationService();
2333
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2334
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2335
2336
        $expectedSubItemAliases = [
2337
            '/Design/Plain-site/Media/Multimedia',
2338
            '/Design/Plain-site/Media/Images',
2339
            '/Design/Plain-site/Media/Files',
2340
        ];
2341
2342
        $this->assertAliasesBeforeCopy($urlAliasService, $expectedSubItemAliases);
2343
2344
        // Copy location "Media" to "Design"
2345
        $locationService->copySubtree(
2346
            $locationToCopy,
2347
            $newParentLocation
2348
        );
2349
2350
        $this->assertGeneratedAliases($urlAliasService, $expectedSubItemAliases);
2351
    }
2352
2353
    /**
2354
     * Asserts that given Content has default ContentStates.
2355
     *
2356
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $contentInfo
2357
     */
2358
    private function assertDefaultContentStates(ContentInfo $contentInfo)
2359
    {
2360
        $repository = $this->getRepository();
2361
        $objectStateService = $repository->getObjectStateService();
2362
2363
        $objectStateGroups = $objectStateService->loadObjectStateGroups();
2364
2365
        foreach ($objectStateGroups as $objectStateGroup) {
2366
            $contentState = $objectStateService->getContentState($contentInfo, $objectStateGroup);
2367
            foreach ($objectStateService->loadObjectStates($objectStateGroup) as $objectState) {
2368
                // Only check the first object state which is the default one.
2369
                $this->assertEquals(
2370
                    $objectState,
2371
                    $contentState
2372
                );
2373
                break;
2374
            }
2375
        }
2376
    }
2377
2378
    /**
2379
     * Test for the copySubtree() method.
2380
     *
2381
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2382
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCopySubtree
2383
     */
2384
    public function testCopySubtreeUpdatesSubtreeProperties()
2385
    {
2386
        $repository = $this->getRepository();
2387
        $locationService = $repository->getLocationService();
2388
2389
        $locationToCopy = $locationService->loadLocation($this->generateId('location', 43));
2390
2391
        // Load Subtree properties before copy
2392
        $expected = $this->loadSubtreeProperties($locationToCopy);
2393
2394
        $mediaLocationId = $this->generateId('location', 43);
2395
        $demoDesignLocationId = $this->generateId('location', 56);
2396
        /* BEGIN: Use Case */
2397
        // $mediaLocationId is the ID of the "Media" page location in
2398
        // an eZ Publish demo installation
2399
2400
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2401
        // Publish demo installation
2402
2403
        // Load the location service
2404
        $locationService = $repository->getLocationService();
2405
2406
        // Load location to copy
2407
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2408
2409
        // Load new parent location
2410
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2411
2412
        // Copy location "Media" to "Demo Design"
2413
        $copiedLocation = $locationService->copySubtree(
2414
            $locationToCopy,
2415
            $newParentLocation
2416
        );
2417
        /* END: Use Case */
2418
2419
        $beforeIds = [];
2420
        foreach ($expected as $properties) {
2421
            $beforeIds[] = $properties['id'];
2422
        }
2423
2424
        $this->refreshSearch($repository);
2425
2426
        // Load Subtree properties after copy
2427
        $actual = $this->loadSubtreeProperties($copiedLocation);
2428
2429
        $this->assertEquals(count($expected), count($actual));
2430
2431
        foreach ($actual as $properties) {
2432
            $this->assertNotContains($properties['id'], $beforeIds);
2433
            $this->assertStringStartsWith(
2434
                $newParentLocation->pathString . $this->parseId('location', $copiedLocation->id) . '/',
2435
                $properties['pathString']
2436
            );
2437
            $this->assertStringEndsWith(
2438
                '/' . $this->parseId('location', $properties['id']) . '/',
2439
                $properties['pathString']
2440
            );
2441
        }
2442
    }
2443
2444
    /**
2445
     * Test for the copySubtree() method.
2446
     *
2447
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2448
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCopySubtree
2449
     */
2450
    public function testCopySubtreeIncrementsChildCountOfNewParent()
2451
    {
2452
        $repository = $this->getRepository();
2453
        $locationService = $repository->getLocationService();
2454
2455
        $childCountBefore = $locationService->getLocationChildCount($locationService->loadLocation(56));
2456
2457
        $mediaLocationId = $this->generateId('location', 43);
2458
        $demoDesignLocationId = $this->generateId('location', 56);
2459
        /* BEGIN: Use Case */
2460
        // $mediaLocationId is the ID of the "Media" page location in
2461
        // an eZ Publish demo installation
2462
2463
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2464
        // Publish demo installation
2465
2466
        // Load the location service
2467
        $locationService = $repository->getLocationService();
2468
2469
        // Load location to copy
2470
        $locationToCopy = $locationService->loadLocation($mediaLocationId);
2471
2472
        // Load new parent location
2473
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2474
2475
        // Copy location "Media" to "Demo Design"
2476
        $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...
2477
            $locationToCopy,
2478
            $newParentLocation
2479
        );
2480
        /* END: Use Case */
2481
2482
        $this->refreshSearch($repository);
2483
2484
        $childCountAfter = $locationService->getLocationChildCount($locationService->loadLocation($demoDesignLocationId));
2485
2486
        $this->assertEquals($childCountBefore + 1, $childCountAfter);
2487
    }
2488
2489
    /**
2490
     * Test for the copySubtree() method.
2491
     *
2492
     * @see \eZ\Publish\API\Repository\LocationService::copySubtree()
2493
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
2494
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCopySubtree
2495
     */
2496 View Code Duplication
    public function testCopySubtreeThrowsInvalidArgumentException()
2497
    {
2498
        $repository = $this->getRepository();
2499
2500
        $communityLocationId = $this->generateId('location', 5);
2501
        /* BEGIN: Use Case */
2502
        // $communityLocationId is the ID of the "Community" page location in
2503
        // an eZ Publish demo installation
2504
2505
        // Load the location service
2506
        $locationService = $repository->getLocationService();
2507
2508
        // Load location to copy
2509
        $locationToCopy = $locationService->loadLocation($communityLocationId);
2510
2511
        // Use a child as new parent
2512
        $childLocations = $locationService->loadLocationChildren($locationToCopy)->locations;
2513
        $newParentLocation = end($childLocations);
2514
2515
        // This call will fail with an "InvalidArgumentException", because the
2516
        // new parent is a child location of the subtree to copy.
2517
        $locationService->copySubtree(
2518
            $locationToCopy,
2519
            $newParentLocation
0 ignored issues
show
Security Bug introduced by
It seems like $newParentLocation defined by end($childLocations) on line 2513 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...
2520
        );
2521
        /* END: Use Case */
2522
    }
2523
2524
    /**
2525
     * Test for the moveSubtree() method.
2526
     *
2527
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2528
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
2529
     */
2530
    public function testMoveSubtree()
2531
    {
2532
        $repository = $this->getRepository();
2533
2534
        $mediaLocationId = $this->generateId('location', 43);
2535
        $demoDesignLocationId = $this->generateId('location', 56);
2536
        /* BEGIN: Use Case */
2537
        // $mediaLocationId is the ID of the "Media" page location in
2538
        // an eZ Publish demo installation
2539
2540
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2541
        // Publish demo installation
2542
2543
        // Load the location service
2544
        $locationService = $repository->getLocationService();
2545
2546
        // Load location to move
2547
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2548
2549
        // Load new parent location
2550
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2551
2552
        // Move location from "Home" to "Demo Design"
2553
        $locationService->moveSubtree(
2554
            $locationToMove,
2555
            $newParentLocation
2556
        );
2557
2558
        // Load moved location
2559
        $movedLocation = $locationService->loadLocation($mediaLocationId);
2560
        /* END: Use Case */
2561
2562
        $this->assertPropertiesCorrect(
2563
            [
2564
                'hidden' => false,
2565
                'invisible' => false,
2566
                'depth' => $newParentLocation->depth + 1,
2567
                'parentLocationId' => $newParentLocation->id,
2568
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $movedLocation->id) . '/',
2569
            ],
2570
            $movedLocation
2571
        );
2572
    }
2573
2574
    /**
2575
     * Test for the moveSubtree() method.
2576
     *
2577
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2578
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2579
     */
2580
    public function testMoveSubtreeHidden()
2581
    {
2582
        $repository = $this->getRepository();
2583
2584
        $mediaLocationId = $this->generateId('location', 43);
2585
        $demoDesignLocationId = $this->generateId('location', 56);
2586
        /* BEGIN: Use Case */
2587
        // $mediaLocationId is the ID of the "Media" page location in
2588
        // an eZ Publish demo installation
2589
2590
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2591
        // Publish demo installation
2592
2593
        // Load the location service
2594
        $locationService = $repository->getLocationService();
2595
2596
        // Load location to move
2597
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2598
2599
        // Load new parent location
2600
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2601
2602
        // Hide the target location before we move
2603
        $newParentLocation = $locationService->hideLocation($newParentLocation);
2604
2605
        // Move location from "Home" to "Demo Design"
2606
        $locationService->moveSubtree(
2607
            $locationToMove,
2608
            $newParentLocation
2609
        );
2610
2611
        // Load moved location
2612
        $movedLocation = $locationService->loadLocation($mediaLocationId);
2613
        /* END: Use Case */
2614
2615
        $this->assertPropertiesCorrect(
2616
            [
2617
                'hidden' => false,
2618
                'invisible' => true,
2619
                'depth' => $newParentLocation->depth + 1,
2620
                'parentLocationId' => $newParentLocation->id,
2621
                'pathString' => $newParentLocation->pathString . $this->parseId('location', $movedLocation->id) . '/',
2622
            ],
2623
            $movedLocation
2624
        );
2625
    }
2626
2627
    /**
2628
     * Test for the moveSubtree() method.
2629
     *
2630
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2631
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2632
     */
2633
    public function testMoveSubtreeUpdatesSubtreeProperties()
2634
    {
2635
        $repository = $this->getRepository();
2636
        $locationService = $repository->getLocationService();
2637
2638
        $locationToMove = $locationService->loadLocation($this->generateId('location', 43));
2639
        $newParentLocation = $locationService->loadLocation($this->generateId('location', 56));
2640
2641
        // Load Subtree properties before move
2642
        $expected = $this->loadSubtreeProperties($locationToMove);
2643
        foreach ($expected as $id => $properties) {
2644
            $expected[$id]['depth'] = $properties['depth'] + 2;
2645
            $expected[$id]['pathString'] = str_replace(
2646
                $locationToMove->pathString,
2647
                $newParentLocation->pathString . $this->parseId('location', $locationToMove->id) . '/',
2648
                $properties['pathString']
2649
            );
2650
        }
2651
2652
        $mediaLocationId = $this->generateId('location', 43);
2653
        $demoDesignLocationId = $this->generateId('location', 56);
2654
        /* BEGIN: Use Case */
2655
        // $mediaLocationId is the ID of the "Media" page location in
2656
        // an eZ Publish demo installation
2657
2658
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2659
        // Publish demo installation
2660
2661
        // Load the location service
2662
        $locationService = $repository->getLocationService();
2663
2664
        // Load location to move
2665
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2666
2667
        // Load new parent location
2668
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2669
2670
        // Move location from "Home" to "Demo Design"
2671
        $locationService->moveSubtree(
2672
            $locationToMove,
2673
            $newParentLocation
2674
        );
2675
2676
        // Load moved location
2677
        $movedLocation = $locationService->loadLocation($mediaLocationId);
2678
        /* END: Use Case */
2679
2680
        $this->refreshSearch($repository);
2681
2682
        // Load Subtree properties after move
2683
        $actual = $this->loadSubtreeProperties($movedLocation);
2684
2685
        $this->assertEquals($expected, $actual);
2686
    }
2687
2688
    /**
2689
     * Test for the moveSubtree() method.
2690
     *
2691
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2692
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtreeUpdatesSubtreeProperties
2693
     */
2694
    public function testMoveSubtreeUpdatesSubtreePropertiesHidden()
2695
    {
2696
        $repository = $this->getRepository();
2697
        $locationService = $repository->getLocationService();
2698
2699
        $locationToMove = $locationService->loadLocation($this->generateId('location', 43));
2700
        $newParentLocation = $locationService->loadLocation($this->generateId('location', 56));
2701
2702
        // Hide the target location before we move
2703
        $newParentLocation = $locationService->hideLocation($newParentLocation);
2704
2705
        // Load Subtree properties before move
2706
        $expected = $this->loadSubtreeProperties($locationToMove);
2707
        foreach ($expected as $id => $properties) {
2708
            $expected[$id]['invisible'] = true;
2709
            $expected[$id]['depth'] = $properties['depth'] + 2;
2710
            $expected[$id]['pathString'] = str_replace(
2711
                $locationToMove->pathString,
2712
                $newParentLocation->pathString . $this->parseId('location', $locationToMove->id) . '/',
2713
                $properties['pathString']
2714
            );
2715
        }
2716
2717
        $mediaLocationId = $this->generateId('location', 43);
2718
        $demoDesignLocationId = $this->generateId('location', 56);
2719
        /* BEGIN: Use Case */
2720
        // $mediaLocationId is the ID of the "Media" page location in
2721
        // an eZ Publish demo installation
2722
2723
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2724
        // Publish demo installation
2725
2726
        // Load the location service
2727
        $locationService = $repository->getLocationService();
2728
2729
        // Load location to move
2730
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2731
2732
        // Load new parent location
2733
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2734
2735
        // Move location from "Home" to "Demo Design"
2736
        $locationService->moveSubtree(
2737
            $locationToMove,
2738
            $newParentLocation
2739
        );
2740
2741
        // Load moved location
2742
        $movedLocation = $locationService->loadLocation($mediaLocationId);
2743
        /* END: Use Case */
2744
2745
        $this->refreshSearch($repository);
2746
2747
        // Load Subtree properties after move
2748
        $actual = $this->loadSubtreeProperties($movedLocation);
2749
2750
        $this->assertEquals($expected, $actual);
2751
    }
2752
2753
    /**
2754
     * Test for the moveSubtree() method.
2755
     *
2756
     * @see \eZ\Publish\API\Repository\LocationService::moveSubtree()
2757
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testMoveSubtree
2758
     */
2759 View Code Duplication
    public function testMoveSubtreeIncrementsChildCountOfNewParent()
2760
    {
2761
        $repository = $this->getRepository();
2762
        $locationService = $repository->getLocationService();
2763
2764
        $newParentLocation = $locationService->loadLocation($this->generateId('location', 56));
2765
2766
        // Load expected properties before move
2767
        $expected = $this->loadLocationProperties($newParentLocation);
2768
        $childCountBefore = $locationService->getLocationChildCount($newParentLocation);
2769
2770
        $mediaLocationId = $this->generateId('location', 43);
2771
        $demoDesignLocationId = $this->generateId('location', 56);
2772
        /* BEGIN: Use Case */
2773
        // $mediaLocationId is the ID of the "Media" page location in
2774
        // an eZ Publish demo installation
2775
2776
        // $demoDesignLocationId is the ID of the "Demo Design" page location in an eZ
2777
        // Publish demo installation
2778
2779
        // Load the location service
2780
        $locationService = $repository->getLocationService();
2781
2782
        // Load location to move
2783
        $locationToMove = $locationService->loadLocation($mediaLocationId);
2784
2785
        // Load new parent location
2786
        $newParentLocation = $locationService->loadLocation($demoDesignLocationId);
2787
2788
        // Move location from "Home" to "Demo Design"
2789
        $locationService->moveSubtree(
2790
            $locationToMove,
2791
            $newParentLocation
2792
        );
2793
2794
        // Load moved location
2795
        $movedLocation = $locationService->loadLocation($mediaLocationId);
0 ignored issues
show
Unused Code introduced by
$movedLocation is not used, you could remove the assignment.

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

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

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

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

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