LocationManager::syncronizeLocationsFromContentObject()   B
last analyzed

Complexity

Conditions 6
Paths 9

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 13
c 1
b 0
f 0
nc 9
nop 1
dl 0
loc 26
ccs 17
cts 17
cp 1
crap 6
rs 8.439
1
<?php
2
3
/**
4
 * This file is part of Transfer.
5
 *
6
 * For the full copyright and license information, please view the LICENSE file located
7
 * in the root directory.
8
 */
9
10
namespace Transfer\EzPlatform\Repository\Manager;
11
12
use eZ\Publish\API\Repository\ContentService;
13
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
14
use eZ\Publish\API\Repository\LocationService;
15
use eZ\Publish\API\Repository\Values\Content\Location;
16
use Psr\Log\LoggerAwareInterface;
17
use Psr\Log\LoggerInterface;
18
use Transfer\Data\ObjectInterface;
19
use Transfer\Data\ValueObject;
20
use Transfer\EzPlatform\Exception\ObjectNotFoundException;
21
use Transfer\EzPlatform\Exception\UnsupportedObjectOperationException;
22
use Transfer\EzPlatform\Repository\Values\ContentObject;
23
use Transfer\EzPlatform\Repository\Values\LocationObject;
24
use Transfer\EzPlatform\Repository\Manager\Type\CreatorInterface;
25
use Transfer\EzPlatform\Repository\Manager\Type\RemoverInterface;
26
use Transfer\EzPlatform\Repository\Manager\Type\UpdaterInterface;
27
28
/**
29
 * Location manager.
30
 *
31
 * @internal
32
 */
