2013-07-01 118 views
3

如何將一個表單(例如日期和時間)中的兩個分隔的字段(必須分隔開)連接到一個實體的propery日期時間以便在表單發佈後持久化?將兩個表單字段合併爲一個實體值

什麼是更好的方法?數據轉換器?表格活動?表單模型?在保留之前手動設置所有實體屬性?

實體:

<?php namespace Acme\DemoBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 

/** 
* @ORM\Entity 
* @ORM\Table(name="event") 
*/ 
class EventEntity 
{ 

    /** 
    * @ORM\Column(name="id", type="integer", nullable=false) 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="IDENTITY") 
    */ 
    private $id; 

    // ... 

    /** 
    * @ORM\Column(name="date_time", type="datetime", nullable=false) 
    */ 
    protected $datetime; 

    public function getId() 
    { 
     return $this->id; 
    } 

    // ... 

    public function getDateTime() 
    { 
     return $this->datetime; 
    } 

    public function setDateTime(\DateTime $datetime) 
    { 
     $this->datetime = $datetime; 
    } 

} 

FormType:

<?php namespace Acme\DemoBundle\Form\Type; 

use JMS\DiExtraBundle\Annotation as DI; 
use Symfony\Component\Form\AbstractType; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\OptionsResolver\OptionsResolverInterface; 

class EventType extends AbstractType 
{ 

    public function buildForm(FormBuilderInterface $builder, array $options) 
    { 
     $builder 
      // ... 
      ->add('date', 'date', [ 
        'required' => true, 
        'widget' => 'single_text', 
        'format' => 'dd.MM.yyyy' 
       ] 
      ) 
      ->add('time', 'time', [ 
        'required' => false, 
        'widget' => 'single_text' 
       ] 
      ); 
    } 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 
    { 
     $resolver->setDefaults(array(
      'data_class' => 'Acme\DemoBundle\Entity\EventEntity' //Acme\DemoBundle\Form\Model\EventModel ? 
     )); 
    } 

    public function getName() 
    { 
     return 'event'; 
    } 

} 
+0

DataTransformers是爲此而設計的。 Symfony使用它們將3字段日期格式(Y/m/d)轉換爲一個DateTime對象。 – Leto

回答

1

呵呵,這是一個很好的問題。

我會選擇最簡單,最通用,可重用的解決方案。 爲了表單映射的緣故,我不會在我的模型上實現方法,但如果它有意義,爲什麼不簡單地使用模型API呢?

<?php 

class EventEntity 
{ 
// assume $this->datetime is initialized and instance of DateTime 

public function setDate(\DateTime $date) 
{ 
    // i don't know if this works! 
    $this->datetime->add($this->datetime->diff($date)); 
} 


public function setTime(\DateTime $date) 
{ 
    $this->datetime->add($this->datetime->diff($date)); 
} 
} 
+0

也許是這樣的 'public function __construct(){$ this-> datetime = new \ DateTime(); } public function setTime(\ DateTime $ datetime){$ this-> datetime-> setTime($ datetime-> format('H'),$ datetime-> format('i')); }日期時間$ datetime $ datetime-> setDate($ datetime-> format('Y'),$ datetime-> format('m'),$ datetime-> format() 'd')); }' – patie

+0

也可以工作。 – Florian

+0

我接受Floarian答案,因爲它更通用。但Pazis的回答對日期/時間非常有用。 – patie

7

如果您在日期時間類型中單獨設置日期和時間小部件,那麼它們將被單獨渲染,但會驗證爲一個字段。

public function buildForm(FormBuilderInterface $builder, array $options) 
{ 
    $builder->add('datetime', 'datetime', array(
      'date_widget' => 'single_text', 
      'time_widget' => 'single_text', 
      'date_format' => 'dd.MM.yyyy', 
     )); 
} 
+0

它可能將時間設置爲不需要? – patie

+0

表單構建器中所需的僅涉及HTML5必需屬性。在驗證中,'NotBlank'是必要的,以驗證字段是否真的被填充。這些要求有點棘手。 –

+0

是的,我知道它唯一的HTML5,但我需要它..憐憫:/但它也可以被「砍死」添加在小枝'{'attr':{'required':'required'},'label_attr':{'class ':'required'}}' – patie

5

我建議使用Pazis解決方案,因爲這是最簡單的解決方案。但是,這也將是一個DataTransformer一個完美的工作:

class MyDataTransformer implements DataTransformerInterface 
{ 
    public function transform($value) 
    { 
    if (null === $value) 
     return; 

    if ($value instanceof \DateTime) 
     return array(
     'date' => $value->format('d.m.Y'), 
     'time' => $value->format('H:i:s') 
    ); 

    return null; 
    } 

    public function reverseTransform($value) 
    { 
    if (null === $value) 
     return null; 

    if (is_array($value) && array_key_exists('date', $value) && array_key_exists('time', $value)) 
     return new \DateTime($value['date'] . ' ' . $value['time']); 

    return null; 
    } 
} 

這樣做的缺點,那你就需要在實體的每一個值,這個變壓器地圖,什麼 - 肯定 - 你不想要。但使用小型表格技巧,這是可以避免的。因此,您將表單添加到表單中,其中包括日期和時間字段以及添加的Transformer。您需要將DateTime對象(「property_path」 - 選項)映射到此子表單或僅將其命名爲「正確」,以便表單框架可以按名稱映射它。

public function buildForm(FormBuilderInterface $builder, array $options) 
{ 
    $builder->add(
     $builder->create('datetime', 'form') 
       ->add('date', 'date', $optionsForDate) 
       ->add('time', 'time', $optionsForTime) 
       ->addViewTransformer(new MyDataTransformer()) 
    ); 
} 

代碼可能不是完美的運行,但我希望將一個實體屬性拆分爲兩個(或更多)表單域的想法很清楚。

+0

偉大的解決方案,爲我節省了另一個問題。謝謝! – Ryall