Completed
Push — master ( 65f512...fe0390 )
by Łukasz
26:26
created

ContentHandler::loadVersionInfo()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 2
dl 0
loc 15
rs 9.7666
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;
14
use eZ\Publish\SPI\Persistence\Content\VersionInfo;
15
use eZ\Publish\SPI\Persistence\Content\ContentInfo;
16
use eZ\Publish\SPI\Persistence\Content\CreateStruct;
17
use eZ\Publish\SPI\Persistence\Content\UpdateStruct;
18
use eZ\Publish\SPI\Persistence\Content\MetadataUpdateStruct;
19
use eZ\Publish\SPI\Persistence\Content\Relation\CreateStruct as RelationCreateStruct;
20
21
/**
22
 * @see \eZ\Publish\SPI\Persistence\Content\Handler
23
 */
24
class ContentHandler extends AbstractHandler implements ContentHandlerInterface
25
{
26
    const ALL_TRANSLATIONS_KEY = '0';
27
28
    /**
29
     * {@inheritdoc}
30
     */
31
    public function create(CreateStruct $struct)
32
    {
33
        // Cached on demand when published or loaded
34
        $this->logger->logCall(__METHOD__, array('struct' => $struct));
35
36
        return $this->persistenceHandler->contentHandler()->create($struct);
37
    }
38
39
    /**
40
     * {@inheritdoc}
41
     */
42
    public function createDraftFromVersion($contentId, $srcVersion, $userId)
43
    {
44
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'version' => $srcVersion, 'user' => $userId));
45
        $draft = $this->persistenceHandler->contentHandler()->createDraftFromVersion($contentId, $srcVersion, $userId);
46
        $this->cache->invalidateTags(["content-$contentId-version-list"]);
47
48
        return $draft;
49
    }
50
51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function copy($contentId, $versionNo = null)
55
    {
56
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'version' => $versionNo));
57
58
        return $this->persistenceHandler->contentHandler()->copy($contentId, $versionNo);
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64
    public function load($contentId, $versionNo, array $translations = null)
65
    {
66
        $translationsKey = empty($translations) ? self::ALL_TRANSLATIONS_KEY : implode('|', $translations);
67
        $cacheItem = $this->cache->getItem("ez-content-${contentId}-${versionNo}-${translationsKey}");
68
        if ($cacheItem->isHit()) {
69
            return $cacheItem->get();
70
        }
71
72
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'version' => $versionNo, 'translations' => $translations));
73
        $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 64 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...
74
        $cacheItem->set($content);
75
        $cacheItem->tag($this->getCacheTags($content->versionInfo->contentInfo, true));
76
        $this->cache->save($cacheItem);
77
78
        return $content;
79
    }
80
81
    public function loadContentList(array $contentLoadStructs): array
