I've created a "PoC" project in order to ease with the bug reproduction, you can find it here: https://github.com/1ma/symfony-cmd-issue
Project contents
A brand new Symfony3 project with an empty entity (Test), its companion repository (TestRepository) and a command (TestCommand) defined as a service, as per the cookbook entry found at http://symfony.com/doc/current/cookbook/console/commands_as_services.html
# app/config/services.yml
services:
test_repo:
class: AppBundle\Repository\TestRepository
factory: ["@doctrine.orm.default_entity_manager", getRepository]
arguments: ["AppBundle:Test"]
test_command:
class: AppBundle\Command\TestCommand
arguments:
- "@test_repo"
tags:
- { name: console.command }
Steps to reproduce
-
$ git clone https://github.com/1ma/symfony-cmd-issue.git
-
$ cd symfony-cmd-issue; composer install
When the prompt shows up, be sure to set valid values for database_user and database_password. They should map to a MySQL user with enough permissions to create the database.
-
At this point the installation will break. Further calls to bin/console will also fail with the following error message:
marcel@workstation:~/workspace/symfony-cmd-issue$ php bin/console
[Doctrine\DBAL\Exception\ConnectionException]
An exception occured in driver: SQLSTATE[42000] [1049] Unknown database 'symfony'
[Doctrine\DBAL\Driver\PDOException]
SQLSTATE[42000] [1049] Unknown database 'symfony'
[PDOException]
SQLSTATE[42000] [1049] Unknown database 'symfony'
-
In order to restore the console, remove the tags: block from the command service definition. Now you'll be able to execute the console and create the database:
marcel@workstation:~/workspace/symfony-cmd-issue$ php bin/console doctrine:database:create
Created database `symfony` for connection named default
-
Once the database is created you can restore the tags: block in the command service definition and the console will still work:
marcel@workstation:~/workspace/symfony-cmd-issue$ php bin/console cmd:test
AppBundle\Entity\Test
-
Drop the database, and the console breaks again:
marcel@workstation:~/workspace/symfony-cmd-issue$ php bin/console doctrine:database:drop --force
Dropped database for connection named `symfony`
marcel@workstation:~/workspace/symfony-cmd-issue$ php bin/console cmd:test
[Doctrine\DBAL\Exception\ConnectionException]
An exception occured in driver: SQLSTATE[42000] [1049] Unknown database 'symfony'
[Doctrine\DBAL\Driver\PDOException]
SQLSTATE[42000] [1049] Unknown database 'symfony'
[PDOException]
SQLSTATE[42000] [1049] Unknown database 'symfony'
Troubleshooting
From what I've seen from the above exception stack trace, it seems that every service tagged with the console.command tag is instantiated at Application::registerCommands().
Then, if one of the command dependencies is a subclass of EntityRepository instantiated as EntityManager->getRepository('AppBundle:EntityName') a connection to the database will be always attempted down the line, even if it doesn't exist yet.
Here is the full stack trace with some of the most relevant entries highlighted in bold font:
#0 .../symfony-cmd-issue/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php(45): Doctrine\DBAL\Driver\PDOConnection::__construct('mysql:host=127....', 'root', 'root', Array)
#1 .../symfony-cmd-issue/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(360): Doctrine\DBAL\Driver\PDOMySql\Driver->connect(Array, 'root', 'root', Array)
#2 .../symfony-cmd-issue/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(429): Doctrine\DBAL\Connection->connect()
#3 .../symfony-cmd-issue/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(389): Doctrine\DBAL\Connection->getDatabasePlatformVersion()
#4 .../symfony-cmd-issue/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(328): Doctrine\DBAL\Connection->detectDatabasePlatform()
#5 .../symfony-cmd-issue/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php(763): Doctrine\DBAL\Connection->getDatabasePlatform()
#6 .../symfony-cmd-issue/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php(616): Doctrine\ORM\Mapping\ClassMetadataFactory->getTargetPlatform()
#7 .../symfony-cmd-issue/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php(174): Doctrine\ORM\Mapping\ClassMetadataFactory->completeIdGeneratorMapping(Object(Doctrine\ORM\Mapping\ClassMetadata))
#8 .../symfony-cmd-issue/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php(332): Doctrine\ORM\Mapping\ClassMetadataFactory->doLoadMetadata(Object(Doctrine\ORM\Mapping\ClassMetadata), NULL, false, Array)
#9 .../symfony-cmd-issue/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php(78): Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory->loadMetadata('AppBundle\Entit...')
#10 .../symfony-cmd-issue/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php(216): Doctrine\ORM\Mapping\ClassMetadataFactory->loadMetadata('AppBundle\Entit...')
#11 .../symfony-cmd-issue/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php(281): Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory->getMetadataFor('AppBundle:Test')
#12 .../symfony-cmd-issue/vendor/doctrine/orm/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php(44): Doctrine\ORM\EntityManager->getClassMetadata('AppBundle:Test')
#13 .../symfony-cmd-issue/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php(698): Doctrine\ORM\Repository\DefaultRepositoryFactory->getRepository(Object(Doctrine\ORM\EntityManager), 'AppBundle:Test')
#14 .../symfony-cmd-issue/var/cache/dev/appDevDebugProjectContainer.php(2465): Doctrine\ORM\EntityManager->getRepository('AppBundle:Test')
#15 .../symfony-cmd-issue/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Container.php(273): appDevDebugProjectContainer->getTestRepoService()
#16 .../symfony-cmd-issue/var/cache/dev/appDevDebugProjectContainer.php(2452): Symfony\Component\DependencyInjection\Container->get('test_repo')
#17 .../symfony-cmd-issue/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Container.php(273): appDevDebugProjectContainer->getTestCommandService()
#18 .../symfony-cmd-issue/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php(101): Symfony\Component\DependencyInjection\Container->get('test_command')
#19 .../symfony-cmd-issue/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php(71): Symfony\Bundle\FrameworkBundle\Console\Application->registerCommands()
#20 .../symfony-cmd-issue/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php(117): Symfony\Bundle\FrameworkBundle\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#21 .../symfony-cmd-issue/bin/console(29): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput))
#22 {main}
Further details
Tested on a Debian Jessie x64 virtual machine with PHP 5.6, Symfony 3.0.2 and Doctrine ORM 2.5.4
I've created a "PoC" project in order to ease with the bug reproduction, you can find it here: https://github.com/1ma/symfony-cmd-issue
Project contents
A brand new Symfony3 project with an empty entity (Test), its companion repository (TestRepository) and a command (TestCommand) defined as a service, as per the cookbook entry found at http://symfony.com/doc/current/cookbook/console/commands_as_services.html
Steps to reproduce
$ git clone https://github.com/1ma/symfony-cmd-issue.git$ cd symfony-cmd-issue; composer installWhen the prompt shows up, be sure to set valid values for
database_useranddatabase_password. They should map to a MySQL user with enough permissions to create the database.At this point the installation will break. Further calls to
bin/consolewill also fail with the following error message:In order to restore the console, remove the
tags:block from the command service definition. Now you'll be able to execute the console and create the database:Once the database is created you can restore the
tags:block in the command service definition and the console will still work:Drop the database, and the console breaks again:
Troubleshooting
From what I've seen from the above exception stack trace, it seems that every service tagged with the
console.commandtag is instantiated atApplication::registerCommands().Then, if one of the command dependencies is a subclass of
EntityRepositoryinstantiated asEntityManager->getRepository('AppBundle:EntityName')a connection to the database will be always attempted down the line, even if it doesn't exist yet.Here is the full stack trace with some of the most relevant entries highlighted in bold font:
#0 .../symfony-cmd-issue/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php(45): Doctrine\DBAL\Driver\PDOConnection::__construct('mysql:host=127....', 'root', 'root', Array)
#1 .../symfony-cmd-issue/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(360): Doctrine\DBAL\Driver\PDOMySql\Driver->connect(Array, 'root', 'root', Array)
#2 .../symfony-cmd-issue/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(429): Doctrine\DBAL\Connection->connect()
#3 .../symfony-cmd-issue/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(389): Doctrine\DBAL\Connection->getDatabasePlatformVersion()
#4 .../symfony-cmd-issue/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php(328): Doctrine\DBAL\Connection->detectDatabasePlatform()
#5 .../symfony-cmd-issue/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php(763): Doctrine\DBAL\Connection->getDatabasePlatform()
#6 .../symfony-cmd-issue/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php(616): Doctrine\ORM\Mapping\ClassMetadataFactory->getTargetPlatform()
#7 .../symfony-cmd-issue/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php(174): Doctrine\ORM\Mapping\ClassMetadataFactory->completeIdGeneratorMapping(Object(Doctrine\ORM\Mapping\ClassMetadata))
#8 .../symfony-cmd-issue/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php(332): Doctrine\ORM\Mapping\ClassMetadataFactory->doLoadMetadata(Object(Doctrine\ORM\Mapping\ClassMetadata), NULL, false, Array)
#9 .../symfony-cmd-issue/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php(78): Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory->loadMetadata('AppBundle\Entit...')
#10 .../symfony-cmd-issue/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php(216): Doctrine\ORM\Mapping\ClassMetadataFactory->loadMetadata('AppBundle\Entit...')
#11 .../symfony-cmd-issue/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php(281): Doctrine\Common\Persistence\Mapping\AbstractClassMetadataFactory->getMetadataFor('AppBundle:Test')
#12 .../symfony-cmd-issue/vendor/doctrine/orm/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php(44): Doctrine\ORM\EntityManager->getClassMetadata('AppBundle:Test')
#13 .../symfony-cmd-issue/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php(698): Doctrine\ORM\Repository\DefaultRepositoryFactory->getRepository(Object(Doctrine\ORM\EntityManager), 'AppBundle:Test')
#14 .../symfony-cmd-issue/var/cache/dev/appDevDebugProjectContainer.php(2465): Doctrine\ORM\EntityManager->getRepository('AppBundle:Test')
#15 .../symfony-cmd-issue/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Container.php(273): appDevDebugProjectContainer->getTestRepoService()
#16 .../symfony-cmd-issue/var/cache/dev/appDevDebugProjectContainer.php(2452): Symfony\Component\DependencyInjection\Container->get('test_repo')
#17 .../symfony-cmd-issue/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Container.php(273): appDevDebugProjectContainer->getTestCommandService()
#18 .../symfony-cmd-issue/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php(101): Symfony\Component\DependencyInjection\Container->get('test_command')
#19 .../symfony-cmd-issue/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php(71): Symfony\Bundle\FrameworkBundle\Console\Application->registerCommands()
#20 .../symfony-cmd-issue/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php(117): Symfony\Bundle\FrameworkBundle\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#21 .../symfony-cmd-issue/bin/console(29): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput))
#22 {main}
Further details
Tested on a Debian Jessie x64 virtual machine with PHP 5.6, Symfony 3.0.2 and Doctrine ORM 2.5.4