33
class LocationManager implements LoggerAwareInterface, CreatorInterface, UpdaterInterface, RemoverInterface
34
{
35
    /**
36
     * @var LoggerInterface Logger
37
     */
38
    protected $logger;
39
40
    /**
41
     * @var LocationService Location service
42
     */
43
    private $locationService;
44
45
    /**
46
     * @var ContentService Content service
47
     */
48
    private $contentService;
49
50
    /**
51
     * @param LocationService $locationService
52
     * @param ContentService  $contentService
53 16
     */
54
    public function __construct(LocationService $locationService, ContentService $contentService)
55 16
    {
56 16
        $this->locationService = $locationService;
57 16
        $this->contentService = $contentService;
58
    }
59
60
    /**
61
     * {@inheritdoc}
62 38
     */
63
    public function setLogger(LoggerInterface $logger)
64 38
    {
65 38
        $this->logger = $logger;
66
    }
67
68
    /**
69
     * {@inheritdoc}
70 17
     */
71
    public function find(ValueObject $object)
72
    {
73 17
        try {
74 12
            if (isset($object->data['remote_id'])) {
75 17
                $location = $this->locationService->loadLocationByRemoteId($object->data['remote_id']);
76 6
            } elseif ($object->getProperty('id')) {
77 12
                $location = $this->locationService->loadLocation($object->getProperty('id'));
78 7
            } elseif (isset($object->data['content_id'])) {
79 7
                $location = $this->getLocationByObject($object);
80 17
            }
81
        } catch (NotFoundException $notFoundException) {
82
            // We'll throw our own exception later instead.
83
        }
84 17
85 5
        if (!isset($location)) {
86
            throw new ObjectNotFoundException(Location::class, array('remote_id', 'id'));
87
        }
88 16
89
        return $location;
90
    }
91
92
    /**
93
     * Get location by content_id and parent_location_id.
94
     *
95
     * @param ValueObject $object
96
     *
97
     * @return Location|null
98 7
     */
99
    private function getLocationByObject(ValueObject $object)
100 7
    {
101 7
        $contentInfo = $this->contentService->loadContentInfo($object->data['content_id']);
102 7
        $locations = $this->locationService->loadLocations($contentInfo);
103 6
        foreach ($locations as $loc) {
104 4
            if ($loc->parentLocationId === $object->data['parent_location_id']) {
105
                return $loc;
106 4
            }
107
        }
108 3
109
        return;
110
    }
111
112
    /**
113
     * Shortcut to find, mainly for locating parents.
114
     *
115
     * @param int $id
116
     *
117
     * @return Location
118
     *
119
     * @throws ObjectNotFoundException
120 5
     */
121
    public function findById($id)
122 5
    {
123
        return $this->find(new ValueObject([], ['id' => $id]));
124
    }
125
126
    /**
127
     * {@inheritdoc}
128 6
     */
129
    public function create(ObjectInterface $object)
130 6
    {
131 1
        if (!$object instanceof LocationObject) {
132
            throw new UnsupportedObjectOperationException(LocationObject::class, get_class($object));
133
        }
134 5
135
        $contentInfo = $this->contentService->loadContentInfo($object->data['content_id']);
136 5
137
        $locationCreateStruct = $this->locationService->newLocationCreateStruct($object->data['parent_location_id']);
138 5
139
        $object->getMapper()->mapObjectToCreateStruct($locationCreateStruct);
140 5
141
        $location = $this->locationService->createLocation($contentInfo, $locationCreateStruct);
142 5
143 5
        if ($this->logger) {
144 5
            $this->logger->info(sprintf('Created location %s on content id %s, with parent location id %s.', $location->id, $contentInfo->id, $location->parentLocationId));
145
        }
146 5
147
        $object->getMapper()->locationToObject($location);
148 5
149
        return $object;
150
    }
151
152
    /**
153
     * {@inheritdoc}
154 16
     */
155
    public function update(ObjectInterface $object)
156 16
    {
157 1
        if (!$object instanceof LocationObject) {
158
            throw new UnsupportedObjectOperationException(LocationObject::class, get_class($object));
159
        }
160 16
161
        $location = $this->find($object);
162
163 16
        // Move if parent_location_id differs.
164 16
        if (isset($object->data['parent_location_id'])) {
165 5
            if ($object->data['parent_location_id'] !== $location->parentLocationId) {
166 5
                $parentLocation = $this->findById($object->data['parent_location_id']);
167 5
                $this->locationService->moveSubtree($location, $parentLocation);
168 16
            }
169
        }
170 16
171
        $locationUpdateStruct = $this->locationService->newLocationUpdateStruct();
172 16
173
        $object->getMapper()->mapObjectToUpdateStruct($locationUpdateStruct);
174 16
175
        $location = $this->locationService->updateLocation($location, $locationUpdateStruct);
176 16
177 16
        if ($this->logger) {
178 16
            $this->logger->info(sprintf('Updated location %s with parent location id %s.', $location->id, $location->parentLocationId));
179
        }
180 16
181
        $object->getMapper()->locationToObject($location);
182 16
183
        return $object;
184
    }
185
186
    /**
187
     * {@inheritdoc}
188 17
     */
189
    public function createOrUpdate(ObjectInterface $object)
190 17
    {
191 1
        if (!$object instanceof LocationObject) {
192
            throw new UnsupportedObjectOperationException(LocationObject::class, get_class($object));
193
        }
194
195 17
        try {
196
            $this->find($object);
197 16
198 5
            return $this->update($object);
199 5
        } catch (NotFoundException $notFound) {
200
            return $this->create($object);
201
        }
202
    }
203
204
    /**
205
     * Creates/updates/deletes locations in ContentObject->parent_locations.
206
     *
207
     * @param ContentObject $object
208 17
     */
209
    public function syncronizeLocationsFromContentObject(ContentObject $object)
210
    {
211 17
        /** @var LocationObject[] $parentLocations */
212 17
        $parentLocations = $object->getProperty('parent_locations');
213 7
        if (is_array($parentLocations) && count($parentLocations) > 0) {
214 7
            $addOrUpdate = [];
215 7
            foreach ($parentLocations as $parentLocation) {
216 7
                $addOrUpdate[$parentLocation->data['parent_location_id']] = $parentLocation;
217
            }
218
219 7
            // Filter which Locations should be created/updated and deleted.
220
            $delible = $this->filterLocationsToBeDeleted($object, $addOrUpdate);
221
222 7
            // Create or update locations, and attach to Content
223 7
            foreach ($addOrUpdate as $parentLocation) {
224 7
                $parentLocation->data['content_id'] = $object->getProperty('content_info')->id;
225 7
                $locationObject = $this->createOrUpdate($parentLocation);
226 7
                $object->addParentLocation($locationObject);
227
            }
228
229 7
            // Lastly delete. We cannot delete first because Content cannot remove it's last Location.
230 1
            foreach ($delible as $delete) {
231 7
                $this->locationService->deleteLocation($delete);
232 7
            }
233 17
        }
234
    }
235
236
    /**
237
     * @param ContentObject    $object
238
     * @param LocationObject[] $locationsToKeep
239
     *
240
     * @return Location[]
241 7
     */
242
    private function filterLocationsToBeDeleted(ContentObject $object, $locationsToKeep)
243 7
    {
244
        $toBeDeleted = [];
245 7
246 6
        foreach ($this->locationService->loadLocations($object->getProperty('content_info')) as $existingLocation) {
247 1
            if (!array_key_exists($existingLocation->parentLocationId, $locationsToKeep)) {
248 1
                $toBeDeleted[] = $existingLocation;
249 7
            }
250
        }
251 7
252
        return $toBeDeleted;
253
    }
254
255
    /**
256
     * {@inheritdoc}
257 7
     */
258 7
    public function remove(ObjectInterface $object)
259 2
    {
260 1
        if (!$object instanceof LocationObject) {
261
            throw new UnsupportedObjectOperationException(LocationObject::class, get_class($object));
262
        }
263 1
264 1
        if ($location = $this->find($object)) {
265 1
            $this->locationService->deleteLocation($location);
266
        }
267 1
268
        return true;
269
    }
270
271
    /**
272
     * Hides a location.
273
     *
274
     * @param Location $location
275
     *
276
     * @return Location
277 1
     */
278
    public function hide(Location $location)
279 1
    {
280
        return $this->locationService->hideLocation($location);
281
    }
282
283
    /**
284
     * Un-hides a location.
285
     *
286
     * @param Location $location
287
     *
288
     * @return Location
289 1
     */
290
    public function unHide(Location $location)
291 1
    {
292
        return $this->locationService->unhideLocation($location);
293
    }
294
295
    /**
296
     * Toggles location visibility.
297
     *
298
     * @param Location $location
299
     *
300
     * @return Location
301 1
     */
302
    public function toggleVisibility(Location $location)
303 1
    {
304 1
        if ($location->hidden) {
305
            return $this->unHide($location);
306
        }
307 1
308
        return $this->hide($location);
309
    }
310
}
311