Issues (36)

lib/Doctrine/Common/Cache/RedisCache.php (1 issue)

1
<?php
2
3
namespace Doctrine\Common\Cache;
4
5
use Redis;
6
use function array_combine;
7
use function array_diff_key;
8
use function array_fill_keys;
9
use function array_filter;
10
use function array_keys;
11
use function count;
12
use function defined;
13
use function extension_loaded;
14
use function is_bool;
15
16
/**
17
 * Redis cache provider.
18
 *
19
 * @link   www.doctrine-project.org
20
 */
21
class RedisCache extends CacheProvider
22
{
23
    /** @var Redis|null */
24
    private $redis;
25
26
    /**
27
     * Sets the redis instance to use.
28
     *
29
     * @return void
30
     */
31 81
    public function setRedis(Redis $redis)
32
    {
33 81
        $redis->setOption(Redis::OPT_SERIALIZER, $this->getSerializerValue());
34 81
        $this->redis = $redis;
35 81
    }
36
37
    /**
38
     * Gets the redis instance used by the cache.
39
     *
40
     * @return Redis|null
41
     */
42 2
    public function getRedis()
43
    {
44 2
        return $this->redis;
45
    }
46
47
    /**
48
     * {@inheritdoc}
49
     */
50 76
    protected function doFetch($id)
51
    {
52 76
        return $this->redis->get($id);
53
    }
54
55
    /**
56
     * {@inheritdoc}
57
     */
58 2
    protected function doFetchMultiple(array $keys)
59
    {
60 2
        $fetchedItems = array_combine($keys, $this->redis->mget($keys));
61
62
        // Redis mget returns false for keys that do not exist. So we need to filter those out unless it's the real data.
63
        $keysToFilter = array_keys(array_filter($fetchedItems, static function ($item) : bool {
64 2
            return $item === false;
65 2
        }));
66
67 2
        if ($keysToFilter) {
68 2
            $multi = $this->redis->multi(Redis::PIPELINE);
69 2
            foreach ($keysToFilter as $key) {
70 2
                $multi->exists($key);
71
            }
72 2
            $existItems     = array_filter($multi->exec());
73 2
            $missedItemKeys = array_diff_key($keysToFilter, $existItems);
74 2
            $fetchedItems   = array_diff_key($fetchedItems, array_fill_keys($missedItemKeys, true));
75
        }
76
77 2
        return $fetchedItems;
78
    }
79
80
    /**
81
     * {@inheritdoc}
82
     */
83 1
    protected function doSaveMultiple(array $keysAndValues, $lifetime = 0)
84
    {
85 1
        if ($lifetime) {
86
            // Keys have lifetime, use SETEX for each of them
87
            $multi = $this->redis->multi(Redis::PIPELINE);
88
            foreach ($keysAndValues as $key => $value) {
89
                $multi->setex($key, $lifetime, $value);
90
            }
91
            $succeeded = array_filter($multi->exec());
92
93
            return count($succeeded) == count($keysAndValues);
94
        }
95
96
        // No lifetime, use MSET
97 1
        return (bool) $this->redis->mset($keysAndValues);
98
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103 71
    protected function doContains($id)
104
    {
105 71
        $exists = $this->redis->exists($id);
106
107 71
        if (is_bool($exists)) {
0 ignored issues
show
The condition is_bool($exists) is always false.
Loading history...
108
            return $exists;
109
        }
110
111 71
        return $exists > 0;
112
    }
113
114
    /**
115
     * {@inheritdoc}
116
     */
117 74
    protected function doSave($id, $data, $lifeTime = 0)
118
    {
119 74
        if ($lifeTime > 0) {
120 3
            return $this->redis->setex($id, $lifeTime, $data);
121
        }
122
123 72
        return $this->redis->set($id, $data);
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129 44
    protected function doDelete($id)
130
    {
131 44
        return $this->redis->del($id) >= 0;
132
    }
133
134
    /**
135
     * {@inheritdoc}
136
     */
137 1
    protected function doDeleteMultiple(array $keys)
138
    {
139 1
        return $this->redis->del($keys) >= 0;
140
    }
141
142
    /**
143
     * {@inheritdoc}
144
     */
145 2
    protected function doFlush()
146
    {
147 2
        return $this->redis->flushDB();
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153 2
    protected function doGetStats()
154
    {
155 2
        $info = $this->redis->info();
156
157
        return [
158 2
            Cache::STATS_HITS   => $info['keyspace_hits'],
159 2
            Cache::STATS_MISSES => $info['keyspace_misses'],
160 2
            Cache::STATS_UPTIME => $info['uptime_in_seconds'],
161 2
            Cache::STATS_MEMORY_USAGE      => $info['used_memory'],
162
            Cache::STATS_MEMORY_AVAILABLE  => false,
163
        ];
164
    }
165
166
    /**
167
     * Returns the serializer constant to use. If Redis is compiled with
168
     * igbinary support, that is used. Otherwise the default PHP serializer is
169
     * used.
170
     *
171
     * @return int One of the Redis::SERIALIZER_* constants
172
     */
173 81
    protected function getSerializerValue()
174
    {
175 81
        if (defined('Redis::SERIALIZER_IGBINARY') && extension_loaded('igbinary')) {
176
            return Redis::SERIALIZER_IGBINARY;
177
        }
178
179 81
        return Redis::SERIALIZER_PHP;
180
    }
181
}
182