Completed
Push — 7.0 ( e06b0d...07af66 )
by André
31:05 queued 19:36
created

ContentHandler::updateContent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 3
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the ContentHandler implementation.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\Core\Persistence\Cache;
10
11
use eZ\Publish\API\Repository\Values\Content\Relation as APIRelation;
12
use eZ\Publish\SPI\Persistence\Content\Handler as ContentHandlerInterface;
13
use eZ\Publish\SPI\Persistence\Content\VersionInfo;
14
use eZ\Publish\SPI\Persistence\Content\ContentInfo;
15
use eZ\Publish\SPI\Persistence\Content\CreateStruct;
16
use eZ\Publish\SPI\Persistence\Content\UpdateStruct;
17
use eZ\Publish\SPI\Persistence\Content\MetadataUpdateStruct;
18
use eZ\Publish\SPI\Persistence\Content\Relation\CreateStruct as RelationCreateStruct;
19
20
/**
21
 * @see \eZ\Publish\SPI\Persistence\Content\Handler
22
 */
23
class ContentHandler extends AbstractHandler implements ContentHandlerInterface
24
{
25
    const ALL_TRANSLATIONS_KEY = '0';
26
27
    /**
28
     * {@inheritdoc}
29
     */
30
    public function create(CreateStruct $struct)
31
    {
32
        // Cached on demand when published or loaded
33
        $this->logger->logCall(__METHOD__, array('struct' => $struct));
34
35
        return $this->persistenceHandler->contentHandler()->create($struct);
36
    }
37
38
    /**
39
     * {@inheritdoc}
40
     */
41
    public function createDraftFromVersion($contentId, $srcVersion, $userId)
42
    {
43
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'version' => $srcVersion, 'user' => $userId));
44
        $draft = $this->persistenceHandler->contentHandler()->createDraftFromVersion($contentId, $srcVersion, $userId);
45
        $this->cache->invalidateTags(["content-$contentId-version-list"]);
46
47
        return $draft;
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53
    public function copy($contentId, $versionNo = null)
54
    {
55
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'version' => $versionNo));
56
57
        return $this->persistenceHandler->contentHandler()->copy($contentId, $versionNo);
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    public function load($contentId, $versionNo, array $translations = null)
64
    {
65
        $translationsKey = empty($translations) ? self::ALL_TRANSLATIONS_KEY : implode('|', $translations);
66
        $cacheItem = $this->cache->getItem("ez-content-${contentId}-${versionNo}-${translationsKey}");
67
        if ($cacheItem->isHit()) {
68
            return $cacheItem->get();
69
        }
70
71
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'version' => $versionNo, 'translations' => $translations));
72
        $content = $this->persistenceHandler->contentHandler()->load($contentId, $versionNo, $translations);
0 ignored issues
show
Bug introduced by
It seems like $translations defined by parameter $translations on line 63 can also be of type array; however, eZ\Publish\SPI\Persistence\Content\Handler::load() 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...
73
        $cacheItem->set($content);
74
        $cacheItem->tag($this->getCacheTags($content->versionInfo->contentInfo, true));
75
        $this->cache->save($cacheItem);
76
77
        return $content;
78
    }
79
80
    /**
81
     * {@inheritdoc}
82
     */
83
    public function loadContentInfo($contentId)
84
    {
85
        $cacheItem = $this->cache->getItem("ez-content-info-${contentId}");
86
        if ($cacheItem->isHit()) {
87
            return $cacheItem->get();
88
        }
89
90
        $this->logger->logCall(__METHOD__, array('content' => $contentId));
91
        $contentInfo = $this->persistenceHandler->contentHandler()->loadContentInfo($contentId);
92
        $cacheItem->set($contentInfo);
93
        $cacheItem->tag($this->getCacheTags($contentInfo));
94
        $this->cache->save($cacheItem);
95
96
        return $contentInfo;
97
    }
98
99 View Code Duplication
    public function loadContentInfoList(array $contentIds)
100
    {
101
        list($cacheMisses, $list) = $this->getMultipleCacheItems($contentIds, 'ez-content-info-');
102
        if (empty($cacheMisses)) {
103
            return $list;
104
        }
105
106
        // Load cache misses
107
        $this->logger->logCall(__METHOD__, array('content' => $cacheMisses));
108
        $cacheMissList = $this->persistenceHandler->contentHandler()->loadContentInfoList($cacheMisses);
109
110
        // Populate cache misses with data and set final info data instead on list
111
        foreach ($cacheMissList as $id => $contentInfo) {
112
            $this->cache->save(
113
                $list[$id]
114
                    ->set($contentInfo)
115
                    ->tag($this->getCacheTags($contentInfo))
116
            );
117
            $list[$id] = $contentInfo;
118
        }
119
120
        return $list;
121
    }
