Doctrine和Symfony 2中的DateTime字段

3

我是 Symfony2 的新手,在通过 Doctrine 将日期时间数据输入到 MySQL 数据库时设置了一个表格,但是我遇到了以下错误:

The form's view data is expected to be of type scalar, array or an instance of \ArrayAccess, but is an instance of class DateTime. You can avoid this error by setting the "data_class" option to "DateTime" or by adding a view transformer that transforms an instance of class DateTime to scalar, array or an instance of \ArrayAccess.

当我尝试为字段使用建议的array('data_class' => 'dateTime')设置时,但在缓存的twig模板中出现以下情况:

Catchable Fatal Error: Object of class DateTime could not be converted to string in

我尝试了几种方法,但无论如何都无法使其工作!
在我的实体中,它被声明如下:
    /**
     * @var \DateTime
     *
     * @ORM\Column(name="my_date", type="datetime", nullable=false)
     * @Assert\Date()
     */
    private $myDate;

同时作为我的表单中的隐藏字段:

$form = $this->createFormBuilder($myClass)
            ->add('myDate', 'hidden')

之所以隐藏起来是因为这些值是通过javascript多级表单添加的。有谁可以解释一下可能的问题,或者我该如何解决它?我应该将实体设置更改为“字符串”吗?

谢谢。

3个回答

13

隐藏文件类型只是一个隐藏的文本字段。

这意味着,为了渲染小部件,它只使用简单小部件模板(请参见hidden_widget.html中的包含语句):

<input type="<?php echo isset($type) ? $view->escape($type) : 'text' ?>" <?php echo $view['form']->block($form, 'widget_attributes') ?><?php if (!empty($value) || is_numeric($value)): ?> value="<?php echo $view->escape($value) ?>"<?php endif ?> />

正如您所看到的,它只是回显了您传递给字段的值(转义函数没有任何重要作用)。存在问题:您将DateTime类作为值传递,而不是字符串。即使指定了传递了DateTime类,它仍然没有更改该值,而是尝试将DateTime对象转换为字符串,这是不可能的。


这就是当前发生的事情。现在,让我们看看如何解决它。它正在尝试呈现的数据($value)实际上被称为视图数据(如您在变量定义中所见)。在当前情况下,视图数据等于Form::$viewData属性(请参见->getViewData()定义)。此属性先前由->normToView()方法定义(请参见$viewData定义)。

正如您在->normToView()方法中所看到的那样,如果可用,则运行视图转换器:

foreach ($this->config->getViewTransformers() as $transformer) {
    $value = $transformer->transform($value);
}

因此,为了将DateTime对象转换为字符串,我们必须使用视图转换器。现在,让我们看看可用的数据转换器。我们非常幸运,因为有一个DateTimeToStringTransformer

/**
 * Transforms between a date string and a DateTime object
 *
 * @author Bernhard Schussek <bschussek@gmail.com>
 * @author Florian Eckerstorfer <florian@eckerstorfer.org>
 */
class DateTimeToStringTransformer extends BaseDateTimeTransformer
{

正是我们所需的!

现在,让我们把这个数据转换器注册为视图转换器,应用到hidden字段中:

use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;

// ...

$builder = $this->createFormBuilder($myClass);
$builder->add(
    $builder->create('myDate', 'hidden')
        ->addViewTransformer(new DateTimeToStringTransformer())
);

完成这些步骤后,表格应该正确生成。由于表单中几乎所有内容都是对称的,所以转换器也可以从字符串转换为日期时间,这意味着您的代码只使用DateTime对象!


非常好的答案,对我来说解释得非常清楚...那么当提交数据回到数据库时,我需要将其转换回来吗?当我提交时,我收到“此值无效”的消息...但是无法确定出自哪里。所有字段看起来都没问题,而且我在所有实体断言上都有自定义消息... - john
1
@john 我刚刚测试了一下,使用这段代码没有出现任何错误。https://gist.github.com/WouterJ/9067186 - Wouter J
我的错,是JavaScript在我的字段中输入日期文本字符串时没有包含h:m:s。现在已经修复并提交了,我猜它在被添加到数据库之前会被转换回来。太棒了! - john
1
@john 是的,正如您在submit方法中所看到的那样,会调用->viewToNorm(),它恰好执行->normToView()的相反操作:遍历所有视图转换器并执行->reverseTransform() - Wouter J

0

要在表单中操作日期,必须使用datetimedatetime表单类型,因为这些类型具有日期时间视图转换器。

因此,在呈现表单时,所有数据都必须是标量类型。

如果您想在隐藏字段中使用datetime对象,则必须使用自定义视图转换器,因为datetime对象没有将值转换为字符串的方法* __toString *,并且无法反向转换为datetime对象。

要创建自定义视图转换器,可以查看Symfony 2 site中的文档。

trasnform - 将datetime对象转换为字符串值,并将该值输入。 reverseTransform - 将来自输入的值(字符串类型)转换为datetime对象。

P.S. 默认情况下,您可以使用Symfony Form包中的DateTimeToStringTransformer


我已经尝试了你提供的教程和课程中的多种方法,但似乎都不适用于我。能否提供一个代码示例? - john

-1
最简单的解决方案是创建一个日期字段并使用CSS隐藏它。
$form = $this->createFormBuilder($myClass)
               ->add('myDate','date',array( 'attr'=>array('style'=>'display:none;')) )

你需要保留 JavaScript 对象日期,并将其作为日期持久化到数据库中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接