Completed
Push — master ( abfc7c...92edcc )
by
unknown
29:53 queued 14:51
created

LocationServiceTest::testUnhideLocation()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 37
rs 9.328
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\Values\Content\Content;
15
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
16
use eZ\Publish\API\Repository\Values\Content\Language;
17
use eZ\Publish\API\Repository\Values\Content\Location;
18
use eZ\Publish\API\Repository\Values\Content\LocationCreateStruct;
19
use eZ\Publish\API\Repository\Values\Content\LocationList;
20
use eZ\Publish\API\Repository\Values\Content\LocationUpdateStruct;
21
use eZ\Publish\API\Repository\Values\Content\Query;
22
use eZ\Publish\API\Repository\Values\Content\Search\SearchHit;
23
24
/**
25
 * Test case for operations in the LocationService using in memory storage.
26
 *
27
 * @see eZ\Publish\API\Repository\LocationService
28
 * @group location
29
 */
30
class LocationServiceTest extends BaseTest
31
{
32
    /**
33
     * Test for the newLocationCreateStruct() method.
34
     *
35
     * @return \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct
36
     *
37
     * @see \eZ\Publish\API\Repository\LocationService::newLocationCreateStruct()
38
     */
39 View Code Duplication
    public function testNewLocationCreateStruct()
40
    {
41
        $repository = $this->getRepository();
42
43
        $parentLocationId = $this->generateId('location', 1);
44
        /* BEGIN: Use Case */
45
        // $parentLocationId is the ID of an existing location
46
        $locationService = $repository->getLocationService();
47
48
        $locationCreate = $locationService->newLocationCreateStruct(
49
            $parentLocationId
50
        );
51
        /* END: Use Case */
52
53
        $this->assertInstanceOf(
54
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\LocationCreateStruct',
55
            $locationCreate
56
        );
57
58
        return $locationCreate;
59
    }
60
61
    /**
62
     * Test for the newLocationCreateStruct() method.
63
     *
64
     * @param \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct $locationCreate
65
     *
66
     * @see \eZ\Publish\API\Repository\LocationService::newLocationCreateStruct()
67
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
68
     */
69
    public function testNewLocationCreateStructValues(LocationCreateStruct $locationCreate)
70
    {
71
        $this->assertPropertiesCorrect(
72
            [
73
                'priority' => 0,
74
                'hidden' => false,
75
                // remoteId should be initialized with a default value
76
                //'remoteId' => null,
77
                'sortField' => Location::SORT_FIELD_NAME,
78
                'sortOrder' => Location::SORT_ORDER_ASC,
79
                'parentLocationId' => $this->generateId('location', 1),
80
            ],
81
            $locationCreate
82
        );
83
    }
84
85
    /**
86
     * Test for the createLocation() method.
87
     *
88
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
89
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
90
     */
91
    public function testCreateLocation()
92
    {
93
        $repository = $this->getRepository();
94
95
        $contentId = $this->generateId('object', 41);
96
        $parentLocationId = $this->generateId('location', 5);
97
        /* BEGIN: Use Case */
98
        // $contentId is the ID of an existing content object
99
        // $parentLocationId is the ID of an existing location
100
        $contentService = $repository->getContentService();
101
        $locationService = $repository->getLocationService();
102
103
        // ContentInfo for "How to use eZ Publish"
104
        $contentInfo = $contentService->loadContentInfo($contentId);
105
106
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
107
        $locationCreate->priority = 23;
108
        $locationCreate->hidden = true;
109
        $locationCreate->remoteId = 'sindelfingen';
110
        $locationCreate->sortField = Location::SORT_FIELD_NODE_ID;
111
        $locationCreate->sortOrder = Location::SORT_ORDER_DESC;
112
113
        $location = $locationService->createLocation(
114
            $contentInfo,
115
            $locationCreate
116
        );
117
        /* END: Use Case */
118
119
        $this->assertInstanceOf(
120
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
121
            $location
122
        );
123
124
        return [
125
            'locationCreate' => $locationCreate,
126
            'createdLocation' => $location,
127
            'contentInfo' => $contentInfo,
128
            'parentLocation' => $locationService->loadLocation($this->generateId('location', 5)),
129
        ];
130
    }
131
132
    /**
133
     * Test for the createLocation() method.
134
     *
135
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
136
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
137
     */
138
    public function testCreateLocationStructValues(array $data)
139
    {
140
        $locationCreate = $data['locationCreate'];
141
        $createdLocation = $data['createdLocation'];
142
        $contentInfo = $data['contentInfo'];
143
144
        $this->assertPropertiesCorrect(
145
            [
146
                'priority' => $locationCreate->priority,
147
                'hidden' => $locationCreate->hidden,
148
                'invisible' => $locationCreate->hidden,
149
                'remoteId' => $locationCreate->remoteId,
150
                'contentInfo' => $contentInfo,
151
                'parentLocationId' => $locationCreate->parentLocationId,
152
                'pathString' => '/1/5/' . $this->parseId('location', $createdLocation->id) . '/',
153
                'depth' => 2,
154
                'sortField' => $locationCreate->sortField,
155
                'sortOrder' => $locationCreate->sortOrder,
156
            ],
157
            $createdLocation
158
        );
159
160
        $this->assertNotNull($createdLocation->id);
161
    }
162
163
    /**
164
     * Test for the createLocation() method.
165
     *
166
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
167
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
168
     */
169
    public function testCreateLocationThrowsInvalidArgumentExceptionContentAlreadyBelowParent()
170
    {
171
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
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
     */
203
    public function testCreateLocationThrowsInvalidArgumentExceptionParentIsSubLocationOfContent()
204
    {
205
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
206
207
        $repository = $this->getRepository();
208
209
        $contentId = $this->generateId('object', 4);
210
        $parentLocationId = $this->generateId('location', 12);
211
        /* BEGIN: Use Case */
212
        // $contentId is the ID of an existing content object
213
        // $parentLocationId is the ID of an existing location which is below a
214
        // location that is assigned to the content
215
        $contentService = $repository->getContentService();
216
        $locationService = $repository->getLocationService();
217
218
        // ContentInfo for "How to use eZ Publish"
219
        $contentInfo = $contentService->loadContentInfo($contentId);
220
221
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
222
223
        // Throws exception, since content is already located at "/1/2/"
224
        $locationService->createLocation(
225
            $contentInfo,
226
            $locationCreate
227
        );
228
        /* END: Use Case */
229
    }
230
231
    /**
232
     * Test for the createLocation() method.
233
     *
234
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
235
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
236
     */
237
    public function testCreateLocationThrowsInvalidArgumentExceptionRemoteIdExists()
238
    {
239
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
240
241
        $repository = $this->getRepository();
242
243
        $contentId = $this->generateId('object', 41);
244
        $parentLocationId = $this->generateId('location', 5);
245
        /* BEGIN: Use Case */
246
        // $contentId is the ID of an existing content object
247
        $contentService = $repository->getContentService();
248
        $locationService = $repository->getLocationService();
249
250
        // ContentInfo for "How to use eZ Publish"
251
        $contentInfo = $contentService->loadContentInfo($contentId);
252
253
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
254
        // This remote ID already exists
255
        $locationCreate->remoteId = 'f3e90596361e31d496d4026eb624c983';
256
257
        // Throws exception, since remote ID is already in use
258
        $locationService->createLocation(
259
            $contentInfo,
260
            $locationCreate
261
        );
262
        /* END: Use Case */
263
    }
264
265
    /**
266
     * Test for the createLocation() method.
267
     *
268
     * @covers \eZ\Publish\API\Repository\LocationService::createLocation()
269
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testNewLocationCreateStruct
270
     * @dataProvider dataProviderForOutOfRangeLocationPriority
271
     */
272 View Code Duplication
    public function testCreateLocationThrowsInvalidArgumentExceptionPriorityIsOutOfRange($priority)
273
    {
274
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
275
276
        $repository = $this->getRepository();
277
278
        $contentId = $this->generateId('object', 41);
279
        $parentLocationId = $this->generateId('location', 5);
280
        /* BEGIN: Use Case */
281
        // $contentId is the ID of an existing content object
282
        // $parentLocationId is the ID of an existing location
283
        $contentService = $repository->getContentService();
284
        $locationService = $repository->getLocationService();
285
286
        // ContentInfo for "How to use eZ Publish"
287
        $contentInfo = $contentService->loadContentInfo($contentId);
288
289
        $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
290
        $locationCreate->priority = $priority;
291
        $locationCreate->hidden = true;
292
        $locationCreate->remoteId = 'sindelfingen';
293
        $locationCreate->sortField = Location::SORT_FIELD_NODE_ID;
294
        $locationCreate->sortOrder = Location::SORT_ORDER_DESC;
295
296
        // Throws exception, since priority is out of range
297
        $locationService->createLocation(
298
            $contentInfo,
299
            $locationCreate
300
        );
301
        /* END: Use Case */
302
    }
303
304
    public function dataProviderForOutOfRangeLocationPriority()
305
    {
306
        return [[-2147483649], [2147483648]];
307
    }
308
309
    /**
310
     * Test for the createLocation() method.
311
     *
312
     * @see \eZ\Publish\API\Repository\LocationService::createLocation()
313
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
314
     */
315
    public function testCreateLocationInTransactionWithRollback()
316
    {
317
        $repository = $this->getRepository();
318
319
        $contentId = $this->generateId('object', 41);
320
        $parentLocationId = $this->generateId('location', 5);
321
        /* BEGIN: Use Case */
322
        // $contentId is the ID of an existing content object
323
        // $parentLocationId is the ID of an existing location
324
        $contentService = $repository->getContentService();
325
        $locationService = $repository->getLocationService();
326
327
        $repository->beginTransaction();
328
329
        try {
330
            // ContentInfo for "How to use eZ Publish"
331
            $contentInfo = $contentService->loadContentInfo($contentId);
332
333
            $locationCreate = $locationService->newLocationCreateStruct($parentLocationId);
334
            $locationCreate->remoteId = 'sindelfingen';
335
336
            $createdLocationId = $locationService->createLocation(
337
                $contentInfo,
338
                $locationCreate
339
            )->id;
340
        } catch (Exception $e) {
341
            // Cleanup hanging transaction on error
342
            $repository->rollback();
343
            throw $e;
344
        }
345
346
        $repository->rollback();
347
348
        try {
349
            // Throws exception since creation of location was rolled back
350
            $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...
351
        } catch (NotFoundException $e) {
352
            return;
353
        }
354
        /* END: Use Case */
355
356
        $this->fail('Objects still exists after rollback.');
357
    }
358
359
    /**
360
     * Test for the loadLocation() method.
361
     *
362
     * @return \eZ\Publish\API\Repository\Values\Content\Location
363
     *
364
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocation
365
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
366
     */
367
    public function testLoadLocation()
368
    {
369
        $repository = $this->getRepository();
370
371
        $locationId = $this->generateId('location', 5);
372
        /* BEGIN: Use Case */
373
        // $locationId is the ID of an existing location
374
        $locationService = $repository->getLocationService();
375
376
        $location = $locationService->loadLocation($locationId);
377
        /* END: Use Case */
378
379
        $this->assertInstanceOf(
380
            Location::class,
381
            $location
382
        );
383
        self::assertEquals(5, $location->id);
384
385
        return $location;
386
    }
387
388
    /**
389
     * Test for the loadLocation() method.
390
     *
391
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
392
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
393
     */
394
    public function testLoadLocationRootStructValues()
395
    {
396
        $repository = $this->getRepository();
397
        $locationService = $repository->getLocationService();
398
        $location = $locationService->loadLocation($this->generateId('location', 1));
399
400
        $this->assertRootLocationStructValues($location);
401
    }
402
403
    public function testLoadLocationRootStructValuesWithPrioritizedLanguages(): void
404
    {
405
        $repository = $this->getRepository();
406
407
        $rootLocation = $repository
408
            ->getLocationService()
409
            ->loadLocation(
410
                $this->generateId('location', 1),
411
                [
412
                    'eng-GB',
413
                    'ger-DE',
414
                ]
415
            );
416
417
        $this->assertRootLocationStructValues($rootLocation);
418
    }
419
420
    private function assertRootLocationStructValues(Location $location): void
421
    {
422
        $legacyDateTime = new \DateTime();
423
        $legacyDateTime->setTimestamp(1030968000);
424
425
        $this->assertInstanceOf(Location::class, $location);
426
        $this->assertPropertiesCorrect(
427
            [
428
                'id' => $this->generateId('location', 1),
429
                'status' => 1,
430
                'priority' => 0,
431
                'hidden' => false,
432
                'invisible' => false,
433
                'remoteId' => '629709ba256fe317c3ddcee35453a96a',
434
                'parentLocationId' => $this->generateId('location', 1),
435
                'pathString' => '/1/',
436
                'depth' => 0,
437
                'sortField' => 1,
438
                'sortOrder' => 1,
439
            ],
440
            $location
441
        );
442
443
        $this->assertInstanceOf(ContentInfo::class, $location->contentInfo);
444
        $this->assertPropertiesCorrect(
445
            [
446
                'id' => $this->generateId('content', 0),
447
                'name' => 'Top Level Nodes',
448
                'sectionId' => 1,
449
                'mainLocationId' => 1,
450
                'contentTypeId' => 1,
451
                'currentVersionNo' => 1,
452
                'published' => 1,
453
                'ownerId' => 14,
454
                'modificationDate' => $legacyDateTime,
455
                'publishedDate' => $legacyDateTime,
456
                'alwaysAvailable' => 1,
457
                'remoteId' => null,
458
                'mainLanguageCode' => 'eng-GB',
459
            ],
460
            $location->contentInfo
461
        );
462
    }
463
464
    /**
465
     * Test for the loadLocation() method.
466
     *
467
     * @param \eZ\Publish\API\Repository\Values\Content\Location $location
468
     *
469
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
470
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
471
     */
472
    public function testLoadLocationStructValues(Location $location)
473
    {
474
        $this->assertPropertiesCorrect(
475
            [
476
                'id' => $this->generateId('location', 5),
477
                'priority' => 0,
478
                'hidden' => false,
479
                'invisible' => false,
480
                'remoteId' => '3f6d92f8044aed134f32153517850f5a',
481
                'parentLocationId' => $this->generateId('location', 1),
482
                'pathString' => '/1/5/',
483
                'depth' => 1,
484
                'sortField' => 1,
485
                'sortOrder' => 1,
486
            ],
487
            $location
488
        );
489
490
        $this->assertInstanceOf(
491
            '\\eZ\\Publish\\API\\Repository\\Values\\Content\\ContentInfo',
492
            $location->contentInfo
493
        );
494
        $this->assertEquals($this->generateId('object', 4), $location->contentInfo->id);
495
496
        // Check lazy loaded proxy on ->content
497
        $this->assertInstanceOf(
498
            Content::class,
499
            $content = $location->getContent()
500
        );
501
        $this->assertEquals(4, $content->contentInfo->id);
502
    }
503
504
    public function testLoadLocationPrioritizedLanguagesFallback()
505
    {
506
        $repository = $this->getRepository();
507
508
        // Add a language
509
        $this->createLanguage('nor-NO', 'Norsk');
510
511
        $locationService = $repository->getLocationService();
512
        $contentService = $repository->getContentService();
513
        $location = $locationService->loadLocation(5);
514
515
        // Translate "Users"
516
        $draft = $contentService->createContentDraft($location->contentInfo);
517
        $struct = $contentService->newContentUpdateStruct();
518
        $struct->setField('name', 'Brukere', 'nor-NO');
519
        $draft = $contentService->updateContent($draft->getVersionInfo(), $struct);
520
        $contentService->publishVersion($draft->getVersionInfo());
521
522
        // Load with priority language (fallback will be the old one)
523
        $location = $locationService->loadLocation(5, ['nor-NO']);
524
525
        $this->assertInstanceOf(
526
            Location::class,
527
            $location
528
        );
529
        self::assertEquals(5, $location->id);
530
        $this->assertInstanceOf(
531
            Content::class,
532
            $content = $location->getContent()
533
        );
534
        $this->assertEquals(4, $content->contentInfo->id);
535
536
        $this->assertEquals($content->getVersionInfo()->getName(), 'Brukere');
537
        $this->assertEquals($content->getVersionInfo()->getName('eng-US'), 'Users');
538
    }
539
540
    /**
541
     * Test that accessing lazy-loaded Content without a translation in the specific
542
     * not available language throws NotFoundException.
543
     */
544
    public function testLoadLocationThrowsNotFoundExceptionForNotAvailableContent(): void
545
    {
546
        $repository = $this->getRepository();
547
548
        $locationService = $repository->getLocationService();
549
550
        $this->createLanguage('pol-PL', 'Polski');
551
552
        $this->expectException(NotFoundException::class);
553
554
        // Note: relying on existing database fixtures to make test case more readable
555
        $locationService->loadLocation(60, ['pol-PL']);
556
    }
557
558
    /**
559
     * Test for the loadLocation() method.
560
     *
561
     * @see \eZ\Publish\API\Repository\LocationService::loadLocation()
562
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
563
     */
564 View Code Duplication
    public function testLoadLocationThrowsNotFoundException()
565
    {
566
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
567
568
        $repository = $this->getRepository();
569
570
        $nonExistentLocationId = $this->generateId('location', 2342);
571
        /* BEGIN: Use Case */
572
        $locationService = $repository->getLocationService();
573
574
        // Throws exception, if Location with $nonExistentLocationId does not
575
        // exist
576
        $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...
577
        /* END: Use Case */
578
    }
579
580
    /**
581
     * Test for the loadLocationList() method.
582
     *
583
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
584
     */
585 View Code Duplication
    public function testLoadLocationList(): void
586
    {
587
        $repository = $this->getRepository();
588
589
        // 5 is the ID of an existing location, 442 is a non-existing id
590
        $locationService = $repository->getLocationService();
591
        $locations = $locationService->loadLocationList([5, 442]);
592
593
        self::assertIsIterable($locations);
594
        self::assertCount(1, $locations);
0 ignored issues
show
Bug introduced by
It seems like $locations defined by $locationService->loadLocationList(array(5, 442)) on line 591 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...
595
        self::assertEquals([5], array_keys($locations));
596
        self::assertInstanceOf(Location::class, $locations[5]);
597
        self::assertEquals(5, $locations[5]->id);
598
    }
599
600
    /**
601
     * Test for the loadLocationList() method.
602
     *
603
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
604
     * @depends testLoadLocationList
605
     */
606
    public function testLoadLocationListPrioritizedLanguagesFallback(): void
607
    {
608
        $repository = $this->getRepository();
609
610
        $this->createLanguage('pol-PL', 'Polski');
611
612
        // 5 is the ID of an existing location, 442 is a non-existing id
613
        $locationService = $repository->getLocationService();
614
        $locations = $locationService->loadLocationList([5, 442], ['pol-PL'], false);
615
616
        self::assertIsIterable($locations);
617
        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 614 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...
618
    }
619
620
    /**
621
     * Test for the loadLocationList() method.
622
     *
623
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
624
     * @depends testLoadLocationListPrioritizedLanguagesFallback
625
     */
626
    public function testLoadLocationListPrioritizedLanguagesFallbackAndAlwaysAvailable(): void
627
    {
628
        $repository = $this->getRepository();
629
630
        $this->createLanguage('pol-PL', 'Polski');
631
632
        // 5 is the ID of an existing location, 442 is a non-existing id
633
        $locationService = $repository->getLocationService();
634
        $locations = $locationService->loadLocationList([5, 442], ['pol-PL'], true);
635
636
        self::assertIsIterable($locations);
637
        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 634 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...
638
        self::assertEquals([5], array_keys($locations));
639
        self::assertInstanceOf(Location::class, $locations[5]);
640
        self::assertEquals(5, $locations[5]->id);
641
    }
642
643
    /**
644
     * Test for the loadLocationList() method.
645
     *
646
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
647
     */
648 View Code Duplication
    public function testLoadLocationListWithRootLocationId()
649
    {
650
        $repository = $this->getRepository();
651
652
        // 1 is the ID of an root location
653
        $locationService = $repository->getLocationService();
654
        $locations = $locationService->loadLocationList([1]);
655
656
        self::assertIsIterable($locations);
657
        self::assertCount(1, $locations);
0 ignored issues
show
Bug introduced by
It seems like $locations defined by $locationService->loadLocationList(array(1)) on line 654 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...
658
        self::assertEquals([1], array_keys($locations));
659
        self::assertInstanceOf(Location::class, $locations[1]);
660
        self::assertEquals(1, $locations[1]->id);
661
    }
662
663
    /**
664
     * Test for the loadLocationList() method.
665
     *
666
     * Ensures the list is returned in the same order as passed IDs array.
667
     *
668
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationList
669
     */
670
    public function testLoadLocationListInCorrectOrder()
671
    {
672
        $repository = $this->getRepository();
673
        $locationService = $repository->getLocationService();
674
675
        $cachedLocationId = 2;
676
        $locationIdsToLoad = [43, $cachedLocationId, 5];
677
678
        // Call loadLocation to cache it in memory as it might possibly affect list order
679
        $locationService->loadLocation($cachedLocationId);
680
681
        $locations = $locationService->loadLocationList($locationIdsToLoad);
682
        $locationIds = array_column($locations, 'id');
683
684
        self::assertEquals($locationIdsToLoad, $locationIds);
685
    }
686
687
    /**
688
     * Test for the loadLocationByRemoteId() method.
689
     *
690
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationByRemoteId()
691
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
692
     */
693 View Code Duplication
    public function testLoadLocationByRemoteId()
694
    {
695
        $repository = $this->getRepository();
696
697
        /* BEGIN: Use Case */
698
        $locationService = $repository->getLocationService();
699
700
        $location = $locationService->loadLocationByRemoteId(
701
            '3f6d92f8044aed134f32153517850f5a'
702
        );
703
        /* END: Use Case */
704
705
        $this->assertEquals(
706
            $locationService->loadLocation($this->generateId('location', 5)),
707
            $location
708
        );
709
    }
710
711
    /**
712
     * Test for the loadLocationByRemoteId() method.
713
     *
714
     * @see \eZ\Publish\API\Repository\LocationService::loadLocationByRemoteId()
715
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
716
     */
717 View Code Duplication
    public function testLoadLocationByRemoteIdThrowsNotFoundException()
718
    {
719
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\NotFoundException::class);
720
721
        $repository = $this->getRepository();
722
723
        /* BEGIN: Use Case */
724
        $locationService = $repository->getLocationService();
725
726
        // Throws exception, since Location with remote ID does not exist
727
        $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...
728
            'not-exists'
729
        );
730
        /* END: Use Case */
731
    }
732
733
    /**
734
     * Test for the loadLocations() method.
735
     *
736
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
737
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testCreateLocation
738
     */
739
    public function testLoadLocations()
740
    {
741
        $repository = $this->getRepository();
742
743
        $contentId = $this->generateId('object', 4);
744
        /* BEGIN: Use Case */
745
        // $contentId contains the ID of an existing content object
746
        $contentService = $repository->getContentService();
747
        $locationService = $repository->getLocationService();
748
749
        $contentInfo = $contentService->loadContentInfo($contentId);
750
751
        $locations = $locationService->loadLocations($contentInfo);
752
        /* END: Use Case */
753
754
        $this->assertIsArray($locations);
755
        self::assertNotEmpty($locations);
756
757
        foreach ($locations as $location) {
758
            self::assertInstanceOf(Location::class, $location);
759
            self::assertEquals($contentInfo->id, $location->getContentInfo()->id);
760
        }
761
762
        return $locations;
763
    }
764
765
    /**
766
     * Test for the loadLocations() method.
767
     *
768
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
769
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
770
     */
771
    public function testLoadLocationsContent(array $locations)
772
    {
773
        $repository = $this->getRepository();
774
        $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...
775
776
        $this->assertCount(1, $locations);
777
        foreach ($locations as $loadedLocation) {
778
            $this->assertInstanceOf(
779
                '\\eZ\\Publish\\API\\Repository\\Values\\Content\\Location',
780
                $loadedLocation
781
            );
782
        }
783
784
        usort(
785
            $locations,
786
            function ($a, $b) {
787
                strcmp($a->id, $b->id);
788
            }
789
        );
790
791
        $this->assertEquals(
792
            [$this->generateId('location', 5)],
793
            array_map(
794
                function (Location $location) {
795
                    return $location->id;
796
                },
797
                $locations
798
            )
799
        );
800
    }
