lib/Phpfastcache/Cluster/ClusterAggregator.php
<?php
/**
*
* This file is part of Phpfastcache.
*
* @license MIT License (MIT)
*
* For full copyright and license information, please see the docs/CREDITS.txt file.
*
* @author Georges.L (Geolim4) <contact@geolim4.com>
*
*/
declare(strict_types=1);
namespace Phpfastcache\Cluster;
use Exception;
use Phpfastcache\CacheManager;
use Phpfastcache\Config\ConfigurationOption;
use Phpfastcache\Event\Event;
use Phpfastcache\EventManager;
use Phpfastcache\Exceptions\PhpfastcacheDriverCheckException;
use Phpfastcache\Exceptions\PhpfastcacheDriverException;
use Phpfastcache\Exceptions\PhpfastcacheDriverNotFoundException;
use Phpfastcache\Exceptions\PhpfastcacheInvalidArgumentException;
use Phpfastcache\Exceptions\PhpfastcacheLogicException;
use stdClass;
class ClusterAggregator implements AggregatorInterface
{
/**
* @var array<string, AggregatablePoolInterface>
*/
protected array $driverPools;
protected ClusterPoolInterface $cluster;
protected string $clusterAggregatorName;
/**
* ClusterAggregator constructor.
* @param string $clusterAggregatorName
* @param array<AggregatablePoolInterface> $driverPools
* @throws PhpfastcacheLogicException
*/
public function __construct(string $clusterAggregatorName = '', AggregatablePoolInterface ...$driverPools)
{
$clusterAggregatorName = trim($clusterAggregatorName);
if (empty($clusterAggregatorName)) {
try {
$clusterAggregatorName = 'cluster_' . \bin2hex(\random_bytes(15));
} catch (Exception) {
$clusterAggregatorName = 'cluster_' . \str_shuffle(\spl_object_hash(new stdClass()));
}
}
$this->clusterAggregatorName = $clusterAggregatorName;
foreach ($driverPools as $driverPool) {
$this->aggregateDriver($driverPool);
}
}
/**
* @param AggregatablePoolInterface $driverPool
*
* @throws PhpfastcacheLogicException
*/
public function aggregateDriver(AggregatablePoolInterface $driverPool): void
{
if (isset($this->cluster)) {
throw new PhpfastcacheLogicException('The cluster has been already build, cannot aggregate more pools.');
}
$splHash = \spl_object_hash($driverPool);
if (!isset($this->driverPools[$splHash])) {
if ($driverPool instanceof ClusterPoolInterface) {
throw new PhpfastcacheLogicException('Recursive cluster aggregation is not allowed !');
}
$this->driverPools[$splHash] = $driverPool;
} else {
throw new PhpfastcacheLogicException('This pool has been already aggregated !');
}
}
/**
* @param string $driverName
* @param ConfigurationOption|null $driverConfig
* @throws PhpfastcacheDriverCheckException
* @throws PhpfastcacheDriverException
* @throws PhpfastcacheDriverNotFoundException
* @throws PhpfastcacheLogicException
*/
public function aggregateDriverByName(string $driverName, ConfigurationOption $driverConfig = null): void
{
if (isset($this->cluster)) {
throw new PhpfastcacheLogicException('The cluster has been already build, cannot aggregate more pools.');
}
$driverInstance = CacheManager::getInstance($driverName, $driverConfig);
if ($driverInstance instanceof AggregatablePoolInterface) {
$this->aggregateDriver($driverInstance);
}
throw new PhpfastcacheDriverException(
\sprintf(
'Driver "%s" does not implements "%s"',
$driverInstance::class,
AggregatablePoolInterface::class
)
);
}
/**
* @param AggregatablePoolInterface $driverPool
*
* @throws PhpfastcacheLogicException
*/
public function disaggregateDriver(AggregatablePoolInterface $driverPool): void
{
if (isset($this->cluster)) {
throw new PhpfastcacheLogicException('The cluster has been already build, cannot disaggregate pools.');
}
$splHash = \spl_object_hash($driverPool);
if (isset($this->driverPools[$splHash])) {
unset($this->driverPools[$splHash]);
} else {
throw new PhpfastcacheLogicException('This pool was not aggregated !');
}
}
/**
* @param int $strategy
*
* @return ClusterPoolInterface
* @throws PhpfastcacheInvalidArgumentException
*/
public function getCluster(int $strategy = AggregatorInterface::STRATEGY_FULL_REPLICATION): ClusterPoolInterface
{
if (isset(ClusterPoolAbstract::STRATEGY[$strategy])) {
if (!isset($this->cluster)) {
$clusterClass = ClusterPoolAbstract::STRATEGY[$strategy];
$this->cluster = new $clusterClass(
$this->getClusterAggregatorName(),
EventManager::getInstance(),
...\array_values($this->driverPools)
);
$this->cluster->getEventManager()->dispatch(Event::CACHE_CLUSTER_BUILT, $this, $this->cluster);
}
} else {
throw new PhpfastcacheInvalidArgumentException('Unknown cluster strategy');
}
return $this->cluster;
}
/**
* @return string
*/
public function getClusterAggregatorName(): string
{
return $this->clusterAggregatorName;
}
}