From 38d32c23a70ec3db6b55db77b091dcaa99c338d3 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 20 Mar 2019 09:43:03 -0400 Subject: [PATCH] Removing deprecated call to Configuration::setFilterSchemaAssetsExpression() ... and making the schema filter stuff a "plugin" system, which is the intention of the new way it's handled in doctrine/dbal --- Dbal/RegexSchemaAssetFilter.php | 25 ++++++ Dbal/SchemaAssetsFilterManager.php | 30 ++++++++ .../Compiler/DbalSchemaFilterPass.php | 55 ++++++++++++++ DependencyInjection/DoctrineExtension.php | 12 ++- Resources/config/dbal.xml | 4 + Tests/Dbal/RegexSchemaAssetFilterTest.php | 17 +++++ Tests/Dbal/SchemaAssetsFilterManagerTest.php | 23 ++++++ .../AbstractDoctrineExtensionTest.php | 76 ++++++++++++++++++- .../config/xml/dbal_schema_filter.xml | 6 +- .../config/yml/dbal_schema_filter.yml | 7 +- 10 files changed, 250 insertions(+), 5 deletions(-) create mode 100644 Dbal/RegexSchemaAssetFilter.php create mode 100644 Dbal/SchemaAssetsFilterManager.php create mode 100644 DependencyInjection/Compiler/DbalSchemaFilterPass.php create mode 100644 Tests/Dbal/RegexSchemaAssetFilterTest.php create mode 100644 Tests/Dbal/SchemaAssetsFilterManagerTest.php diff --git a/Dbal/RegexSchemaAssetFilter.php b/Dbal/RegexSchemaAssetFilter.php new file mode 100644 index 000000000..08ab7d233 --- /dev/null +++ b/Dbal/RegexSchemaAssetFilter.php @@ -0,0 +1,25 @@ +filterExpression = $filterExpression; + } + + public function __invoke($assetName): bool + { + if ($assetName instanceof AbstractAsset) { + $assetName = $assetName->getName(); + } + + return preg_match($this->filterExpression, $assetName); + } +} diff --git a/Dbal/SchemaAssetsFilterManager.php b/Dbal/SchemaAssetsFilterManager.php new file mode 100644 index 000000000..b20782dfd --- /dev/null +++ b/Dbal/SchemaAssetsFilterManager.php @@ -0,0 +1,30 @@ +schemaAssetFilters = $schemaAssetFilters; + } + + public function __invoke($assetName): bool + { + foreach ($this->schemaAssetFilters as $schemaAssetFilter) { + if (false === $schemaAssetFilter($assetName)) { + return false; + } + } + + return true; + } +} diff --git a/DependencyInjection/Compiler/DbalSchemaFilterPass.php b/DependencyInjection/Compiler/DbalSchemaFilterPass.php new file mode 100644 index 000000000..97e8980a9 --- /dev/null +++ b/DependencyInjection/Compiler/DbalSchemaFilterPass.php @@ -0,0 +1,55 @@ +findTaggedServiceIds('doctrine.dbal.schema_filter'); + + if (count($filters) > 0 && !method_exists(\Doctrine\DBAL\Configuration::class, 'setSchemaAssetsFilter')) { + throw new \LogicException('The doctrine.dbal.schema_filter tag is only supported when using doctrine/dbal 2.9 or higher.'); + } + + $connectionFilters = []; + foreach ($filters as $id => $tagAttributes) { + foreach ($tagAttributes as $attributes) { + $name = isset($attributes['connection']) ? $attributes['connection'] : $container->getParameter('doctrine.default_connection'); + + if (!isset($connectionFilters[$name])) { + $connectionFilters[$name] = []; + } + + $connectionFilters[$name][] = new Reference($id); + } + } + + foreach ($connectionFilters as $name => $references) { + $configurationId = sprintf('doctrine.dbal.%s_connection.configuration', $name); + + if (!$container->hasDefinition($configurationId)) { + continue; + } + + $definition = new ChildDefinition('doctrine.dbal.schema_asset_filter_manager'); + $definition->setArgument(0, $references); + + $id = sprintf('doctrine.dbal.%s_schema_asset_filter_manager', $name); + $container->setDefinition($id, $definition); + $container->findDefinition($configurationId) + ->addMethodCall('setSchemaAssetsFilter', [new Reference($id)]); + } + } +} diff --git a/DependencyInjection/DoctrineExtension.php b/DependencyInjection/DoctrineExtension.php index 8c54f7bef..20371c8e4 100644 --- a/DependencyInjection/DoctrineExtension.php +++ b/DependencyInjection/DoctrineExtension.php @@ -2,6 +2,7 @@ namespace Doctrine\Bundle\DoctrineBundle\DependencyInjection; +use Doctrine\Bundle\DoctrineBundle\Dbal\RegexSchemaAssetFilter; use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\ServiceRepositoryCompilerPass; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryInterface; use Doctrine\Bundle\DoctrineCacheBundle\DependencyInjection\CacheProviderLoader; @@ -150,7 +151,16 @@ protected function loadDbalConnection($name, array $connection, ContainerBuilder unset($connection['auto_commit']); if (isset($connection['schema_filter']) && $connection['schema_filter']) { - $configuration->addMethodCall('setFilterSchemaAssetsExpression', [$connection['schema_filter']]); + if (method_exists(\Doctrine\DBAL\Configuration::class, 'setSchemaAssetsFilter')) { + $definition = new Definition(RegexSchemaAssetFilter::class, [ + $connection['schema_filter'] + ]); + $definition->addTag('doctrine.dbal.schema_filter', ['connection' => $name]); + $container->setDefinition(sprintf('doctrine.dbal.%s_regex_schema_filter', $name), $definition); + } else { + // backwards compatibility with dbal < 2.9 + $configuration->addMethodCall('setFilterSchemaAssetsExpression', [$connection['schema_filter']]); + } } unset($connection['schema_filter']); diff --git a/Resources/config/dbal.xml b/Resources/config/dbal.xml index a94e91755..d0f2a868b 100644 --- a/Resources/config/dbal.xml +++ b/Resources/config/dbal.xml @@ -70,6 +70,10 @@ + + + + diff --git a/Tests/Dbal/RegexSchemaAssetFilterTest.php b/Tests/Dbal/RegexSchemaAssetFilterTest.php new file mode 100644 index 000000000..14c77fa5c --- /dev/null +++ b/Tests/Dbal/RegexSchemaAssetFilterTest.php @@ -0,0 +1,17 @@ +assertTrue($filter('do_not_t_ignore_me')); + $this->assertFalse($filter('t_ignore_me')); + } +} \ No newline at end of file diff --git a/Tests/Dbal/SchemaAssetsFilterManagerTest.php b/Tests/Dbal/SchemaAssetsFilterManagerTest.php new file mode 100644 index 000000000..0c0609583 --- /dev/null +++ b/Tests/Dbal/SchemaAssetsFilterManagerTest.php @@ -0,0 +1,23 @@ +assertSame( + ['do_not_filter'], + array_values(array_filter($tables, $manager)) + ); + } +} \ No newline at end of file diff --git a/Tests/DependencyInjection/AbstractDoctrineExtensionTest.php b/Tests/DependencyInjection/AbstractDoctrineExtensionTest.php index dae83e586..89c72f693 100644 --- a/Tests/DependencyInjection/AbstractDoctrineExtensionTest.php +++ b/Tests/DependencyInjection/AbstractDoctrineExtensionTest.php @@ -2,8 +2,11 @@ namespace Doctrine\Bundle\DoctrineBundle\Tests\DependencyInjection; +use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DbalSchemaFilterPass; use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\EntityListenerPass; use Doctrine\Bundle\DoctrineBundle\DependencyInjection\DoctrineExtension; +use Doctrine\DBAL\Configuration; +use Doctrine\DBAL\Schema\AbstractAsset; use Doctrine\ORM\EntityManager; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\DependencyInjection\CompilerPass\RegisterEventListenersAndSubscribersPass; @@ -761,10 +764,60 @@ public function testDbalOracleInstancename() public function testDbalSchemaFilter() { + if (method_exists(\Doctrine\DBAL\Configuration::class, 'setSchemaAssetsFilter')) { + $this->markTestSkipped('Test only applies to doctrine/dbal 2.8 or lower'); + } + $container = $this->loadContainer('dbal_schema_filter'); - $definition = $container->getDefinition('doctrine.dbal.default_connection.configuration'); - $this->assertDICDefinitionMethodCallOnce($definition, 'setFilterSchemaAssetsExpression', ['^sf2_']); + $definition = $container->getDefinition('doctrine.dbal.connection1_connection.configuration'); + $this->assertDICDefinitionMethodCallOnce($definition, 'setFilterSchemaAssetsExpression', ['~^(?!t_)~']); + } + + public function testDbalSchemaFilterNewConfig() + { + if (!method_exists(\Doctrine\DBAL\Configuration::class, 'setSchemaAssetsFilter')) { + $this->markTestSkipped('Test requires doctrine/dbal 2.9 or higher'); + } + + $container = $this->getContainer([]); + $loader = new DoctrineExtension(); + $container->registerExtension($loader); + $container->addCompilerPass(new DbalSchemaFilterPass()); + + // ignore table1 table on "default" connection + $container->register('dummy_filter1', DummySchemaAssetsFilter::class) + ->setArguments(['table1']) + ->addTag('doctrine.dbal.schema_filter'); + + // ignore table2 table on "connection2" connection + $container->register('dummy_filter2', DummySchemaAssetsFilter::class) + ->setArguments(['table2']) + ->addTag('doctrine.dbal.schema_filter', ['connection' => 'connection2']); + + $this->loadFromFile($container, 'dbal_schema_filter'); + + $assetNames = ['table1', 'table2', 'table3', 't_ignored']; + $expectedConnectionAssets = [ + // ignores table1 + schema_filter applies + 'connection1' => ['table2', 'table3'], + // ignores table2, no schema_filter applies + 'connection2' => ['table1', 'table3', 't_ignored'], + // connection3 has no ignores, handled separately + ]; + + $this->compileContainer($container); + + $getConfiguration = function(string $connectionName) use ($container): Configuration { + return $container->get(sprintf('doctrine.dbal.%s_connection', $connectionName))->getConfiguration(); + }; + + foreach ($expectedConnectionAssets as $connectionName => $expectedTables) { + $connConfig = $getConfiguration($connectionName); + $this->assertSame($expectedTables, array_values(array_filter($assetNames, $connConfig->getSchemaAssetsFilter())), sprintf('Filtering for connection "%s"', $connectionName)); + } + + $this->assertNull($connConfig = $getConfiguration('connection3')->getSchemaAssetsFilter()); } public function testEntityListenerResolver() @@ -1048,3 +1101,22 @@ private function compileContainer(ContainerBuilder $container) $container->compile(); } } + +class DummySchemaAssetsFilter +{ + private $tableToIgnore; + + public function __construct(string $tableToIgnore) + { + $this->tableToIgnore = $tableToIgnore; + } + + public function __invoke($assetName): bool + { + if ($assetName instanceof AbstractAsset) { + $assetName = $assetName->getName(); + } + + return $assetName !== $this->tableToIgnore; + } +} diff --git a/Tests/DependencyInjection/Fixtures/config/xml/dbal_schema_filter.xml b/Tests/DependencyInjection/Fixtures/config/xml/dbal_schema_filter.xml index 2a897bb84..55f433269 100644 --- a/Tests/DependencyInjection/Fixtures/config/xml/dbal_schema_filter.xml +++ b/Tests/DependencyInjection/Fixtures/config/xml/dbal_schema_filter.xml @@ -7,6 +7,10 @@ http://symfony.com/schema/dic/doctrine http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd"> - + + + + + diff --git a/Tests/DependencyInjection/Fixtures/config/yml/dbal_schema_filter.yml b/Tests/DependencyInjection/Fixtures/config/yml/dbal_schema_filter.yml index 8a94d8092..c557507a1 100644 --- a/Tests/DependencyInjection/Fixtures/config/yml/dbal_schema_filter.yml +++ b/Tests/DependencyInjection/Fixtures/config/yml/dbal_schema_filter.yml @@ -1,3 +1,8 @@ doctrine: dbal: - schema_filter: ^sf2_ + default_connection: connection1 + connections: + connection1: + schema_filter: ~^(?!t_)~ + connection2: [] + connection3: []