Completed
Push — 7.5 ( 56e68a...d77893 )
by
unknown
18:51
created

testMoveSubtreeThrowsExceptionOnMoveToSame()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22

Duplication

Lines 22
Ratio 100 %

Importance

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

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

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

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

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

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