3

如何以一种形式(例如日期和时间)将两个单独的字段(必须分开)连接到一个实体属性 datetime 以便在表单发布后持续存在?

有什么更好的方法?数据转换器 ? 形成事件?表格模型 ? 在持久化之前手动设置所有实体属性?

实体:

<?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;
    }

}

表格类型:

<?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';
    }

}
4

3 回答 3

7

如果您在 datetime 类型中单独设置日期和时间小部件,则它们会单独呈现,但会作为一个字段进行验证。

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',
        ));
}
于 2013-07-01T20:55:19.793 回答
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”-option)到此子表单,或者只是“正确”命名它,以便表单框架可以按名称映射它。

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

代码可能无法完美运行,但我希望将一个实体属性拆分为两个(或更多)表单字段的想法很清楚。

于 2013-07-02T08:39:35.420 回答
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));
}
}
于 2013-07-01T20:54:10.380 回答