2013-07-01 81 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