801
802
    /**
803
     * Test for the loadLocations() method.
804
     *
805
     * @return \eZ\Publish\API\Repository\Values\Content\Location[]
806
     *
807
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations($contentInfo, $rootLocation)
808
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
809
     */
810
    public function testLoadLocationsLimitedSubtree()
811
    {
812
        $repository = $this->getRepository();
813
814
        $originalLocationId = $this->generateId('location', 54);
815
        $originalParentLocationId = $this->generateId('location', 48);
816
        $newParentLocationId = $this->generateId('location', 43);
817
        /* BEGIN: Use Case */
818
        // $originalLocationId is the ID of an existing location
819
        // $originalParentLocationId is the ID of the parent location of
820
        //     $originalLocationId
821
        // $newParentLocationId is the ID of an existing location outside the tree
822
        // of $originalLocationId and $originalParentLocationId
823
        $locationService = $repository->getLocationService();
824
825
        // Location at "/1/48/54"
826
        $originalLocation = $locationService->loadLocation($originalLocationId);
827
828
        // Create location under "/1/43/"
829
        $locationCreate = $locationService->newLocationCreateStruct($newParentLocationId);
830
        $locationService->createLocation(
831
            $originalLocation->contentInfo,
832
            $locationCreate
833
        );
834
835
        $findRootLocation = $locationService->loadLocation($originalParentLocationId);
836
837
        // Returns an array with only $originalLocation
838
        $locations = $locationService->loadLocations(
839
            $originalLocation->contentInfo,
840
            $findRootLocation
841
        );
842
        /* END: Use Case */
843
844
        $this->assertIsArray($locations);
845
846
        return $locations;
847
    }
848
849
    /**
850
     * Test for the loadLocations() method.
851
     *
852
     * @param \eZ\Publish\API\Repository\Values\Content\Location[] $locations
853
     *
854
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
855
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocationsLimitedSubtree
856
     */
857
    public function testLoadLocationsLimitedSubtreeContent(array $locations)
858
    {
859
        $this->assertCount(1, $locations);
860
861
        $this->assertEquals(
862
            $this->generateId('location', 54),
863
            reset($locations)->id
864
        );
865
    }
866
867
    /**
868
     * Test for the loadLocations() method.
869
     *
870
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations()
871
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
872
     */
873 View Code Duplication
    public function testLoadLocationsThrowsBadStateException()
874
    {
875
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
876
877
        $repository = $this->getRepository();
878
879
        /* BEGIN: Use Case */
880
        $contentTypeService = $repository->getContentTypeService();
881
        $contentService = $repository->getContentService();
882
        $locationService = $repository->getLocationService();
883
884
        // Create new content, which is not published
885
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
886
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
887
        $contentCreate->setField('name', 'New Folder');
888
        $content = $contentService->createContent($contentCreate);
889
890
        // Throws Exception, since $content has no published version, yet
891
        $locationService->loadLocations(
892
            $content->contentInfo
893
        );
894
        /* END: Use Case */
895
    }
896
897
    /**
898
     * Test for the loadLocations() method.
899
     *
900
     * @see \eZ\Publish\API\Repository\LocationService::loadLocations($contentInfo, $rootLocation)
901
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocations
902
     */
903
    public function testLoadLocationsThrowsBadStateExceptionLimitedSubtree()
904
    {
905
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\BadStateException::class);
906
907
        $repository = $this->getRepository();
908
909
        $someLocationId = $this->generateId('location', 2);
910
        /* BEGIN: Use Case */
911
        // $someLocationId is the ID of an existing location
912
        $contentTypeService = $repository->getContentTypeService();
913
        $contentService = $repository->getContentService();
914
        $locationService = $repository->getLocationService();
915
916
        // Create new content, which is not published
917
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
918
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
919
        $contentCreate->setField('name', 'New Folder');
920
        $content = $contentService->createContent($contentCreate);
921
922
        $findRootLocation = $locationService->loadLocation($someLocationId);
923
924
        // Throws Exception, since $content has no published version, yet
925
        $locationService->loadLocations(
926
            $content->contentInfo,
927
            $findRootLocation
928
        );
929
        /* END: Use Case */
930
    }
931
932
    /**
933
     * Test for the loadLocationChildren() method.
934
     *
935
     * @covers \eZ\Publish\API\Repository\LocationService::loadLocationChildren
936
     * @depends eZ\Publish\API\Repository\Tests\LocationServiceTest::testLoadLocation
937
     */
