API控制器,用于使用DateTime创建新实体

时间:2016-03-18 09:06:02

标签: javascript ajax symfony doctrine-orm

我在Symfony2(2.8)中有一个用于日历事件的控制器,但在DateTime字段中有一些问题。控制器是仅api控制器,但使用与“普通”控制器相同的实体和形式。

在Ajax调用中,我得到一个响应,即日期时间字段的值无效。我试着阅读它,发现我需要创建一个DataTransformer来将其转换为DateTime对象,反之亦然。当我向日历事件表单添加DataTransformer时,“正常”会创建中断。它似乎将值转换两次?

删除模型转换器,并且“普通”创建有效,但Ajax继续在开始和结束日期时间字段中返回无效。

如果有人能指出我正确的方向,我真的很感激。

我读过的资源: https://tech.enekochan.com/en/2015/11/21/symfony-forms-and-bootstrap-datetimepicker/ http://symfony.com/doc/current/cookbook/form/data_transformers.html 还有一些我现在找不到的。

贝娄是我的代码。如果我要发布更多信息,请告诉我。

感谢您的时间。

我的CalendarEvent实体如下所示:

<?php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping AS ORM;

/**
 * @ORM\Entity(repositoryClass="AppBundle\Entity\CalendarEventRepository")
 * @ORM\Table(name="calendar_events")
 */
class CalendarEvent
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer", name="id")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255, nullable=true, name="name")
     */
    private $name;

    /**
     * @ORM\Column(type="datetime", nullable=true, name="start")
     */
    private $start;

    /**
     * @ORM\Column(type="datetime", nullable=true, name="end")
     */
    private $end;

    /**
     * @ORM\Column(type="string", length=255, nullable=true, name="status")
     */
    private $status;

    /**
     * @ORM\Column(type="text", nullable=true, name="description")
     */
    private $description;

    /**
     * @ORM\Column(type="boolean", nullable=true, options={"default":0})
     */
    private $busy;

    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\User", fetch="EAGER")
     * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
     */
    private $user;



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


    /**
     * @return User
     */
    public function getUser()
    {
        return $this->user;
    }

    /**
     * @param User $user
     * @return CalendarEvent
     */
    public function setUser(User $user)
    {
        $this->user = $user;

        return $this;
    }

    /**
     * @return mixed
     */
    public function getBusy()
    {
        return $this->busy;
    }

    /**
     * @param mixed $busy
     * @return CalendarEvent
     */
    public function setBusy($busy)
    {
        $this->busy = $busy;

        return $this;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return CalendarEvent
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set start
     *
     * @param \DateTime $start
     * @return CalendarEvent
     */
    public function setStart($start)
    {
        $this->start = $start;

        return $this;
    }

    /**
     * Get start
     *
     * @return \DateTime
     */
    public function getStart()
    {
        return $this->start;
    }

    /**
     * Set end
     *
     * @param \DateTime $end
     * @return CalendarEvent
     */
    public function setEnd($end)
    {
        $this->end = $end;

        return $this;
    }

    /**
     * Get end
     *
     * @return \DateTime
     */
    public function getEnd()
    {
        return $this->end;
    }

    /**
     * Set status
     *
     * @param string $status
     * @return CalendarEvent
     */
    public function setStatus($status)
    {
        $this->status = $status;

        return $this;
    }

    /**
     * Get status
     *
     * @return string
     */
    public function getStatus()
    {
        return $this->status;
    }

    /**
     * Set description
     *
     * @param string $description
     * @return CalendarEvent
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Get description
     *
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }
}

CalendarEventType如下所示:

<?php

namespace AppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use AppBundle\Form\DataTransformer\DateTimeTransformer;

class CalendarEventType extends AbstractType
{
    private $tokenStorage;

    public function __construct($date = null, $tokenStorage)
    {
        $this->tokenStorage = $tokenStorage;
    }

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
          ->add('name', null, array(
            'attr' => array(
              'placeholder' => 'app.forms.calendar.name',
            ),
            'label' => 'app.forms.calendar.name',
            'translation_domain' => 'AppBundle'
          ))
          ->add('description', TextareaType::class, array(
            'label' => 'app.forms.calendar.description',
            'translation_domain' => 'AppBundle'
          ))
          ->add('start', DateTimeType::class, array(
             'label'              => 'app.forms.calendar.start',
             'translation_domain' => 'AppBundle',
             'date_widget' => 'single_text',
             'time_widget' => 'text'
           ))
           ->add('end', DateTimeType::class, array(
              'label'              => 'app.forms.calendar.end',
              'translation_domain' => 'AppBundle',
              'date_widget' => 'single_text',
              'time_widget' => 'text'
           ));

        $builder->get('start')->addModelTransformer(new DateTimeTransformer());
        $builder->get('end')->addModelTransformer(new DateTimeTransformer());
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\CalendarEvent',
            'csrf_protection' => true,
            'csrf_field_name' => '_token',
            // a unique key to help generate the secret token
            'intention'       => 'calendar_event',
        ));
    }

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

DateTimeTransformer:

<?php

namespace AppBundle\Form\DataTransformer;

use Symfony\Component\Form\DataTransformerInterface;

class DateTimeTransformer implements DataTransformerInterface
{
    /**
     * Transforms an object (DateTime) to a string.
     *
     * @param  \DateTime|null $datetime
     * @return string
     */
    public function reverseTransform($datetime)
    {
        if (null === $datetime) {
            return '';
        }

        return $datetime->format('yyyy-MM-dd HH:ii');
    }

    /**
     * Transforms a string to an object (DateTime).
     *
     * @param  string $datetime
     * @return \DateTime|null
     */
    public function transform($datetime)
    {
        // datetime optional
        if (!$datetime) {
            return null;
        }

        return date_create_from_format('yyyy-MM-dd', $datetime);
    }
}

