Description
Symfony version(s) affected
5.4.17
Description
After upgrading to symfony/dependency-injection 5.4.17, several users (including me) encountered the following exception when clearing cache:
In MissingMappingDriverImplementation.php line 11:
[Doctrine\ORM\Exception\MissingMappingDriverImplementation]
It's a requirement to specify a Metadata Driver and pass it to Doctrine\ORM\Configuration::setMetadataDriverImpl().
Exception trace:
at /var/www/app/vendor/doctrine/orm/lib/Doctrine/ORM/Exception/MissingMappingDriverImplementation.php:11
Doctrine\ORM\Exception\MissingMappingDriverImplementation::create() at /var/www/app/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php:162
Doctrine\ORM\EntityManager->__construct() at /var/www/app/var/cache/dev/ContainerXpmlFIp/srcApp_KernelDevDebugContainer.php:4128
Rolling back to 5.4.16 fix the exception.
We started discussing this in the #48814 issue but it finaly doesn't look like the same problem.
------ Following is the first comment from #48814 by @julienfastre ----------------
I experience a problem which may be similar, with a complex configuration of EntityManagerInterface
.
With symfony/dependency-injection on 5.4.17, the kernel "prepares" the EntityManager like this:
/**
* Gets the public 'doctrine.orm.default_entity_manager' shared service.
*
* @return \Doctrine\ORM\EntityManager
*/
protected function getDoctrine_Orm_DefaultEntityManagerService($lazyLoad = true)
{
$a = ($this->services['doctrine.dbal.default_connection'] ?? $this->getDoctrine_Dbal_DefaultConnectionService());
if (isset($this->services['doctrine.orm.default_entity_manager'])) {
return $this->services['doctrine.orm.default_entity_manager'];
}
$b = new \Doctrine\ORM\Configuration();
$c = new \Doctrine\Persistence\Mapping\Driver\MappingDriverChain();
$d = ($this->privates['doctrine.orm.default_annotation_metadata_driver'] ?? $this->getDoctrine_Orm_DefaultAnnotationMetadataDriverService());
$c->addDriver($d, 'App\\Entity');
$c->addDriver($d, 'Chill\\MainBundle\\Entity');
$c->addDriver($d, 'Chill\\PersonBundle\\Entity');
$c->addDriver($d, 'Chill\\CustomFieldsBundle\\Entity');
$c->addDriver($d, 'Chill\\ActivityBundle\\Entity');
$c->addDriver($d, 'Chill\\DocStoreBundle\\Entity');
$c->addDriver($d, 'Chill\\DocGeneratorBundle\\Entity');
$c->addDriver($d, 'Chill\\AsideActivityBundle\\Entity');
$c->addDriver($d, 'Chill\\CalendarBundle\\Entity');
$c->addDriver($d, 'Chill\\TaskBundle\\Entity');
$c->addDriver($d, 'Chill\\ThirdPartyBundle\\Entity');
$c->addDriver($d, 'Chill\\BudgetBundle\\Entity');
// here, an exception is thrown because the configuration ($b) does not contains a mapping driver,
// which is added later in the function
$this->services['doctrine.orm.default_entity_manager'] = $instance = new \Doctrine\ORM\EntityManager($a, $b);
(new \Doctrine\Bundle\DoctrineBundle\ManagerConfigurator([], []))->configure($instance);
$b->setEntityNamespaces(['App' => 'App\\Entity', 'ChillMainBundle' => 'Chill\\MainBundle\\Entity', 'ChillPersonBundle' => 'Chill\\PersonBundle\\Entity', 'ChillCustomFieldsBundle' => 'Chill\\CustomFieldsBundle\\Entity', 'ChillActivityBundle' => 'Chill\\ActivityBundle\\Entity', 'ChillDocStoreBundle' => 'Chill\\DocStoreBundle\\Entity', 'ChillDocGeneratorBundle' => 'Chill\\DocGeneratorBundle\\Entity', 'ChillAsideActivityBundle' => 'Chill\\AsideActivityBundle\\Entity', 'ChillCalendarBundle' => 'Chill\\CalendarBundle\\Entity', 'ChillTaskBundle' => 'Chill\\TaskBundle\\Entity', 'ChillThirdPartyBundle' => 'Chill\\ThirdPartyBundle\\Entity', 'ChillBudgetBundle' => 'Chill\\BudgetBundle\\Entity']);
$b->setMetadataCache(new \Symfony\Component\Cache\Adapter\ArrayAdapter());
$b->setQueryCache(($this->privates['cache.doctrine.orm.default.query'] ?? $this->getCache_Doctrine_Orm_Default_QueryService()));
$b->setResultCache(($this->privates['cache.doctrine.orm.default.result'] ?? $this->getCache_Doctrine_Orm_Default_ResultService()));
/// here is added the missing metadata driver
$b->setMetadataDriverImpl($c);
$b->setProxyDir(($this->targetDir.''.'/doctrine/orm/Proxies'));
$b->setProxyNamespace('Proxies');
$b->setAutoGenerateProxyClasses(true);
$b->setSchemaIgnoreClasses([]);
$b->setClassMetadataFactoryName('Doctrine\\ORM\\Mapping\\ClassMetadataFactory');
$b->setDefaultRepositoryClassName('Doctrine\\ORM\\EntityRepository');
$b->setNamingStrategy(new \Doctrine\ORM\Mapping\DefaultNamingStrategy());
$b->setQuoteStrategy(new \Doctrine\ORM\Mapping\DefaultQuoteStrategy());
$b->setEntityListenerResolver(($this->services['doctrine.orm.default_entity_listener_resolver'] ?? $this->getDoctrine_Orm_DefaultEntityListenerResolverService()));
$b->setRepositoryFactory( /* etc. etc. */)
$b->addCustomHydrationMode('chill_flat_hierarchy_list', 'Chill\\MainBundle\\Doctrine\\ORM\\Hydration\\FlatHierarchyEntityHydrator');
$b->addCustomStringFunction('GET_PERSON_ADDRESS_ADDRESS_ID', 'Chill\\PersonBundle\\Doctrine\\DQL\\AddressPart\\AddressPartAddressId');
// ...
// add a lot of other custom function there ...
// ...
return $instance;
}
This cause a bug because the EntityManager instance is created too early:
In MissingMappingDriverImplementation.php line 11:
[Doctrine\ORM\Exception\MissingMappingDriverImplementation]
It's a requirement to specify a Metadata Driver and pass it to Doctrine\ORM\Configuration::setMetadataDriverImpl().
Exception trace:
at /var/www/app/vendor/doctrine/orm/lib/Doctrine/ORM/Exception/MissingMappingDriverImplementation.php:11
Doctrine\ORM\Exception\MissingMappingDriverImplementation::create() at /var/www/app/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php:162
Doctrine\ORM\EntityManager->__construct() at /var/www/app/var/cache/dev/ContainerXpmlFIp/srcApp_KernelDevDebugContainer.php:4128
If I move those two lines at the end of the method, just before the return $instance;
, it does work:
protected function getDoctrine_Orm_DefaultEntityManagerService($lazyLoad = true)
{
// ...
$this->services['doctrine.orm.default_entity_manager'] = $instance = new \Doctrine\ORM\EntityManager($a, $b);
(new \Doctrine\Bundle\DoctrineBundle\ManagerConfigurator([], []))->configure($instance);
return $instance;
}
If I downgrade symfony/dependency-injection to 5.4.16 (composer require symfony/dependency-injection 5.4.16
), the container is compiled in this manner, and the problem is fixed.
EDIT 30/12/22 add comment in code block and correct version mismatch
Originally posted by @julienfastre in #48814 (comment)
How to reproduce
I didn't succed to create a reproducer.
------ Following is a comment from #48814 by @HeinDR who tracked the bug down to a change from a commit ----------------
I also experience a similar problem with the doctrine configuration when I add an extra entity manager. After the update te symfony/dependency-injection 5.4.17 I get this error:
It's a requirement to specify a Metadata Driver and pass it to Doctrine\ORM\Configuration::setMetadataDriverImpl().
when I clear the cache.
I could trace the problem back to commit 58f2988 where in the PhpDumper the edge->isLazy()
check is removed in favor of checks further down the foreach.
private function collectCircularReferences(string $sourceId, array $edges, array &$checkedNodes, array &$loops = [], array $path = [], bool $byConstructor = true): void
{
$path[$sourceId] = $byConstructor;
$checkedNodes[$sourceId] = true;
foreach ($edges as $edge) {
$node = $edge->getDestNode();
$id = $node->getId();
if ($sourceId === $id || !$node->getValue() instanceof Definition || $edge->isWeak()) {
continue;
}
//..
}
When I add the edge->isLazy()
check and manualy delete the cache the error is gone.
private function collectCircularReferences(string $sourceId, array $edges, array &$checkedNodes, array &$loops = [], array $path = [], bool $byConstructor = true): void
{
$path[$sourceId] = $byConstructor;
$checkedNodes[$sourceId] = true;
foreach ($edges as $edge) {
$node = $edge->getDestNode();
$id = $node->getId();
if ($sourceId === $id || !$node->getValue() instanceof Definition || $edge->isLazy() || $edge->isWeak()) {
continue;
}
//..
}
Originally posted by @HeinDR in #48814 (comment)
Possible Solution
No response
Additional Context
No response