allow to cache entity loader based on query builder

This commit is contained in:
Dominik Zogg 2015-03-07 10:38:36 +01:00
parent 0f00f7c7e8
commit 42b682b883
2 changed files with 127 additions and 10 deletions

View File

@ -12,10 +12,16 @@
namespace Symfony\Bridge\Doctrine\Form\Type; namespace Symfony\Bridge\Doctrine\Form\Type;
use Doctrine\Common\Persistence\ObjectManager; use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader; use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader;
class EntityType extends DoctrineType class EntityType extends DoctrineType
{ {
/**
* @var ORMQueryBuilderLoader[]
*/
private $loaderCache = array();
/** /**
* Return the default loader object. * Return the default loader object.
* *
@ -27,11 +33,55 @@ class EntityType extends DoctrineType
*/ */
public function getLoader(ObjectManager $manager, $queryBuilder, $class) public function getLoader(ObjectManager $manager, $queryBuilder, $class)
{ {
return new ORMQueryBuilderLoader( if (!$queryBuilder instanceof QueryBuilder) {
$queryBuilder, return new ORMQueryBuilderLoader(
$manager, $queryBuilder,
$class $manager,
); $class
);
}
$queryBuilderHash = $this->getQueryBuilderHash($queryBuilder);
$loaderHash = $this->getLoaderHash($manager, $queryBuilderHash, $class);
if (!isset($this->loaderCache[$loaderHash])) {
$this->loaderCache[$loaderHash] = new ORMQueryBuilderLoader(
$queryBuilder,
$manager,
$class
);
}
return $this->loaderCache[$loaderHash];
}
/**
* @param QueryBuilder $queryBuilder
*
* @return string
*/
private function getQueryBuilderHash(QueryBuilder $queryBuilder)
{
return hash('sha256', json_encode(array(
'sql' => $queryBuilder->getQuery()->getSQL(),
'parameters' => $queryBuilder->getParameters(),
)));
}
/**
* @param ObjectManager $manager
* @param string $queryBuilderHash
* @param string $class
*
* @return string
*/
private function getLoaderHash(ObjectManager $manager, $queryBuilderHash, $class)
{
return hash('sha256', json_encode(array(
'manager' => spl_object_hash($manager),
'queryBuilder' => $queryBuilderHash,
'class' => $class,
)));
} }
public function getName() public function getName()

View File

@ -11,7 +11,11 @@
namespace Symfony\Bridge\Doctrine\Tests\Form\Type; namespace Symfony\Bridge\Doctrine\Tests\Form\Type;
use Symfony\Bridge\Doctrine\Form\DoctrineOrmTypeGuesser;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\Forms;
use Symfony\Component\Form\Test\TypeTestCase; use Symfony\Component\Form\Test\TypeTestCase;
use Symfony\Bridge\Doctrine\Tests\Fixtures\GroupableEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\GroupableEntity;
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity;
@ -22,6 +26,7 @@ use Symfony\Bridge\Doctrine\Form\DoctrineOrmExtension;
use Doctrine\ORM\Tools\SchemaTool; use Doctrine\ORM\Tools\SchemaTool;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Form\Extension\Core\View\ChoiceView; use Symfony\Component\Form\Extension\Core\View\ChoiceView;
use Symfony\Component\PropertyAccess\PropertyAccess;
class EntityTypeTest extends TypeTestCase class EntityTypeTest extends TypeTestCase
{ {
@ -656,7 +661,7 @@ class EntityTypeTest extends TypeTestCase
'class' => self::SINGLE_IDENT_CLASS, 'class' => self::SINGLE_IDENT_CLASS,
'query_builder' => function ($repository) { 'query_builder' => function ($repository) {
return $repository->createQueryBuilder('e') return $repository->createQueryBuilder('e')
->where('e.id IN (1, 2)'); ->where('e.id IN (1, 2)');
}, },
'property' => 'name', 'property' => 'name',
)); ));
@ -680,7 +685,7 @@ class EntityTypeTest extends TypeTestCase
'class' => self::COMPOSITE_IDENT_CLASS, 'class' => self::COMPOSITE_IDENT_CLASS,
'query_builder' => function ($repository) { 'query_builder' => function ($repository) {
return $repository->createQueryBuilder('e') return $repository->createQueryBuilder('e')
->where('e.id1 IN (10, 50)'); ->where('e.id1 IN (10, 50)');
}, },
'property' => 'name', 'property' => 'name',
)); ));
@ -766,13 +771,75 @@ class EntityTypeTest extends TypeTestCase
)); ));
} }
public function testLoaderCaching()
{
$entity1 = new SingleIntIdEntity(1, 'Foo');
$entity2 = new SingleIntIdEntity(2, 'Bar');
$entity3 = new SingleIntIdEntity(3, 'Baz');
$this->persist(array($entity1, $entity2, $entity3));
$repository = $this->em->getRepository(self::SINGLE_IDENT_CLASS);
$qb = $repository->createQueryBuilder('e')->where('e.id IN (1, 2)');
$entityType = new EntityType(
$this->emRegistry,
PropertyAccess::createPropertyAccessor()
);
$entityTypeGuesser = new DoctrineOrmTypeGuesser($this->emRegistry);
$factory = Forms::createFormFactoryBuilder()
->addType($entityType)
->addTypeGuesser($entityTypeGuesser)
->getFormFactory();
$formBuilder = $factory->createNamedBuilder('form', 'form');
$formBuilder->add('property1', 'entity', array(
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
'query_builder' => $qb,
));
$formBuilder->add('property2', 'entity', array(
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
'query_builder' => $qb,
));
$formBuilder->add('property3', 'entity', array(
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
'query_builder' => $qb,
));
$form = $formBuilder->getForm();
$form->submit(array(
'property1' => 1,
'property2' => 1,
'property3' => 2,
));
$reflectionClass = new \ReflectionObject($entityType);
$reflectionProperty = $reflectionClass->getProperty('loaderCache');
$reflectionProperty->setAccessible(true);
$loaders = $reflectionProperty->getValue($entityType);
$reflectionProperty->setAccessible(false);
$this->assertCount(1, $loaders);
}
protected function createRegistryMock($name, $em) protected function createRegistryMock($name, $em)
{ {
$registry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry'); $registry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry');
$registry->expects($this->any()) $registry->expects($this->any())
->method('getManager') ->method('getManager')
->with($this->equalTo($name)) ->with($this->equalTo($name))
->will($this->returnValue($em)); ->will($this->returnValue($em));
return $registry; return $registry;
} }