Completed
Push — EZEE-3159 ( 56bba0...79049c )
by
unknown
18:48
created

Handler::loadLocationsByTrashContent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
5
 * @license For full copyright and license information view LICENSE file distributed with this source code.
6
 */
7
namespace eZ\Publish\Core\Persistence\Legacy\Content\Location;
8
9
use eZ\Publish\SPI\Persistence\Content;
10
use eZ\Publish\SPI\Persistence\Content\Location;
11
use eZ\Publish\SPI\Persistence\Content\Location\CreateStruct;
12
use eZ\Publish\SPI\Persistence\Content\Location\UpdateStruct;
13
use eZ\Publish\SPI\Persistence\Content\Location\Handler as BaseLocationHandler;
14
use eZ\Publish\Core\Persistence\Legacy\Content\Handler as ContentHandler;
15
use eZ\Publish\Core\Persistence\Legacy\Content\TreeHandler;
16
use eZ\Publish\Core\Persistence\Legacy\Content\ObjectState\Handler as ObjectStateHandler;
17
use eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway as LocationGateway;
18
use eZ\Publish\Core\Persistence\Legacy\Content\Location\Mapper as LocationMapper;
19
use eZ\Publish\SPI\Persistence\Content\MetadataUpdateStruct;
20
21
/**
22
 * The Location Handler interface defines operations on Location elements in the storage engine.
23
 */
24
class Handler implements BaseLocationHandler
25
{
26
    /**
27
     * Gateway for handling location data.
28
     *
29
     * @var \eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway
30
     */
31
    protected $locationGateway;
32
33
    /**
34
     * Location locationMapper.
35
     *
36
     * @var \eZ\Publish\Core\Persistence\Legacy\Content\Location\Mapper
37
     */
38
    protected $locationMapper;
39
40
    /**
41
     * Content handler.
42
     *
43
     * @var \eZ\Publish\Core\Persistence\Legacy\Content\Handler
44
     */
45
    protected $contentHandler;
46
47
    /**
48
     * Object state handler.
49
     *
50
     * @var \eZ\Publish\Core\Persistence\Legacy\Content\ObjectState\Handler
51
     */
52
    protected $objectStateHandler;
53
54
    /**
55
     * Tree handler.
56
     *
57
     * @var \eZ\Publish\Core\Persistence\Legacy\Content\TreeHandler
58
     */
59
    protected $treeHandler;
60
61
    /**
62
     * Construct from userGateway.
63
     *
64
     * @param \eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway $locationGateway
65
     * @param \eZ\Publish\Core\Persistence\Legacy\Content\Location\Mapper $locationMapper
66
     * @param \eZ\Publish\Core\Persistence\Legacy\Content\Handler $contentHandler
67
     * @param \eZ\Publish\Core\Persistence\Legacy\Content\ObjectState\Handler $objectStateHandler
68
     * @param \eZ\Publish\Core\Persistence\Legacy\Content\TreeHandler $treeHandler
69
     *
70
     * @return \eZ\Publish\Core\Persistence\Legacy\Content\Location\Handler
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
71
     */
72
    public function __construct(
73
        LocationGateway $locationGateway,
74
        LocationMapper $locationMapper,
75
        ContentHandler $contentHandler,
76
        ObjectStateHandler $objectStateHandler,
77
        TreeHandler $treeHandler
78
    ) {
79
        $this->locationGateway = $locationGateway;
80
        $this->locationMapper = $locationMapper;
81
        $this->contentHandler = $contentHandler;
82
        $this->objectStateHandler = $objectStateHandler;
83
        $this->treeHandler = $treeHandler;
84
    }
85
86
    /**
87
     * Returns parent path string for a path string.
88
     *
89
     * @param string $pathString
90
     *
91
     * @return string
92
     */
93
    protected function getParentPathString($pathString)
94
    {
95
        return implode('/', array_slice(explode('/', $pathString), 0, -2)) . '/';
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101
    public function load($locationId, array $translations = null, bool $useAlwaysAvailable = true)
102
    {
103
        return $this->treeHandler->loadLocation($locationId, $translations, $useAlwaysAvailable);
0 ignored issues
show
Bug introduced by
It seems like $translations defined by parameter $translations on line 101 can also be of type array; however, eZ\Publish\Core\Persiste...Handler::loadLocation() does only seem to accept null|array<integer,string>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109
    public function loadList(array $locationIds, array $translations = null, bool $useAlwaysAvailable = true): iterable
110
    {
111
        $list = $this->locationGateway->getNodeDataList($locationIds, $translations, $useAlwaysAvailable);
0 ignored issues
show
Bug introduced by
It seems like $translations defined by parameter $translations on line 109 can also be of type array; however, eZ\Publish\Core\Persiste...eway::getNodeDataList() does only seem to accept null|array<integer,string>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
112
113
        $locations = [];
114
        foreach ($list as $row) {
115
            $id = (int)$row['node_id'];
116
            if (!isset($locations[$id])) {
117
                $locations[$id] = $this->locationMapper->createLocationFromRow($row);
118
            }
119
        }
120
121
        return $locations;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $locations; (array) is incompatible with the return type declared by the interface eZ\Publish\SPI\Persisten...ation\Handler::loadList of type eZ\Publish\SPI\Persisten...ntent\Location\iterable.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
122
    }
123
124
    /**
125
     * Loads the subtree ids of the location identified by $locationId.
126
     *
127
     * @param int $locationId
128
     *
129
     * @return array Location ids are in the index, Content ids in the value.
130
     */
131
    public function loadSubtreeIds($locationId)
132
    {
133
        return $this->locationGateway->getSubtreeContent($locationId, true);
134
    }
135
136
    /**
137
     * {@inheritdoc}
138
     */
139
    public function loadByRemoteId($remoteId, array $translations = null, bool $useAlwaysAvailable = true)
140
    {
141
        $data = $this->locationGateway->getBasicNodeDataByRemoteId($remoteId, $translations, $useAlwaysAvailable);
0 ignored issues
show
Bug introduced by
It seems like $translations defined by parameter $translations on line 139 can also be of type array; however, eZ\Publish\Core\Persiste...sicNodeDataByRemoteId() does only seem to accept null|array<integer,string>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
142
143
        return $this->locationMapper->createLocationFromRow($data);
144
    }
145
146
    /**
147
     * Loads all locations for $contentId, optionally limited to a sub tree
148
     * identified by $rootLocationId.
149
     *
150
     * @param int $contentId
151
     * @param int $rootLocationId
152
     *
153
     * @return \eZ\Publish\SPI\Persistence\Content\Location[]
154
     */
155
    public function loadLocationsByContent($contentId, $rootLocationId = null)
156
    {
157
        $rows = $this->locationGateway->loadLocationDataByContent($contentId, $rootLocationId);
158
159
        return $this->locationMapper->createLocationsFromRows($rows);
160
    }
161
162
    /**
163
     * @see \eZ\Publish\SPI\Persistence\Content\Location\Handler::loadParentLocationsForDraftContent
164
     */
165
    public function loadParentLocationsForDraftContent($contentId)
166
    {
167
        $rows = $this->locationGateway->loadParentLocationsDataForDraftContent($contentId);
168
169
        return $this->locationMapper->createLocationsFromRows($rows);
170
    }
171
172
    /**
173
     * Returns an array of default content states with content state group id as key.
174
     *
175
     * @return \eZ\Publish\SPI\Persistence\Content\ObjectState[]
176
     */
177
    protected function getDefaultContentStates()
178
    {
179
        $defaultObjectStatesMap = [];
180
181
        foreach ($this->objectStateHandler->loadAllGroups() as $objectStateGroup) {
182
            foreach ($this->objectStateHandler->loadObjectStates($objectStateGroup->id) as $objectState) {
183
                // Only register the first object state which is the default one.
184
                $defaultObjectStatesMap[$objectStateGroup->id] = $objectState;
185
                break;
186
            }
187
        }
188
189
        return $defaultObjectStatesMap;
190
    }
191
192
    /**
193
     * @param Content $content
194
     * @param \eZ\Publish\SPI\Persistence\Content\ObjectState[] $contentStates
195
     */
196
    protected function setContentStates(Content $content, array $contentStates)
197
    {
198
        foreach ($contentStates as $contentStateGroupId => $contentState) {
199
            $this->objectStateHandler->setContentState(
200
                $content->versionInfo->contentInfo->id,
201
                $contentStateGroupId,
202
                $contentState->id
203
            );
204
        }
205
    }
206
207
    /**
208
     * Copy location object identified by $sourceId, into destination identified by $destinationParentId.
209
     *
210
     * Performs a deep copy of the location identified by $sourceId and all of
211
     * its child locations, copying the most recent published content object
212
     * for each location to a new content object without any additional version
213
     * information. Relations are not copied. URLs are not touched at all.
214
     *
215
     * @todo Either move to async/batch or find ways toward optimizing away operations per object.
216
     * @todo Optionally retain dates and set creator
217
     *
218
     * @param mixed $sourceId
219
     * @param mixed $destinationParentId
220
     * @param int|null $newOwnerId
221
     *
222
     * @return Location the newly created Location.
223
     *
224
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
225
     */
226
    public function copySubtree($sourceId, $destinationParentId, $newOwnerId = null)
227
    {
228
        $children = $this->locationGateway->getSubtreeContent($sourceId);
229
        $destinationParentData = $this->locationGateway->getBasicNodeData($destinationParentId);
230
        $defaultObjectStates = $this->getDefaultContentStates();
231
        $contentMap = [];
232
        $locationMap = [
233
            $children[0]['parent_node_id'] => [
234
                'id' => $destinationParentId,
235
                'hidden' => (bool)$destinationParentData['is_hidden'],
236
                'invisible' => (bool)$destinationParentData['is_invisible'],
237
                'path_identification_string' => $destinationParentData['path_identification_string'],
238
            ],
239
        ];
240
241
        $locations = [];
242
        foreach ($children as $child) {
243
            $locations[$child['contentobject_id']][$child['node_id']] = true;
244
        }
245
246
        $time = time();
247
        $mainLocations = [];
248
        $mainLocationsUpdate = [];
249
        foreach ($children as $index => $child) {
250
            // Copy content
251
            if (!isset($contentMap[$child['contentobject_id']])) {
252
                $content = $this->contentHandler->copy(
253
                    (int)$child['contentobject_id'],
254
                    (int)$child['contentobject_version'],
255
                    $newOwnerId
256
                );
257
258
                $this->setContentStates($content, $defaultObjectStates);
259
260
                $content = $this->contentHandler->publish(
261
                    $content->versionInfo->contentInfo->id,
262
                    $content->versionInfo->contentInfo->currentVersionNo,
263
                    new MetadataUpdateStruct(
264
                        [
265
                            'publicationDate' => $time,
266
                            'modificationDate' => $time,
267
                        ]
268
                    )
269
                );
270
271
                $contentMap[$child['contentobject_id']] = $content->versionInfo->contentInfo->id;
272
            }
273
274
            $createStruct = $this->locationMapper->getLocationCreateStruct($child);
275
            $createStruct->contentId = $contentMap[$child['contentobject_id']];
276
            $parentData = $locationMap[$child['parent_node_id']];
277
            $createStruct->parentId = $parentData['id'];
278
            $createStruct->invisible = $createStruct->hidden || $parentData['hidden'] || $parentData['invisible'];
279
            $pathString = explode('/', $child['path_identification_string']);
280
            $pathString = end($pathString);
281
            $createStruct->pathIdentificationString = strlen($pathString) > 0
282
                ? $parentData['path_identification_string'] . '/' . $pathString
283
                : null;
284
285
            // Use content main location if already set, otherwise create location as main
286
            if (isset($mainLocations[$child['contentobject_id']])) {
287
                $createStruct->mainLocationId = $locationMap[$mainLocations[$child['contentobject_id']]]['id'];
288
            } else {
289
                $createStruct->mainLocationId = true;
290
                $mainLocations[$child['contentobject_id']] = $child['node_id'];
291
292
                // If needed mark for update
293
                if (
294
                    isset($locations[$child['contentobject_id']][$child['main_node_id']]) &&
295
                    count($locations[$child['contentobject_id']]) > 1 &&
296
                    $child['node_id'] !== $child['main_node_id']
297
                ) {
298
                    $mainLocationsUpdate[$child['contentobject_id']] = $child['main_node_id'];
299
                }
300
            }
301
302
            $newLocation = $this->create($createStruct);
303
304
            $locationMap[$child['node_id']] = [
305
                'id' => $newLocation->id,
306
                'hidden' => $newLocation->hidden,
307
                'invisible' => $newLocation->invisible,
308
                'path_identification_string' => $newLocation->pathIdentificationString,
309
            ];
310
            if ($index === 0) {
311
                $copiedSubtreeRootLocation = $newLocation;
312
            }
313
        }
314
315
        // Update main locations
316
        foreach ($mainLocationsUpdate as $contentId => $mainLocationId) {
317
            $this->changeMainLocation(
318
                $contentMap[$contentId],
319
                $locationMap[$mainLocationId]['id']
320
            );
321
        }
322
323
        $destinationParentSectionId = $this->getSectionId($destinationParentId);
324
        $this->updateSubtreeSectionIfNecessary($copiedSubtreeRootLocation, $destinationParentSectionId);
0 ignored issues
show
Bug introduced by
The variable $copiedSubtreeRootLocation does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
325
326
        return $copiedSubtreeRootLocation;
327
    }
328
329
    /**
330
     * Retrieves section ID of the location's content.
331
     *
332
     * @param int $locationId
333
     *
334
     * @return int
335
     */
336
    private function getSectionId($locationId)
337
    {
338
        $location = $this->load($locationId);
339
        $locationContentInfo = $this->contentHandler->loadContentInfo($location->contentId);
340
341
        return $locationContentInfo->sectionId;
342
    }
343
344
    /**
345
     * If the location is the main location for its content, updates subtree section.
346
     *
347
     * @param Location $location
348
     * @param int $sectionId
349
     */
350
    private function updateSubtreeSectionIfNecessary(Location $location, $sectionId)
351
    {
352
        if ($this->isMainLocation($location)) {
353
            $this->setSectionForSubtree($location->id, $sectionId);
354
        }
355
    }
356
357
    /**
358
     * Checks if the location is the main location for its content.
359
     *
360
     * @param Location $location
361
     *
362
     * @return bool
363
     */
364
    private function isMainLocation(Location $location)
365
    {
366
        $locationContentInfo = $this->contentHandler->loadContentInfo($location->contentId);
367
368
        return $locationContentInfo->mainLocationId === $location->id;
369
    }
370
371
    /**
372
     * Moves location identified by $sourceId into new parent identified by $destinationParentId.
373
     *
374
     * Performs a full move of the location identified by $sourceId to a new
375
     * destination, identified by $destinationParentId. Relations do not need
376
     * to be updated, since they refer to Content. URLs are not touched.
377
     *
378
     * @param mixed $sourceId
379
     * @param mixed $destinationParentId
380
     *
381
     * @return bool
382
     */
383
    public function move($sourceId, $destinationParentId)
384
    {
385
        $sourceNodeData = $this->locationGateway->getBasicNodeData($sourceId);
386
        $destinationNodeData = $this->locationGateway->getBasicNodeData($destinationParentId);
387
388
        $this->locationGateway->moveSubtreeNodes(
389
            $sourceNodeData,
390
            $destinationNodeData
391
        );
392
393
        $this->locationGateway->updateNodeAssignment(
394
            $sourceNodeData['contentobject_id'],
395
            $sourceNodeData['parent_node_id'],
396
            $destinationParentId,
397
            Gateway::NODE_ASSIGNMENT_OP_CODE_MOVE
398
        );
399
400
        $sourceLocation = $this->load($sourceId);
401
        $destinationParentSectionId = $this->getSectionId($destinationParentId);
402
        $this->updateSubtreeSectionIfNecessary($sourceLocation, $destinationParentSectionId);
403
    }
404
405
    /**
406
     * Marks the given nodes and all ancestors as modified.
407
     *
408
     * Optionally a time stamp with the modification date may be specified,
409
     * otherwise the current time is used.
410
     *
411
     * @param int|string $locationId
412
     * @param int $timestamp
413
     */
414
    public function markSubtreeModified($locationId, $timestamp = null)
415
    {
416
        $nodeData = $this->locationGateway->getBasicNodeData($locationId);
417
        $timestamp = $timestamp ?: time();
418
        $this->locationGateway->updateSubtreeModificationTime($nodeData['path_string'], $timestamp);
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\Core\Persiste...btreeModificationTime() has been deprecated with message: Not supposed to be in use anymore.

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...
419
    }
420
421
    /**
422
     * Sets a location to be hidden, and it self + all children to invisible.
423
     *
424
     * @param mixed $id Location ID
425
     */
426
    public function hide($id)
427
    {
428
        $sourceNodeData = $this->locationGateway->getBasicNodeData($id);
429
430
        $this->locationGateway->hideSubtree($sourceNodeData['path_string']);
431
    }
432
433
    /**
434
     * Sets a location to be unhidden, and self + children to visible unless a parent is hiding the tree.
435
     * If not make sure only children down to first hidden node is marked visible.
436
     *
437
     * @param mixed $id
438
     */
439
    public function unHide($id)
440
    {
441
        $sourceNodeData = $this->locationGateway->getBasicNodeData($id);
442
443
        $this->locationGateway->unhideSubtree($sourceNodeData['path_string']);
444
    }
445
446
    /**
447
     * Sets a location + all children to invisible.
448
     *
449
     * @param int $id Location ID
450
     */
451
    public function setInvisible(int $id): void
452
    {
453
        $sourceNodeData = $this->locationGateway->getBasicNodeData($id);
454
455
        $this->locationGateway->setNodeWithChildrenInvisible($sourceNodeData['path_string']);
456
    }
457
458
    /**
459
     * Sets a location + all children to visible.
460
     *
461
     * @param int $id Location ID
462
     */
463
    public function setVisible(int $id): void
464
    {
465
        $sourceNodeData = $this->locationGateway->getBasicNodeData($id);
466
467
        $this->locationGateway->setNodeWithChildrenVisible($sourceNodeData['path_string']);
468
    }
469
470
    /**
471
     * Swaps the content object being pointed to by a location object.
472
     *
473
     * Make the location identified by $locationId1 refer to the Content
474
     * referred to by $locationId2 and vice versa.
475
     *
476
     * @param mixed $locationId1
477
     * @param mixed $locationId2
478
     *
479
     * @return bool
480
     */
481
    public function swap($locationId1, $locationId2)
482
    {
483
        $this->locationGateway->swap($locationId1, $locationId2);
484
    }
485
486
    /**
487
     * Updates an existing location.
488
     *
489
     * @param \eZ\Publish\SPI\Persistence\Content\Location\UpdateStruct $location
490
     * @param int $locationId
491
     */
492
    public function update(UpdateStruct $location, $locationId)
493
    {
494
        $this->locationGateway->update($location, $locationId);
495
    }
496
497
    /**
498
     * Creates a new location rooted at $location->parentId.
499
     *
500
     * @param \eZ\Publish\SPI\Persistence\Content\Location\CreateStruct $createStruct
501
     *
502
     * @return \eZ\Publish\SPI\Persistence\Content\Location
503
     */
504
    public function create(CreateStruct $createStruct)
505
    {
506
        $parentNodeData = $this->locationGateway->getBasicNodeData($createStruct->parentId);
507
        $locationStruct = $this->locationGateway->create($createStruct, $parentNodeData);
508
        $this->locationGateway->createNodeAssignment(
509
            $createStruct,
510
            $parentNodeData['node_id'],
511
            LocationGateway::NODE_ASSIGNMENT_OP_CODE_CREATE_NOP
512
        );
513
514
        return $locationStruct;
515
    }
516
517
    /**
518
     * Removes all Locations under and including $locationId.
519
     *
520
     * Performs a recursive delete on the location identified by $locationId,
521
     * including all of its child locations. Content which is not referred to
522
     * by any other location is automatically removed. Content which looses its
523
     * main Location will get the first of its other Locations assigned as the
524
     * new main Location.
525
     *
526
     * @param mixed $locationId
527
     *
528
     * @return bool
529
     */
530
    public function removeSubtree($locationId)
531
    {
532
        $this->treeHandler->removeSubtree($locationId);
533
    }
534
535
    /**
536
     * Set section on all content objects in the subtree.
537
     *
538
     * @param mixed $locationId
539
     * @param mixed $sectionId
540
     */
541
    public function setSectionForSubtree($locationId, $sectionId)
542
    {
543
        $this->treeHandler->setSectionForSubtree($locationId, $sectionId);
544
    }
545
546
    /**
547
     * Changes main location of content identified by given $contentId to location identified by given $locationId.
548
     *
549
     * Updates ezcontentobject_tree and eznode_assignment tables (eznode_assignment for content current version number).
550
     *
551
     * @param mixed $contentId
552
     * @param mixed $locationId
553
     */
554
    public function changeMainLocation($contentId, $locationId)
555
    {
556
        $this->treeHandler->changeMainLocation($contentId, $locationId);
557
    }
558
559
    /**
560
     * Get the total number of all existing Locations. Can be combined with loadAllLocations.
561
     *
562
     * @return int
563
     */
564
    public function countAllLocations()
565
    {
566
        return $this->locationGateway->countAllLocations();
567
    }
568
569
    /**
570
     * Bulk-load all existing Locations, constrained by $limit and $offset to paginate results.
571
     *
572
     * @param int $offset
573
     * @param int $limit
574
     *
575
     * @return \eZ\Publish\SPI\Persistence\Content\Location[]
576
     */
577
    public function loadAllLocations($offset, $limit)
578
    {
579
        $rows = $this->locationGateway->loadAllLocationsData($offset, $limit);
580
581
        return $this->locationMapper->createLocationsFromRows($rows);
582
    }
583
}
584