【问题标题】:DataTransformer - split DateTime into two fieldsDataTransformer - 将 DateTime 拆分为两个字段
【发布时间】:2012-07-12 10:07:34
【问题描述】:

我最近构建了一个DataTransformer,它最终将接受各种不同的日期格式(如 12/12/2012 或 12.12.2012 或 2012-12-12)。

我的问题是:在我将日期和时间分成两个不同的字段之前:

$builder->add('date_end', 'datetime', array(
        'label' => 'Date/Time',
        'date_widget' => 'single_text',
        'time_widget' => 'single_text',
        'date_format' => 'dd.MM.yyyy',
        'with_seconds' => false,
        'required' => false,
    ) )

效果很好。我如何使用新的DataTransformer 来实现这一点?

在我的实体类型中:

public function buildForm(FormBuilder $builder, array $options) {

    builder->add('date_end', 'dateTime', array(
        'label' => 'Date/Time',
        'required' => false,
    ) )
}

我创建的对应的DateTimeType:

class DateTimeType extends AbstractType {
    private $om;

    public function __construct(ObjectManager $om) {
        $this->om = $om;
    }

    public function buildForm(FormBuilder $builder, array $options) {
        $transformer = new DateTimeTransformer($this->om);
        $builder->appendClientTransformer($transformer);
    }

    public function getDefaultOptions(array $options) {
        return array(
            'invalid_message' => 'TODO INVALID',
        );
    }

    public function getParent(array $options) {
        return 'text';
    }

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

到目前为止我的变压器:

/**
 * @param  \DateTime|null $dateTime
 * @return string|null
 */
public function transform($dateTime) {
    if (null === $dateTime) {
        return null;
    }

    return $dateTime->format('Y-m-d H:i');
}

/**
 * @param  string $value
 * @return string|null
 */
public function reverseTransform($value)
{
    if ( (null === $value) || empty($value) ) {
        return null;
    }
    return new \DateTime( $value );

}

【问题讨论】:

  • 您是否只需将原始的 $builder->add(...) 调用放入新的 buildForm() 方法并将 ->appendClientTransformer($transformer) 附加到它?我不确定我是否完全理解这个问题。
  • 当我使用appendClientTransformer 时,整个表单被传递给转换器,我实际上只希望传递必填字段。当我尝试离开选项时,我得到了这个异常:“选项“date_widget”、“time_widget”、“date_format”、“with_seconds”不存在”。我还更新了关于如何调用变压器。
  • 那么使用上面的代码,转换被正确应用,只是你的日期字段没有显示为两个小部件?
  • 是的,这正是我的问题。
  • 你需要一个特定的表单类型,你知道吗?好像您只关心 DataTransformer,但没有显示表单类型。如果你已经有了它,你可以用它来更新问题。

标签: php forms symfony


【解决方案1】:

我假设您使用的是 Symfony 2.0。我读过表单组件在 2.1 中有所改变。

我有一个类似的问题 - 我想要一个日期时间字段,它使用单独的小部件进行日期和时间(小时)输入。

首先,您必须为此字段创建一个单独的表单类型(实际上它本身就是一个表单)。

我的代码看起来与此类似(针对此示例进行了更改):

class MyDateTimeType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
        ->add('date', 'date', array(
            'label'  => 'label.form.date',
            'input'  => 'datetime',
            'widget' => 'single_text',
            'format' => 'yyyy-MM-dd',
            'error_bubbling' => true
        ))
        ->add('time', 'time', array(
            'label'  => 'label.form.time',
            'input'  => 'datetime',
            'widget' => 'choice',
            'error_bubbling' => true
        ));

        $builder->appendClientTransformer(new DateTimeToDateTimeArrayTransformer());
    }

    public function getDefaultOptions(array $options)
    {
        return array(
            'label' => 'label.form.date',
            'error_bubbling' => false
        );
    }

    public function getParent(array $options)
    {
        return 'form';
    }

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

如您所见,它是一个表单(不要让您感到困惑),但我们会将其用作单个逻辑字段。这就是数据转换器的用武之地。它必须将单个 DateTime 实例拆分为日期和时间,以便在显示表单时获取两个子字段的数据,反之亦然。

error_bubbling 设置确保子字段生成的错误附加到我们的新子字段并且不会传播到顶级表单,但您可能有不同的目标。

我的数据转换器如下所示:

class DateTimeToDateTimeArrayTransformer implements DataTransformerInterface
{
    public function transform($datetime)
    {
        if(null !== $datetime)
        {
            $date = clone $datetime;
            $date->setTime(12, 0, 0);

            $time = clone $datetime;
            $time->setDate(1970, 1, 1);
        }
        else
        {
            $date = null;
            $time = null;
        }

        $result = array(
            'date' => $date,
            'time' => $time
        );

        return $result;
    }

    public function reverseTransform($array)
    {
        $date = $array['date'];
        $time = $array['time'];

        if(null == $date || null == $time)
            return null;

        $date->setTime($time->format('G'), $time->format('i'));

        return $date;
    }
}

终于可以这样使用了:

$builder->add('startDate', 'my_datetime', array(
       'label' => 'label.form.date'
));

你必须register it as a service通过别名使用它,否则直接实例化它(new MyDateTimeType())。

这可能不是最漂亮的解决方案,但 Symfony 2.0 中的表单组件也是如此。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-06
    • 2016-07-25
    • 2018-01-01
    • 1970-01-01
    • 2018-05-19
    • 1970-01-01
    • 2010-10-12
    • 1970-01-01
    相关资源
    最近更新 更多