Passed
Pull Request — master (#43)
by Buster
09:23
created

Psr6Cache::has()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpMyAdmin\MoTranslator\Cache;
6
7
use PhpMyAdmin\MoTranslator\MoParser;
8
use Psr\Cache\CacheItemPoolInterface;
9
10
use function array_combine;
11
use function array_keys;
12
use function array_map;
13
use function is_string;
14
use function md5;
15
16
final class Psr6Cache implements CacheInterface
17
{
18
    public const LOADED_KEY = '__TRANSLATIONS_LOADED__';
19
20
    /** @var CacheItemPoolInterface */
21
    private $psr6Cache;
22
23
    /** @var MoParser */
24
    private $parser;
25
26
    /** @var string */
27
    private $locale;
28
29
    /** @var string */
30
    private $domain;
31
32
    /** @var int */
33
    private $ttl;
34
35
    /** @var bool */
36
    private $reloadOnMiss;
37
38
    /** @var string */
39
    private $prefix;
40
41
    /** @var string */
42
    private $separator;
43
44
    public function __construct(
45
        CacheItemPoolInterface $psr6Cache,
46
        MoParser $parser,
47
        string $locale,
48
        string $domain,
49
        int $ttl = 0,
50
        bool $reloadOnMiss = true,
51
        string $prefix = 'mo_',
52
        string $separator = '.'
53
    ) {
54
        $this->psr6Cache = $psr6Cache;
55
        $this->parser = $parser;
56
        $this->locale = $locale;
57
        $this->domain = $domain;
58
        $this->ttl = $ttl;
59
        $this->reloadOnMiss = $reloadOnMiss;
60
        $this->prefix = $prefix;
61
        $this->separator = $separator;
62
63
        $this->ensureTranslationsLoaded();
64
    }
65
66
    public function get(string $msgid): string
67
    {
68
        $cacheItem = $this->psr6Cache->getItem($this->getKey($msgid));
69
        $cacheItemValue = $cacheItem->isHit() ? $cacheItem->get() : null;
70
        if (is_string($cacheItemValue)) {
71
            return $cacheItemValue;
72
        }
73
74
        if (! $this->reloadOnMiss) {
75
            return $msgid;
76
        }
77
78
        $cacheItem->set($msgid);
79
        if ($this->ttl > 0) {
80
            $cacheItem->expiresAfter($this->ttl);
81
        }
82
83
        $this->psr6Cache->save($cacheItem);
84
85
        // reload .mo file, in case entry has been evicted
86
        $this->parser->parseIntoCache($this);
87
88
        $cacheItem = $this->psr6Cache->getItem($this->getKey($msgid));
89
        $cacheItemValue = $cacheItem->isHit() ? $cacheItem->get() : null;
90
91
        return is_string($cacheItemValue)
92
            ? $cacheItemValue
93
            : $msgid;
94
    }
95
96
    public function set(string $msgid, string $msgstr): void
97
    {
98
        $cacheItem = $this->psr6Cache->getItem($this->getKey($msgid));
99
        $cacheItem->set($msgstr);
100
        if ($this->ttl > 0) {
101
            $cacheItem->expiresAfter($this->ttl);
102
        }
103
104
        $this->psr6Cache->save($cacheItem);
105
    }
106
107
    public function has(string $msgid): bool
108
    {
109
        return $this->psr6Cache->hasItem($this->getKey($msgid));
110
    }
111
112
    public function setAll(array $translations): void
113
    {
114
        $keys = array_map(function (string $msgid): string {
115
            return $this->getKey($msgid);
116
        }, array_keys($translations));
117
        $translations = array_combine($keys, $translations);
118
119
        foreach ($this->psr6Cache->getItems($keys) as $cacheItem) {
120
            $cacheItem->set($translations[$cacheItem->getKey()]);
121
            if ($this->ttl > 0) {
122
                $cacheItem->expiresAfter($this->ttl);
123
            }
124
125
            $this->psr6Cache->saveDeferred($cacheItem);
126
        }
127
128
        $this->psr6Cache->commit();
129
    }
130
131
    private function getKey(string $msgid): string
132
    {
133
        // Hash the message ID to avoid using restricted characters in various cache adapters.
134
        return $this->prefix . $this->locale . $this->separator . $this->domain . $this->separator . md5($msgid);
135
    }
136
137
    private function ensureTranslationsLoaded(): void
138
    {
139
        // Try to prevent cache slam if multiple processes are trying to load translations. There is still a race
140
        // between the exists check and creating the entry, but at least it's small
141
        $cacheItem = $this->psr6Cache->getItem($this->getKey(self::LOADED_KEY));
142
        if ($cacheItem->isHit()) {
143
            return;
144
        }
145
146
        $this->parser->parseIntoCache($this);
147
148
        $cacheItem->set(1);
149
        if ($this->ttl > 0) {
150
            $cacheItem->expiresAfter($this->ttl);
151
        }
152
153
        $this->psr6Cache->save($cacheItem);
154
    }
155
}
156