Viewing file: ApcuCache.php (3.72 KB) -rwxr-x--- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
declare(strict_types=1);
namespace PhpMyAdmin\MoTranslator\Cache;
use PhpMyAdmin\MoTranslator\CacheException; use PhpMyAdmin\MoTranslator\MoParser;
use function apcu_enabled; use function apcu_entry; use function apcu_exists; use function apcu_fetch; use function apcu_store; use function array_combine; use function array_keys; use function array_map; use function assert; use function function_exists; use function is_array; use function is_string;
final class ApcuCache implements CacheInterface { public const LOADED_KEY = '__TRANSLATIONS_LOADED__';
/** @var MoParser */ private $parser; /** @var string */ private $locale; /** @var string */ private $domain; /** @var int */ private $ttl; /** @var bool */ private $reloadOnMiss; /** @var string */ private $prefix;
public function __construct( MoParser $parser, string $locale, string $domain, int $ttl = 0, bool $reloadOnMiss = true, string $prefix = 'mo_' ) { if (! (function_exists('apcu_enabled') && apcu_enabled())) { throw new CacheException('ACPu extension must be installed and enabled'); }
$this->parser = $parser; $this->locale = $locale; $this->domain = $domain; $this->ttl = $ttl; $this->reloadOnMiss = $reloadOnMiss; $this->prefix = $prefix;
$this->ensureTranslationsLoaded(); }
public function get(string $msgid): string { $msgstr = apcu_fetch($this->getKey($msgid), $success); if ($success && is_string($msgstr)) { return $msgstr; }
if (! $this->reloadOnMiss) { return $msgid; }
return $this->reloadOnMiss($msgid); }
private function reloadOnMiss(string $msgid): string { // store original if translation is not present $cached = apcu_entry($this->getKey($msgid), static function () use ($msgid) { return $msgid; }, $this->ttl); // if another process has updated cache, return early if ($cached !== $msgid && is_string($cached)) { return $cached; }
// reload .mo file, in case entry has been evicted $this->parser->parseIntoCache($this);
$msgstr = apcu_fetch($this->getKey($msgid), $success);
return $success && is_string($msgstr) ? $msgstr : $msgid; }
public function set(string $msgid, string $msgstr): void { apcu_store($this->getKey($msgid), $msgstr, $this->ttl); }
public function has(string $msgid): bool { return apcu_exists($this->getKey($msgid)); }
public function setAll(array $translations): void { $keys = array_map(function (string $msgid): string { return $this->getKey($msgid); }, array_keys($translations)); $translations = array_combine($keys, $translations); assert(is_array($translations));
apcu_store($translations, null, $this->ttl); }
private function getKey(string $msgid): string { return $this->prefix . $this->locale . '.' . $this->domain . '.' . $msgid; }
private function ensureTranslationsLoaded(): void { // Try to prevent cache slam if multiple processes are trying to load translations. There is still a race // between the exists check and creating the entry, but at least it's small $key = $this->getKey(self::LOADED_KEY); $loaded = apcu_exists($key) || apcu_entry($key, static function (): int { return 0; }, $this->ttl); if ($loaded) { return; }
$this->parser->parseIntoCache($this); apcu_store($this->getKey(self::LOADED_KEY), 1, $this->ttl); } }
|