Completed
Pull Request — 1.0 (#67)
by Harald
06:03
created

LocationManager::find()   C

Complexity

Conditions 8
Paths 22

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 8

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 27
ccs 18
cts 18
cp 1
rs 5.3846
cc 8
eloc 17
nc 22
nop 1
crap 8
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\Repository;
16
use eZ\Publish\API\Repository\Values\Content\Location;
17
use Psr\Log\LoggerAwareInterface;
18
use Psr\Log\LoggerInterface;
19
use Transfer\Data\ObjectInterface;
20
use Transfer\Data\ValueObject;
21
use Transfer\EzPlatform\Exception\ObjectNotFoundException;
22
use Transfer\EzPlatform\Exception\UnsupportedObjectOperationException;
23
use Transfer\EzPlatform\Repository\Values\ContentObject;
24
use Transfer\EzPlatform\Repository\Values\LocationObject;
25
use Transfer\EzPlatform\Repository\Manager\Type\CreatorInterface;
26
use Transfer\EzPlatform\Repository\Manager\Type\RemoverInterface;
27
use Transfer\EzPlatform\Repository\Manager\Type\UpdaterInterface;
28
29
/**
30
 * Location manager.
31
 *
32
 * @internal
33
 */
34
class LocationManager implements LoggerAwareInterface, CreatorInterface, UpdaterInterface, RemoverInterface
35
{
36
    /**
37
     * @var LoggerInterface Logger
38
     */
39
    protected $logger;
40
41
    /**
42
     * @var Repository
43
     */
44
    private $repository;
45
46
    /**
47
     * @var LocationService Location service
48
     */
49
    private $locationService;
50
51
    /**
52
     * @var ContentService Content service
53
     */
54
    private $contentService;
55
56
    /**
57
     * @param Repository $repository
58
     */
59 14
    public function __construct(Repository $repository)
60
    {
61 14
        $this->repository = $repository;
62 14
        $this->locationService = $repository->getLocationService();
63 14
        $this->contentService = $repository->getContentService();
64 14
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69 33
    public function setLogger(LoggerInterface $logger)
70
    {
71 33
        $this->logger = $logger;
72 33
    }
73
74
    /**
75
     * {@inheritdoc}
76
     */
77 13
    public function find(ValueObject $object)
78
    {
79
        try {
80 13
            if (isset($object->data['remote_id'])) {
81 11
                $location = $this->locationService->loadLocationByRemoteId($object->data['remote_id']);
82 13
            } elseif ($object->getProperty('id')) {
83 3
                $location = $this->locationService->loadLocation($object->getProperty('id'));
84 6
            } elseif (isset($object->data['content_id'])) {
85 3
                $contentInfo = $this->contentService->loadContentInfo($object->data['content_id']);
86 3
                $locations = $this->locationService->loadLocations($contentInfo);
87 3
                foreach ($locations as $loc) {
88 3
                    if ($loc->parentLocationId === $object->data['parent_location_id']) {
89 1
                        $location = $loc;
90 1
                        break;
91
                    }
92 3
                }
93 3
            }
94 13
        } catch (NotFoundException $notFoundException) {
95
            // We'll throw our own exception later instead.
96
        }
97
98 13
        if (!isset($location)) {
99 4
            throw new ObjectNotFoundException(Location::class, array('remote_id', 'id'));
100
        }
101
102 12
        return $location;
103
    }
104
105
    /**
106
     * Shortcut to find, mainly for locating parents.
107
     *
108
     * @param int $id
109
     *
110
     * @return Location
111
     *
112
     * @throws ObjectNotFoundException
113
     */
114 2
    public function findById($id)
115
    {
116 2
        return $this->find(new ValueObject([], ['id' => $id]));
117
    }
118
119
    /**
120
     * {@inheritdoc}
121
     */
122 5
    public function create(ObjectInterface $object)
123
    {
124 5
        if (!$object instanceof LocationObject) {
125 1
            throw new UnsupportedObjectOperationException(LocationObject::class, get_class($object));
126
        }
127
128 4
        $contentInfo = $this->repository->getContentService()->loadContentInfo($object->data['content_id']);
129
130 4
        $locationCreateStruct = $this->locationService->newLocationCreateStruct($object->data['parent_location_id']);
131
132 4
        $object->getMapper()->getNewLocationCreateStruct($locationCreateStruct);
133
134 4
        $location = $this->locationService->createLocation($contentInfo, $locationCreateStruct);
135
136 4
        if ($this->logger) {
137 4
            $this->logger->info(sprintf('Created location %s on content id %s, with parent location id %s.', $location->id, $contentInfo->id, $location->parentLocationId));
138 4
        }
139
140 4
        $object->getMapper()->locationToObject($location);
141
142 4
        return $object;
143
    }
144
145
    /**
146
     * {@inheritdoc}
147
     */
148 12
    public function update(ObjectInterface $object)
149
    {
150 12
        if (!$object instanceof LocationObject) {
151 1
            throw new UnsupportedObjectOperationException(LocationObject::class, get_class($object));
152
        }
153
154 12
        $location = $this->find($object);
155
156
        // Move if parent_location_id differs.
157 12
        if (isset($object->data['parent_location_id'])) {
158 12
            if ($object->data['parent_location_id'] !== $location->parentLocationId) {
159 2
                $parentLocation = $this->findById($object->data['parent_location_id']);
160 2
                $this->locationService->moveSubtree($location, $parentLocation);
161 2
            }
162 12
        }
163
164 12
        $locationUpdateStruct = $this->locationService->newLocationUpdateStruct();
165
166 12
        $object->getMapper()->getNewLocationUpdateStruct($locationUpdateStruct);
167
168 12
        $location = $this->locationService->updateLocation($location, $locationUpdateStruct);
169
170 12
        if ($this->logger) {
171 12
            $this->logger->info(sprintf('Updated location %s with parent location id %s.', $location->id, $location->parentLocationId));
172 12
        }
173
174 12
        $object->getMapper()->locationToObject($location);
175
176 12
        return $object;
177
    }
178
179
    /**
180
     * {@inheritdoc}
181
     */
182 13 View Code Duplication
    public function createOrUpdate(ObjectInterface $object)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
183
    {
184 13
        if (!$object instanceof LocationObject) {
185 1
            throw new UnsupportedObjectOperationException(LocationObject::class, get_class($object));
186
        }
187
188
        try {
189 13
            $this->find($object);
190
191 12
            return $this->update($object);
192 4
        } catch (NotFoundException $notFound) {
193 4
            return $this->create($object);
194
        }
195
    }
196
197
    /**
198
     * Creates/updates/deletes locations in ContentObject->parent_locations.
199
     *
200
     * @param ContentObject $object
201
     */
202 16
    public function syncronizeLocationsFromContentObject(ContentObject $object)
203
    {
204
        /** @var LocationObject[] $parentLocations */
205 16
        $parentLocations = $object->getProperty('parent_locations');
206 16
        if (is_array($parentLocations) && count($parentLocations) > 0) {
207 3
            $addOrUpdate = [];
208 3
            foreach ($parentLocations as $parentLocation) {
209 3
                $addOrUpdate[$parentLocation->data['parent_location_id']] = $parentLocation;
210 3
            }
211
212
            // Filter which Locations should be created/updated and deleted.
213 3
            $delible = $this->filterLocationsToBeDeleted($object, $addOrUpdate);
214
215
            // Create or update locations, and attach to Content
216 3
            foreach ($addOrUpdate as $parentLocation) {
217 3
                $parentLocation->data['content_id'] = $object->getProperty('content_info')->id;
218 3
                $locationObject = $this->createOrUpdate($parentLocation);
219 3
                $object->addParentLocation($locationObject);
220 3
            }
221
222
            // Lastly delete. We cannot delete first because Content cannot remove it's last Location.
223 3
            foreach ($delible as $delete) {
224 1
                $this->locationService->deleteLocation($delete);
225 3
            }
226 3
        }
227 16
    }
228
229
    /**
230
     * @param ContentObject    $object
231
     * @param LocationObject[] $locationsToKeep
232
     *
233
     * @return Location[]
234
     */
235 3
    private function filterLocationsToBeDeleted(ContentObject $object, $locationsToKeep)
236
    {
237 3
        $toBeDeleted = [];
238
239 3
        foreach ($this->locationService->loadLocations($object->getProperty('content_info')) as $existingLocation) {
240 3
            if (!array_key_exists($existingLocation->parentLocationId, $locationsToKeep)) {
241 1
                $toBeDeleted[] = $existingLocation;
242 1
            }
243 3
        }
244
245 3
        return $toBeDeleted;
246
    }
247
248
    /**
249
     * {@inheritdoc}
250
     */
251 5 View Code Duplication
    public function remove(ObjectInterface $object)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
252
    {
253 5
        if (!$object instanceof LocationObject) {
254 1
            throw new UnsupportedObjectOperationException(LocationObject::class, get_class($object));
255
        }
256
257 1
        if ($location = $this->find($object)) {
258 4
            $this->locationService->deleteLocation($location);
259 1
        }
260
261 1
        return true;
262
    }
263
264
    /**
265
     * Hides a location.
266
     *
267
     * @param Location $location
268
     *
269
     * @return Location
270
     */
271 2
    public function hide(Location $location)
272
    {
273 2
        return $this->locationService->hideLocation($location);
274
    }
275
276
    /**
277
     * Un-hides a location.
278
     *
279
     * @param Location $location
280
     *
281
     * @return Location
282
     */
283 1
    public function unHide(Location $location)
284
    {
285 1
        return $this->locationService->unhideLocation($location);
286
    }
287
288
    /**
289
     * Toggles location visibility.
290
     *
291
     * @param Location $location
292
     *
293
     * @return Location
294
     */
295 2
    public function toggleVisibility(Location $location)
296
    {
297 2
        if ($location->hidden) {
298 1
            return $this->unHide($location);
299
        }
300
301 2
        return $this->hide($location);
302
    }
303
}
304