如何以一种形式(例如日期和时间)将两个单独的字段(必须分开)连接到一个实体的有效日期时间,以便在表单发布后保留?
有什么更好的方法?数据转换器?表格活动?表格模型?在持久化之前手动设置所有实体属性?
实体:
<?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 :(得分: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',
));
}
答案 1 :(得分: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())
);
}
代码可能没有完美运行,但我希望将一个实体属性拆分为两个(或更多)表单字段背后的想法是明确的。
答案 2 :(得分: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));
}
}