Form validation - Override loading of an entity field
-
21-12-2019 - |
Question
I'm building a REST API based on FOSRestBundle. In order to create some entities, the consumer sends the following JSON in a POST HTTP request:
{
"myentity":
{
"field1": "field1 value",
"field2": "field2 value",
"user": 1,
"createdAt": {"date":{"year":"2012", "month":"11", "day":"8"}, "time":{"hour":"13","minute":"22"}}
}
}
The field user contains the id of the user. I want to change it by the user email or phone number. I'm trying to figure out how can I create an instance of the entity user and passe it to myentity instance.
Here is a sample code of my form:
<?php
namespace Acme\DemoBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class MyFormType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('field1')
->add('field2')
->add('createdAt')
->add('user');
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\DemoBundle\Entity\MyEntity',
'csrf_protection' => false
));
}
/**
* @return string
*/
public function getName()
{
return 'myform';
}
}
And this is how I validate data provided by the API consumer:
/**
* @Rest\View
*/
public function saveAction()
{
return $this->processForm(new MyEntity());
}
/**
* @Rest\View
*/
private function processForm(MyEntity $myEntity)
{
$form = $this->createForm(new MyFormType(), $myEntity);
$form->bind($this->getRequest());
if ($form->isValid()) {
//$position->save();
$response = new Response();
$response->setStatusCode(204);
return $response;
}
return $this->view($form, 400);
}
Solution
Solved!
I used a DataTransformer: http://symfony.com/en/doc/current/cookbook/form/data_transformers.html
You have to create a DataTransformer:
<?php
namespace Acme\DemoBundle\Form;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Doctrine\Common\Persistence\ObjectManager;
use Acme\DemoBundle\Entity\User;
class PhoneNumberToUserTransformer implements DataTransformerInterface {
/**
* @var ObjectManager
*/
private $om;
/**
* @param ObjectManager $om
*/
public function __construct(ObjectManager $om) {
$this->om = $om;
}
/**
* Transforms an object (User) to a string (phonenumber).
*
* @param User|null $issue
* @return string
*/
public function transform($user) {
if (null === $user) {
return "";
}
return $user->getPhonenumber();
}
/**
* Transforms a string (phonenumber) to an object (User).
*
* @param string $phonenumber
* @return User|null
* @throws TransformationFailedException if object (user) is not found.
*/
public function reverseTransform($phonenumber) {
if (!$phonenumber) {
return null;
}
$user = $this->om
->getRepository('AcmeDemoBundle:User')
->findOneBy(array('phonenumber' => $phonenumber))
;
if (null === $user) {
throw new TransformationFailedException(sprintf(
'L\'utilisateur avec le numéro "%s" ne peut pas être trouvé!', $phonenumber
));
}
return $user;
}
}
?>
In the Form definition:
public function buildForm(FormBuilderInterface $builder, array $options) {
$entityManager = $options['em'];
$transformer = new PhoneNumberToUserTransformer($entityManager);
$builder
->add('field1')
->add('field2')
->add('createdAt')
->add($builder->create('user', 'text')->addModelTransformer($transformer));
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'Acme\DemoBundle\Entity\MyEntity',
'csrf_protection' => false,
'em' => null
));
}
And finally in the controller:
$form = $this->createForm(new MyFormType(), $myentity, array(
'em' => $this->getDoctrine()->getManager()
));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow