Search code examples
validationrestsymfonytimestampfosrestbundle

Symfony2 FOSRestBundle timestamp validation fails


I'm trying to send a post request including two timestamps to my REST api. The problem is that the timestamps are marked as invalid. "This value is not valid."

What am I doing wrong?

This is the request:

POST http://localhost:8000/app_test.php/api/projects/1/tasks/1/timetrackings

Accept: application/json 
Content-Type: application/json

{"timeStart":1390757625,"timeEnd":1390757625,"projectMember":1}

The Controller looks as follows:

class MemberController extends BaseApiController implements ClassResourceInterface
{
    public function postAction($projectId, $taskId, Request $request)
    {
        /** @var EntityManager $em */
        $em = $this->getDoctrine()->getManager();
        $this->findProject($em, $projectId);
        $task = $this->findTask($em, $projectId, $taskId);

        $request->request->add(array(
            'task' => $taskId,
        ));
        $form = $this->createForm(new TimeTrackType(), new TimeTrack());
        $form->submit($request->request->all());
        if ($form->isValid())
        {
            /** @var TimeTrack $tracking */
            $tracking = $form->getData();
            $task->addTimeTrack($tracking);
            $em->flush();
            return $this->redirectView(
                $this->generateUrl('api_get_project_task_timetracking', array(
                    'projectId'  => $projectId,
                    'taskId'     => $taskId,
                    'trackingId' => $tracking->getId(),
                )),
                Codes::HTTP_CREATED
            );
        }
        return View::create($form, Codes::HTTP_BAD_REQUEST);
    }
}

The TimeTrackType class:

namespace PMTool\ApiBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class TimeTrackType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('timeStart', 'datetime', array(
                'input' => 'timestamp',
            ))
            ->add('timeEnd', 'datetime', array(
                'input' => 'timestamp',
            ))
            ->add('projectMember')
            ->add('task')
        ;
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'PMTool\ApiBundle\Entity\TimeTrack',
            'csrf_protection' => false,
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'timetrack';
    }
}

The entity class:

namespace PMTool\ApiBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use \DateTime;

/**
 * TimeTrack
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="PMTool\ApiBundle\Entity\TimeTrackRepository")
 */
class TimeTrack
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var DateTime
     *
     * @ORM\Column(name="timeStart", type="datetime")
     */
    private $timeStart;

    /**
     * @var DateTime
     *
     * @ORM\Column(name="timeEnd", type="datetime")
     */
    private $timeEnd;


    /**
     * @var ProjectMember
     *
     * @ORM\ManyToOne(targetEntity="ProjectMember")
     */
    private $projectMember;

    /**
     * @var Task
     *
     * @ORM\ManyToOne(targetEntity="Task", inversedBy="timeTracks")
     * @ORM\JoinColumn(name="taskId", referencedColumnName="id")
     */
    private $task;


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set timeStart
     *
     * @param DateTime $timeStart
     * @return TimeTrack
     */
    public function setTimeStart($timeStart)
    {
        $this->timeStart = $timeStart;

        return $this;
    }

    /**
     * Get timeStart
     *
     * @return DateTime
     */
    public function getTimeStart()
    {
        return $this->timeStart;
    }

    /**
     * Set timeEnd
     *
     * @param DateTime $timeEnd
     * @return TimeTrack
     */
    public function setTimeEnd($timeEnd)
    {
        $this->timeEnd = $timeEnd;

        return $this;
    }

    /**
     * Get timeEnd
     *
     * @return DateTime
     */
    public function getTimeEnd()
    {
        return $this->timeEnd;
    }

    /**
     * @return \PMTool\ApiBundle\Entity\Task
     */
    public function getTask()
    {
        return $this->task;
    }

    /**
     * @param \PMTool\ApiBundle\Entity\Task $task
     * @return $this
     */
    public function setTask($task)
    {
        $this->task = $task;
        return $this;
    }

    /**
     * @return \PMTool\ApiBundle\Entity\ProjectMember
     */
    public function getProjectMember()
    {
        return $this->projectMember;
    }

    /**
     * @param \PMTool\ApiBundle\Entity\ProjectMember $projectMember
     * @return $this
     */
    public function setProjectMember($projectMember)
    {
        $this->projectMember = $projectMember;
        return $this;
    }
}

Solution

  • You can use a transformer to achieve this. (See Symfony Transformers)

    Here is an Example of my FormType:

    use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
    
    ...
    
    $transformer = new DateTimeToTimestampTransformer();
    $builder->add($builder->create('validFrom', 'text')
                    ->addModelTransformer($transformer)
            )
    

    Be sure to use "'text'" as an input type, otherwise it didn't work for me.