ixarlie/mutex-bundle

View on GitHub
src/LockExecutor.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php declare(strict_types=1);

namespace IXarlie\MutexBundle;

use IXarlie\MutexBundle\Exception\MutexException;
use IXarlie\MutexBundle\LockingStrategy\LockingStrategy;
use Symfony\Component\Lock\Exception\ExceptionInterface;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\LockInterface;

/**
 * Class LockExecutor.
 *
 * @author Carlos Dominguez <ixarlie@gmail.com>
 * @final
 */
class LockExecutor
{
    /**
     * @var LockFactory[]
     */
    private array $factories = [];

    /**
     * @var LockingStrategy[]
     */
    private array $strategies = [];

    public function addLockFactory(string $id, LockFactory $factory): void
    {
        $this->factories[$id] = $factory;
    }

    public function addLockStrategy(LockingStrategy $strategy): void
    {
        $name = $strategy->getName();
        if (array_key_exists($name, $this->strategies)) {
            throw new \RuntimeException('Cannot register the same strategy more than once.');
        }

        $this->strategies[$name] = $strategy;
    }

    /**
     * @throws MutexException
     */
    public function execute(MutexRequest $config): LockInterface
    {
        if (null === $config->name) {
            throw new \RuntimeException('Configuration must have a name.');
        }

        $factory = $this->factories[$config->service] ?? null;
        if (null === $factory) {
            throw new \RuntimeException(sprintf('Cannot find the "%s" service.', $config->service));
        }

        $strategy = $this->strategies[$config->strategy] ?? null;
        if (null === $strategy) {
            throw new \RuntimeException(sprintf('Cannot find the "%s" strategy.', $config->strategy));
        }

        try {
            $lock = $factory->createLock($config->name, $config->ttl);
            $strategy->execute($lock);
        } catch (ExceptionInterface $e) {
            throw new MutexException($config, $e);
        }

        return $lock;
    }
}