Command "orm:validate-schema --skip-sync" still expects a valid DB connection #6287

Closed
opened 2026-01-22 15:30:10 +01:00 by admin · 3 comments
Owner

Originally created by @delolmo on GitHub (Aug 21, 2019).

Originally assigned to: @lcobucci on GitHub.

Bug Report

Q A
BC Break no
Version 2.6.3

Summary

The command orm:validate-schema --skip-sync will throw a PDOException if a valid connection is not given.

Current behavior

For a specific use case, we have a private repo with some shared entities and entity repositories which are common to several PHP projects. The only dependency of the private repo is doctrine/orm, version ^2.6.

Because the repo is so specific to Doctrine ORM, we have a Composer script that executes the following command as part of the CI strategy:

    doctrine orm:validate-schema --skip-sync --no-interaction

...the goal being to check if the entity mappings are valid.

However, due to the way that Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand is coded (the EntityManager requires a valid connection as its first parameter), if there is no connection to the database the command will fail, throwing a PDOException.

    $em = $this->getHelper('em')->getEntityManager();
    $validator = new SchemaValidator($em);
    $exit = 0;

    // ...

    if ($input->getOption('skip-sync')) {
        $ui->text('<comment>[SKIPPED] The database was not checked for synchronicity.</comment>');
    } elseif ( ! $validator->schemaInSyncWithMetadata()) {
        $ui->error('The database schema is not in sync with the current mapping file.');
        $exit += 2;
    } else {
        $ui->success('The database schema is in sync with the mapping files.');
    }

The SchemaValidator requires the EntityManager because it needs to access the metadata factory (\Doctrine\ORM\Mapping\ClassMetadataFactory).

Should a new class be made, i.e. MappingValidator, which receives in its constructor a ClassMetadataFactory as its only argument? Is there any other way to circumvent this error (i.e. passing a dummy database connection)?

I am unsure on how to proceed to try and solve this bug because I don't know the internals of Doctrine very well, but I will be happy to try and help coding something if someone can give me some guidance.

How to reproduce

Execute orm:validate-schema --skip-sync without a valid database connection available.

Expected behavior

The command is expected to check either for valid entity mappings, for synchronicity with the database or both. If only the first option is selected, there is no reason to require a database connection to validate the entity mappings.

Originally created by @delolmo on GitHub (Aug 21, 2019). Originally assigned to: @lcobucci on GitHub. ### Bug Report | Q | A |------------ | ------ | BC Break | no | Version | 2.6.3 #### Summary The command `orm:validate-schema --skip-sync` will throw a PDOException if a valid connection is not given. #### Current behavior For a specific use case, we have a private repo with some shared entities and entity repositories which are common to several PHP projects. The only dependency of the private repo is doctrine/orm, version ^2.6. Because the repo is so specific to Doctrine ORM, we have a Composer script that executes the following command as part of the CI strategy: doctrine orm:validate-schema --skip-sync --no-interaction ...the goal being to check if the entity mappings are valid. However, due to the way that `Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand` is coded (the EntityManager requires a valid connection as its first parameter), if there is no connection to the database the command will fail, throwing a PDOException. $em = $this->getHelper('em')->getEntityManager(); $validator = new SchemaValidator($em); $exit = 0; // ... if ($input->getOption('skip-sync')) { $ui->text('<comment>[SKIPPED] The database was not checked for synchronicity.</comment>'); } elseif ( ! $validator->schemaInSyncWithMetadata()) { $ui->error('The database schema is not in sync with the current mapping file.'); $exit += 2; } else { $ui->success('The database schema is in sync with the mapping files.'); } The SchemaValidator requires the EntityManager because it needs to access the metadata factory (`\Doctrine\ORM\Mapping\ClassMetadataFactory`). Should a new class be made, i.e. MappingValidator, which receives in its constructor a ClassMetadataFactory as its only argument? Is there any other way to circumvent this error (i.e. passing a dummy database connection)? I am unsure on how to proceed to try and solve this bug because I don't know the internals of Doctrine very well, but I will be happy to try and help coding something if someone can give me some guidance. #### How to reproduce Execute `orm:validate-schema --skip-sync` without a valid database connection available. #### Expected behavior The command is expected to check either for valid entity mappings, for synchronicity with the database or both. If only the first option is selected, there is no reason to require a database connection to validate the entity mappings.
admin added the Question label 2026-01-22 15:30:10 +01:00
admin closed this issue 2026-01-22 15:30:10 +01:00
Author
Owner

@lcobucci commented on GitHub (Aug 22, 2019):

@delolmo this is a tricky one due to how the EM is created and the configuration of the CLI tool...

I think we could improve this for 3.x series but I wouldn't change 2.x drastically to accommodate these needs (it might create more complexity, which is not desired now for 2.x).

My suggestion to you is to setup the CLI config to use an in-memory SQLite connection, which won't be used at all in your use case. Which would make your cli-config.php look like this:

<?php
declare(strict_types=1);

use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntitiyManager;
use Doctrine\ORM\Tools\Console\ConsoleRunner;

$config = new Configuration(); // apply your configuration

