Skip to content

Instantly share code, notes, and snippets.

@lologhi
Last active October 26, 2015 01:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lologhi/bb900f061f8205841f6a to your computer and use it in GitHub Desktop.
Save lologhi/bb900f061f8205841f6a to your computer and use it in GitHub Desktop.
Entity choicelist without bringing the whole entity (thx to @winzou)
<?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';
}
}
<?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');
}
}
<?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());
})
;
}
}
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