Completed
Push — 7.5 ( 01cb7b...6ae97c )
by Łukasz
20:27
created

LocationServiceTest::assertAliasExists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 3
dl 0
loc 17
rs 9.7
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the LocationServiceTest class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\API\Repository\Tests;
10
11
use Exception;
12
use eZ\Publish\API\Repository\Exceptions\BadStateException;
13
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
14
use eZ\Publish\API\Repository\URLAliasService as URLAliasServiceInterface;
15
use eZ\Publish\API\Repository\Values\Content\Content;
16
use eZ\Publish\API\Repository\Values\Content\ContentCreateStruct;
17
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
18
use eZ\Publish\API\Repository\Values\Content\Location;
19
use eZ\Publish\API\Repository\Values\Content\LocationCreateStruct;
20
use eZ\Publish\API\Repository\Values\Content\LocationList;
21
use eZ\Publish\API\Repository\Values\Content\LocationUpdateStruct;
22
use eZ\Publish\API\Repository\Values\Content\Query;
23
use eZ\Publish\API\Repository\Values\Content\Search\SearchHit;
24
use eZ\Publish\API\Repository\Values\Content\URLAlias;
25
26
/**
27
 * Test case for operations in the LocationService using in memory storage.
28
 *
29
 * @see eZ\Publish\API\Repository\LocationService
30
 * @group location
31
 */
