我在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"
答案 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方面解决这个问题,我很乐意接受这个作为答案。