Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
CredisStorage
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 5
90
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 save
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 fetch
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 delete
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 createRedisKey
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3/**
4 * Credis storage adapter for Rate Limiter.
5 *
6 * PHP version 8
7 *
8 * Copyright (C) The National Library of Finland 2024.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2,
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 * @category VuFind
24 * @package  Cache
25 * @author   Ere Maijala <ere.maijala@helsinki.fi>
26 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
27 * @link     https://vufind.org Main Page
28 */
29
30namespace VuFind\RateLimiter\Storage;
31
32use Symfony\Component\RateLimiter\LimiterStateInterface;
33use Symfony\Component\RateLimiter\Storage\StorageInterface;
34
35/**
36 * Credis storage adapter for Rate Limiter.
37 *
38 * @category VuFind
39 * @package  Cache
40 * @author   Ere Maijala <ere.maijala@helsinki.fi>
41 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
42 * @link     https://vufind.org Main Page
43 */
44class CredisStorage implements StorageInterface
45{
46    /**
47     * Redis version
48     *
49     * @var int
50     */
51    protected $redisVersion;
52
53    /**
54     * Cache namespace
55     *
56     * @var string
57     */
58    protected $namespace;
59
60    /**
61     * Constructor
62     *
63     * @param \Credis_Client $redis  Redis connection object
64     * @param array          $config Redis configuration
65     * config.ini)
66     */
67    public function __construct(protected \Credis_Client $redis, protected array $config = [])
68    {
69        $this->redisVersion = (int)($config['redis_version'] ?? 6);
70        $this->namespace = (string)($config['namespace'] ?? '');
71    }
72
73    /**
74     * Save limiter state
75     *
76     * @param LimiterStateInterface $limiterState Limiter state
77     *
78     * @return void
79     */
80    public function save(LimiterStateInterface $limiterState): void
81    {
82        $options = [];
83        if (null !== ($expireAfter = $limiterState->getExpirationTime())) {
84            $options['EX'] = $expireAfter;
85        }
86        $this->redis->set($this->createRedisKey($limiterState->getId()), serialize($limiterState), $options);
87    }
88
89    /**
90     * Get limiter state by ID
91     *
92     * @param string $limiterStateId Limiter state ID
93     *
94     * @return ?LimiterStateInterface
95     */
96    public function fetch(string $limiterStateId): ?LimiterStateInterface
97    {
98        $state = $this->redis->get($this->createRedisKey($limiterStateId));
99        return $state !== false ? unserialize($state) : null;
100    }
101
102    /**
103     * Delete limiter state by ID
104     *
105     * @param string $limiterStateId Limiter state ID
106     *
107     * @return void
108     */
109    public function delete(string $limiterStateId): void
110    {
111        $this->redis->get($this->createRedisKey($limiterStateId));
112        $unlinkMethod = ($this->redisVersion >= 4) ? 'unlink' : 'del';
113        $this->redis->$unlinkMethod($this->createRedisKey($limiterStateId));
114    }
115
116    /**
117     * Create a Redis key from a Limiter state ID
118     *
119     * @param string $id Limiter state ID
120     *
121     * @return string
122     */
123    protected function createRedisKey(string $id): string
124    {
125        $id = sha1($id);
126        return $this->namespace ? "$this->namespace/$id" : $id;
127    }
128}