32
class LocationServiceTest extends BaseTest
33
{
34
    /**
35
     * Test for the newLocationCreateStruct() method.
36
     *
37
     * @return \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct
38
     *
39
     * @see \eZ\Publish\API\Repository\LocationService::newLocationCreateStruct()
40
     */
41
    public function testNewLocationCreateStruct()
42
    {
43
        $repository = $this->getRepository();
44
45
        $parentLocationId = $this->generateId('location', 1);
46
        /* BEGIN: Use Case */
47
        // $parentLocationId is the ID of an existing location
48
        $locationService = $repository->getLocationService();
49
50
        $locationCreate = $locationService->newLocationCreateStruct(
51
            $parentLocationId
52
        );
53
        /* END: Use Case */
54
55
        $this->assertInstanceOf(
56
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\LocationCreateStruct',
57
            $locationCreate
58
        );
59
60
        return $locationCreate;
61
    }
62
63
    /**
64
     * Test for the newLocationCreateStruct() method.
65
     *
66
     * @param \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct $locationCreate
67
     *
68
     * @see \eZ\Publish\API\Repository\LocationService::newLocationCreateStruct()
69
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
70
     */
71
    public function testNewLocationCreateStructValues(LocationCreateStruct $locationCreate)
72
    {
73
        $this->assertPropertiesCorrect(
74
            [
75
                'priority' => 0,
76
                'hidden' => false,
77
                // remoteId should be initialized with a default value
78
                //'remoteId' => null,
79
                'sortField' => null,
80
                'sortOrder' => null,
81
                'parentLocationId' => $this->generateId('location', 1),
82
            ],
83
            $locationCreate
84
        );
85
    }
86
87
    /**
88
     * Test for the createLocation() method.
89
     *
90
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
91
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
92
     */
93
    public function testCreateLocation()
94
    {
95
        $repository = $this->getRepository();
96
97
        $contentId = $this->generateId('object', 41);
98
        $parentLocationId = $this->generateId('location', 5);
99
        /* BEGIN: Use Case */
100
        // $contentId is the ID of an existing content object
101
        // $parentLocationId is the ID of an existing location
102
        $contentService = $repository->getContentService();
103
        $locationService = $repository->getLocationService();
104
105
        // ContentInfo for "How to use eZ Publish"
106
        $contentInfo = $contentService->loadContentInfo($contentId);
107
108
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
109
        $locationCreate->priority = 23;
110
        $locationCreate->hidden = true;
111
        $locationCreate->remoteId = 'sindelfingen';
112
        $locationCreate->sortField = Location::SORT_FIELD_NODE_ID;
113
        $locationCreate->sortOrder = Location::SORT_ORDER_DESC;
114
115
        $location = $locationService->createLocation(
116
            $contentInfo,
117
            $locationCreate
118
        );
119
        /* END: Use Case */
120
121
        $this->assertInstanceOf(
122
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
123
            $location
124
        );
125
126
        return [
127
            'locationCreate' => $locationCreate,
128
            'createdLocation' => $location,
129
            'contentInfo' => $contentInfo,
130
            'parentLocation' => $locationService->loadLocation($this->generateId('location', 5)),
131
        ];
132
    }
133
134
    /**
135
     * Test for the createLocation() method with utilizing default ContentType sorting options.
136
     *
137
     * @covers \eZ\Publish\API\Repository\LocationService::createLocation
138
     */
139
    public function testCreateLocationWithContentTypeSortingOptions(): void
140
    {
141
        $repository = $this->getRepository();
142
143
        $contentId = $this->generateId('object', 41);
144
        $parentLocationId = $this->generateId('location', 5);
145
        // $contentId is the ID of an existing content object
146
        // $parentLocationId is the ID of an existing location
147
        $contentService = $repository->getContentService();
148
        $contentTypeService = $repository->getContentTypeService();
149
        $locationService = $repository->getLocationService();
150
151
        // ContentInfo for "How to use eZ Publish"
152
        $contentInfo = $contentService->loadContentInfo($contentId);
153
154
        // ContentType loading
155
        $contentType = $contentTypeService->loadContentType($contentInfo->contentTypeId);
156
157
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
158
        $locationCreate->priority = 23;
159
        $locationCreate->hidden = true;
160
        $locationCreate->remoteId = 'sindelfingen';
161
162
        $location = $locationService->createLocation(
163
            $contentInfo,
164
            $locationCreate
165
        );
166
167
        $this->assertEquals($contentType->defaultSortField, $location->sortField);
168
        $this->assertEquals($contentType->defaultSortOrder, $location->sortOrder);
169
    }
170
171
    /**
172
     * Test for the createLocation() method.
173
     *
174
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
175
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
176
     */
177
    public function testCreateLocationStructValues(array $data)
178
    {
179
        $locationCreate = $data['locationCreate'];
180
        $createdLocation = $data['createdLocation'];
181
        $contentInfo = $data['contentInfo'];
182
183
        $this->assertPropertiesCorrect(
184
            [
185
                'priority' => $locationCreate->priority,
186
                'hidden' => $locationCreate->hidden,
187
                'invisible' => $locationCreate->hidden,
188
                'remoteId' => $locationCreate->remoteId,
189
                'contentInfo' => $contentInfo,
190
                'parentLocationId' => $locationCreate->parentLocationId,
191
                'pathString' => '/1/5/' . $this->parseId('location', $createdLocation->id) . '/',
192
                'depth' => 2,
193
                'sortField' => $locationCreate->sortField,
194
                'sortOrder' => $locationCreate->sortOrder,
195
            ],
196
            $createdLocation
197
        );
198
199
        $this->assertNotNull($createdLocation->id);
200
    }
201
202
    /**
203
     * Test for the createLocation() method.
204
     *
205
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
206
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
207
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
208
     */
209 View Code Duplication
    public function testCreateLocationThrowsInvalidArgumentExceptionContentAlreadyBelowParent()
210
    {
211
        $repository = $this->getRepository();
212
213
        $contentId = $this->generateId('object', 11);
214
        $parentLocationId = $this->generateId('location', 5);
215
        /* BEGIN: Use Case */
216
        // $contentId is the ID of an existing content object
217
        // $parentLocationId is the ID of an existing location which already
218
        // has the content assigned to one of its descendant locations
219
        $contentService = $repository->getContentService();
220
        $locationService = $repository->getLocationService();
221
222
        // ContentInfo for "How to use eZ Publish"
223
        $contentInfo = $contentService->loadContentInfo($contentId);
224
225
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
226
227
        // Throws exception, since content is already located at "/1/2/107/110/"
228
        $locationService->createLocation(
229
            $contentInfo,
230
            $locationCreate
231
        );
232
        /* END: Use Case */
233
    }
234
235
    /**
236
     * Test for the createLocation() method.
237
     *
238
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
239
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
240
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
241
     */
242 View Code Duplication
    public function testCreateLocationThrowsInvalidArgumentExceptionParentIsSubLocationOfContent()
243
    {
244
        $repository = $this->getRepository();
245
246
        $contentId = $this->generateId('object', 4);
247
        $parentLocationId = $this->generateId('location', 12);
248
        /* BEGIN: Use Case */
249
        // $contentId is the ID of an existing content object
250
        // $parentLocationId is the ID of an existing location which is below a
251
        // location that is assigned to the content
252
        $contentService = $repository->getContentService();
253
        $locationService = $repository->getLocationService();
254
255
        // ContentInfo for "How to use eZ Publish"
256
        $contentInfo = $contentService->loadContentInfo($contentId);
257
258
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
259
260
        // Throws exception, since content is already located at "/1/2/"
261
        $locationService->createLocation(
262
            $contentInfo,
263
            $locationCreate
264
        );
265
        /* END: Use Case */
266
    }
267
268
    /**
269
     * Test for the createLocation() method.
270
     *
271
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
272
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
273
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
274
     */
275 View Code Duplication
    public function testCreateLocationThrowsInvalidArgumentExceptionRemoteIdExists()
276
    {
277
        $repository = $this->getRepository();
278
279
        $contentId = $this->generateId('object', 41);
280
        $parentLocationId = $this->generateId('location', 5);
281
        /* BEGIN: Use Case */
282
        // $contentId is the ID of an existing content object
283
        $contentService = $repository->getContentService();
284
        $locationService = $repository->getLocationService();
285
286
        // ContentInfo for "How to use eZ Publish"
287
        $contentInfo = $contentService->loadContentInfo($contentId);
288
289
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
290
        // This remote ID already exists
291
        $locationCreate->remoteId = 'f3e90596361e31d496d4026eb624c983';
292
293
        // Throws exception, since remote ID is already in use
294
        $locationService->createLocation(
295
            $contentInfo,
296
            $locationCreate
297
        );
298
        /* END: Use Case */
299
    }
300
301
    /**
302
     * Test for the createLocation() method.
303
     *
304
     * @covers \eZ\Publish\API\Repository\LocationService::createLocation()
305
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
306
     * @dataProvider dataProviderForOutOfRangeLocationPriority
307
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
308
     */
309 View Code Duplication
    public function testCreateLocationThrowsInvalidArgumentExceptionPriorityIsOutOfRange($priority)
310
    {
311
        $repository = $this->getRepository();
312
313
        $contentId = $this->generateId('object', 41);
314
        $parentLocationId = $this->generateId('location', 5);
315
        /* BEGIN: Use Case */
316
        // $contentId is the ID of an existing content object
317
        // $parentLocationId is the ID of an existing location
318
        $contentService = $repository->getContentService();
319
        $locationService = $repository->getLocationService();
320
321
        // ContentInfo for "How to use eZ Publish"
322
        $contentInfo = $contentService->loadContentInfo($contentId);
323
324
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
325
        $locationCreate->priority = $priority;
326
        $locationCreate->hidden = true;
327
        $locationCreate->remoteId = 'sindelfingen';
328
        $locationCreate->sortField = Location::SORT_FIELD_NODE_ID;
329
        $locationCreate->sortOrder = Location::SORT_ORDER_DESC;
330
331
        // Throws exception, since priority is out of range
332
        $locationService->createLocation(
333
            $contentInfo,
334
            $locationCreate
335
        );
336
        /* END: Use Case */
337
    }
338
339
    public function dataProviderForOutOfRangeLocationPriority()
340
    {
341
        return [[-2147483649], [2147483648]];
342
    }
343
344
    /**
345
     * Test for the createLocation() method.
346
     *
347
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
348
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
349
     */
350
    public function testCreateLocationInTransactionWithRollback()
351
    {
352
        $repository = $this->getRepository();
353
354
        $contentId = $this->generateId('object', 41);
355
        $parentLocationId = $this->generateId('location', 5);
356
        /* BEGIN: Use Case */
357
        // $contentId is the ID of an existing content object
358
        // $parentLocationId is the ID of an existing location
359
        $contentService = $repository->getContentService();
360
        $locationService = $repository->getLocationService();
361
362
        $repository->beginTransaction();
363
364
        try {
365
            // ContentInfo for "How to use eZ Publish"
366
            $contentInfo = $contentService->loadContentInfo($contentId);
367
368
            $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
369
            $locationCreate->remoteId = 'sindelfingen';
370
371
            $createdLocationId = $locationService->createLocation(
372
                $contentInfo,
373
                $locationCreate
374
            )->id;
375
        } catch (Exception $e) {
376
            // Cleanup hanging transaction on error
377
            $repository->rollback();
378
            throw $e;
379
        }
380
381
        $repository->rollback();
382
383
        try {
384
            // Throws exception since creation of location was rolled back
385
            $location = $locationService->loadLocation($createdLocationId);
0 ignored issues
show
Unused Code introduced by
$location is not used, you could remove the assignment.

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

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

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

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

Loading history...
386
        } catch (NotFoundException $e) {
387
            return;
388
        }
389
        /* END: Use Case */
390
391
        $this->fail('Objects still exists after rollback.');
392
    }
393
394
    /**
395
     * Test for the loadLocation() method.
396
     *
397
     * @return \eZ\Publish\API\Repository\Values\Content\Location
398
     *
399
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocation
400
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
401
     */
402
    public function testLoadLocation()
403
    {
404
        $repository = $this->getRepository();
405
406
        $locationId = $this->generateId('location', 5);
407
        /* BEGIN: Use Case */
408
        // $locationId is the ID of an existing location
409
        $locationService = $repository->getLocationService();
410
411
        $location = $locationService->loadLocation($locationId);
412
        /* END: Use Case */
413
414
        $this->assertInstanceOf(
415
            Location::class,
416
            $location
417
        );
418
        self::assertEquals(5, $location->id);
419
420
        return $location;
421
    }
422
423
    /**
424
     * Test for the loadLocation() method.
425
     *
426
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
427
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
428
     */
429
    public function testLoadLocationRootStructValues()
430
    {
431
        $repository = $this->getRepository();
432
        $locationService = $repository->getLocationService();
433
        $location = $locationService->loadLocation($this->generateId('location', 1));
434
435
        $this->assertRootLocationStructValues($location);
436
    }
437
438
    public function testLoadLocationRootStructValuesWithPrioritizedLanguages(): void
439
    {
440
        $repository = $this->getRepository();
441
442
        $rootLocation = $repository
443
            ->getLocationService()
444
            ->loadLocation(
445
                $this->generateId('location', 1),
446
                [
447
                    'eng-GB',
448
                    'ger-DE',
449
                ]
450
            );
451
452
        $this->assertRootLocationStructValues($rootLocation);
453
    }
454
455
    private function assertRootLocationStructValues(Location $location): void
456
    {
457
        $legacyDateTime = new \DateTime();
458
        $legacyDateTime->setTimestamp(1030968000);
459
460
        $this->assertInstanceOf(Location::class, $location);
461
        $this->assertPropertiesCorrect(
462
            [
463
                'id' => $this->generateId('location', 1),
464
                'status' => 1,
465
                'priority' => 0,
466
                'hidden' => false,
467
                'invisible' => false,
468
                'remoteId' => '629709ba256fe317c3ddcee35453a96a',
469
                'parentLocationId' => $this->generateId('location', 1),
470
                'pathString' => '/1/',
471
                'depth' => 0,
472
                'sortField' => 1,
473
                'sortOrder' => 1,
474
            ],
475
            $location
476
        );
477
478
        $this->assertInstanceOf(ContentInfo::class, $location->contentInfo);
479
        $this->assertPropertiesCorrect(
480
            [
481
                'id' => $this->generateId('content', 0),
482
                'name' => 'Top Level Nodes',
483
                'sectionId' => 1,
484
                'mainLocationId' => 1,
485
                'contentTypeId' => 1,
486
                'currentVersionNo' => 1,
487
                'published' => 1,
488
                'ownerId' => 14,
489
                'modificationDate' => $legacyDateTime,
490
                'publishedDate' => $legacyDateTime,
491
                'alwaysAvailable' => 1,
492
                'remoteId' => null,
493
                'mainLanguageCode' => 'eng-GB',
494
            ],
495
            $location->contentInfo
496
        );
497
    }
498
499
    /**
500
     * Test for the loadLocation() method.
501
     *
502
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
503
     *
504
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
505
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
506
     */
507
    public function testLoadLocationStructValues(Location $location)
508
    {
509
        $this->assertPropertiesCorrect(
510
            [
511
                'id' => $this->generateId('location', 5),
512
                'priority' => 0,
513
                'hidden' => false,
514
                'invisible' => false,
515
                'remoteId' => '3f6d92f8044aed134f32153517850f5a',
516
                'parentLocationId' => $this->generateId('location', 1),
517
                'pathString' => '/1/5/',
518
                'depth' => 1,
519
                'sortField' => 1,
520
                'sortOrder' => 1,
521
            ],
522
            $location
523
        );
524
525
        $this->assertInstanceOf(
526
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\ContentInfo',
527
            $location->contentInfo
528
        );
529
        $this->assertEquals($this->generateId('object', 4), $location->contentInfo->id);
530
531
        // Check lazy loaded proxy on ->content
532
        $this->assertInstanceOf(
533
            Content::class,
534
            $content = $location->getContent()
535
        );
536
        $this->assertEquals(4, $content->contentInfo->id);
537
    }
538
539
    public function testLoadLocationPrioritizedLanguagesFallback()
540
    {
541
        $repository = $this->getRepository();
542
543
        // Add a language
544
        $this->createLanguage('nor-NO', 'Norsk');
545
546
        $locationService = $repository->getLocationService();
547
        $contentService = $repository->getContentService();
548
        $location = $locationService->loadLocation(5);
549
550
        // Translate "Users"
551
        $draft = $contentService->createContentDraft($location->contentInfo);
552
        $struct = $contentService->newContentUpdateStruct();
553
        $struct->setField('name', 'Brukere', 'nor-NO');
554
        $draft = $contentService->updateContent($draft->getVersionInfo(), $struct);
555
        $contentService->publishVersion($draft->getVersionInfo());
556
557
        // Load with priority language (fallback will be the old one)
558
        $location = $locationService->loadLocation(5, ['nor-NO']);
559
560
        $this->assertInstanceOf(
561
            Location::class,
562
            $location
563
        );
564
        self::assertEquals(5, $location->id);
565
        $this->assertInstanceOf(
566
            Content::class,
567
            $content = $location->getContent()
568
        );
569
        $this->assertEquals(4, $content->contentInfo->id);
570
571
        $this->assertEquals($content->getVersionInfo()->getName(), 'Brukere');
572
        $this->assertEquals($content->getVersionInfo()->getName('eng-US'), 'Users');
573
    }
574
575
    /**
576
     * Test that accessing lazy-loaded Content without a translation in the specific
577
     * not available language throws NotFoundException.
578
     */
579
    public function testLoadLocationThrowsNotFoundExceptionForNotAvailableContent(): void
580
    {
581
        $repository = $this->getRepository();
582
583
        $locationService = $repository->getLocationService();
584
585
        $this->createLanguage('pol-PL', 'Polski');
586
587
        $this->expectException(NotFoundException::class);
588
589
        // Note: relying on existing database fixtures to make test case more readable
590
        $locationService->loadLocation(60, ['pol-PL']);
591
    }
592
593
    /**
594
     * Test for the loadLocation() method.
595
     *
596
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
597
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
598
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
599
     */
600
    public function testLoadLocationThrowsNotFoundException()
601
    {
602
        $repository = $this->getRepository();
603
604
        $nonExistentLocationId = $this->generateId('location', 2342);
605
        /* BEGIN: Use Case */
606
        $locationService = $repository->getLocationService();
607
608
        // Throws exception, if Location with $nonExistentLocationId does not
609
        // exist
610
        $location = $locationService->loadLocation($nonExistentLocationId);
0 ignored issues
show
Unused Code introduced by
$location is not used, you could remove the assignment.

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

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

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

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

Loading history...
611
        /* END: Use Case */
612
    }
613
614
    /**
615
     * Test for the loadLocationList() method.
616
     *
617
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
618
     */
619 View Code Duplication
    public function testLoadLocationList(): void
620
    {
621
        $repository = $this->getRepository();
622
623
        // 5 is the ID of an existing location, 442 is a non-existing id
624
        $locationService = $repository->getLocationService();
625
        $locations = $locationService->loadLocationList([5, 442]);
626
627
        self::assertInternalType('iterable', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

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

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

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

    return array();
}

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

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

Loading history...
629
        self::assertEquals([5], array_keys($locations));
630
        self::assertInstanceOf(Location::class, $locations[5]);
631
        self::assertEquals(5, $locations[5]->id);
632
    }
633
634
    /**
635
     * Test for the loadLocationList() method.
636
     *
637
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
638
     * @depends testLoadLocationList
639
     */
640
    public function testLoadLocationListPrioritizedLanguagesFallback(): void
641
    {
642
        $repository = $this->getRepository();
643
644
        $this->createLanguage('pol-PL', 'Polski');
645
646
        // 5 is the ID of an existing location, 442 is a non-existing id
647
        $locationService = $repository->getLocationService();
648
        $locations = $locationService->loadLocationList([5, 442], ['pol-PL'], false);
649
650
        self::assertInternalType('iterable', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

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

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

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

    return array();
}

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

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

Loading history...
652
    }
653
654
    /**
655
     * Test for the loadLocationList() method.
656
     *
657
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
658
     * @depends testLoadLocationListPrioritizedLanguagesFallback
659
     */
660
    public function testLoadLocationListPrioritizedLanguagesFallbackAndAlwaysAvailable(): void
661
    {
662
        $repository = $this->getRepository();
663
664
        $this->createLanguage('pol-PL', 'Polski');
665
666
        // 5 is the ID of an existing location, 442 is a non-existing id
667
        $locationService = $repository->getLocationService();
668
        $locations = $locationService->loadLocationList([5, 442], ['pol-PL'], true);
669
670
        self::assertInternalType('iterable', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

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

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

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

    return array();
}

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

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

Loading history...
672
        self::assertEquals([5], array_keys($locations));
673
        self::assertInstanceOf(Location::class, $locations[5]);
674
        self::assertEquals(5, $locations[5]->id);
675
    }
676
677
    /**
678
     * Test for the loadLocationList() method.
679
     *
680
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
681
     */
682 View Code Duplication
    public function testLoadLocationListWithRootLocationId()
683
    {
684
        $repository = $this->getRepository();
685
686
        // 1 is the ID of an root location
687
        $locationService = $repository->getLocationService();
688
        $locations = $locationService->loadLocationList([1]);
689
690
        self::assertInternalType('iterable', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

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

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

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

    return array();
}

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

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

Loading history...
692
        self::assertEquals([1], array_keys($locations));
693
        self::assertInstanceOf(Location::class, $locations[1]);
694
        self::assertEquals(1, $locations[1]->id);
695
    }
696
697
    /**
698
     * Test for the loadLocationList() method.
699
     *
700
     * Ensures the list is returned in the same order as passed IDs array.
701
     *
702
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
703
     */
704
    public function testLoadLocationListInCorrectOrder()
705
    {
706
        $repository = $this->getRepository();
707
        $locationService = $repository->getLocationService();
708
709
        $cachedLocationId = 2;
710
        $locationIdsToLoad = [43, $cachedLocationId, 5];
711
712
        // Call loadLocation to cache it in memory as it might possibly affect list order
713
        $locationService->loadLocation($cachedLocationId);
714
715
        $locations = $locationService->loadLocationList($locationIdsToLoad);
716
        $locationIds = array_column($locations, 'id');
717
718
        self::assertEquals($locationIdsToLoad, $locationIds);
719
    }
720
721
    /**
722
     * Test for the loadLocationByRemoteId() method.
723
     *
724
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationByRemoteId()
725
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
726
     */
727 View Code Duplication
    public function testLoadLocationByRemoteId()
728
    {
729
        $repository = $this->getRepository();
730
731
        /* BEGIN: Use Case */
732
        $locationService = $repository->getLocationService();
733
734
        $location = $locationService->loadLocationByRemoteId(
735
            '3f6d92f8044aed134f32153517850f5a'
736
        );
737
        /* END: Use Case */
738
739
        $this->assertEquals(
740
            $locationService->loadLocation($this->generateId('location', 5)),
741
            $location
742
        );
743
    }
744
745
    /**
746
     * Test for the loadLocationByRemoteId() method.
747
     *
748
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationByRemoteId()
749
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
750
     * @expectedException \eZ\Publish\API\Repository\Exceptions\NotFoundException
751
     */
752
    public function testLoadLocationByRemoteIdThrowsNotFoundException()
753
    {
754
        $repository = $this->getRepository();
755
756
        /* BEGIN: Use Case */
757
        $locationService = $repository->getLocationService();
758
759
        // Throws exception, since Location with remote ID does not exist
760
        $location = $locationService->loadLocationByRemoteId(
0 ignored issues
show
Unused Code introduced by
$location is not used, you could remove the assignment.

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

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

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

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

Loading history...
761
            'not-exists'
762
        );
763
        /* END: Use Case */
764
    }
765
766
    /**
767
     * Test for the loadLocations() method.
768
     *
769
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
770
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
771
     */
772
    public function testLoadLocations()
773
    {
774
        $repository = $this->getRepository();
775
776
        $contentId = $this->generateId('object', 4);
777
        /* BEGIN: Use Case */
778
        // $contentId contains the ID of an existing content object
779
        $contentService = $repository->getContentService();
780
        $locationService = $repository->getLocationService();
781
782
        $contentInfo = $contentService->loadContentInfo($contentId);
783
784
        $locations = $locationService->loadLocations($contentInfo);
785
        /* END: Use Case */
786
787
        $this->assertInternalType('array', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

Loading history...
788
        self::assertNotEmpty($locations);
789
790
        foreach ($locations as $location) {
791
            self::assertInstanceOf(Location::class, $location);
792
            self::assertEquals($contentInfo->id, $location->getContentInfo()->id);
793
        }
794
795
        return $locations;
796
    }
797
798
    /**
799
     * Test for the loadLocations() method.
800
     *
801
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
802
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
803
     */
804
    public function testLoadLocationsContent(array $locations)
805
    {
806
        $repository = $this->getRepository();
807
        $locationService = $repository->getLocationService();
0 ignored issues
show
Unused Code introduced by
$locationService is not used, you could remove the assignment.

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

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

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

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

Loading history...
808
809
        $this->assertEquals(1, count($locations));
810
        foreach ($locations as $loadedLocation) {
811
            $this->assertInstanceOf(
812
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
813
                $loadedLocation
814
            );
815
        }
816
817
        usort(
818
            $locations,
819
            function ($a, $b) {
820
                strcmp($a->id, $b->id);
821
            }
822
        );
823
824
        $this->assertEquals(
825
            [$this->generateId('location', 5)],
826
            array_map(
827
                function (Location $location) {
828
                    return $location->id;
829
                },
830
                $locations
831
            )
832
        );
833
    }
834
835
    /**
836
     * Test for the loadLocations() method.
837
     *
838
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
839
     *
840
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations($contentInfo, $rootLocation)
841
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
842
     */
843
    public function testLoadLocationsLimitedSubtree()
844
    {
845
        $repository = $this->getRepository();
846
847
        $originalLocationId = $this->generateId('location', 54);
848
        $originalParentLocationId = $this->generateId('location', 48);
849
        $newParentLocationId = $this->generateId('location', 43);
850
        /* BEGIN: Use Case */
851
        // $originalLocationId is the ID of an existing location
852
        // $originalParentLocationId is the ID of the parent location of
853
        //     $originalLocationId
854
        // $newParentLocationId is the ID of an existing location outside the tree
855
        // of $originalLocationId and $originalParentLocationId
856
        $locationService = $repository->getLocationService();
857
858
        // Location at "/1/48/54"
859
        $originalLocation = $locationService->loadLocation($originalLocationId);
860
861
        // Create location under "/1/43/"
862
        $locationCreate = $locationService->newLocationCreateStruct($newParentLocationId);
863
        $locationService->createLocation(
864
            $originalLocation->contentInfo,
865
            $locationCreate
866
        );
867
868
        $findRootLocation = $locationService->loadLocation($originalParentLocationId);
869
870
        // Returns an array with only $originalLocation
871
        $locations = $locationService->loadLocations(
872
            $originalLocation->contentInfo,
873
            $findRootLocation
874
        );
875
        /* END: Use Case */
876
877
        $this->assertInternalType('array', $locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

Loading history...
878
879
        return $locations;
880
    }
881
882
    /**
883
     * Test for the loadLocations() method.
884
     *
885
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $locations
886
     *
887
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
888
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationsLimitedSubtree
889
     */
890
    public function testLoadLocationsLimitedSubtreeContent(array $locations)
891
    {
892
        $this->assertEquals(1, count($locations));
893
894
        $this->assertEquals(
895
            $this->generateId('location', 54),
896
            reset($locations)->id
897
        );
898
    }
899
900
    /**
901
     * Test for the loadLocations() method.
902
     *
903
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
904
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
905
     * @expectedException \eZ\Publish\API\Repository\Exceptions\BadStateException
906
     */
907 View Code Duplication
    public function testLoadLocationsThrowsBadStateException()
908
    {
909
        $repository = $this->getRepository();
910
911
        /* BEGIN: Use Case */
912
        $contentTypeService = $repository->getContentTypeService();
913
        $contentService = $repository->getContentService();
914
        $locationService = $repository->getLocationService();
915
916
        // Create new content, which is not published
917
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
918
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
919
        $contentCreate->setField('name', 'New Folder');
920
        $content = $contentService->createContent($contentCreate);
921
922
        // Throws Exception, since $content has no published version, yet
923
        $locationService->loadLocations(
924
            $content->contentInfo
925
        );
926
        /* END: Use Case */
927
    }
928
929
    /**
930
     * Test for the loadLocations() method.
931
     *
932
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations($contentInfo, $rootLocation)
933
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
934
     * @expectedException \eZ\Publish\API\Repository\Exceptions\BadStateException
935
     */
936
    public function testLoadLocationsThrowsBadStateExceptionLimitedSubtree()
937
    {
938
        $repository = $this->getRepository();
939
940
        $someLocationId = $this->generateId('location', 2);
941
        /* BEGIN: Use Case */
942
        // $someLocationId is the ID of an existing location
943
        $contentTypeService = $repository->getContentTypeService();
944
        $contentService = $repository->getContentService();
945
        $locationService = $repository->getLocationService();
946
947
        // Create new content, which is not published
948
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
949
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
950
        $contentCreate->setField('name', 'New Folder');
951
        $content = $contentService->createContent($contentCreate);
952
953
        $findRootLocation = $locationService->loadLocation($someLocationId);
954
955
        // Throws Exception, since $content has no published version, yet
956
        $locationService->loadLocations(
957
            $content->contentInfo,
958
            $findRootLocation
959
        );
960
        /* END: Use Case */
961
    }
962
963
    /**
964
     * Test for the loadLocationChildren() method.
965
     *
966
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationChildren
967
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
968
     */
969
    public function testLoadLocationChildren()
970
    {
971
        $repository = $this->getRepository();
972
973
        $locationId = $this->generateId('location', 5);
974
        /* BEGIN: Use Case */
975
        // $locationId is the ID of an existing location
976
        $locationService = $repository->getLocationService();
977
978
        $location = $locationService->loadLocation($locationId);
979
980
        $childLocations = $locationService->loadLocationChildren($location);
981
        /* END: Use Case */
982
983
        $this->assertInstanceOf(LocationList::class, $childLocations);
984
        $this->assertInternalType('array', $childLocations->locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

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

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

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

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

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

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

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

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

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

Loading history...
1132
1133
        return $childLocations;
1134
    }
1135
1136
    /**
1137
     * Test for the loadLocationChildren() method.
1138
     *
1139
     * @param \eZ\Publish\API\Repository\Values\Content\LocationList $locations
1140
     *
1141
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset)
1142
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildrenWithOffset
1143
     */
1144 View Code Duplication
    public function testLoadLocationChildrenDataWithOffset(LocationList $locations)
1145
    {
1146
        $this->assertEquals(3, count($locations->locations));
1147
        $this->assertEquals(5, $locations->totalCount);
1148
1149
        foreach ($locations->locations as $location) {
1150
            $this->assertInstanceOf(
1151
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
1152
                $location
1153
            );
1154
        }
1155
1156
        $this->assertEquals(
1157
            [
1158
                $this->generateId('location', 14),
1159
                $this->generateId('location', 44),
1160
                $this->generateId('location', 61),
1161
            ],
1162
            array_map(
1163
                function (Location $location) {
1164
                    return $location->id;
1165
                },
1166
                $locations->locations
1167
            )
1168
        );
1169
    }
1170
1171
    /**
1172
     * Test for the loadLocationChildren() method.
1173
     *
1174
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
1175
     *
1176
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationChildren($location, $offset, $limit)
1177
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationChildren
1178
     */
1179 View Code Duplication
    public function testLoadLocationChildrenWithOffsetAndLimit()
1180
    {
1181
        $repository = $this->getRepository();
1182
1183
        $locationId = $this->generateId('location', 5);
1184
        /* BEGIN: Use Case */
1185
        // $locationId is the ID of an existing location
1186
        $locationService = $repository->getLocationService();
1187
1188
        $location = $locationService->loadLocation($locationId);
1189
1190
        $childLocations = $locationService->loadLocationChildren($location, 2, 2);
1191
        /* END: Use Case */
1192
1193
        $this->assertInstanceOf('\\eZ\\Publish\\API\\Repository\\Values\\Content\\LocationList', $childLocations);
1194
        $this->assertInternalType('array', $childLocations->locations);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\Assert::assertInternalType() has been deprecated with message: https://github.com/sebastianbergmann/phpunit/issues/3369

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

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

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

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

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

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

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

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

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

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

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

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

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

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