控制器(我这里只包括创建功能):

/**
 * @Route("/events", name="api_event_create")
 * @Method("post")
 *
 * @param Request $request
 * @return array
 */
public function createAction(Request $request)
{
    $response = new Response();

    // Get logged in user if it exists, else return unauthorized status code
    $user = $this->getUser();
    if( ! ($user instanceof User)) {
        $response->setStatusCode(401);
        $response->send();
    };

    // Handle the request
    // Get data from post
    $data = $request->request->get('appbundle_calendarevent');

    // Create new entity
    $entity = new CalendarEvent();

    // Create form
    $form = $this->createForm(new CalendarEventType('', $this->get('security.token_storage')), $entity);

    // Submit form data
    $form->submit($data);

    // Check if form is valid
    if($form->isValid()) {
        $em = $this->getDoctrine()->getManager();

        $title = (array_key_exists('name', $data)) ? $data['name'] : 'Ny hendelse';
        $desc  = (array_key_exists('description', $data)) ? $data['description'] : NULL;

        $entity->setUser($user);
        $entity->setName($title);
        $entity->setDescription($desc);
        $entity->setStatus('normal');

        $em->persist($entity);
        $em->flush();

        $response = new Response();
        $response->setStatusCode(201);
        $response->headers->set(
            'Location',
            $this->generateUrl('calendar_events_show', array('id' => $entity->getId()))
            );
    } else {
        return array('errors' => $form->getErrors());
    }

    $response->send();
}

用于Ajax的Javascript调用:

(function($){
    $('.calendar td').on('dblclick', function() {
        var self = $(this);
        newEvent(self).done(handleDone);
    });

    var newEvent = function(self) {
        var url = 'url to api';
        var method = 'post';
        var selectedDate = self.attr('id');
        var eventStartDate = moment(selectedDate, "YYYYMMDD").format('YYYY-MM-DD HH:mm'); // Start date
        var eventEndDate   = moment(selectedDate, "YYYYMMDD").format('YYYY-MM-DD HH:mm'); // End date

        return $.ajax({
            url: url,
            method: method,
            data: {
                "appbundle_calendarevent[name]": 'New event',
                "appbundle_calendarevent[start]": eventStartDate,
                "appbundle_calendarevent[end]": eventEndDate,
                "appbundle_calendarevent[_token]": form_token
            },
            statusCode: {
                400: handleStatus400,
                401: handleStatus401,
                402: handleStatus402,
                404: handleStatus404,
                422: handleStatus422,
                500: handleStatus500
            }
        });
    };

    function handleDone(data) {
        console.log(data);
    }

    function handleStatus400() {
        console.log('400');
    }

    function handleStatus401() {
        console.log('401');
    }

    function handleStatus402() {
        console.log('402');
    }

    function handleStatus404() {
        console.log('404');
    }

    function handleStatus422() {
        console.log('422');
    }

    function handleStatus500() {
        console.log('500');
    }
})(jQuery);

进行Ajax调用会发送以下参数:

appbundle_calendarevent[name]:"New+event"
appbundle_calendarevent[start]:"2016-03-25+00:00"
appbundle_calendarevent[end]:"2016-03-25+00:00"
appbundle_calendarevent[_token]:"97Ygs8Q9y70gi0vs24Mrg1LfpCvZ2wjaIcc41KASjkg"

1 个答案:

答案 0 :(得分:0)

似乎没有DateTimeTransformer就可以解决这个问题。 @LBA让我进入谷歌搜索女巫带我到这篇文章:http://www.keithwatanabe.net/2013/12/24/symfony-2-annoying-issue-with-data-transformers-datetime-timezones-and-php-ini/

这是我做的:

首先,我从DataTransformer删除了CalendarEntityType。 其次,我更新了Javascript和参数值,如下所示:

var eventStartDate = moment(selectedDate, "YYYYMMDD").format('YYYY-MM-DDTHH:mm:ss+01:00');
var eventEndDate   = moment(selectedDate, "YYYYMMDD").format('YYYY-MM-DDTHH:mm:ss+01:00');

猜猜这是一个时区问题。如果有人知道如何在symfony方面解决这个问题,我很乐意接受这个作为答案。