Let there be two entities (correctly mapped for Doctrine).
Post
with properties {$id
(integer, autoinc), $name>
I took a slightly different approach using Select2's tag input:
It has the advantage that it prevents duplicates on the client side and looks pretty.
To create the newly added entities, I am using a EventSubscriber rather than a DataTransformer.
For a few more details, see my gist. Below are the TagType and the AddEntityChoiceSubscriber.
AppBundle/Form/Type/TagType:
addEventSubscriber($subscriber);
}
/**
* {@inheritdoc}
*/
public function getParent()
{
return EntityType::class;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'tag';
}
}
AppBundle/Form/EventListener/AddEntityChoiceSubscriber:
em = $em;
$this->entityName = $entityName;
}
public static function getSubscribedEvents()
{
return [
FormEvents::PRE_SUBMIT => 'preSubmit',
];
}
public function preSubmit(FormEvent $event)
{
$data = $event->getData();
if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
$data = [];
}
// loop through all values
$repository = $this->em->getRepository($this->entityName);
$choices = array_map('strval', $repository->findAll());
$className = $repository->getClassName();
$newChoices = [];
foreach($data as $key => $choice) {
// if it's numeric we consider it the primary key of an existing choice
if(is_numeric($choice) || in_array($choice, $choices)) {
continue;
}
$entity = new $className($choice);
$newChoices[] = $entity;
$this->em->persist($entity);
}
$this->em->flush();
// now we need to replace the text values with their new primary key
// otherwise, the newly added choice won't be marked as selected
foreach($newChoices as $newChoice) {
$key = array_search($newChoice->__toString(), $data);
$data[$key] = $newChoice->getId();
}
$event->setData($data);
}
}