diff --git a/lib/Doctrine/DBAL/Configuration.php b/lib/Doctrine/DBAL/Configuration.php index c05a2c4bcfa..0e34e87dcea 100644 --- a/lib/Doctrine/DBAL/Configuration.php +++ b/lib/Doctrine/DBAL/Configuration.php @@ -4,6 +4,8 @@ use Doctrine\Common\Cache\Cache; use Doctrine\DBAL\Logging\SQLLogger; +use Doctrine\DBAL\Schema\AbstractAsset; +use function preg_match; /** * Configuration container for the Doctrine DBAL. @@ -75,6 +77,11 @@ public function setResultCacheImpl(Cache $cacheImpl) public function setFilterSchemaAssetsExpression($filterExpression) { $this->_attributes['filterSchemaAssetsExpression'] = $filterExpression; + if ($filterExpression) { + $this->_attributes['filterSchemaAssetsExpressionCallable'] = $this->buildSchemaAssetsFilterFromExpression($filterExpression); + } else { + $this->_attributes['filterSchemaAssetsExpressionCallable'] = null; + } } /** @@ -87,6 +94,36 @@ public function getFilterSchemaAssetsExpression() return $this->_attributes['filterSchemaAssetsExpression'] ?? null; } + /** + * @param string $filterExpression + */ + private function buildSchemaAssetsFilterFromExpression($filterExpression) : callable + { + return static function ($assetName) use ($filterExpression) { + if ($assetName instanceof AbstractAsset) { + $assetName = $assetName->getName(); + } + return preg_match($filterExpression, $assetName); + }; + } + + /** + * Sets the callable to use to filter schema assets. + */ + public function setSchemaAssetsFilter(?callable $callable = null) : ?callable + { + $this->_attributes['filterSchemaAssetsExpression'] = null; + return $this->_attributes['filterSchemaAssetsExpressionCallable'] = $callable; + } + + /** + * Returns the callable to use to filter schema assets. + */ + public function getSchemaAssetsFilter() : ?callable + { + return $this->_attributes['filterSchemaAssetsExpressionCallable'] ?? null; + } + /** * Sets the default auto-commit mode for connections. * diff --git a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php index cacb0acddd5..0858e6771f1 100644 --- a/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php +++ b/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php @@ -219,18 +219,12 @@ public function listTableNames() */ protected function filterAssetNames($assetNames) { - $filterExpr = $this->getFilterSchemaAssetsExpression(); - if (! $filterExpr) { + $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter(); + if (! $filter) { return $assetNames; } - return array_values( - array_filter($assetNames, static function ($assetName) use ($filterExpr) { - $assetName = $assetName instanceof AbstractAsset ? $assetName->getName() : $assetName; - - return preg_match($filterExpr, $assetName); - }) - ); + return array_values(array_filter($assetNames, $filter)); } /** diff --git a/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php b/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php index 053ead6c1bc..676c02cd413 100644 --- a/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php +++ b/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php @@ -10,6 +10,7 @@ use Doctrine\DBAL\Schema\DB2SchemaManager; use PHPUnit\Framework\TestCase; use PHPUnit_Framework_MockObject_MockObject; +use function in_array; /** * @covers \Doctrine\DBAL\Schema\DB2SchemaManager @@ -60,4 +61,139 @@ public function testListTableNamesFiltersAssetNamesCorrectly() $this->manager->listTableNames() ); } + + /** + * @return void + * + * @group DBAL-2701 + */ + public function testAssetFilteringSetsACallable() + { + $filterExpression = '/^(?!T_)/'; + $this->conn->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); + $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue([ + ['name' => 'FOO'], + ['name' => 'T_FOO'], + ['name' => 'BAR'], + ['name' => 'T_BAR'], + ])); + + self::assertSame( + [ + 'FOO', + 'BAR', + ], + $this->manager->listTableNames() + ); + + $callable = $this->conn->getConfiguration()->getSchemaAssetsFilter(); + $this->assertInternalType('callable', $callable); + + // BC check: Test that regexp expression is still preserved & accessible. + $this->assertEquals($filterExpression, $this->conn->getConfiguration()->getFilterSchemaAssetsExpression()); + } + + /** + * @return void + */ + public function testListTableNamesFiltersAssetNamesCorrectlyWithCallable() + { + $accepted = ['T_FOO', 'T_BAR']; + $this->conn->getConfiguration()->setSchemaAssetsFilter(static function ($assetName) use ($accepted) { + return in_array($assetName, $accepted); + }); + $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue([ + ['name' => 'FOO'], + ['name' => 'T_FOO'], + ['name' => 'BAR'], + ['name' => 'T_BAR'], + ])); + + self::assertSame( + [ + 'T_FOO', + 'T_BAR', + ], + $this->manager->listTableNames() + ); + + $this->assertNull($this->conn->getConfiguration()->getFilterSchemaAssetsExpression()); + } + + /** + * @return void + */ + public function testSettingNullExpressionWillResetCallable() + { + $accepted = ['T_FOO', 'T_BAR']; + $this->conn->getConfiguration()->setSchemaAssetsFilter(static function ($assetName) use ($accepted) { + return in_array($assetName, $accepted); + }); + $this->conn->expects($this->atLeastOnce())->method('fetchAll')->will($this->returnValue([ + ['name' => 'FOO'], + ['name' => 'T_FOO'], + ['name' => 'BAR'], + ['name' => 'T_BAR'], + ])); + + self::assertSame( + [ + 'T_FOO', + 'T_BAR', + ], + $this->manager->listTableNames() + ); + + $this->conn->getConfiguration()->setFilterSchemaAssetsExpression(null); + + self::assertSame( + [ + 'FOO', + 'T_FOO', + 'BAR', + 'T_BAR', + ], + $this->manager->listTableNames() + ); + + $this->assertNull($this->conn->getConfiguration()->getSchemaAssetsFilter()); + } + + /** + * @return void + */ + public function testSettingNullAsCallableClearsExpression() + { + $filterExpression = '/^(?!T_)/'; + $this->conn->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); + + $this->conn->expects($this->exactly(2))->method('fetchAll')->will($this->returnValue([ + ['name' => 'FOO'], + ['name' => 'T_FOO'], + ['name' => 'BAR'], + ['name' => 'T_BAR'], + ])); + + self::assertSame( + [ + 'FOO', + 'BAR', + ], + $this->manager->listTableNames() + ); + + $this->conn->getConfiguration()->setSchemaAssetsFilter(null); + + self::assertSame( + [ + 'FOO', + 'T_FOO', + 'BAR', + 'T_BAR', + ], + $this->manager->listTableNames() + ); + + $this->assertNull($this->conn->getConfiguration()->getFilterSchemaAssetsExpression()); + } }