938
    public function testLoadLocationChildren()
939
    {
940
        $repository = $this->getRepository();
941
942
        $locationId = $this->generateId('location', 5);
943
        /* BEGIN: Use Case */
944
        // $locationId is the ID of an existing location
945
        $locationService = $repository->getLocationService();
946
947
        $location = $locationService->loadLocation($locationId);
948
949
        $childLocations = $locationService->loadLocationChildren($location);
950
        /* END: Use Case */
951
952
        $this->assertInstanceOf(LocationList::class, $childLocations);
953
        $this->assertIsArray($childLocations->locations);
954
        $this->assertNotEmpty($childLocations->locations);
955
        $this->assertIsInt($childLocations->totalCount);
956
957
        foreach ($childLocations->locations as $childLocation) {
958
            $this->assertInstanceOf(Location::class, $childLocation);
959
            $this->assertEquals($location->id, $childLocation->parentLocationId);
960
        }
961
962
        return $childLocations;
963
    }
964
965
    /**
966
     * Test loading parent Locations for draft Content.
967
     *
968
     * @covers \eZ\Publish\API\Repository\LocationService::loadParentLocationsForDraftContent
969
     */
970
    public function testLoadParentLocationsForDraftContent()
971
    {
972
        $repository = $this->getRepository();
973
        $locationService = $repository->getLocationService();
974
        $contentService = $repository->getContentService();
975
        $contentTypeService = $repository->getContentTypeService();
976
977
        // prepare locations
978
        $locationCreateStructs = [
979
            $locationService->newLocationCreateStruct(2),
980
            $locationService->newLocationCreateStruct(5),
981
        ];
982
983
        // Create new content
984
        $folderType = $contentTypeService->loadContentTypeByIdentifier('folder');
985
        $contentCreate = $contentService->newContentCreateStruct($folderType, 'eng-US');
986
        $contentCreate->setField('name', 'New Folder');
987
        $contentDraft = $contentService->createContent($contentCreate, $locationCreateStructs);
988
989
        // Test loading parent Locations
990
        $locations = $locationService->loadParentLocationsForDraftContent($contentDraft->versionInfo);
991
992
        self::assertCount(2, $locations);
993
        foreach ($locations as $location) {
994
            // test it is one of the given parent locations
995
            self::assertTrue($location->id === 2 || $location->id === 5);
996
        }
997
998
        return $contentDraft;
999
    }
1000
1001
    /**
1002
     * Test that trying to load parent Locations throws Exception if Content is not a draft.
1003
     *
1004
     * @depends testLoadParentLocationsForDraftContent
1005
     *
1006
     * @param \eZ\Publish\API\Repository\Values\Content\Content $contentDraft
1007
     */
1008
    public function testLoadParentLocationsForDraftContentThrowsBadStateException(Content $contentDraft)
1009
    {
1010
        $this->expectException(BadStateException::class);
1011
        $this->expectExceptionMessageRegExp('/is already published/');
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit\Framework\TestCa...xceptionMessageRegExp() has been deprecated with message: Use expectExceptionMessageMatches() instead

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