Passed
Push — v9 ( 555fde...51468f )
by Georges
01:56
created

ClusterPoolAbstract   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 227
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 83
dl 0
loc 227
rs 10
c 1
b 0
f 0
wmc 22

11 Methods

Rating   Name   Duplication   Size   Complexity  
A deleteItems() 0 10 3
A remapCacheItem() 0 12 2
A getItems() 0 9 2
A getStandardizedItem() 0 23 3
A getStats() 0 37 1
A getIO() 0 9 2
A saveDeferred() 0 12 3
A getConfig() 0 3 1
A __construct() 0 8 2
A getConfigs() 0 9 2
A getClusterPools() 0 3 1
1
<?php
2
3
/**
4
 *
5
 * This file is part of phpFastCache.
6
 *
7
 * @license MIT License (MIT)
8
 *
9
 * For full copyright and license information, please see the docs/CREDITS.txt file.
10
 *
11
 * @author  Georges.L (Geolim4)  <[email protected]>
12
 *
13
 */
14
declare(strict_types=1);
15
16
namespace Phpfastcache\Cluster;
17
18
use Phpfastcache\Cluster\Drivers\FullReplication\Driver as FullReplicationCluster;
19
use Phpfastcache\Cluster\Drivers\MasterSlaveReplication\Driver as MasterSlaveReplicationCluster;
20
use Phpfastcache\Cluster\Drivers\RandomReplication\Driver as RandomReplicationCluster;
21
use Phpfastcache\Cluster\Drivers\SemiReplication\Driver as SemiReplicationCluster;
22
use Phpfastcache\Config\ConfigurationOption;
23
use Phpfastcache\Core\Item\ExtendedCacheItemInterface;
24
use Phpfastcache\Core\Pool\ExtendedCacheItemPoolInterface;
25
use Phpfastcache\Core\Pool\TaggableCacheItemPoolTrait;
26
use Phpfastcache\Entities\DriverIO;
27
use Phpfastcache\Entities\DriverStatistic;
28
use Phpfastcache\EventManager;
29
use Phpfastcache\Exceptions\PhpfastcacheCoreException;
30
use Phpfastcache\Exceptions\PhpfastcacheDriverCheckException;
31
use Phpfastcache\Exceptions\PhpfastcacheDriverConnectException;
32
use Phpfastcache\Exceptions\PhpfastcacheDriverException;
33
use Phpfastcache\Exceptions\PhpfastcacheInvalidArgumentException;
34
use Phpfastcache\Exceptions\PhpfastcacheIOException;
35
use Phpfastcache\Exceptions\PhpfastcacheLogicException;
36
use Psr\Cache\CacheItemInterface;
37
use Psr\Cache\InvalidArgumentException;
38
39
/**
40
 * @property ConfigurationOption $config
41
 */
