diff --git a/README.md b/README.md index 07535c9..1f3b66e 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,12 @@ Rule is based on [regular expression](https://en.wikipedia.org/wiki/Regular_expr #### Negated RegEx Based on the RegEx strategy, but negates the result. Helpful if only a few pages should be restricted. +### Add custom strategy + +The strategy configuration is meant to be extensible. You can create an own strategy by creating a new class that +implements the `\BitExpert\SyliusForceCustomerLoginPlugin\Model\StrategyInterface` interface and is tagged with +`force_customer_login.url_strategy` in your service configuration. + ## Tests You can run the unit tests with the following command (requires dependency installation): diff --git a/src/BitExpertSyliusForceCustomerLoginPlugin.php b/src/BitExpertSyliusForceCustomerLoginPlugin.php index a9f5026..06a8b85 100644 --- a/src/BitExpertSyliusForceCustomerLoginPlugin.php +++ b/src/BitExpertSyliusForceCustomerLoginPlugin.php @@ -12,9 +12,12 @@ namespace BitExpert\SyliusForceCustomerLoginPlugin; +use BitExpert\SyliusForceCustomerLoginPlugin\DependencyInjection\Compiler\RegisterDoctrineMiddlewareCompilerPass; +use BitExpert\SyliusForceCustomerLoginPlugin\DependencyInjection\Compiler\RegisterDoctrineTypeCompilerPass; use Sylius\Bundle\CoreBundle\Application\SyliusPluginTrait; use Sylius\Bundle\ResourceBundle\AbstractResourceBundle; use Sylius\Bundle\ResourceBundle\SyliusResourceBundle; +use Symfony\Component\DependencyInjection\ContainerBuilder; final class BitExpertSyliusForceCustomerLoginPlugin extends AbstractResourceBundle { @@ -26,4 +29,12 @@ public function getSupportedDrivers(): array SyliusResourceBundle::DRIVER_DOCTRINE_ORM, ]; } + + public function build(ContainerBuilder $container): void + { + parent::build($container); + + $container->addCompilerPass(new RegisterDoctrineTypeCompilerPass()); + $container->addCompilerPass(new RegisterDoctrineMiddlewareCompilerPass()); + } } diff --git a/src/DependencyInjection/Compiler/RegisterDoctrineMiddlewareCompilerPass.php b/src/DependencyInjection/Compiler/RegisterDoctrineMiddlewareCompilerPass.php new file mode 100644 index 0000000..aee4556 --- /dev/null +++ b/src/DependencyInjection/Compiler/RegisterDoctrineMiddlewareCompilerPass.php @@ -0,0 +1,51 @@ +getDefinition('doctrine.dbal.default_connection.configuration'); + + $middlewareMethodCallArgs = $this->extractMethodCallArgs($configDefinition); + $middlewareMethodCallArgs[0] = array_merge( + $middlewareMethodCallArgs[0] ?? [], + [new Reference('bitexpert.sylius_force_customer_login_plugin.doctrine.middleware')], + ); + + $configDefinition + ->removeMethodCall('setMiddlewares') + ->addMethodCall('setMiddlewares', $middlewareMethodCallArgs); + } + + /** @return Reference[] */ + private function extractMethodCallArgs(Definition $definition): array + { + foreach ($definition->getMethodCalls() as $methodCall) { + if ('setMiddlewares' === $methodCall[0]) { + return $methodCall[1]; + } + } + + return []; + } +} diff --git a/src/DependencyInjection/Compiler/RegisterDoctrineTypeCompilerPass.php b/src/DependencyInjection/Compiler/RegisterDoctrineTypeCompilerPass.php new file mode 100644 index 0000000..1355586 --- /dev/null +++ b/src/DependencyInjection/Compiler/RegisterDoctrineTypeCompilerPass.php @@ -0,0 +1,39 @@ +hasParameter(self::CONTAINER_TYPES_PARAMETER)) { + return; + } + + $typeDefinition = $container->getParameter(self::CONTAINER_TYPES_PARAMETER); + if (!isset($typeDefinition[Strategy::NAME])) { + $typeDefinition[Strategy::NAME] = ['class' => Strategy::class]; + } + + $container->setParameter(self::CONTAINER_TYPES_PARAMETER, $typeDefinition); + } +} diff --git a/src/Doctrine/DBAL/Types/Strategy.php b/src/Doctrine/DBAL/Types/Strategy.php new file mode 100644 index 0000000..56db439 --- /dev/null +++ b/src/Doctrine/DBAL/Types/Strategy.php @@ -0,0 +1,65 @@ +strategies = $strategies; + } + + public function getSQLDeclaration(array $column, AbstractPlatform $platform) + { + return $platform->getStringTypeDeclarationSQL($column); + } + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if (!is_string($value)) { + return parent::convertToPHPValue($value, $platform); + } + + if (isset($this->strategies[$value])) { + return $this->strategies[$value]; + } + + throw new \RuntimeException(sprintf('Unsupported strategy "%s"!', $value)); + } + + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + if (!($value instanceof StrategyInterface)) { + return parent::convertToDatabaseValue($value, $platform); + } + + return $value->getType(); + } +} diff --git a/src/Doctrine/StrategyTypeConfigurationMiddleware.php b/src/Doctrine/StrategyTypeConfigurationMiddleware.php new file mode 100644 index 0000000..59e1595 --- /dev/null +++ b/src/Doctrine/StrategyTypeConfigurationMiddleware.php @@ -0,0 +1,48 @@ +strategies as $strategy) { + /** @var StrategyInterface $strategy */ + $strategies[$strategy->getType()] = $strategy; + } + + try { + /** @var Strategy $type */ + $type = Type::getType(Strategy::NAME); + $type->setStrategies($strategies); + } catch (\Exception $e) { + } + + return $driver; + } +} diff --git a/src/Form/Type/WhitelistEntryType.php b/src/Form/Type/WhitelistEntryType.php index aea4e6a..90258bf 100644 --- a/src/Form/Type/WhitelistEntryType.php +++ b/src/Form/Type/WhitelistEntryType.php @@ -12,20 +12,35 @@ namespace BitExpert\SyliusForceCustomerLoginPlugin\Form\Type; -use BitExpert\SyliusForceCustomerLoginPlugin\Model\NegatedRegexMatcher; -use BitExpert\SyliusForceCustomerLoginPlugin\Model\RegexMatcher; -use BitExpert\SyliusForceCustomerLoginPlugin\Model\StaticMatcher; use BitExpert\SyliusForceCustomerLoginPlugin\Model\StrategyInterface; use Sylius\Bundle\ChannelBundle\Form\Type\ChannelChoiceType; use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType; +use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; class WhitelistEntryType extends AbstractResourceType { + /** + * @param RewindableGenerator $strategies + */ + public function __construct( + private readonly iterable $strategies, + string $dataClass, + array $validationGroups = [], + ) { + parent::__construct($dataClass, $validationGroups); + } + public function buildForm(FormBuilderInterface $builder, array $options): void { + $strategies = []; + foreach ($this->strategies as $strategy) { + /** @var StrategyInterface $strategy */ + $strategies[] = $strategy; + } + $builder ->add('channels', ChannelChoiceType::class, [ 'multiple' => true, @@ -41,11 +56,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'empty_data' => '', ]) ->add('strategy', ChoiceType::class, [ - 'choices' => [ - new StaticMatcher(), - new RegexMatcher(), - new NegatedRegexMatcher(), - ], + 'choices' => $strategies, 'choice_value' => 'name', 'choice_label' => function (?StrategyInterface $strategy): string { return is_object($strategy) ? $strategy->getName() : ''; diff --git a/src/Model/WhitelistEntry.php b/src/Model/WhitelistEntry.php index 86c5a31..84084b4 100644 --- a/src/Model/WhitelistEntry.php +++ b/src/Model/WhitelistEntry.php @@ -27,7 +27,7 @@ class WhitelistEntry implements WhitelistEntryInterface private string $urlRule; - private string $strategy; + private StrategyInterface $strategy; public function __construct() { @@ -85,27 +85,11 @@ public function setUrlRule(string $urlRule): void public function getStrategy(): StrategyInterface { - $staticMatcher = new StaticMatcher(); - $regexMatcher = new RegexMatcher(); - $negatedRegexMatcher = new NegatedRegexMatcher(); - - if ($this->strategy === $staticMatcher->getType()) { - return $staticMatcher; - } - - if ($this->strategy === $regexMatcher->getType()) { - return $regexMatcher; - } - - if ($this->strategy === $negatedRegexMatcher->getType()) { - return $negatedRegexMatcher; - } - - throw new \RuntimeException('Unsupported strategy!'); + return $this->strategy; } public function setStrategy(StrategyInterface $strategy): void { - $this->strategy = $strategy->getType(); + $this->strategy = $strategy; } } diff --git a/src/Resources/config/doctrine/model/WhitelistEntry.orm.xml b/src/Resources/config/doctrine/model/WhitelistEntry.orm.xml index ff1263b..bffbf3c 100644 --- a/src/Resources/config/doctrine/model/WhitelistEntry.orm.xml +++ b/src/Resources/config/doctrine/model/WhitelistEntry.orm.xml @@ -24,6 +24,6 @@ - + diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index a3a2347..0732ce7 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -1,10 +1,11 @@ - + + diff --git a/src/Resources/config/services/doctrine.xml b/src/Resources/config/services/doctrine.xml new file mode 100644 index 0000000..a79d3a6 --- /dev/null +++ b/src/Resources/config/services/doctrine.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/src/Resources/config/services/form.xml b/src/Resources/config/services/form.xml index 59aaa8e..0c30b48 100644 --- a/src/Resources/config/services/form.xml +++ b/src/Resources/config/services/form.xml @@ -5,6 +5,7 @@ + BitExpert\SyliusForceCustomerLoginPlugin\Model\WhitelistEntry diff --git a/src/Resources/config/services/strategies.xml b/src/Resources/config/services/strategies.xml new file mode 100644 index 0000000..7d25eb5 --- /dev/null +++ b/src/Resources/config/services/strategies.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + +