Symfony 调用getReference()时,ReferencePository会剥离相关实体
我正在编写一个严重依赖于数据装置的symfony2单元测试。作为一种快捷方式,我连接了一个方法,该方法将允许我访问fixture loader的Symfony 调用getReference()时,ReferencePository会剥离相关实体,symfony,doctrine-orm,Symfony,Doctrine Orm,我正在编写一个严重依赖于数据装置的symfony2单元测试。作为一种快捷方式,我连接了一个方法,该方法将允许我访问fixture loader的referencepository,以便我可以访问测试中的共享实体 但是,当我从referenceposition中拉出一个对象时,它没有关系,即使我将它们保存在数据装置中 奇怪的是,referencepositional中有一些代码似乎在剥离这些关系,我不明白它为什么要这样做(更不用说如何防止了) 例如,以下是数据固定装置的外观: public fun
referencepository
,以便我可以访问测试中的共享实体
但是,当我从referenceposition
中拉出一个对象时,它没有关系,即使我将它们保存在数据装置中
奇怪的是,referencepositional
中有一些代码似乎在剥离这些关系,我不明白它为什么要这样做(更不用说如何防止了)
例如,以下是数据固定装置的外观:
public function load(ObjectManager $manager)
{
$project = new Project();
// ... populate fields ...
/* Add one detail field to the Project. */
$detail = new ProjectDetail();
// ... populate fields ...
$project->addDetail($detail);
$manager->persist($project);
$manager->flush();
$this->addReference('project-onedetail', $project);
}
在我的测试用例中,我正在做(或多或少)类似这样的事情:
$project =
$this->fixtureLoader->getReferenceRepository()
->getReference('project-onedetail');
当我在测试用例中调用方法来获取这个项目
对象时,我注意到一些奇怪的行为:
来自条令\Common\DataFixtures\referenceposition
(添加注释):
referencepository->getReference()中发生了什么?为什么要从$reference
中删除相关对象,如何防止这种情况发生?发生了什么
fixture loader运行后,它将清除UnitOfWork的标识映射
请参阅\doctor\Common\DataFixtures\Executor\AbstractExecutor
:
public function load(ObjectManager $manager, FixtureInterface $fixture)
{
...
$fixture->load($manager);
$manager->clear();
}
因此,条件$夹具加载程序完成后,referencepository->getReference()
中的uow->isInIdentityMap($reference)
将始终计算为false
解决办法
您可以通过清除referencepository->$identies
来解决此问题。不幸的是,您无法直接访问此阵列,因此需要执行一些稍微笨拙的操作,如:
/* @kludge The fixture loader clears out its UnitOfWork object after
* loading each fixture, so we also need to clear the
* ReferenceRepository's identity map.
*/
$repository = $this->fixtureLoader->getReferenceRepository();
$identities = array_keys($repository->getIdentities());
foreach($identities as $key)
{
$repository->setReferenceIdentity($key, null);
}
但是,如果这样做,如果在测试夹具中设置相关对象,则可能会遇到一些讨厌的或InvalidargumentException
s:
/** Executes data fixtures for unit tests.
*/
class TestExecutor extends ORMExecutor
{
/** Load a fixture with the given persistence manager.
*
* @param ObjectManager|EntityManager $manager
* @param FixtureInterface $fixture
*/
public function load(ObjectManager $manager, FixtureInterface $fixture)
{
/** @kludge Unfortunately, we have to copy-paste a bit of code.
*
* The only difference between this method and AbstractExecutor->load()
* is that we don't call $manager->clear() when we're done loading.
*/
if($this->logger)
{
$prefix = '';
if($fixture instanceof OrderedFixtureInterface)
{
$prefix = sprintf('[%d] ', $fixture->getOrder());
}
$this->log('loading ' . $prefix . get_class($fixture));
}
// additionally pass the instance of reference repository to shared fixtures
if($fixture instanceof SharedFixtureInterface)
{
$fixture->setReferenceRepository($this->referenceRepository);
}
$fixture->load($manager);
/* Do NOT clear the unit of work; we will keep managed entities so that
* they are available to tests.
*/
}
}
条令\ORM\ORMInvalidArgumentException:通过关系“…”找到了一个新实体,该关系未配置为级联实体url的持久化操作。要解决此问题,请对此未知实体显式调用EntityManager#persist(),或在映射中配置cascade persist此关联,例如@manytone(..,cascade={“persist”})
解决方案
最终,如果您想让它正常工作,您需要更改您在测试用例中使用的fixture executor的行为,以便它在加载fixture后不会清除管理器:
/** Executes data fixtures for unit tests.
*/
class TestExecutor extends ORMExecutor
{
/** Load a fixture with the given persistence manager.
*
* @param ObjectManager|EntityManager $manager
* @param FixtureInterface $fixture
*/
public function load(ObjectManager $manager, FixtureInterface $fixture)
{
/** @kludge Unfortunately, we have to copy-paste a bit of code.
*
* The only difference between this method and AbstractExecutor->load()
* is that we don't call $manager->clear() when we're done loading.
*/
if($this->logger)
{
$prefix = '';
if($fixture instanceof OrderedFixtureInterface)
{
$prefix = sprintf('[%d] ', $fixture->getOrder());
}
$this->log('loading ' . $prefix . get_class($fixture));
}
// additionally pass the instance of reference repository to shared fixtures
if($fixture instanceof SharedFixtureInterface)
{
$fixture->setReferenceRepository($this->referenceRepository);
}
$fixture->load($manager);
/* Do NOT clear the unit of work; we will keep managed entities so that
* they are available to tests.
*/
}
}