Completed
Push — 1.0 ( c1af37...0d48a1 )
by Valentin
01:22
created

LocationManager::find()   B

Complexity

Conditions 6
Paths 14

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6

Importance

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