122
123
    /**
124
     * {@inheritdoc}
125
     */
126
    public function loadContentInfoByRemoteId($remoteId)
127
    {
128
        $cacheItem = $this->cache->getItem("ez-content-info-byRemoteId-${remoteId}");
129
        if ($cacheItem->isHit()) {
130
            return $cacheItem->get();
131
        }
132
133
        $this->logger->logCall(__METHOD__, array('content' => $remoteId));
134
        $contentInfo = $this->persistenceHandler->contentHandler()->loadContentInfoByRemoteId($remoteId);
135
        $cacheItem->set($contentInfo);
136
        $cacheItem->tag($this->getCacheTags($contentInfo));
137
        $this->cache->save($cacheItem);
138
139
        return $contentInfo;
140
    }
141
142
    /**
143
     * {@inheritdoc}
144
     */
145
    public function loadVersionInfo($contentId, $versionNo)
146
    {
147
        $cacheItem = $this->cache->getItem("ez-content-version-info-${contentId}-${versionNo}");
148
        if ($cacheItem->isHit()) {
149
            return $cacheItem->get();
150
        }
151
152
        $this->logger->logCall(__METHOD__, ['content' => $contentId, 'version' => $versionNo]);
153
        $versionInfo = $this->persistenceHandler->contentHandler()->loadVersionInfo($contentId, $versionNo);
154
        $cacheItem->set($versionInfo);
155
        $cacheItem->tag($this->getCacheTags($versionInfo->contentInfo));
156
        $this->cache->save($cacheItem);
157
158
        return $versionInfo;
159
    }
160
161
    /**
162
     * {@inheritdoc}
163
     */
164
    public function loadDraftsForUser($userId)
165
    {
166
        $this->logger->logCall(__METHOD__, array('user' => $userId));
167
168
        return $this->persistenceHandler->contentHandler()->loadDraftsForUser($userId);
169
    }
170
171
    /**
172
     * {@inheritdoc}
173
     */
174
    public function setStatus($contentId, $status, $versionNo)
175
    {
176
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'status' => $status, 'version' => $versionNo));
177
        $return = $this->persistenceHandler->contentHandler()->setStatus($contentId, $status, $versionNo);
178
179
        $this->cache->deleteItem("ez-content-version-info-${contentId}-${versionNo}");
180
        if ($status === VersionInfo::STATUS_PUBLISHED) {
181
            $this->cache->invalidateTags(['content-' . $contentId]);
182
        } else {
183
            $this->cache->invalidateTags(["content-$contentId-version-list"]);
184
        }
185
186
        return $return;
187
    }
188
189
    /**
190
     * {@inheritdoc}
191
     */
192
    public function updateMetadata($contentId, MetadataUpdateStruct $struct)
193
    {
194
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'struct' => $struct));
195
        $contentInfo = $this->persistenceHandler->contentHandler()->updateMetadata($contentId, $struct);
196
        $this->cache->invalidateTags(['content-' . $contentId]);
197
198
        return $contentInfo;
199
    }
200
201
    /**
202
     * {@inheritdoc}
203
     */
204
    public function updateContent($contentId, $versionNo, UpdateStruct $struct)
205
    {
206
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'version' => $versionNo, 'struct' => $struct));
207
        $content = $this->persistenceHandler->contentHandler()->updateContent($contentId, $versionNo, $struct);
208
        $this->cache->invalidateTags(['content-' . $contentId]);
209
210
        return $content;
211
    }
212
213
    /**
214
     * {@inheritdoc}
215
     */
216
    public function deleteContent($contentId)
217
    {
218
        $this->logger->logCall(__METHOD__, array('content' => $contentId));
219
220
        // Load reverse field relations first
221
        $reverseRelations = $this->persistenceHandler->contentHandler()->loadReverseRelations(
222
            $contentId,
223
            APIRelation::FIELD
224
        );
225
226
        $return = $this->persistenceHandler->contentHandler()->deleteContent($contentId);
227
228
        $this->cache->invalidateTags(['content-' . $contentId]);
229
        if (!empty($reverseRelations)) {
230
            $this->cache->invalidateTags(
231
                array_map(
232
                    function ($relation) {
233
                        // only the full content object *with* fields is affected by this
234
                        return 'content-fields-' . $relation->sourceContentId;
235
                    },
236
                    $reverseRelations
237
                )
238
            );
239
        }
240
241
        return $return;
242
    }
243
244
    /**
245
     * {@inheritdoc}
246
     */
247
    public function deleteVersion($contentId, $versionNo)
248
    {
249
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'version' => $versionNo));
250
        $return = $this->persistenceHandler->contentHandler()->deleteVersion($contentId, $versionNo);
251
        $this->cache->invalidateTags(['content-' . $contentId]);
