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;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader;
class EntityType extends DoctrineType
{
/**
* @var ORMQueryBuilderLoader[]
*/
private $loaderCache = array();
/**
* Return the default loader object.
*
@ -27,11 +33,55 @@ class EntityType extends DoctrineType
*/
public function getLoader(ObjectManager $manager, $queryBuilder, $class)
{
return new ORMQueryBuilderLoader(
$queryBuilder,
$manager,
$class
);
if (!$queryBuilder instanceof QueryBuilder) {
return new ORMQueryBuilderLoader(
$queryBuilder,
$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()

View File

@ -11,7 +11,11 @@
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\Component\Form\FormBuilder;
use Symfony\Component\Form\Forms;
use Symfony\Component\Form\Test\TypeTestCase;
use Symfony\Bridge\Doctrine\Tests\Fixtures\GroupableEntity;
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity;
@ -22,6 +26,7 @@ use Symfony\Bridge\Doctrine\Form\DoctrineOrmExtension;
use Doctrine\ORM\Tools\SchemaTool;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Form\Extension\Core\View\ChoiceView;
use Symfony\Component\PropertyAccess\PropertyAccess;
class EntityTypeTest extends TypeTestCase
{
@ -656,7 +661,7 @@ class EntityTypeTest extends TypeTestCase
'class' => self::SINGLE_IDENT_CLASS,
'query_builder' => function ($repository) {
return $repository->createQueryBuilder('e')
->where('e.id IN (1, 2)');
->where('e.id IN (1, 2)');
},
'property' => 'name',
));
@ -680,7 +685,7 @@ class EntityTypeTest extends TypeTestCase
'class' => self::COMPOSITE_IDENT_CLASS,
'query_builder' => function ($repository) {
return $repository->createQueryBuilder('e')
->where('e.id1 IN (10, 50)');
->where('e.id1 IN (10, 50)');
},
'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)
{
$registry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry');
$registry->expects($this->any())
->method('getManager')
->with($this->equalTo($name))
->will($this->returnValue($em));
->method('getManager')
->with($this->equalTo($name))
->will($this->returnValue($em));
return $registry;
}