return ConsoleRunner::createHelperSet(
    EntitiyManager::create(
        ['driver' => 'pdo_sqlite', 'memory' => true],
        $config
    )
);

It's not a perfect solution but should solve your need, what do you think?

@lcobucci commented on GitHub (Aug 22, 2019): @delolmo this is a tricky one due to how the EM is created and the configuration of the CLI tool... I think we could improve this for `3.x` series but I wouldn't change `2.x` drastically to accommodate these needs (it might create more complexity, which is not desired now for `2.x`). My suggestion to you is to setup the CLI config to use an in-memory SQLite connection, which won't be used at all in your use case. Which would make your `cli-config.php` look like this: ```php <?php declare(strict_types=1); use Doctrine\ORM\Configuration; use Doctrine\ORM\EntitiyManager; use Doctrine\ORM\Tools\Console\ConsoleRunner; $config = new Configuration(); // apply your configuration return ConsoleRunner::createHelperSet( EntitiyManager::create( ['driver' => 'pdo_sqlite', 'memory' => true], $config ) ); ``` It's not a perfect solution but should solve your need, what do you think?
Author
Owner

@delolmo commented on GitHub (Aug 23, 2019):

It works perfectly. However, I had to go a little bit further because some developers also do db updates from the repository. The orm:schema-tool:* commands obviously need a db connection.

What I finally did was add a config/.env file to the .gitignore. If the file is present, the EM will be created using the environment variables defined in that file. If not, it will create the EM with the in-memory connection you suggested.

<?php

declare(strict_types=1);

use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntitiyManager;
use Doctrine\ORM\Tools\Console\ConsoleRunner;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Setup;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Dotenv\Dotenv;

// Load Composer's autoloader
require_once 'vendor/autoload.php';

// Create configuration
$configuration = new Configuration(); // our configuration

// Check if the .env file is present
if (\class_exists(Dotenv::class) &&
    \file_exists('config/.env')) {

    // Load environment variables
    (new Dotenv())->load('config/.env');

    /* @var $connection array */
    $connection = array(
        'host'     => getenv('ORM_HOST'),
        'driver'   => getenv('ORM_DRIVER'),
        'user'     => getenv('ORM_USER'),
        'password' => getenv('ORM_PASSWORD'),
        'dbname'   => getenv('ORM_DBNAME')
    );

    /* @var $entityManager \Doctrine\ORM\EntityManager */
    $entityManager = EntityManager::create(
        $connection,
        $configuration
    );
}

// Create an in-memory SQLite connection if EM doesn't exist
$entityManager = $entityManager ??
    EntityManager::create(
        ['driver' => 'pdo_sqlite', 'memory' => true],
        $configuration
    );

// Create HelperSet
$helperSet = new HelperSet(array(
    'em' => new EntityManagerHelper($entityManager)
    ));

// Return HelperSet
return $helperSet;

The approach may not be perfect, but it will allow us to work locally and to use the CI tool.

What do you think?

@delolmo commented on GitHub (Aug 23, 2019): It works perfectly. However, I had to go a little bit further because some developers also do db updates from the repository. The `orm:schema-tool:*` commands obviously need a db connection. What I finally did was add a `config/.env` file to the .gitignore. If the file is present, the EM will be created using the environment variables defined in that file. If not, it will create the EM with the in-memory connection you suggested. ```php <?php declare(strict_types=1); use Doctrine\ORM\Configuration; use Doctrine\ORM\EntitiyManager; use Doctrine\ORM\Tools\Console\ConsoleRunner; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Tools\Setup; use Symfony\Component\Console\Helper\HelperSet; use Symfony\Component\Dotenv\Dotenv; // Load Composer's autoloader require_once 'vendor/autoload.php'; // Create configuration $configuration = new Configuration(); // our configuration // Check if the .env file is present if (\class_exists(Dotenv::class) && \file_exists('config/.env')) { // Load environment variables (new Dotenv())->load('config/.env'); /* @var $connection array */ $connection = array( 'host' => getenv('ORM_HOST'), 'driver' => getenv('ORM_DRIVER'), 'user' => getenv('ORM_USER'), 'password' => getenv('ORM_PASSWORD'), 'dbname' => getenv('ORM_DBNAME') ); /* @var $entityManager \Doctrine\ORM\EntityManager */ $entityManager = EntityManager::create( $connection, $configuration ); } // Create an in-memory SQLite connection if EM doesn't exist $entityManager = $entityManager ?? EntityManager::create( ['driver' => 'pdo_sqlite', 'memory' => true], $configuration ); // Create HelperSet $helperSet = new HelperSet(array( 'em' => new EntityManagerHelper($entityManager) )); // Return HelperSet return $helperSet; ``` The approach may not be perfect, but it will allow us to work locally and to use the CI tool. What do you think?
Author
Owner

@delolmo commented on GitHub (Aug 30, 2019):

Closing this issue. Thanks @lcobucci.

Hope to see mapping validation in the 3.x version without requiring a valid database connection.

@delolmo commented on GitHub (Aug 30, 2019): Closing this issue. Thanks @lcobucci. Hope to see mapping validation in the 3.x version without requiring a valid database connection.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#6287