Completed
Pull Request — 1.0 (#52)
by Harald
04:55
created

ContentManager::ensureNotTrashed()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 3.0884

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 16
ccs 11
cts 14
cp 0.7856
rs 9.4285
cc 3
eloc 11
nc 3
nop 1
crap 3.0884
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\ContentTypeService;
14
use eZ\Publish\API\Repository\LocationService;
15
use eZ\Publish\API\Repository\Repository;
16
use eZ\Publish\API\Repository\Values\Content\Content;
17
use eZ\Publish\API\Repository\Values\Content\ContentCreateStruct;
18
use eZ\Publish\API\Repository\Values\Content\ContentUpdateStruct;
19
use eZ\Publish\API\Repository\Values\Content\Location;
20
use eZ\Publish\API\Repository\Values\Content\Query;
21
use eZ\Publish\Core\Repository\Values\Content\TrashItem;
22
use Psr\Log\LoggerAwareInterface;
23
use Psr\Log\LoggerInterface;
24
use Transfer\Data\ObjectInterface;
25
use Transfer\EzPlatform\Data\ContentObject;
26
use Transfer\EzPlatform\Exception\MissingIdentificationPropertyException;
27
use Transfer\EzPlatform\Repository\Manager\Type\CreatorInterface;
28
use Transfer\EzPlatform\Repository\Manager\Type\RemoverInterface;
29
use Transfer\EzPlatform\Repository\Manager\Type\UpdaterInterface;
30
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
31
32
/**
33
 * Content manager.
34
 *
35
 * @internal
36
 */
37
class ContentManager implements LoggerAwareInterface, CreatorInterface, UpdaterInterface, RemoverInterface
38
{
39
    /**
40
     * @var Repository
41
     */
42
    private $repository;
43
44
    /**
45
     * @var ContentService
46
     */
47
    protected $contentService;
48
49
    /**
50
     * @var ContentTypeService
51
     */
52
    protected $contentTypeService;
53
54
    /**
55
     * @var LocationService
56
     */
57
    protected $locationService;
58
59
    /**
60
     * @var LoggerInterface
61
     */
62
    protected $logger;
63
64
    /**
65
     * @var array List of created content objects.
66
     */
67
    private $created = array();
68
69
    /**
70
     * @param Repository $repository
71
     */
72 20
    public function __construct(Repository $repository)
73
    {
74 20
        $this->repository = $repository;
75 20
        $this->contentService = $repository->getContentService();
76 20
        $this->contentTypeService = $repository->getContentTypeService();
77 20
        $this->locationService = $repository->getLocationService();
78 20
        $this->repository = $repository;
79 20
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84 12
    public function setLogger(LoggerInterface $logger)
85
    {
86 12
        $this->logger = $logger;
87 12
    }
88
89
    /**
90
     * Finds a content object by remote ID.
91
     *
92
     * @param string $remoteId Remote ID
93
     *
94
     * @return ContentObject
95
     */
96 13
    public function findByRemoteId($remoteId)
97
    {
98
        try {
99 13
            $content = $this->contentService->loadContentByRemoteId($remoteId);
100 13
        } catch (\Exception $e) {
101 9
            return;
102
        }
103
104 8
        $object = new ContentObject($content->fields);
105 8
        $object->setContentInfo($content->contentInfo);
106
107 8
        $type = $this->contentTypeService->loadContentType($content->contentInfo->contentTypeId);
108 8
        $object->setContentType($type->identifier);
109
110 8
        return $object;
111
    }
112
113
    /**
114
     * {@inheritdoc}
115
     */
116 9
    public function create(ObjectInterface $object)
117
    {
118 9
        if (!$object instanceof ContentObject) {
119 1
            throw new \InvalidArgumentException('Object is not supported for creation.');
120
        }
121
122 8
        $createStruct = $this->contentService->newContentCreateStruct(
123 8
            $this->contentTypeService->loadContentTypeByIdentifier($object->getProperty('content_type_identifier')),
124 8
            $object->getProperty('language')
125 8
        );
126
127 8
        $this->mapObjectToStruct($object, $createStruct);
128
129 8
        $content = $this->contentService->createContent($createStruct);
130 8
        $this->contentService->publishVersion($content->versionInfo);
131
132 8
        if ($this->logger) {
133 2
            $this->logger->info(sprintf('Published new version of %s', $object->getProperty('name')), array('ContentManager::create'));
134 2
        }
135
136 8
        $object->setVersionInfo($content->versionInfo);
137 8
        $object->setContentInfo($content->contentInfo);
138
139 8
        $this->created[] = $object;
140
141 8
        return $object;
142
    }
143
144
    /**
145
     * {@inheritdoc}
146
     */
147 7
    public function update(ObjectInterface $object)
148
    {
149 7
        if (!$object instanceof ContentObject) {
150 1
            throw new \InvalidArgumentException('Object is not supported for update.');
151
        }
152
153 6
        $existingContent = $this->findByRemoteId($object->getRemoteId());
154 6
        if (null === $object->getProperty('content_info')) {
155 2
            $object->setProperty('content_info', $existingContent->getContentInfo());
156 2
        }
157
158 6
        $this->ensureNotTrashed($object);
159
160 6
        $contentDraft = $this->contentService->createContentDraft($object->getProperty('content_info'));
161
162 6
        $contentUpdateStruct = $this->contentService->newContentUpdateStruct();
163 6
        $this->mapObjectToUpdateStruct($object, $contentUpdateStruct);
164
165 6
        $contentDraft = $this->contentService->updateContent($contentDraft->versionInfo, $contentUpdateStruct);
166 6
        $content = $this->contentService->publishVersion($contentDraft->versionInfo);
167
168 6
        if ($this->logger) {
169 2
            $this->logger->info(sprintf('Published new version of %s', $object->getProperty('name')), array('ContentManager::update'));
170 2
        }
171
172 6
        $object->setVersionInfo($content->versionInfo);
173 6
        $object->setContentInfo($content->contentInfo);
174
175 6
        return $object;
176
    }
177
178
    /**
179
     * {@inheritdoc}
180
     */
181 12
    public function createOrUpdate(ObjectInterface $object)
182
    {
183 12
        if (!$object instanceof ContentObject) {
184 1
            throw new \InvalidArgumentException('Object is not supported for creation or update.');
185
        }
186
187 11
        if (!$object->getProperty('content_id') && !$object->getProperty('remote_id')) {
188 3
            throw new MissingIdentificationPropertyException($object);
189
        }
190
191 9
        if ($this->findByRemoteId($object->getRemoteId())) {
192 5
            return $this->update($object);
193
        } else {
194 7
            return $this->create($object);
195
        }
196
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201 3
    public function remove(ObjectInterface $object)
202
    {
203 3
        if (!$object instanceof ContentObject) {
204 1
            throw new \InvalidArgumentException('Object is not supported for deletion.');
205
        }
206
207 2
        $object = $this->findByRemoteId($object->getRemoteId());
208
209 2
        if ($object instanceof ContentObject && $object->getProperty('content_info')) {
210 1
            $this->contentService->deleteContent($object->getProperty('content_info'));
211
212 1
            return true;
213
        }
214
215 1
        return false;
216
    }
217
218
    /**
219
     * Assigns a main location ID for a content object.
220
     *
221
     * @param ContentObject $object   Content object
222
     * @param Location      $location Location
223
     *
224
     * @return Content
225
     */
226 4
    public function setMainLocation(ContentObject $object, Location $location)
227
    {
228 4
        $contentMetadataUpdateStruct = $this->contentService->newContentMetadataUpdateStruct();
229
230 4
        $contentMetadataUpdateStruct->mainLocationId = $location->id;
231
232 4
        $object->setMainLocationId($location->id);
233
234 4
        return $this->contentService->updateContentMetadata($object->getContentInfo(), $contentMetadataUpdateStruct);
235
    }
236
237
    /**
238
     * Maps object data to create struct.
239
     *
240
     * @param ContentObject       $object       Content object to map from
241
     * @param ContentCreateStruct $createStruct Content create struct to map to
242
     *
243
     * @throws \InvalidArgumentException
244
     */
245 8
    private function mapObjectToStruct(ContentObject $object, ContentCreateStruct $createStruct)
246
    {
247 8
        $this->assignStructFieldValues($object, $createStruct);
248
249 8
        if ($object->getProperty('language')) {
250 8
            $createStruct->mainLanguageCode = $object->getProperty('language');
251 8
        }
252
253 8
        if ($object->getProperty('remote_id')) {
254 8
            $createStruct->remoteId = $object->getProperty('remote_id');
255 8
        }
256 8
    }
257
258
    /**
259
     * Maps object data to update struct.
260
     *
261
     * @param ContentObject       $object              Content object to map from
262
     * @param ContentUpdateStruct $contentUpdateStruct Content update struct to map to
263
     *
264
     * @throws \InvalidArgumentException
265
     */
266 6
    private function mapObjectToUpdateStruct(ContentObject $object, ContentUpdateStruct $contentUpdateStruct)
267
    {
268 6
        $this->assignStructFieldValues($object, $contentUpdateStruct);
269 6
    }
270
271
    /**
272
     * Copies content object data from a struct.
273
     *
274
     * @param ContentObject $object Content object to get values from
275
     * @param object        $struct Struct to assign values to
276
     */
277 11
    private function assignStructFieldValues(ContentObject $object, $struct)
278
    {
279 11
        foreach ($object->data as $key => $value) {
280 11
            if (is_array($value)) {
281 2
                $value = end($value);
282 2
            }
283
284 11
            $struct->setField($key, $value);
285 11
        }
286 11
    }
287
288
    /**
289
     * @param ContentObject $object
290
     * @param Location      $location
0 ignored issues
show
Bug introduced by
There is no parameter named $location. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
291
     */
292 6
    private function ensureNotTrashed(ContentObject $object)
293
    {
294 6
        $query = new Query();
295 6
        $query->filter = new Criterion\ContentId($object->getContentInfo()->id);
296 6
        $trash = $this->repository->getTrashService()->findTrashItems($query);
297 6
        if ($trash->count > 0) {
298
            /** @var TrashItem $trashItem */
299 1
            $trashItem = $trash->items[0];
300 1
            $parentLocation = $this->repository->getLocationService()->loadLocation($trashItem->parentLocationId);
301 1
            $this->repository->getTrashService()->recover($trashItem, $parentLocation);
302 2
            if ($this->logger) {
303
                $this->logger->warning(sprintf('Content with remote id %s was found in the trash, recovering it and continues the proccess. '.
304
                    'Please check if this is correct, and prevent it from happening again.', $object->getRemoteId()));
305
            }
306 1
        }
307 6
    }
308
}
309