From f5c3fa30872025f128930364ce1a1ef0b36eb6f5 Mon Sep 17 00:00:00 2001 From: Alexander Dmitryuk Date: Mon, 14 Nov 2022 15:47:03 +0600 Subject: [PATCH] Add Doctrine DHMiddleware by default (#331) --- ...trineProviderConfigurationCompilerPass.php | 43 +++++++ tests/App/Command/CreatePostCommand.php | 9 +- tests/App/config/packages/sf6/framework.yaml | 1 + .../DoctrineMiddlewareCompilerPassTest.php | 110 ++++++++++++++++++ 4 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 tests/DependencyInjection/Compiler/DoctrineMiddlewareCompilerPassTest.php diff --git a/src/DependencyInjection/Compiler/DoctrineProviderConfigurationCompilerPass.php b/src/DependencyInjection/Compiler/DoctrineProviderConfigurationCompilerPass.php index 086ef882..855674e8 100644 --- a/src/DependencyInjection/Compiler/DoctrineProviderConfigurationCompilerPass.php +++ b/src/DependencyInjection/Compiler/DoctrineProviderConfigurationCompilerPass.php @@ -5,16 +5,22 @@ namespace DH\AuditorBundle\DependencyInjection\Compiler; use DH\Auditor\Provider\Doctrine\Auditing\Annotation\AnnotationLoader; +use DH\Auditor\Provider\Doctrine\Auditing\Logger\Middleware\DHMiddleware; use DH\Auditor\Provider\Doctrine\DoctrineProvider; use DH\Auditor\Provider\Doctrine\Service\AuditingService; use DH\Auditor\Provider\Doctrine\Service\StorageService; +use Doctrine\DBAL\Driver\Middleware; +use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; +/** @see \DH\AuditorBundle\Tests\DependencyInjection\Compiler\DoctrineMiddlewareCompilerPassTest */ class DoctrineProviderConfigurationCompilerPass implements CompilerPassInterface { + private bool $isDHMiddlewareSupported = false; + public function process(ContainerBuilder $container): void { if (!$container->hasDefinition(DoctrineProvider::class)) { @@ -46,6 +52,9 @@ public function process(ContainerBuilder $container): void } \assert(\is_array($config) && \array_key_exists('auditing_services', $config)); + + $this->registerDHMiddleware($container); + foreach (array_unique($config['auditing_services']) as $entityManagerName) { $entityManagerName = str_replace('@', '', $entityManagerName); $entityManagerReference = new Reference($entityManagerName); @@ -62,6 +71,40 @@ public function process(ContainerBuilder $container): void $container->setDefinition(AnnotationLoader::class, $annotationLoaderDefinition); $providerDefinition->addMethodCall('registerAuditingService', [$serviceReference]); + $this->configureDHMiddleware($container, $entityManagerName); + } + } + + private function registerDHMiddleware(ContainerBuilder $container): void + { + if (interface_exists(Middleware::class) && class_exists(DHMiddleware::class)) { + $this->isDHMiddlewareSupported = true; + $container->register('doctrine.dbal.dh_middleware', DHMiddleware::class); + } + } + + private function configureDHMiddleware(ContainerBuilder $container, string $entityManagerName): void + { + if (false === $this->isDHMiddlewareSupported) { + return; + } + + $argument = $container->getDefinition($entityManagerName)->getArgument(0); + if (!$argument instanceof Reference) { + return; + } + $connectionName = (string) $argument; + + /** @see vendor/doctrine/doctrine-bundle/DependencyInjection/DoctrineExtension.php */ + $configurationName = $connectionName.'.configuration'; + if (!$container->hasDefinition($configurationName)) { + return; } + $configuration = $container->getDefinition($configurationName); + $DHMiddlewareDef = $container->setDefinition( + $connectionName.'.dh_middleware', + new ChildDefinition('doctrine.dbal.dh_middleware') + ); + $configuration->addMethodCall('setMiddlewares', [[$DHMiddlewareDef]]); } } diff --git a/tests/App/Command/CreatePostCommand.php b/tests/App/Command/CreatePostCommand.php index 70144a09..aee89d56 100644 --- a/tests/App/Command/CreatePostCommand.php +++ b/tests/App/Command/CreatePostCommand.php @@ -15,15 +15,20 @@ class CreatePostCommand extends Command { - protected static $defaultName = 'app:post:create'; private DoctrineProvider $doctrineProvider; public function __construct(DoctrineProvider $doctrineProvider) { - parent::__construct(self::$defaultName); + parent::__construct(); $this->doctrineProvider = $doctrineProvider; } + protected function configure(): void + { + $this->setName('app:post:create'); + parent::configure(); + } + protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); diff --git a/tests/App/config/packages/sf6/framework.yaml b/tests/App/config/packages/sf6/framework.yaml index 5f908f76..6d906914 100644 --- a/tests/App/config/packages/sf6/framework.yaml +++ b/tests/App/config/packages/sf6/framework.yaml @@ -1,6 +1,7 @@ framework: secret: '%env(APP_SECRET)%' test: true + http_method_override: false router: utf8: true session: diff --git a/tests/DependencyInjection/Compiler/DoctrineMiddlewareCompilerPassTest.php b/tests/DependencyInjection/Compiler/DoctrineMiddlewareCompilerPassTest.php new file mode 100644 index 00000000..2694a9d8 --- /dev/null +++ b/tests/DependencyInjection/Compiler/DoctrineMiddlewareCompilerPassTest.php @@ -0,0 +1,110 @@ +container->setParameter('kernel.cache_dir', sys_get_temp_dir()); + $this->container->setParameter('kernel.debug', false); + $this->container->setParameter('kernel.bundles', []); + $doctrineConfig = [ + 'dbal' => [ + 'default_connection' => 'default', + 'connections' => [ + 'default' => [], + ], + ], + 'orm' => [ + 'auto_mapping' => true, + ], + ]; + $this->setParameter('doctrine', $doctrineConfig); + + $DHConfig = [ + 'enabled' => true, + 'timezone' => 'UTC', + 'user_provider' => 'dh_auditor.user_provider', + 'security_provider' => 'dh_auditor.security_provider', + 'role_checker' => 'dh_auditor.role_checker', + 'providers' => [ + 'doctrine' => [ + 'table_prefix' => '', + 'table_suffix' => '_audit', + 'ignored_columns' => [ + 0 => 'createdAt', + 1 => 'updatedAt', + ], + 'entities' => [ + Author::class => [ + 'enabled' => true, + ], + Post::class => [ + 'enabled' => true, + ], + Comment::class => [ + 'enabled' => true, + ], + Tag::class => [ + 'enabled' => true, + ], + ], + 'storage_services' => [ + 0 => '@doctrine.orm.default_entity_manager', + ], + 'auditing_services' => [ + 0 => '@doctrine.orm.default_entity_manager', + ], + 'viewer' => true, + 'storage_mapper' => null, + ], + ], + ]; + $this->setParameter('dh_auditor.configuration', $DHConfig); + + $auditorService = new Definition(); + $this->setDefinition(Configuration::class, $auditorService); + $this->container->loadFromExtension('doctrine', $doctrineConfig); + $this->container->loadFromExtension('dh_auditor', $DHConfig); + $this->compile(); + + $this->assertContainerBuilderHasServiceDefinitionWithMethodCall( + 'doctrine.dbal.default_connection.configuration', + 'setMiddlewares', + [[new ChildDefinition('doctrine.dbal.dh_middleware')]] + ); + } + + protected function registerCompilerPass(ContainerBuilder $container): void + { + $this->container->registerExtension(new DoctrineExtension()); + $this->container->registerExtension(new DHAuditorExtension()); + $container->addCompilerPass(new DoctrineProviderConfigurationCompilerPass()); + } +}