252
253
        return $return;
254
    }
255
256
    /**
257
     * {@inheritdoc}
258
     */
259
    public function listVersions($contentId, $status = null, $limit = -1)
260
    {
261
        $cacheItem = $this->cache->getItem("ez-content-${contentId}-version-list" . ($status ? "-byStatus-${status}" : ''));
262
        if ($cacheItem->isHit()) {
263
            return $cacheItem->get();
264
        }
265
266
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'status' => $status));
267
        $versions = $this->persistenceHandler->contentHandler()->listVersions($contentId, $status, $limit);
268
        $cacheItem->set($versions);
269
        $tags = ["content-$contentId", "content-$contentId-version-list"];
270
        $cacheItem->tag(empty($versions) ? $tags : $this->getCacheTags($versions[0]->contentInfo, false, $tags));
271
        $this->cache->save($cacheItem);
272
273
        return $versions;
274
    }
275
276
    /**
277
     * {@inheritdoc}
278
     */
279
    public function addRelation(RelationCreateStruct $relation)
280
    {
281
        $this->logger->logCall(__METHOD__, array('struct' => $relation));
282
283
        return $this->persistenceHandler->contentHandler()->addRelation($relation);
284
    }
285
286
    /**
287
     * {@inheritdoc}
288
     */
289
    public function removeRelation($relationId, $type)
290
    {
291
        $this->logger->logCall(__METHOD__, array('relation' => $relationId, 'type' => $type));
292
        $this->persistenceHandler->contentHandler()->removeRelation($relationId, $type);
293
    }
294
295
    /**
296
     * {@inheritdoc}
297
     */
298
    public function loadRelations($sourceContentId, $sourceContentVersionNo = null, $type = null)
299
    {
300
        $this->logger->logCall(
301
            __METHOD__,
302
            array(
303
                'content' => $sourceContentId,
304
                'version' => $sourceContentVersionNo,
305
                'type' => $type,
306
            )
307
        );
308
309
        return $this->persistenceHandler->contentHandler()->loadRelations($sourceContentId, $sourceContentVersionNo, $type);
310
    }
311
312
    /**
313
     * {@inheritdoc}
314
     */
315
    public function loadReverseRelations($destinationContentId, $type = null)
316
    {
317
        $this->logger->logCall(__METHOD__, array('content' => $destinationContentId, 'type' => $type));
318
319
        return $this->persistenceHandler->contentHandler()->loadReverseRelations($destinationContentId, $type);
320
    }
321
322
    /**
323
     * {@inheritdoc}
324
     */
325
    public function publish($contentId, $versionNo, MetadataUpdateStruct $struct)
326
    {
327
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'version' => $versionNo, 'struct' => $struct));
328
        $content = $this->persistenceHandler->contentHandler()->publish($contentId, $versionNo, $struct);
329
        $this->cache->invalidateTags(['content-' . $contentId]);
330
331
        return $content;
332
    }
333
334
    /**
335
     * Return relevant content and location tags so cache can be purged reliably.
336
     *
337
     * @param \eZ\Publish\SPI\Persistence\Content\ContentInfo $contentInfo
338
     * @param bool $withFields Set to true if item contains fields which should be expired on relation or type updates.
339
     * @param array $tags Optional, can be used to specify other tags.
340
     *
341
     * @return array
342
     */
343
    private function getCacheTags(ContentInfo $contentInfo, $withFields = false, array $tags = [])
344
    {
345
        $tags[] = 'content-' . $contentInfo->id;
346
347
        if ($withFields) {
348
            $tags[] = 'content-fields-' . $contentInfo->id;
349
            $tags[] = 'content-fields-type-' . $contentInfo->contentTypeId;
350
        }
351
352
        if ($contentInfo->mainLocationId) {
353
            $tags[] = 'location-' . $contentInfo->mainLocationId;
354
355
            $location = $this->persistenceHandler->locationHandler()->load($contentInfo->mainLocationId);
356 View Code Duplication
            foreach (explode('/', trim($location->pathString, '/')) as $pathId) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
357
                $tags[] = 'location-path-' . $pathId;
358
            }
359
        }
360
361
        return $tags;
362
    }
363
364
    /**
365
     * {@inheritdoc}
366
     */
367
    public function removeTranslationFromContent($contentId, $languageCode)
368
    {
369
        $this->logger->logCall(
370
            __METHOD__,
371
            [
372
                'contentId' => $contentId,
373
                'languageCode' => $languageCode,
374
            ]
375
        );
376
377
        $this->persistenceHandler->contentHandler()->removeTranslationFromContent($contentId, $languageCode);
378
379
        $this->cache->clear('content', $contentId);
380
        $this->cache->clear('content', 'info', $contentId);
381
    }
382
}
383