90 lines
3.0 KiB
PHP
90 lines
3.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* This file is part of the TYPO3 CMS project.
|
|
*
|
|
* It is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License, either version 2
|
|
* of the License, or any later version.
|
|
*
|
|
* For the full copyright and license information, please read the
|
|
* LICENSE.txt file that was distributed with this source code.
|
|
*
|
|
* The TYPO3 project - inspiring people to share!
|
|
*/
|
|
|
|
namespace TYPO3\CMS\Core\Locking;
|
|
|
|
use TYPO3\CMS\Core\Locking\Exception\LockCreateException;
|
|
use TYPO3\CMS\Core\SingletonInterface;
|
|
|
|
/**
|
|
* Factory class to retrieve a locking method
|
|
*/
|
|
class LockFactory implements SingletonInterface
|
|
{
|
|
/**
|
|
* @var array<class-string, bool>
|
|
*/
|
|
protected array $lockingStrategy = [
|
|
SemaphoreLockStrategy::class => true,
|
|
FileLockStrategy::class => true,
|
|
SimpleLockStrategy::class => true,
|
|
];
|
|
|
|
/**
|
|
* Add a locking method.
|
|
*
|
|
* @param class-string $className
|
|
*/
|
|
public function addLockingStrategy(string $className): void
|
|
{
|
|
$interfaces = class_implements($className);
|
|
if (isset($interfaces[LockingStrategyInterface::class])) {
|
|
$this->lockingStrategy[$className] = true;
|
|
} else {
|
|
throw new \InvalidArgumentException('The given class name ' . $className . ' does not implement the required LockingStrategyInterface interface.', 1425990198);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove a locking method.
|
|
*
|
|
* @param class-string $className
|
|
*/
|
|
public function removeLockingStrategy(string $className): void
|
|
{
|
|
unset($this->lockingStrategy[$className]);
|
|
}
|
|
|
|
/**
|
|
* Get best matching locking method
|
|
*
|
|
* @param string $id ID to identify this lock in the system
|
|
* @param int-mask-of<LockingStrategyInterface::LOCK_CAPABILITY_*> $capabilities LockingStrategyInterface::LOCK_CAPABILITY_* elements combined with bit-wise OR
|
|
* @return LockingStrategyInterface Class name for a locking method
|
|
* @throws LockCreateException if no locker could be created with the requested capabilities
|
|
*/
|
|
public function createLocker(string $id, int $capabilities = LockingStrategyInterface::LOCK_CAPABILITY_EXCLUSIVE): LockingStrategyInterface
|
|
{
|
|
$queue = new \SplPriorityQueue();
|
|
|
|
/** @var class-string<LockingStrategyInterface> $method */
|
|
foreach ($this->lockingStrategy as $method => $_) {
|
|
$supportedCapabilities = $capabilities & $method::getCapabilities();
|
|
if ($supportedCapabilities === $capabilities) {
|
|
$queue->insert($method, $method::getPriority());
|
|
}
|
|
}
|
|
if ($queue->count() > 0) {
|
|
$className = $queue->top();
|
|
// We use 'new' here on purpose!
|
|
// Locking might be used very early in the bootstrap process, where makeInstance() does not work
|
|
return new $className($id);
|
|
}
|
|
throw new LockCreateException('Could not find a matching locking method with requested capabilities.', 1425990190);
|
|
}
|
|
}
|