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

API Controller for creating new entities with DateTime

本文关键字:实体 API 控制器 DateTime 创建 新实体 用于      更新时间:2023-09-26

我在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还有几个我现在找不到的。

波纹管是我的代码。请让我知道我是否应该发布更多信息。

谢谢你的时间。

我的日历事件实体如下所示:

<?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;
    }
}

日历事件类型如下所示:

<?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';
    }
}

日期时间转换器:

<?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();
}

Javascript for Ajax 调用:

(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"

似乎这可以在没有DateTimeTransformer的情况下解决。 @LBA把我放在谷歌搜索女巫把我带到了这篇文章:http://www.keithwatanabe.net/2013/12/24/symfony-2-annoying-issue-with-data-transformers-datetime-timezones-and-php-ini/。

这是我所做的:

首先,我从CalendarEntityType中删除了DataTransformer。其次,我更新了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方面解决这个问题,我很乐意接受这个答案。