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..8902042579db1 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Form/DataTransformer/OneEntityToIdTransformer.php @@ -0,0 +1,111 @@ + + * + * 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 Symfony\Component\Form\Exception\FormException; +use Symfony\Component\Form\Util\PropertyPath; + +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\NoResultException; + +class OneEntityToIdTransformer implements DataTransformerInterface +{ + private $em; + private $class; + private $property; + private $queryBuilder; + + private $unitOfWork; + + public function __construct(EntityManager $em, $class, $property, $queryBuilder) + { + if (null !== $queryBuilder && ! $queryBuilder instanceof \Closure) { + throw new UnexpectedTypeException($queryBuilder, '\Closure'); + } + + if (null === $class) { + throw new UnexpectedTypeException($class, 'string'); + } + + $this->em = $em; + $this->unitOfWork = $em->getUnitOfWork(); + $this->class = $class; + $this->queryBuilder = $queryBuilder; + + if ($property) { + $this->property = $property; + } + } + + /** + * Fetch the id of the entity to populate the form + */ + public function transform($data) + { + if (null === $data) { + return null; + } + if (!$this->unitOfWork->isInIdentityMap($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)); + } + + /** + * Try to fetch the entity from its id in the database + */ + public function reverseTransform($data) + { + if (!$data) { + return null; + } + + $em = $this->em; + $repository = $em->getRepository($this->class); + + if ($qb = $this->queryBuilder) { + // Call the closure with the repository and the id + $qb = $qb($repository, $data); + + try { + $result = $qb->getQuery()->getSingleResult(); + } catch (NoResultException $e) { + $result = null; + } + } else { + // Defaults to find() + if ($this->property) { + $result = $repository->findOneBy(array($this->property => $data)); + } else { + $result = $repository->find($data); + } + } + + if (!$result) { + throw new TransformationFailedException('Can not find entity'); + } + + return $result; + } +} + diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdentifierType.php b/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdentifierType.php new file mode 100644 index 0000000000000..61364272ed30c --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Form/Type/EntityIdentifierType.php @@ -0,0 +1,68 @@ + + * + * 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; +use Symfony\Component\Form\Exception\FormException; + +class EntityIdentifierType extends AbstractType +{ + protected $registry; + + public function __construct(RegistryInterface $registry) + { + $this->registry = $registry; + } + + public function buildForm(FormBuilder $builder, array $options) + { + $builder->prependClientTransformer(new OneEntityToIdTransformer( + $this->registry->getEntityManager($options['em']), + $options['class'], + $options['property'], + $options['query_builder'] + )); + } + + public function getDefaultOptions(array $options) + { + $defaultOptions = array( + 'required' => true, + 'em' => null, + 'class' => null, + 'query_builder' => null, + 'property' => null, + 'hidden' => true + ); + + $options = array_replace($defaultOptions, $options); + + if (null === $options['class']) { + throw new FormException('You must provide a class option for the entity_identifier field'); + } + + return $defaultOptions; + } + + public function getParent(array $options) + { + return $options['hidden'] ? 'hidden' : 'field'; + } + + public function getName() + { + return 'entity_identifier'; + } +} diff --git a/src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml b/src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml index 85e1e7153a81a..59ed227d810b7 100644 --- a/src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml +++ b/src/Symfony/Bundle/DoctrineBundle/Resources/config/orm.xml @@ -58,6 +58,11 @@ + + + + +