82
    {
83
        // Extract id's and make key suffix for each one (handling undefined versionNo and languages)
84
        $contentIds = [];
85
        $keySuffixes = [];
86
        foreach ($contentLoadStructs as $struct) {
87
            $contentIds[] = $struct->id;
88
            $keySuffixes[$struct->id] = ($struct->versionNo ? "-{$struct->versionNo}-" : '-') .
89
                (empty($struct->languages) ? self::ALL_TRANSLATIONS_KEY : implode('|', $struct->languages));
90
        }
91
92
        return $this->getMultipleCacheItems(
93
            $contentIds,
94
            'ez-content-',
95
            function (array $cacheMissIds) use ($contentLoadStructs) {
96
                $this->logger->logCall(__CLASS__ . '::loadContentList', ['content' => $cacheMissIds]);
97
98
                $filteredStructs = [];
99
                /* @var $contentLoadStructs \eZ\Publish\SPI\Persistence\Content\LoadStruct[] */
100
                foreach ($contentLoadStructs as $struct) {
101
                    if (in_array($struct->id, $cacheMissIds)) {
102
                        $filteredStructs[] = $struct;
103
                    }
104
                }
105
106
                return $this->persistenceHandler->contentHandler()->loadContentList($filteredStructs);
107
            },
108
            function (Content $content) {
109
                return $this->getCacheTags($content->versionInfo->contentInfo, true);
110
            },
111
            $keySuffixes
112
        );
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118
    public function loadContentInfo($contentId)
119
    {
120
        $cacheItem = $this->cache->getItem("ez-content-info-${contentId}");
121
        if ($cacheItem->isHit()) {
122
            return $cacheItem->get();
123
        }
124
125
        $this->logger->logCall(__METHOD__, array('content' => $contentId));
126
        $contentInfo = $this->persistenceHandler->contentHandler()->loadContentInfo($contentId);
127
        $cacheItem->set($contentInfo);
128
        $cacheItem->tag($this->getCacheTags($contentInfo));
129
        $this->cache->save($cacheItem);
130
131
        return $contentInfo;
132
    }
133
134
    public function loadContentInfoList(array $contentIds)
135
    {
136
        return $this->getMultipleCacheItems(
137
            $contentIds,
138
            'ez-content-info-',
139
            function (array $cacheMissIds) {
140
                $this->logger->logCall(__CLASS__ . '::loadContentInfoList', ['content' => $cacheMissIds]);
141
142
                return $this->persistenceHandler->contentHandler()->loadContentInfoList($cacheMissIds);
143
            },
144
            function (ContentInfo $info) {
145
                return $this->getCacheTags($info);
146
            }
147
        );
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153
    public function loadContentInfoByRemoteId($remoteId)
154
    {
155
        $cacheItem = $this->cache->getItem("ez-content-info-byRemoteId-${remoteId}");
156
        if ($cacheItem->isHit()) {
157
            return $cacheItem->get();
158
        }
159
160
        $this->logger->logCall(__METHOD__, array('content' => $remoteId));
161
        $contentInfo = $this->persistenceHandler->contentHandler()->loadContentInfoByRemoteId($remoteId);
162
        $cacheItem->set($contentInfo);
163
        $cacheItem->tag($this->getCacheTags($contentInfo));
164
        $this->cache->save($cacheItem);
165
166
        return $contentInfo;
167
    }
168
169
    /**
170
     * {@inheritdoc}
171
     */
172
    public function loadVersionInfo($contentId, $versionNo)
173
    {
174
        $cacheItem = $this->cache->getItem("ez-content-version-info-${contentId}-${versionNo}");
175
        if ($cacheItem->isHit()) {
176
            return $cacheItem->get();
177
        }
178
179
        $this->logger->logCall(__METHOD__, ['content' => $contentId, 'version' => $versionNo]);
180
        $versionInfo = $this->persistenceHandler->contentHandler()->loadVersionInfo($contentId, $versionNo);
181
        $cacheItem->set($versionInfo);
182
        $cacheItem->tag($this->getCacheTags($versionInfo->contentInfo));
183
        $this->cache->save($cacheItem);
184
185
        return $versionInfo;
186
    }
187
188
    /**
189
     * {@inheritdoc}
190
     */
191
    public function loadDraftsForUser($userId)
192
    {
193
        $this->logger->logCall(__METHOD__, array('user' => $userId));
194
195
        return $this->persistenceHandler->contentHandler()->loadDraftsForUser($userId);
196
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201
    public function setStatus($contentId, $status, $versionNo)
202
    {
203
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'status' => $status, 'version' => $versionNo));
204
        $return = $this->persistenceHandler->contentHandler()->setStatus($contentId, $status, $versionNo);
205
206
        $this->cache->deleteItem("ez-content-version-info-${contentId}-${versionNo}");
207
        if ($status === VersionInfo::STATUS_PUBLISHED) {
208
            $this->cache->invalidateTags(['content-' . $contentId]);
209
        } else {
210
            $this->cache->invalidateTags(["content-$contentId-version-list"]);
211
        }
212
213
        return $return;
214
    }
215
216
    /**
217
     * {@inheritdoc}
218
     */
219
    public function updateMetadata($contentId, MetadataUpdateStruct $struct)
220
    {
221
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'struct' => $struct));
222
        $contentInfo = $this->persistenceHandler->contentHandler()->updateMetadata($contentId, $struct);
