Completed
Push — inmemory-content-meta ( 00873c...41469f )
by André
94:52 queued 73:53
created

AbstractHandler   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 117
Duplicated Lines 6.84 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 8
loc 117
rs 10
c 0
b 0
f 0
wmc 10
lcom 1
cbo 1

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
B getMultipleCacheItems() 0 55 8
A escapeForCacheKey() 8 8 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
/**
4
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
5
 * @license For full copyright and license information view LICENSE file distributed with this source code.
6
 */
7
namespace eZ\Publish\Core\Persistence\Cache;
8
9
use eZ\Publish\SPI\Persistence\Handler as PersistenceHandler;
10
use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface;
11
12
/**
13
 * Class AbstractHandler.
14
 *
15
 * Abstract handler for use in other Persistence Cache Handlers.
16
 */
17
abstract class AbstractHandler
18
{
19
    /**
20
     * @var \Symfony\Component\Cache\Adapter\TagAwareAdapterInterface
21
     */
22
    protected $cache;
23
24
    /**
25
     * @var \eZ\Publish\SPI\Persistence\Handler
26
     */
27
    protected $persistenceHandler;
28
29
    /**
30
     * @var \eZ\Publish\Core\Persistence\Cache\PersistenceLogger
31
     */
32
    protected $logger;
33
34
    /**
35
     * Setups current handler with everything needed.
36
     *
37
     * @param \Symfony\Component\Cache\Adapter\TagAwareAdapterInterface $cache
38
     * @param \eZ\Publish\SPI\Persistence\Handler $persistenceHandler
39
     * @param \eZ\Publish\Core\Persistence\Cache\PersistenceLogger $logger
40
     */
41
    public function __construct(
42
        TagAwareAdapterInterface $cache,
43
        PersistenceHandler $persistenceHandler,
44
        PersistenceLogger $logger
45
    ) {
46
        $this->cache = $cache;
47
        $this->persistenceHandler = $persistenceHandler;
48
        $this->logger = $logger;
49
    }
50
51
    /**
52
     * Helper for getting multiple cache items in one call and do the id extraction for you.
53
     *
54
     * Cache items must be stored with a key in the following format "${keyPrefix}${id}", like "ez-content-info-${id}",
55
     * in order for this method to be able to prefix key on id's and also extract key prefix afterwards.
56
     *
57
     * It also optionally supports a key suffixs, for use on a variable argument that affects all lookups,
58
     * like translations, i.e. "ez-content-${id}-${translationKey}" where $keySuffixes = [$id => "-${translationKey}"].
59
     *
60
     * @param array $ids
61
     * @param string $keyPrefix E.g "ez-content-"
62
     * @param callable $missingLoader Function for loading missing objects, gets array with missing id's as argument,
63
     *                                expects return value to be array with id as key. Missing items should be missing.
64
     * @param callable $loadedTagger Function for tagging loaded object, gets object as argument, return array of tags.
65
     * @param array $keySuffixes Optional, key is id as provided in $ids, and value is a key suffix e.g. "-eng-Gb"
66
     *
67
     * @return array
68
     */
69
    final protected function getMultipleCacheItems(
70
        array $ids,
71
        string $keyPrefix,
72
        callable $missingLoader,
73
        callable $loadedTagger,
74
        array $keySuffixes = []
75
    ): array {
76
        if (empty($ids)) {
77
            return [];
78
        }
79
80
        // Generate unique cache keys
81
        $cacheKeys = [];
82
        $cacheKeysToIdMap = [];
83
        foreach (\array_unique($ids) as $id) {
84
            $key = $keyPrefix . $id . ($keySuffixes[$id] ?? '');
85
            $cacheKeys[] = $key;
86
            $cacheKeysToIdMap[$key] = $id;
87
        }
88
89
        // Load cache items by cache keys (will contain hits and misses)
90
        $list = [];
91
        $cacheMisses = [];
92
        foreach ($this->cache->getItems($cacheKeys) as $key => $cacheItem) {
93
            $id = $cacheKeysToIdMap[$key];
94
            if ($cacheItem->isHit()) {
95
                $list[$id] = $cacheItem->get();
96
            } else {
97
                $cacheMisses[] = $id;
98
                $list[$id] = $cacheItem;
99
            }
100
        }
101
102
        // No misses, return completely cached list
103
        if (empty($cacheMisses)) {
104
            return $list;
105
        }
106
107
        // Load missing items, save to cache & apply to list if found
108
        $loadedList = $missingLoader($cacheMisses);
109
        foreach ($cacheMisses as $id) {
110
            if (isset($loadedList[$id])) {
111
                $this->cache->save(
112
                    $list[$id]
113
                        ->set($loadedList[$id])
114
                        ->tag($loadedTagger($loadedList[$id]))
115
                );
116
                $list[$id] = $loadedList[$id];
117
            } else {
118
                unset($list[$id]);
119
            }
120
        }
121
122
        return $list;
123
    }
124
125 View Code Duplication
    final protected function escapeForCacheKey(string $identifier)
126
    {
127
        return \str_replace(
128
            ['_', '/', ':', '(', ')', '@', '\\', '{', '}'],
129
            ['__', '_S', '_C', '_BO', '_BC', '_A', '_BS', '_CBO', '_CBC'],
130
            $identifier
131
        );
132
    }
133
}
134