Completed
Push — EZP-30760-fix-broken-link-afte... ( dbc3fe...c14a26 )
by
unknown
19:36
created

LocationServiceTest::createForumStruct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

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