223
        $this->cache->invalidateTags(['content-' . $contentId]);
224
225
        return $contentInfo;
226
    }
227
228
    /**
229
     * {@inheritdoc}
230
     */
231
    public function updateContent($contentId, $versionNo, UpdateStruct $struct)
232
    {
233
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'version' => $versionNo, 'struct' => $struct));
234
        $content = $this->persistenceHandler->contentHandler()->updateContent($contentId, $versionNo, $struct);
235
        $this->cache->invalidateTags(['content-' . $contentId]);
236
237
        return $content;
238
    }
239
240
    /**
241
     * {@inheritdoc}
242
     */
243 View Code Duplication
    public function deleteContent($contentId)
244
    {
245
        $this->logger->logCall(__METHOD__, array('content' => $contentId));
246
247
        // Load reverse field relations first
248
        $reverseRelations = $this->persistenceHandler->contentHandler()->loadReverseRelations(
249
            $contentId,
250
            APIRelation::FIELD
251
        );
252
253
        $return = $this->persistenceHandler->contentHandler()->deleteContent($contentId);
254
255
        $this->cache->invalidateTags(['content-' . $contentId]);
256
        if (!empty($reverseRelations)) {
257
            $this->cache->invalidateTags(
258
                array_map(
259
                    function ($relation) {
260
                        // only the full content object *with* fields is affected by this
261
                        return 'content-fields-' . $relation->sourceContentId;
262
                    },
263
                    $reverseRelations
264
                )
265
            );
266
        }
267
268
        return $return;
269
    }
270
271
    /**
272
     * {@inheritdoc}
273
     */
274
    public function deleteVersion($contentId, $versionNo)
275
    {
276
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'version' => $versionNo));
277
        $return = $this->persistenceHandler->contentHandler()->deleteVersion($contentId, $versionNo);
278
        $this->cache->invalidateTags(['content-' . $contentId]);
279
280
        return $return;
281
    }
282
283
    /**
284
     * {@inheritdoc}
285
     */
286
    public function listVersions($contentId, $status = null, $limit = -1)
287
    {
288
        $cacheItem = $this->cache->getItem("ez-content-${contentId}-version-list" . ($status ? "-byStatus-${status}" : ''));
289
        if ($cacheItem->isHit()) {
290
            return $cacheItem->get();
291
        }
292
293
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'status' => $status));
294
        $versions = $this->persistenceHandler->contentHandler()->listVersions($contentId, $status, $limit);
295
        $cacheItem->set($versions);
296
        $tags = ["content-$contentId", "content-$contentId-version-list"];
297
        $cacheItem->tag(empty($versions) ? $tags : $this->getCacheTags($versions[0]->contentInfo, false, $tags));
298
        $this->cache->save($cacheItem);
299
300
        return $versions;
301
    }
302
303
    /**
304
     * {@inheritdoc}
305
     */
306
    public function addRelation(RelationCreateStruct $relation)
307
    {
308
        $this->logger->logCall(__METHOD__, array('struct' => $relation));
309
310
        return $this->persistenceHandler->contentHandler()->addRelation($relation);
311
    }
312
313
    /**
314
     * {@inheritdoc}
315
     */
316
    public function removeRelation($relationId, $type)
317
    {
318
        $this->logger->logCall(__METHOD__, array('relation' => $relationId, 'type' => $type));
319
        $this->persistenceHandler->contentHandler()->removeRelation($relationId, $type);
320
    }
321
322
    /**
323
     * {@inheritdoc}
324
     */
325
    public function loadRelations($sourceContentId, $sourceContentVersionNo = null, $type = null)
326
    {
327
        $this->logger->logCall(
328
            __METHOD__,
329
            array(
330
                'content' => $sourceContentId,
331
                'version' => $sourceContentVersionNo,
332
                'type' => $type,
333
            )
334
        );
335
336
        return $this->persistenceHandler->contentHandler()->loadRelations($sourceContentId, $sourceContentVersionNo, $type);
337
    }
338
339
    /**
340
     * {@inheritdoc}
341
     */
342
    public function loadReverseRelations($destinationContentId, $type = null)
343
    {
344
        $this->logger->logCall(__METHOD__, array('content' => $destinationContentId, 'type' => $type));
345
346
        return $this->persistenceHandler->contentHandler()->loadReverseRelations($destinationContentId, $type);
347
    }
348
349
    /**
350
     * {@inheritdoc}
351
     */
352
    public function publish($contentId, $versionNo, MetadataUpdateStruct $struct)
353
    {
354
        $this->logger->logCall(__METHOD__, array('content' => $contentId, 'version' => $versionNo, 'struct' => $struct));
355
        $content = $this->persistenceHandler->contentHandler()->publish($contentId, $versionNo, $struct);
356
        $this->cache->invalidateTags(['content-' . $contentId]);
357
358
        return $content;
359
    }
360
361
    /**
362
     * {@inheritdoc}
363
     */
364
    public function removeTranslationFromContent($contentId, $languageCode)
365
    {
366
        $this->deleteTranslationFromContent($contentId, $languageCode);
367
    }
368
369
    /**
370
     * {@inheritdoc}
371
     */
372 View Code Duplication
    public function deleteTranslationFromContent($contentId, $languageCode)
373
    {
374
        $this->logger->logCall(
375
            __METHOD__,
376
            [
377
                'contentId' => $contentId,
378
                'languageCode' => $languageCode,
379
            ]
380
        );
381
382
        $this->persistenceHandler->contentHandler()->deleteTranslationFromContent($contentId, $languageCode);
383
        $this->cache->invalidateTags(['content-' . $contentId]);
384
    }
385
386
    /**
387
     * {@inheritdoc}
388
     */
389
    public function deleteTranslationFromDraft($contentId, $versionNo, $languageCode)
390
    {
391
        $this->logger->logCall(
392
            __METHOD__,
393
            ['content' => $contentId, 'version' => $versionNo, 'languageCode' => $languageCode]
394
        );
395
        $content = $this->persistenceHandler->contentHandler()->deleteTranslationFromDraft(
396
            $contentId,
397
            $versionNo,
398
            $languageCode
399
        );
400
        $this->cache->invalidateTags(['content-' . $contentId]);
401
402
        return $content;
403
    }
404
405
    /**
406
     * Return relevant content and location tags so cache can be purged reliably.
407
     *
408
     * For use when generating cache, not on invalidation.
409
     *
410
     * @param \eZ\Publish\SPI\Persistence\Content\ContentInfo $contentInfo
411
     * @param bool $withFields Set to true if item contains fields which should be expired on relation or type updates.
412
     * @param array $tags Optional, can be used to specify other tags.
413
     *
414
     * @return array
415
     */
416
    private function getCacheTags(ContentInfo $contentInfo, $withFields = false, array $tags = [])
417
    {
418
        $tags[] = 'content-' . $contentInfo->id;
419
420
        if ($withFields) {
421
            $tags[] = 'content-fields-' . $contentInfo->id;
422
            $tags[] = 'content-fields-type-' . $contentInfo->contentTypeId;
423
        }
424
425 View Code Duplication
        if ($contentInfo->mainLocationId) {
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...
426
            $locations = $this->persistenceHandler->locationHandler()->loadLocationsByContent($contentInfo->id);
427
            foreach ($locations as $location) {
428
                $tags[] = 'location-' . $location->id;
429
                foreach (explode('/', trim($location->pathString, '/')) as $pathId) {
430
                    $tags[] = 'location-path-' . $pathId;
431
                }
432
            }
433
        }
434
435
        return array_unique($tags);
436
    }
437
}
438