Just made this on Symfony 3 and realised it's a bit different from what has already been posted here so I figured it was worth sharing.
I just made a generic data transformer that could be easily reusable across all your form types. You just have to pass in your form type and that's it. No need to create a custom form type.
First of all let's take a look at the data transformer:
<?php
namespace AppBundle\Form;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
/**
* Class EntityHiddenTransformer
*
* @package AppBundle\Form
* @author Francesco Casula <fra.casula@gmail.com>
*/
class EntityHiddenTransformer implements DataTransformerInterface
{
/**
* @var ObjectManager
*/
private $objectManager;
/**
* @var string
*/
private $className;
/**
* @var string
*/
private $primaryKey;
/**
* EntityHiddenType constructor.
*
* @param ObjectManager $objectManager
* @param string $className
* @param string $primaryKey
*/
public function __construct(ObjectManager $objectManager, $className, $primaryKey)
{
$this->objectManager = $objectManager;
$this->className = $className;
$this->primaryKey = $primaryKey;
}
/**
* @return ObjectManager
*/
public function getObjectManager()
{
return $this->objectManager;
}
/**
* @return string
*/
public function getClassName()
{
return $this->className;
}
/**
* @return string
*/
public function getPrimaryKey()
{
return $this->primaryKey;
}
/**
* Transforms an object (entity) to a string (number).
*
* @param object|null $entity
*
* @return string
*/
public function transform($entity)
{
if (null === $entity) {
return '';
}
$method = 'get' . ucfirst($this->getPrimaryKey());
// Probably worth throwing an exception if the method doesn't exist
// Note: you can always use reflection to get the PK even though there's no public getter for it
return $entity->$method();
}
/**
* Transforms a string (number) to an object (entity).
*
* @param string $identifier
*
* @return object|null
* @throws TransformationFailedException if object (entity) is not found.
*/
public function reverseTransform($identifier)
{
if (!$identifier) {
return null;
}
$entity = $this->getObjectManager()
->getRepository($this->getClassName())
->find($identifier);
if (null === $entity) {
// causes a validation error
// this message is not shown to the user
// see the invalid_message option
throw new TransformationFailedException(sprintf(
'An entity with ID "%s" does not exist!',
$identifier
));
}
return $entity;
}
}
So the idea is that you call it by passing the object manager there, the entity that you want to use and then the field name to get the entity ID.
Basically like this:
new EntityHiddenTransformer(
$this->getObjectManager(),
Article::class, // in your case this would be FoodAnalytics\Recipe::class
'articleId' // I guess this for you would be recipeId?
)
Let's put it all together now. We just need the form type and a bit of YAML configuration and then we're good to go.
<?php
namespace AppBundle\Form;
use AppBundle\Entity\Article;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Class JustAFormType
*
* @package AppBundle\CmsBundle\Form
* @author Francesco Casula <fra.casula@gmail.com>
*/
class JustAFormType extends AbstractType
{
/**
* @var ObjectManager
*/
private $objectManager;
/**
* JustAFormType constructor.
*
* @param ObjectManager $objectManager
*/
public function __construct(ObjectManager $objectManager)
{
$this->objectManager = $objectManager;
}
/**
* @return ObjectManager
*/
public function getObjectManager()
{
return $this->objectManager;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('article', HiddenType::class)
->add('save', SubmitType::class);
$builder
->get('article')
->addModelTransformer(new EntityHiddenTransformer(
$this->getObjectManager(),
Article::class,
'articleId'
));
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\MyEntity',
]);
}
}
And then in your services.yml
file:
app.form.type.article:
class: AppBundle\Form\JustAFormType
arguments: ["@doctrine.orm.entity_manager"]
tags:
- { name: form.type }
And in your controller:
$form = $this->createForm(JustAFormType::class, new MyEntity());
$form->handleRequest($request);
That's it :-)