Completed
Push — inmemory-abstract-trait ( 124d36...8e914a )
by André
42:51 queued 18:52
created

ContentHandler::deleteTranslationFromContent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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