Skip to content

[Doc][Advanced][Doctrine][Schema] Allow set callable class in doctrine.dbal.schema_filter configuration parameter #20996

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ksn135 opened this issue May 25, 2025 · 0 comments

Comments

@ksn135
Copy link

ksn135 commented May 25, 2025

Hi there!

Hoping it will help someone and be useful to someone else

You are free to use it as you see fit.

Problem

Sometimes when you have to rewrite an old monolith you face such a problem when there are a lot of tables in the database (more than seven hundred tables) that are not related to the implemented functionality, but they cannot be touched.

There is a convenient implemented functionality in Doctrine that allows you to filter tables by different criteria, setting your own anonymous function for filtering, using a method setSchemaAssetsFilter .

      $config->setSchemaAssetsFilter(function (string|AbstractAsset $assetName): bool {
          if ($assetName instanceof AbstractAsset) {
              $assetName = $assetName->getName();
          }
  
          return !str_starts_with($assetName, 'audit_');
      });

But the current Symfony 7.3 configuration setting does not allow to add its own anonymous function (Callable) to the doctrine.dbal.schema_filter parameter. It's only a text regular expression allowed.

The proposed solution, allows you to specify your class name and automatically call its __invoke(AbstractAsset|string $assetName): bool method with any logic required by the developer.

<?php // config/packages/doctrine.php

use App\Common\Doctrine\SchemaFilter\DoctrineIgnoreTables;
use App\Common\Doctrine\Types\JsonArrayType;
use Symfony\Bridge\Doctrine\Types\DatePointType;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $containerConfigurator->extension('doctrine', [
        'dbal' => [
            'url' => '%env(resolve:DATABASE_URL)%',
            'profiling_collect_backtrace' => '%kernel.debug%',
            'use_savepoints' => true,
            'types' => [
                DatePointType::NAME => DatePointType::class,
                JsonArrayType::NAME => JsonArrayType::class,
            ],
            // Just imagine listing over 700 tables here!!!
            // 'schema_filter' => '/^prefix_/', // <== the OLD RegExp way
            // YOU don't need it anymore. 
        ], 
        'orm' => [
            'auto_generate_proxy_classes' => true,
 // ....
        ]);
    }
};

Solution

<?php // src/Common/di.php

declare(strict_types=1);

/*
 * This file is part of BAZE informational system package.
 *
 * (c) Serg N. Kalachev <[email protected]>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace App\Common;

use App\Common\Doctrine\DBAL\PrefixSchemaAssetFilter; // <== see below
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $containerConfigurator
        ->services()
        ->defaults()
        ->autowire()
        ->autoconfigure()
        ->load(__NAMESPACE__.'\\', '.')
        ->exclude([
            './{di.php,routing.php}',
            // './**/{Command,Filter,Message}.php',
        ])
    ;
    $containerConfigurator
        ->services()
        ->set(PrefixSchemaAssetFilter::class) 
        ->tag('doctrine.dbal.schema_filter', ['connection' => 'default'])
        ->arg(0, [
            '1c_contractor',
            'approver',
            'archive',
            'audit',
            'author',
            'bank',
            'bkr',
            'boss',
            'box',
            'budget',
            'cabinet',

/** ... skipping over hundred lines here!!! */

            'warehouse',
            'waybill',
            'workflow',
        ])
    ;
    $containerConfigurator->extension('doctrine', [
        'orm' => [
            'mappings' => [
                __NAMESPACE__ => [
                    'is_bundle' => false,
                    'type' => 'xml',
                    'dir' => __DIR__.'/Doctrine/ORM/Mapping',
                    'prefix' => __NAMESPACE__.'\Doctrine\Entity',
                    'alias' => basename(__DIR__),
                ],
            ],
        ],
    ]);
    $containerConfigurator->extension('twig', [
        'paths' => [
            __DIR__.'/templates' => basename(__DIR__),
        ],
    ]);
};
<?php // src/Common/Doctrine/DBAL/PrefixSchemaAssetFilter.php

declare(strict_types=1);

/*
 * This file is part of BAZE informational system package.
 *
 * (c) Serg N. Kalachev <[email protected]>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace App\Common\Doctrine\DBAL;

use Doctrine\DBAL\Schema\AbstractAsset;

use function str_starts_with;

class PrefixSchemaAssetFilter
{
    /** @param string[] $prefixes */
    public function __construct(
        private readonly array $prefixes,
    ) {}

    /** @param AbstractAsset|string $assetName */
    public function __invoke($assetName): bool
    {
        if ($assetName instanceof AbstractAsset) {
            $assetName = $assetName->getName();
        }

        foreach ($this->prefixes as $prefix) {
            if (str_starts_with($assetName, $prefix)) {
                return false;
            }
        }

        return true;
    }
}

That's all folks!

@ksn135 ksn135 changed the title [Doc][Advanced] Allow set callable class in doctrine.dbal.schema_filter configuration parameter [Doc][Advanced][Doctrine][Schema] Allow set callable class in doctrine.dbal.schema_filter configuration parameter May 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant