2013-06-05 2 views
0

사용자가 지정된 날짜, 시간 및 시간대에 이벤트를 예약하도록하는 양식을 만드는 중입니다. 세 가지 양식 필드의 입력을 결합하여 데이터베이스의 한 datetime 열에 저장하려고합니다. 입력에 따라 지정된 날짜와 시간을 UTC로 변환하려고합니다.Zend Framework 2 양식으로 지정된 시간대로 날짜 및 시간 처리하기

그러나이 양식 코드를 작성하는 방법을 완전히 모르겠습니다. 나는 필드 집합을 확장하는 FIELDSET 클래스를 작성하고이 필드 셋에 세 개의 필드를 추가했다 : 다음과 같이 내 양식이 필드 셋을 추가

<?php 
namespace Application\Form\Fieldset; 

use Zend\Form\Fieldset; 
use Zend\InputFilter\InputFilterInterface; 
use Zend\InputFilter\InputFilterProviderInterface; 
use Zend\Stdlib\Hydrator\ClassMethods; 

class SendDateFieldset extends Fieldset implements InputFilterProviderInterface 
{ 
    public function __construct() 
    { 
     parent::__construct('senddate'); 

     $this->add(array(
       'name' => 'date', 
       'type' => 'Text', 
       'options' => array(
         'label' => 'Date to send:', 
       ) 
      ) 
     ); 

     $this->add(array(
       'name' => 'time', 
       'type' => 'Text', 
       'options' => array(
         'label' => 'Time to send:', 
       ) 
      ) 
     ); 

     $this->add(array(
       'name' => 'timezone', 
       'type' => 'Select', 
       'options'  => array(
       'label'    => "Recipient's timezone", 
       'value_options'  => array(
        -12   => '(GMT-12:00) International Date Line West', 
        -11   => '(GMT-11:00) Midway Island, Samoa', 
        -10   => '(GMT-10:00) Hawaii', 
       ), 
      ), 
      ) 
     ); 
    } 

    public function getInputFilterSpecification() 
    { 
     return array(
       'date' => array(
        'required' => true, 
        'filters' => array(
         array('name' => 'StringTrim'), 
        ), 
        'validators' => array(
         array(
          'name' => 'Date', 
          'break_chain_on_failure' => true, 
          'options' => array(
           'message' => 'Invalid date' 
          ), 
         ), 
        ), 
       ), 

       'time' => array(
        'required' => true, 
        'filters' => array(
         array('name' => 'StringTrim'), 
        ), 
       ), 

       'timezone' => array(
        'required' => true, 
       ), 
     ); 
    } 
} 

: 나는 다른 필드 셋을 추가합니다 물론

<?php 
namespace Application\Form; 

use Zend\Form\Form; 

class Order extends Form 
{ 
    public function __construct() 
    { 
     parent::__construct("new-order"); 
     $this->setAttribute('action', '/order'); 
     $this->setAttribute('method', 'post'); 

     $this->add(
       array(
        'type' => 'Application\Form\Fieldset\SendDateFieldset', 
        'options' => array(
          'use_as_base_fieldset' => false 
        ),  
       ) 
     ); 
    } 
} 

양식, 주문 정보 자체의 기본 필드 세트 및 수신자 정보가있는 다른 필드 세트.

  1. 은 무엇 세 개의 필드를 처리하고 데이터베이스에 (UTC로 변환) 한 날짜로 저장할 수있는 가장 우아한 방법이 될 것이다 :

    나는 이것에 대해 두 가지 질문이 있습니까? 나는 도 주문 서비스 개체가 새로운 주문 처리에 대한 책임이 있으므로 에 대한 책임이있는 메서드에서 처리 할 수 ​​있으므로 더 좋은 방법이 있습니까?

  2. SendDate 필드 세트에 시간대 목록의 작은 스 니펫 (snippet)을 게시했습니다. 이 목록을 렌더링하는 더 깨끗한 방법이 있습니까?

+0

['Zend \ Form \ Element \ DateTime'] (https://github.com/zendframework/zf2/blob/master/library/Zend/Form/Element/DateTimeSelect.php)을보고 싶을 수도 있습니다.). 실제로 TimeZone을 선택할 수 있도록 이것을 확장해야 할 수도 있지만, 본질적으로 모든 것이 있습니다. 값 출력은'filters' 콜백의 하단에 정의되어 있습니다.) – Sam

+0

제안 샘에게 감사드립니다. 이것에 대해 살펴 보았지만, 렌더링을 위해서는 HTML5 datetime 양식 요소를 사용하는 것으로 보입니다. 이 사이트는 광범위한 청취자에게 초점을 맞추기 때문에 이것을 렌더링 할 수있는 브라우저를 사용하여 사용자에게 의존 할 수는 없습니다. 내 fieldset에 충실하고 jQuery 날짜 및 시간 선택기로 클라이언트 측을 처리 할 것입니다. 내가 마음을 결심하고 해결책을 생각해 내면 여기에 게시 할 것이다. – Ruben

+0

브라우저 지원이 제공되지 않을 때 DateTimeElement (입력)는 일반적인'type = text'로 취급됩니다. 따라서 datetime 요소를 그대로 사용하는 것이 안전합니다. 그런 다음'Modernizr' 등을 사용하여 BrowserDateTimeElement의 기능을 확인하고, 제공되지 않을 경우 jQueryUI를 대신 사용할 수 있습니다. – Sam

답변

0

오케이, 약속대로이 문제에 대한 해결책을 알려 드리겠습니다. 다행히 앞으로 다른 사람을 도울 것입니다.

나는 처음에 이미 가지고 있던 SendDateFieldset을 사용하여 끝냈다.

응용 프로그램 \ 양식 \ FIELDSET \ SendDateFieldset :이 필드 셋에서 볼 수 있듯이

<?php 
namespace Application\Form\Fieldset; 

use Application\Hydrator\SendDate as SendDateHydrator; 

use Zend\Form\Fieldset; 
use Zend\InputFilter\InputFilterInterface; 
use Zend\InputFilter\InputFilterProviderInterface; 

class SendDateFieldset extends Fieldset implements InputFilterProviderInterface 
{ 
    public function __construct() 
    { 
     parent::__construct('senddate'); 
     $this->setHydrator(new SendDateHydrator()); 
     $this->setObject(new \DateTime()); 

     $this->add(array(
       'name' => 'date', 
       'type' => 'Text', 
       'options' => array(
         'label' => 'Date to send:', 
       ) 
      ) 
     ); 

     $this->add(array(
       'name' => 'time', 
       'type' => 'Text', 
       'options' => array(
         'label' => 'Time to send:', 
       ) 
      ) 
     ); 

     $this->add(array(
       'name' => 'timezone', 
       'type' => 'Select', 
       'options'  => array(
       'label'    => "Recipient's timezone", 
       'value_options'  => array(
         // The list of timezones is being populated by the OrderFormFactory 
       ), 
      ), 
      ) 
     ); 
    } 

    public function getInputFilterSpecification() 
    { 
     return array(
       'date' => array(
        'required' => true, 
        'filters' => array(
         array('name' => 'StringTrim'), 
        ), 
        'validators' => array(
         array(
          'name' => 'Date', 
          'break_chain_on_failure' => true, 
          'options' => array(
           'message' => 'Invalid date' 
          ), 
         ), 
        ), 
       ), 

       'time' => array(
        'required' => true, 
        'filters' => array(
         array('name' => 'StringTrim'), 
        ), 
        'validators' => array(
         array(
          'name' => 'Callback', 
          'options' => array(
            'callback' => function($value, $context) 
            { 
             // @todo: check if date and time is in the future 
             return true; 
            } 
          ), 
         ), 
        ), 
       ), 

       'timezone' => array(
        'required' => true, 
       ), 
     ); 
    } 
} 

지금 엔티티로 일반 DateTime 개체를 사용합니다. SendDateHydrator, 다음과 같습니다 :

<?php 
namespace Application\Hydrator; 

use Zend\Stdlib\Hydrator\AbstractHydrator; 
use DateTime; 
use DateTimeZone; 

class SendDate extends AbstractHydrator 
{ 
    public function __construct($underscoreSeparatedKeys = true) 
    { 
     parent::__construct(); 
    } 

    /** 
    * Extract values from an object 
    * 
    * @param object $object 
    * @return array 
    * @throws Exception\BadMethodCallException for a non-object $object 
    */ 
    public function extract($object) 
    { 
     throw new Exception\BadMethodCallException(sprintf(
        '%s is not implemented yet)', __METHOD__ 
      )); 
    } 

    /** 
    * Hydrate data into DateTime object 
    * 
    * @param array $data 
    * @param object $object 
    * @return object 
    * @throws Exception\BadMethodCallException for a non-object $object 
    */ 
    public function hydrate(array $data, $object) 
    { 
     if (!$object instanceof DateTime) 
     { 
      throw new Exception\BadMethodCallException(sprintf(
        '%s expects the provided $object to be a DateTime object)', __METHOD__ 
      )); 
     } 

     $object = null; 
     $object = new DateTime(); 

     if (array_key_exists('date', $data) && array_key_exists('time', $data) && array_key_exists('timezone', $data)) 
     { 
      $object = new DateTime($data['date'] . ' ' . $data['time'], new DateTimeZone($data['timezone'])); 
     } 
     else 
     { 
      throw new Exception\BadMethodCallException(sprintf(
        '%s expects the provided $data to contain a date, time and timezone)', __METHOD__ 
      )); 
     } 

     return $object; 
    } 
} 

하이드레이트의 방법은 선택 박스를 사용하여 사용자가 지정한 시간대를 사용하여 날짜 시간 객체를 생성을 담당 나는이 FIELDSET에 대한 사용자 지정 하이드 레이터를 사용하는 DateTime 개체를 채우려면.

형태로 시간대 선택을 생성하려면 DateTimeZone을 사용하여 시간대 목록을 생성하고 멋지게 형식을 지정하는 작은 서비스를 만들었습니다. 최종 결과는 select의 값 옵션에 전달할 수있는 연관 배열입니다. 이 배열의 키는 DateTimeZone이 처리 할 수있는 공식 시간대 식별자입니다.

응용 프로그램 \ 공장 \ OrderFormFactory : :이 선택 박스를 사용하여 어디 형태를 만들기위한 책임이있는 팩토리 클래스에서이 목록을 통과 Screenshot

: 형태로 생성 된 필드 셋은 다음과 같습니다

<?php 
namespace Application\Factory; 

use Application\Service\TimezoneService; 

use Zend\ServiceManager\FactoryInterface; 
use Zend\ServiceManager\ServiceLocatorInterface; 

use Application\Form\Order as OrderForm; 

class OrderFormFactory implements FactoryInterface 
{ 
    public function createService(ServiceLocatorInterface $serviceLocator) 
    { 
     $orderForm = new OrderForm(); 

     /* @var $timezoneSvc TimezoneService */ 
     $timezoneSvc = $serviceLocator->get('Application\Service\TimezoneService'); 

     // Set list of timezones in SendDate fieldset 
     $orderForm->get('order')->get('senddate')->get('timezone')->setValueOptions(
      $timezoneSvc->getListOfTimezones() 
     ); 
     return $orderForm; 
    } 
} 

주문을 저장하면 주문 서비스가 데이터베이스에 저장하기 전에 DateTime을 UTC 시간으로 변환합니다.