Skip to content

MySQL warning: Deprecated usage of mixed qualified and unqualified column names. #12115

@wkania

Description

@wkania

Related to PR.
My current setup consists of one database with the central schema and additional schemas (one per client). Until now, I was able to define entities in the code using the central schema. The rest did not have a defined schema — each client had a different one — and there is a single code repository.

Now, when I run doctrine:schema:validate, I get the following warning:

User Deprecated: Using unqualified names to create or reference objects in a schema that uses qualified names and lacks a default namespace configuration is deprecated.
(Schema.php:254 called by Schema.php:145, [Doctrine PR doctrine/dbal#6677](https://github.com/doctrine/dbal/pull/6677#user-content-unqualified-names), package doctrine/dbal)
  1. How can I fix this, and is it even possible?
  2. I understand that the PR fixes problems with SQL Server, but it breaks other configurations. Is there a way to maybe add a parameter that would allow mixing schemas as before?

My config and code:

// doctrine.yaml
doctrine:
  dbal:
    default_connection: default
    connections:
      default:
        host: '%database_host%'
        port: '%database_port%'
        dbname: '%database_name%'
        user: '%database_user%'
        password: '%database_password%'
        server_version: '8.0.32'
        charset: utf8mb4
        use_savepoints: true
        schema_manager_factory: App\Component\Doctrine\CustomSchemaManagerFactory
        default_table_options:
          charset: utf8mb4
          collate: utf8mb4_unicode_ci

// services.yaml
services:
  App\Component\Doctrine\CustomSchemaManager:
    autowire: true
    arguments:
      - '@doctrine.dbal.default_connection'
    tags:
      - { name: 'doctrine.dbal.schema_manager', priority: 1 }

  App\Component\Doctrine\CustomSchemaManagerFactory:
    autowire: true
// CustomSchemaManagerFactory.php
namespace App\Component\Doctrine;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Platforms\AbstractMySQLPlatform;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
use Doctrine\DBAL\Schema\SchemaManagerFactory;

final readonly class CustomSchemaManagerFactory implements SchemaManagerFactory
{
    private SchemaManagerFactory $defaultFactory;

    public function __construct()
    {
        $this->defaultFactory = new DefaultSchemaManagerFactory();
    }

    public function createSchemaManager(Connection $connection): AbstractSchemaManager
    {
        $platform = $connection->getDatabasePlatform();
        if ($platform instanceof AbstractMySQLPlatform) {
            return new CustomSchemaManager($connection, $platform);
        }

        return $this->defaultFactory->createSchemaManager($connection);
    }
}

// CustomSchemaManager.php
namespace App\Component\Doctrine;

use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Exception\DatabaseRequired;
use Doctrine\DBAL\Schema\MySQLSchemaManager;
use Doctrine\DBAL\Schema\Table;

class CustomSchemaManager extends MySQLSchemaManager
{
    public function listTables(): array
    {
        $database = $this->getDatabase(__METHOD__);

        $tables = $this->listTablesForDatabase($database);
        $centralTables = $this->listTablesForDatabase('central');
        /** @var Table $centralTable */
        foreach ($centralTables as $centralTable) {
            $name = 'central.'.$centralTable->getName();
            $tables[$name] = new Table(
                $name,
                $centralTable->getColumns(),
                $centralTable->getIndexes(),
                $centralTable->getUniqueConstraints(),
                $centralTable->getForeignKeys(),
                $centralTable->getOptions(),
            );
        }

        return $tables;
    }

    private function listTablesForDatabase(string $database): array
    {
        $tableColumnsByTable = $this->fetchTableColumnsByTable($database);
        $indexColumnsByTable = $this->fetchIndexColumnsByTable($database);
        $foreignKeyColumnsByTable = $this->fetchForeignKeyColumnsByTable($database);
        $tableOptionsByTable = $this->fetchTableOptionsByTable($database);

        $filter = $this->connection->getConfiguration()->getSchemaAssetsFilter();
        $tables = [];

        foreach ($tableColumnsByTable as $tableName => $tableColumns) {
            if (!$filter($tableName)) {
                continue;
            }

            $tables[] = new Table(
                $tableName,
                $this->_getPortableTableColumnList($tableName, $database, $tableColumns),
                $this->_getPortableTableIndexesList($indexColumnsByTable[$tableName] ?? [], $tableName),
                [],
                $this->_getPortableTableForeignKeysList($foreignKeyColumnsByTable[$tableName] ?? []),
                $tableOptionsByTable[$tableName] ?? [],
            );
        }

        return $tables;
    }

    /** @throws Exception */
    private function getDatabase(string $methodName): string
    {
        $database = $this->connection->getDatabase();

        if (null === $database) {
            throw DatabaseRequired::new($methodName);
        }

        return $database;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions