2016-03-18 3 views
0

У меня есть контроллер в Symfony2 (2.8) для событий календаря, но у вас есть некоторые проблемы с полем DateTime. Контроллер является только контроллером api, но использует тот же объект и форму, что и «обычный» контроллер.API-контроллер для создания новых объектов с DateTime

В вызовах 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 и несколько больше, я не мог найти прямо сейчас.

Bellow - мой код. Пожалуйста, дайте мне знать, если я напишу дополнительную информацию.

Спасибо за ваше время.

Мой 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'; 
    } 
} 

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

Javascript для 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" 
+0

Вместо 'date_create_from_format ('yyyy-MM-dd', $ datetime);' try 'new \ DateTime ($ datetime);' – LBA

+0

Я пробовал, но, увы, это не сработало. Благодарю вас за предложение. – pusle

ответ

0

Кажется, это может быть решена без DateTimeTransformer. @LBA поставил меня на поисковик Google, который привел меня на этот пост: 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, я с радостью принимаю это как ответ.

Смежные вопросы