Last active
October 26, 2015 01:42
-
-
Save lologhi/bb900f061f8205841f6a to your computer and use it in GitHub Desktop.
Entity choicelist without bringing the whole entity (thx to @winzou)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace CommonBundle\Form; | |
use CommonBundle\Form\Transformer\EntityToIdTransformer; | |
use Doctrine\Bundle\DoctrineBundle\Registry; | |
use Doctrine\Common\Persistence\ManagerRegistry; | |
use Doctrine\Common\Persistence\ObjectManager; | |
use Symfony\Component\Form\AbstractType; | |
use Symfony\Component\Form\FormBuilderInterface; | |
use Symfony\Component\OptionsResolver\Options; | |
use Symfony\Component\OptionsResolver\OptionsResolver; | |
class EntityChoiceType extends AbstractType | |
{ | |
/** | |
* @var Registry | |
*/ | |
private $registry; | |
public function __construct(Registry $registry) | |
{ | |
$this->registry = $registry; | |
} | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder->addModelTransformer( | |
new EntityToIdTransformer($options['em']->getRepository($options['class'])) | |
); | |
} | |
public function configureOptions(OptionsResolver $resolver) | |
{ | |
$registry = $this->registry; | |
$resolver->setDefaults(array( | |
'empty_value' => false, | |
'empty_data' => null, | |
'em' => null, | |
'query_builder' => null, | |
'field' => 'id', | |
)); | |
$resolver->setRequired(array( | |
'class' | |
)); | |
$resolver->setDefault('choices', function (Options $options) use ($registry) { | |
if (null === $options['query_builder']) { | |
$results = $options['em'] | |
->createQueryBuilder() | |
->select('e.id', 'e.'.$options['field']) | |
->from($options['class'], 'e', 'e.id') | |
->orderBy('e.'.$options['field'], 'ASC') | |
->getQuery() | |
->getArrayResult() | |
; | |
} else { | |
$results = $options['query_builder'] | |
->getQuery() | |
->getArrayResult() | |
; | |
} | |
return array_map( | |
function($value) { | |
return end($value); | |
}, $results | |
); | |
}); | |
$queryBuilderNormalizer = function (Options $options, $queryBuilder) { | |
if (is_callable($queryBuilder)) { | |
$queryBuilder = call_user_func($queryBuilder, $options['em']->getRepository($options['class'])); | |
} | |
return $queryBuilder; | |
}; | |
$emNormalizer = function (Options $options, $em) use ($registry) { | |
/* @var ManagerRegistry $registry */ | |
if (null !== $em) { | |
if ($em instanceof ObjectManager) { | |
return $em; | |
} | |
return $registry->getManager($em); | |
} | |
$em = $registry->getManagerForClass($options['class']); | |
if (null === $em) { | |
throw new \Exception(sprintf( | |
'Class "%s" seems not to be a managed Doctrine entity. '. | |
'Did you forget to map it?', | |
$options['class'] | |
)); | |
} | |
return $em; | |
}; | |
$resolver->setNormalizer('em', $emNormalizer); | |
$resolver->setNormalizer('query_builder', $queryBuilderNormalizer); | |
} | |
public function getParent() | |
{ | |
return 'choice'; | |
} | |
public function getName() | |
{ | |
return 'entity_choice'; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace CommonBundle\Form\Transformer; | |
use Doctrine\Common\Persistence\ObjectRepository; | |
use Symfony\Component\Form\DataTransformerInterface; | |
use Symfony\Component\Form\Exception\TransformationFailedException; | |
class EntityToIdTransformer implements DataTransformerInterface | |
{ | |
private $entityRepository; | |
public function __construct(ObjectRepository $entityRepository) | |
{ | |
$this->entityRepository = $entityRepository; | |
} | |
/** | |
* @param object|array $entity | |
* @return int|int[] | |
* | |
* @throws TransformationFailedException | |
*/ | |
public function transform($entity) | |
{ | |
if ($entity === null) { | |
return null; | |
} elseif (is_array($entity) || $entity instanceof \Doctrine\ORM\PersistentCollection) { | |
$ids = array(); | |
foreach ($entity as $subEntity) { | |
$ids[] = $subEntity->getId(); | |
} | |
return $ids; | |
} elseif (is_object($entity)) { | |
return $entity->getId(); | |
} | |
throw new TransformationFailedException((is_object($entity)? get_class($entity) : '').'('.gettype($entity).') is not a valid class for EntityToIdTransformer'); | |
} | |
/** | |
* @param int|array $id | |
* @return object|object[] | |
* | |
* @throws TransformationFailedException | |
*/ | |
public function reverseTransform($id) | |
{ | |
if ($id === null) { | |
return null; | |
} elseif (is_numeric($id)) { | |
$entity = $this->entityRepository->findOneBy(array('id' => $id)); | |
if ($entity === null) { | |
throw new TransformationFailedException('A '.$this->entityRepository->getClassName().' with id #'.$id.' does not exist!'); | |
} | |
return $entity; | |
} elseif (is_array($id)) { | |
if (empty($id)) { | |
return array(); | |
} | |
$entities = $this->entityRepository->findBy(array('id' => $id)); // its array('id' => array(...)), resulting in many entities!! | |
if (count($id) != count($entities)) { | |
throw new TransformationFailedException('Some '.$this->entityRepository->getClassName().' with ids #'.implode(', ', $id).' do not exist!'); | |
} | |
return $entities; | |
} | |
throw new TransformationFailedException(gettype($id).' is not a valid type for EntityToIdTransformer'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace MyBundle\Form; | |
use Symfony\Component\Form\AbstractType; | |
use Symfony\Component\Form\FormBuilderInterface; | |
use Symfony\Component\Form\FormEvent; | |
use Symfony\Component\Form\FormEvents; | |
use Symfony\Component\Form\FormInterface; | |
use Symfony\Component\OptionsResolver\OptionsResolver; | |
class MyFormType extends AbstractType | |
{ | |
public function buildForm(FormBuilderInterface $builder, array $options) | |
{ | |
$builder | |
->add('thing', 'entity_choice', array( | |
'class' => 'MyBundle:MyEntity', | |
'field' => 'my_entity_name', | |
)) | |
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options) { | |
/** @var Request $request */ | |
$request = $event->getData(); | |
$thing = (null !== $request && null !== $request->getThing()) ? $request->getThing() : null; | |
$this->addThingFields($event->getForm(), $options, $thing); | |
}) | |
; | |
$builder->get('thing')->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use ($options) { | |
$this->addThingFields($event->getForm()->getParent(), $options, $event->getForm()->getData()); | |
}) | |
; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
services: | |
common.form.entity_choice: | |
class: CommonBundle\Form\EntityChoiceType | |
arguments: | |
- @doctrine | |
tags: | |
- { name: form.type, alias: entity_choice } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment