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);
}
Was it helpful?

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
scroll top