From 05a064a93ba0029357d734ba147fca22e11f8921 Mon Sep 17 00:00:00 2001 From: Gregwar Date: Fri, 12 Aug 2011 19:03:13 +0200 Subject: [PATCH 1/8] [Form] Added the entity_id type (#1946) --- .../OneEntityToIdTransformer.php | 97 +++++++++++++++++++ .../Doctrine/Form/Type/EntityIdType.php | 59 +++++++++++ .../DoctrineBundle/Resources/config/orm.xml | 5 + 3 files changed, 161 insertions(+) create mode 100755 src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php create mode 100644 src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php diff --git a/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php b/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php new file mode 100755 index 0000000000000..125cf3a7d72d8 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Form\DataTransformer; + +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\DataTransformerInterface; +use Symfony\Component\Form\FormError; +use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Exception\UnexpectedTypeException; + +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\NoResultException; + +class OneEntityToIdTransformer implements DataTransformerInterface +{ + private $em; + private $class; + private $queryBuilder; + + public function __construct(EntityManager $em, $class, $queryBuilder) + { + if (!(null === $queryBuilder || $queryBuilder instanceof \Closure)) { + throw new UnexpectedTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder or \Closure'); + } + + if (null == $class) + throw new UnexpectedTypeException($class, 'string'); + + $this->em = $em; + $this->class = $class; + $this->queryBuilder = $queryBuilder; + } + + /** + * Fetch the id of the entity to populate the form + */ + public function transform($data) + { + if (null === $data) + return null; + + $meta = $this->em->getClassMetadata($this->class); + + if (!$meta->getReflectionClass()->isInstance($data)) + throw new TransformationFailedException('Invalid data, must be an instance of '.$this->class); + + $identifierField = $meta->getSingleIdentifierFieldName(); + $id = $meta->getReflectionProperty($identifierField)->getValue($data); + + return $id; + } + + /** + * Try to fetch the entity from its id in the database + */ + public function reverseTransform($data) + { + if (!$data) { + return null; + } + + $em = $this->em; + $class = $this->class; + $repository = $em->getRepository($class); + + if ($qb = $this->queryBuilder) { + // If a closure was passed, call id with the repository and the id + if ($qb instanceof \Closure) { + $qb = $qb($repository, $data); + } + + try { + $result = $qb->getQuery()->getSingleResult(); + } catch (NoResultException $e) { + $result = null; + } + } else { + // Defaults to find() + $result = $repository->find($data); + } + + if (!$result) + throw new TransformationFailedException('Can not find entity'); + + return $result; + } +} + diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php b/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php new file mode 100644 index 0000000000000..9ab750fb31814 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Form\Type; + +use Symfony\Component\Form\FormBuilder; +use Symfony\Bridge\Doctrine\RegistryInterface; +use Symfony\Bridge\Doctrine\Form\DataTransformer\OneEntityToIdTransformer; +use Symfony\Component\Form\AbstractType; + +class EntityIdType extends AbstractType +{ + protected $em; + + public function __construct(RegistryInterface $registry) + { + $this->em = $registry->getEntityManager(); + } + + public function buildForm(FormBuilder $builder, array $options) + { + $em = $options['em'] ?: $this->em; + + $builder->prependClientTransformer(new OneEntityToIdTransformer($em, $options['class'], $options['query_builder'])); + } + + public function getDefaultOptions(array $options) + { + $defaultOptions = array( + 'required' => true, + 'em' => null, + 'class' => null, + 'query_builder' => null, + 'hidden' => true + ); + + $options = array_replace($defaultOptions, $options); + + return $defaultOptions; + } + + public function getParent(array $options) + { + return $options['hidden'] ? 'hidden' : 'field'; + } + + public function getName() + { + return 'entity_id'; + } +} diff --git a/src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml b/src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml index 85e1e7153a81a..9f0a108e9ea38 100644 --- a/src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml +++ b/src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml @@ -58,6 +58,11 @@ + + + + + From 662691af9875c96f7807bdb260c1a6f20bb703b9 Mon Sep 17 00:00:00 2001 From: Gregwar Date: Mon, 15 Aug 2011 21:33:34 +0200 Subject: [PATCH 2/8] [Form] Fixing coding standard problems (see PR #1951) --- .../OneEntityToIdTransformer.php | 17 ++++++++++------- .../Bridge/Doctrine/Form/Type/EntityIdType.php | 12 +++++++----- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php b/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php index 125cf3a7d72d8..2cbae573a5b27 100755 --- a/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php +++ b/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php @@ -28,12 +28,13 @@ class OneEntityToIdTransformer implements DataTransformerInterface public function __construct(EntityManager $em, $class, $queryBuilder) { - if (!(null === $queryBuilder || $queryBuilder instanceof \Closure)) { + if (null !== $queryBuilder && ! $queryBuilder instanceof \Closure) { throw new UnexpectedTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder or \Closure'); } - if (null == $class) + if (null === $class) { throw new UnexpectedTypeException($class, 'string'); + } $this->em = $em; $this->class = $class; @@ -45,13 +46,15 @@ public function __construct(EntityManager $em, $class, $queryBuilder) */ public function transform($data) { - if (null === $data) + if (null === $data) { return null; + } $meta = $this->em->getClassMetadata($this->class); - if (!$meta->getReflectionClass()->isInstance($data)) + if (!$meta->getReflectionClass()->isInstance($data)) { throw new TransformationFailedException('Invalid data, must be an instance of '.$this->class); + } $identifierField = $meta->getSingleIdentifierFieldName(); $id = $meta->getReflectionProperty($identifierField)->getValue($data); @@ -69,8 +72,7 @@ public function reverseTransform($data) } $em = $this->em; - $class = $this->class; - $repository = $em->getRepository($class); + $repository = $em->getRepository($this->class); if ($qb = $this->queryBuilder) { // If a closure was passed, call id with the repository and the id @@ -88,8 +90,9 @@ public function reverseTransform($data) $result = $repository->find($data); } - if (!$result) + if (!$result) { throw new TransformationFailedException('Can not find entity'); + } return $result; } diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php b/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php index 9ab750fb31814..87f068f115bf8 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php @@ -18,18 +18,20 @@ class EntityIdType extends AbstractType { - protected $em; + protected $registry; public function __construct(RegistryInterface $registry) { - $this->em = $registry->getEntityManager(); + $this->registry = $registry; } public function buildForm(FormBuilder $builder, array $options) { - $em = $options['em'] ?: $this->em; - - $builder->prependClientTransformer(new OneEntityToIdTransformer($em, $options['class'], $options['query_builder'])); + $builder->prependClientTransformer(new OneEntityToIdTransformer( + $this->registry->getEntityManager($options['em']), + $options['class'], + $options['query_builder'] + )); } public function getDefaultOptions(array $options) From 4a62fc3a70353bcc609f1c7cb06217983c91a553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Passault?= Date: Tue, 16 Aug 2011 12:17:50 +0200 Subject: [PATCH 3/8] [Form] Changes the way the identifier is retrieved --- .../DataTransformer/OneEntityToIdTransformer.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php b/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php index 2cbae573a5b27..a300fd7656b3c 100755 --- a/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php +++ b/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php @@ -16,6 +16,7 @@ use Symfony\Component\Form\FormError; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\UnexpectedTypeException; +use Symfony\Component\Form\Exception\FormException; use Doctrine\ORM\EntityManager; use Doctrine\ORM\NoResultException; @@ -26,6 +27,8 @@ class OneEntityToIdTransformer implements DataTransformerInterface private $class; private $queryBuilder; + private $unitOfWork; + public function __construct(EntityManager $em, $class, $queryBuilder) { if (null !== $queryBuilder && ! $queryBuilder instanceof \Closure) { @@ -37,6 +40,7 @@ public function __construct(EntityManager $em, $class, $queryBuilder) } $this->em = $em; + $this->unitOfWork = $em->getUnitOfWork(); $this->class = $class; $this->queryBuilder = $queryBuilder; } @@ -49,17 +53,11 @@ public function transform($data) if (null === $data) { return null; } - - $meta = $this->em->getClassMetadata($this->class); - - if (!$meta->getReflectionClass()->isInstance($data)) { - throw new TransformationFailedException('Invalid data, must be an instance of '.$this->class); + if (!$this->unitOfWork->isInIdentityMap($data)) { + throw new FormException('Entities passed to the choice field must be managed'); } - $identifierField = $meta->getSingleIdentifierFieldName(); - $id = $meta->getReflectionProperty($identifierField)->getValue($data); - - return $id; + return current($this->unitOfWork->getEntityIdentifier($data)); } /** From 6f110756179921e2567854ded94416127e890e0f Mon Sep 17 00:00:00 2001 From: Gregwar Date: Tue, 16 Aug 2011 22:01:57 +0200 Subject: [PATCH 4/8] [Form] Added support of "property" on the "entity_id" type --- .../OneEntityToIdTransformer.php | 19 +++++++++++++++++-- .../Doctrine/Form/Type/EntityIdType.php | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php b/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php index a300fd7656b3c..4e1ebecb6d923 100755 --- a/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php +++ b/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php @@ -17,6 +17,7 @@ use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Exception\FormException; +use Symfony\Component\Form\Util\PropertyPath; use Doctrine\ORM\EntityManager; use Doctrine\ORM\NoResultException; @@ -25,11 +26,12 @@ class OneEntityToIdTransformer implements DataTransformerInterface { private $em; private $class; + private $property; private $queryBuilder; private $unitOfWork; - public function __construct(EntityManager $em, $class, $queryBuilder) + public function __construct(EntityManager $em, $class, $property, $queryBuilder) { if (null !== $queryBuilder && ! $queryBuilder instanceof \Closure) { throw new UnexpectedTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder or \Closure'); @@ -43,6 +45,10 @@ public function __construct(EntityManager $em, $class, $queryBuilder) $this->unitOfWork = $em->getUnitOfWork(); $this->class = $class; $this->queryBuilder = $queryBuilder; + + if ($property) { + $this->property = $property; + } } /** @@ -57,6 +63,11 @@ public function transform($data) throw new FormException('Entities passed to the choice field must be managed'); } + if ($this->property) { + $propertyPath = new PropertyPath($this->property); + return $propertyPath->getValue($data); + } + return current($this->unitOfWork->getEntityIdentifier($data)); } @@ -85,7 +96,11 @@ public function reverseTransform($data) } } else { // Defaults to find() - $result = $repository->find($data); + if ($this->property) { + $result = $repository->findOneBy(array($this->property => $data)); + } else { + $result = $repository->find($data); + } } if (!$result) { diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php b/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php index 87f068f115bf8..aeee04245207d 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php @@ -30,6 +30,7 @@ public function buildForm(FormBuilder $builder, array $options) $builder->prependClientTransformer(new OneEntityToIdTransformer( $this->registry->getEntityManager($options['em']), $options['class'], + $options['property'], $options['query_builder'] )); } @@ -41,6 +42,7 @@ public function getDefaultOptions(array $options) 'em' => null, 'class' => null, 'query_builder' => null, + 'property' => null, 'hidden' => true ); From 0802d83b891b35730aad12db28dbd21c89a39ceb Mon Sep 17 00:00:00 2001 From: Gregwar Date: Sun, 21 Aug 2011 19:29:01 +0200 Subject: [PATCH 5/8] Added a RuntimeException when no class is provided --- src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php b/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php index aeee04245207d..ad517e69d932d 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php @@ -48,6 +48,10 @@ public function getDefaultOptions(array $options) $options = array_replace($defaultOptions, $options); + if (null === $options['class']) { + throw new \RunTimeException('You must provide a class option for the entity_id field'); + } + return $defaultOptions; } From 295bd6d34c788e5b669011515470168e24cb09c2 Mon Sep 17 00:00:00 2001 From: Gregwar Date: Sun, 21 Aug 2011 20:04:02 +0200 Subject: [PATCH 6/8] [Form] Using FormException instead of RuntimeException for entity_id --- src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php b/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php index ad517e69d932d..6d7f53f66c93f 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php @@ -15,6 +15,7 @@ use Symfony\Bridge\Doctrine\RegistryInterface; use Symfony\Bridge\Doctrine\Form\DataTransformer\OneEntityToIdTransformer; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Exception\FormException; class EntityIdType extends AbstractType { @@ -49,7 +50,7 @@ public function getDefaultOptions(array $options) $options = array_replace($defaultOptions, $options); if (null === $options['class']) { - throw new \RunTimeException('You must provide a class option for the entity_id field'); + throw new FormException('You must provide a class option for the entity_id field'); } return $defaultOptions; From 38713e2552ece9e56dbddc3d934b503fecca5344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Passault?= Date: Tue, 23 Aug 2011 11:20:20 +0200 Subject: [PATCH 7/8] [Form] Renamed field type name "entity_id" to "entity_identifier" --- .../Type/{EntityIdType.php => EntityIdentifierType.php} | 6 +++--- src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/Symfony/Bridge/Doctrine/Form/Type/{EntityIdType.php => EntityIdentifierType.php} (93%) diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php b/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdentifierType.php similarity index 93% rename from src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php rename to src/Symfony/Bridge/Doctrine/Form/Type/EntityIdentifierType.php index 6d7f53f66c93f..61364272ed30c 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdentifierType.php @@ -17,7 +17,7 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Exception\FormException; -class EntityIdType extends AbstractType +class EntityIdentifierType extends AbstractType { protected $registry; @@ -50,7 +50,7 @@ public function getDefaultOptions(array $options) $options = array_replace($defaultOptions, $options); if (null === $options['class']) { - throw new FormException('You must provide a class option for the entity_id field'); + throw new FormException('You must provide a class option for the entity_identifier field'); } return $defaultOptions; @@ -63,6 +63,6 @@ public function getParent(array $options) public function getName() { - return 'entity_id'; + return 'entity_identifier'; } } diff --git a/src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml b/src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml index 9f0a108e9ea38..59ed227d810b7 100644 --- a/src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml +++ b/src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml @@ -58,8 +58,8 @@ - - + + From fc400f54c7e50b80b245cf88e4d707fd92cba2ac Mon Sep 17 00:00:00 2001 From: Gregwar Date: Mon, 17 Oct 2011 09:42:31 +0200 Subject: [PATCH 8/8] [Form] OneEntityToIdTransformer, fixing problems with QueryBuilder type --- .../Form/DataTransformer/OneEntityToIdTransformer.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php b/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php index 4e1ebecb6d923..8902042579db1 100755 --- a/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php +++ b/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php @@ -34,7 +34,7 @@ class OneEntityToIdTransformer implements DataTransformerInterface public function __construct(EntityManager $em, $class, $property, $queryBuilder) { if (null !== $queryBuilder && ! $queryBuilder instanceof \Closure) { - throw new UnexpectedTypeException($queryBuilder, 'Doctrine\ORM\QueryBuilder or \Closure'); + throw new UnexpectedTypeException($queryBuilder, '\Closure'); } if (null === $class) { @@ -84,10 +84,8 @@ public function reverseTransform($data) $repository = $em->getRepository($this->class); if ($qb = $this->queryBuilder) { - // If a closure was passed, call id with the repository and the id - if ($qb instanceof \Closure) { - $qb = $qb($repository, $data); - } + // Call the closure with the repository and the id + $qb = $qb($repository, $data); try { $result = $qb->getQuery()->getSingleResult();