42
abstract class ClusterPoolAbstract implements ClusterPoolInterface
43
{
44
    use TaggableCacheItemPoolTrait;
45
    use ClusterPoolTrait {
46
        TaggableCacheItemPoolTrait::__construct as private __parentConstruct;
47
    }
48
49
    public const STRATEGY = [
50
        AggregatorInterface::STRATEGY_FULL_REPLICATION => FullReplicationCluster::class,
51
        AggregatorInterface::STRATEGY_SEMI_REPLICATION => SemiReplicationCluster::class,
52
        AggregatorInterface::STRATEGY_MASTER_SLAVE => MasterSlaveReplicationCluster::class,
53
        AggregatorInterface::STRATEGY_RANDOM_REPLICATION => RandomReplicationCluster::class,
54
    ];
55
56
    /**
57
     * @var ExtendedCacheItemPoolInterface[]
58
     */
59
    protected array $clusterPools;
60
61
    /**
62
     * ClusterPoolAbstract constructor.
63
     * @param string $clusterName
64
     * @param ExtendedCacheItemPoolInterface ...$driverPools
65
     * @throws PhpfastcacheDriverCheckException
66
     * @throws PhpfastcacheDriverConnectException
67
     * @throws PhpfastcacheInvalidArgumentException
68
     * @throws PhpfastcacheCoreException
69
     * @throws PhpfastcacheDriverException
70
     * @throws PhpfastcacheIOException
71
     */
72
    public function __construct(string $clusterName, ExtendedCacheItemPoolInterface ...$driverPools)
73
    {
74
        if (count($driverPools) < 2) {
75
            throw new PhpfastcacheInvalidArgumentException('A cluster requires at least two pools to be working.');
76
        }
77
        $this->clusterPools = $driverPools;
78
        $this->__parentConstruct(new ConfigurationOption(), $clusterName);
79
        $this->setEventManager(EventManager::getInstance());
80
    }
81
82
    /**
83
     * @inheritDoc
84
     */
85
    public function getIO(): DriverIO
86
    {
87
        $io = new DriverIO();
88
        foreach ($this->clusterPools as $clusterPool) {
89
            $io->setReadHit($io->getReadHit() + $clusterPool->getIO()->getReadHit())
90
                ->setReadMiss($io->getReadMiss() + $clusterPool->getIO()->getReadMiss())
91
                ->setWriteHit($io->getWriteHit() + $clusterPool->getIO()->getWriteHit());
92
        }
93
        return $io;
94
    }
95
96
    /**
97
     * @inheritDoc
98
     */
99
    public function getClusterPools(): array
100
    {
101
        return $this->clusterPools;
102
    }
103
104
    /**
105
     * @inheritDoc
106
     */
107
    public function getConfigs() : array
108
    {
109
        $configs = [];
110
111
        foreach ($this->getClusterPools() as $clusterPool) {
112
            $configs[$clusterPool->getDriverName()] = $clusterPool->getConfig();
113
        }
114
115
        return $configs;
116
    }
117
118
    /**
119
     * @inheritDoc
120
     */
121
    public function getItems(array $keys = []): iterable
122
    {
123
        $items = [];
124
125
        foreach ($keys as $key) {
126
            $items[$key] = $this->getItem($key);
127
        }
128
129
        return $items;
130
    }
131
    /**
132
     * Shared method used by All Clusters
133
     */
134
135
    /**
136
     * @inheritDoc
137
     */
138
    public function deleteItems(array $keys): bool
139
    {
140
        $hasDeletedOnce = false;
141
        foreach ($this->clusterPools as $driverPool) {
142
            if ($result = $driverPool->deleteItems($keys)) {
143
                $hasDeletedOnce = $result;
144
            }
145
        }
146
        // Return true only if at least one backend confirmed the "clear" operation
147
        return $hasDeletedOnce;
148
    }
149
150
    /**
151
     * @param CacheItemInterface $item
152
     * @return bool
153
     * @throws InvalidArgumentException
154
     * @throws PhpfastcacheLogicException
155
     */
156
    public function saveDeferred(CacheItemInterface $item): bool
157
    {
158
        /** @var ExtendedCacheItemInterface $item */
159
        $hasSavedOnce = false;
160
        foreach ($this->clusterPools as $driverPool) {
161
            $poolItem = $this->getStandardizedItem($item, $driverPool);
162
            if ($result = $driverPool->saveDeferred($poolItem)) {
163
                $hasSavedOnce = $result;
164
            }
165
        }
166
        // Return true only if at least one backend confirmed the "commit" operation
167
        return $hasSavedOnce;
168
    }
169
170
    /**
171
     * @param ExtendedCacheItemInterface $item
172
     * @param ExtendedCacheItemPoolInterface $driverPool
173
     * @return ExtendedCacheItemInterface
174
     * @throws InvalidArgumentException
175
     * @throws PhpfastcacheLogicException
176
     */
177
    protected function getStandardizedItem(ExtendedCacheItemInterface $item, ExtendedCacheItemPoolInterface $driverPool): ExtendedCacheItemInterface
178
    {
179
        if (!$item->doesItemBelongToThatDriverBackend($driverPool)) {
180
            /**
181
             * Avoid infinite loop
182
             */
183
            if ($driverPool === $this) {
0 ignored issues
show
introduced by
The condition $driverPool === $this is always false.
Loading history...
184
                /** @var ExtendedCacheItemInterface $itemPool */
185
                $itemClass = $driverPool->getItemClass();
186
                $itemPool = new $itemClass($this, $item->getKey());
187
188
                $this->remapCacheItem($item, $itemPool, $driverPool);
189
190
                return $itemPool;
191
            }
192
193
            $itemPool = $driverPool->getItem($item->getKey());
194
            $this->remapCacheItem($item, $itemPool, $driverPool);
195
196
            return $itemPool;
197
        }
198
199
        return $item->setEventManager($this->getEventManager());
200
    }
201
202
    /**
203
     * @param ExtendedCacheItemInterface $itemSource
204
     * @param ExtendedCacheItemInterface $itemTarget
205
     * @param ExtendedCacheItemPoolInterface $driverPool
206
     * @throws PhpfastcacheInvalidArgumentException
207
     * @throws PhpfastcacheLogicException
208
     */
209
    protected function remapCacheItem(ExtendedCacheItemInterface $itemSource, ExtendedCacheItemInterface $itemTarget, ExtendedCacheItemPoolInterface $driverPool): void
210
    {
211
        $itemTarget->setEventManager($this->getEventManager())
212
            ->set($itemSource->get())
213
            ->setHit($itemSource->isHit())
214
            ->setTags($itemSource->getTags())
215
            ->expiresAt($itemSource->getExpirationDate())
216
            ->setDriver($driverPool);
217
218
        if ($driverPool->getConfig()->isItemDetailedDate()) {
219
            $itemTarget->setCreationDate($itemSource->getCreationDate())
220
                ->setModificationDate($itemSource->getModificationDate());
221
        }
222
    }
223
224
    /**
225
     * @return DriverStatistic
226
     */
227
    public function getStats(): DriverStatistic
228
    {
229
        $stats = new DriverStatistic();
230
        $stats->setInfo(
231
            sprintf(
232
                'Using %d pool(s): %s',
233
                \count($this->clusterPools),
234
                \implode(
235
                    ', ',
236
                    \array_map(
237
                        static fn (ExtendedCacheItemPoolInterface $pool) => \get_class($pool),
238
                        $this->clusterPools
239
                    )
240
                )
241
            )
242
        );
243
244
        $stats->setSize(
245
            (int)\array_sum(
246
                \array_map(
247
                    static fn (ExtendedCacheItemPoolInterface $pool) => $pool->getStats()->getSize(),
248
                    $this->clusterPools
249
                )
250
            )
251
        );
252
253
        $stats->setData(
254
            \implode(
255
                ', ',
256
                \array_map(
257
                    static fn (ExtendedCacheItemPoolInterface $pool) => $pool->getStats()->getData(),
258
                    $this->clusterPools
259
                )
260
            )
261
        );
262
263
        return $stats;
264
    }
265
266
    public function getConfig() : ConfigurationOption
267
    {
268
        return $this->config;
269
    }
270
}
271