使用Symfony 2.8生成表单会引发Twig_Error_Runtime错误。

26

最近几天Symfony发布了最新的LTS版本(2015年11月30日),我开始研究它。不幸的是,我无法使用在Symfony 2.7.7中正常工作的相同代码生成带有写操作的CRUD。

首先我使用Linux Mint 17.2下的bash创建了一个新的Symfony项目:

symfony new tasks lts

在一个新的Symfony 2.8.0项目中,创建了一个名为tasks的新目录。

在调整了app/config/parameters.yml中的数据库凭据后,我创建了数据库:

app/console doctrine:database:create

并生成一个新的打包文件:

app/console generate:bundle --namespace=Acme/TasksBundle --format=yml
然后我创建一个新目录 src/Acme/TasksBundle/Resources/config/doctrine 并在其中放置两个文件来定义我的模型。这些文件分别是:

Task.orm.yml

Acme\TasksBundle\Entity\Task:
    type: entity
    repositoryClass: Acme\TasksBundle\Repository\TaskRepository
    table: task
    id:
        id:
            type: integer
            generator: { strategy : AUTO }
    fields:
        description:
            type: text
    manyToMany:
        tags:
            targetEntity: Tag
            inversedBy: tasks
            cascade: [ "persist" ]
            joinTable:
                name: task_tag
                joinColumns:
                    task_id:
                        referencedColumnName: id
                inverseJoinColumns:
                    tag_id:
                        referencedColumnName: id

Tag.orm.yml

Acme\TasksBundle\Entity\Tag:
    type: entity
    repositoryClass: Acme\TasksBundle\Repository\TagRepository
    table: tag
    id:
        id:
            type: integer
            generator: { strategy : AUTO }
    fields:
        name:
            type: string
            length: 50
    manyToMany:
        tasks:
            targetEntity: Task
            mappedBy: tags

数据库模式应该像这样:

+----------------+     +--------------+
| task           |     | task_tag     |     +---------+
+----------------+     +--------------+     | tag     |
|   id           |<--->|   task_id    |     +---------+
|   description  |     |   tag_id     |<--->|   id    |
+----------------+     +--------------+     |   name  |
                                            +---------+

现在我可以生成实体:

app/console generate:doctrine:entities AcmeTasksBundle

这个代码可以正常运行,因此数据库可以被更新:

app/console doctrine:schema:update --force

到目前为止一切都好。 表已经在数据库中了。现在我想生成带有写入操作的CRUD:

app/console generate:doctrine:crud --entity=AcmeTasksBundle:Task --with-write --format=yml

确认了几个问题后,它生成CRUD并打印出:

Generating the CRUD code: OK

然后出现以下错误:

[Twig_Error_Runtime]                                                                                    
Key "tags" for array with keys "id, description" does not exist in "form/FormType.php.twig" at line 29

控制器被创建,但表单未被创建。

没有编写选项生成CRUD能正常工作。相同的代码在Symfony 2.7.7中运行完美无缺。

我检查了版本间 form/FormType.php.twig文件的区别,以下是相关部分:

Symfony 2.7.7
vendor/sensio/generator-bundle/Sensio/Bundle/GeneratorBundle/Resources/skeleton/form/FormType.php.twig

{%- if fields|length > 0 %}
/**
 * @param FormBuilderInterface $builder
 * @param array $options
 */
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
    {%- for field in fields %}

        ->add('{{ field }}')
    {%- endfor %}

    ;
}
{% endif %}

Symfony 2.8.0
vendor/sensio/generator-bundle/Resources/skeleton/form/FormType.php.twig

{%- if fields|length > 0 %}
/**
 * @param FormBuilderInterface $builder
 * @param array $options
 */
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder

    {%- for field in fields -%}
        {%- if fields_mapping[field]['type'] in ['date', 'time', 'datetime'] %}

        ->add('{{ field }}', '{{ fields_mapping[field]['type'] }}')

        {%- else %}

        ->add('{{ field }}')

        {%- endif -%}
    {%- endfor %}

    ;
}
{% endif %}

在for循环的if条件语句中,我认为错误发生的地方就在那里。(我猜测表达式fields_mapping[field]['type']引起了问题,因为多对多字段(tag)没有type属性。)

我做错了什么?我怎样才能解决这个问题?非常感谢您的帮助。

编辑: 在Symfony 3.0.0中也会出现相同的问题。自版本2.8以来,文件form/FormType.php.twig已更改。

3个回答

17

在生成器包中进行日期时间修复后,似乎出现了回归。

一个快速的解决方案是将composer.json回滚到v2.*版本:

"sensio/generator-bundle": "^2.5",
最佳解决方案是 fork 仓库,修复错误并创建一个拉取请求以回馈社区。
由于您已经完成了隔离错误的所有工作,所以修复问题是微不足道的:检查 Resources/skeleton/form/FormType.php.twig 中是否存在 type。类似这样的内容
{%- if fields_mapping[field]['type'] is defined and fields_mapping[field]['type'] in ['date', 'time', 'datetime'] %}

除非该错误掩盖了基于相同假设的更多隐藏错误。


谢谢!我正在撰写一篇长答案,陈述我的研究结果。我的解决方案只是稍有不同,但思路是相同的。 - cezar

17

我正在进行一些研究,并尝试调试错误。

正如我上面提到的,自2.8.0版本以来,文件form/FormType.php.twig已更改。

显然Symfony的开发者们想要增强表单并自动解析类型datetimedatetime。这发生在以下代码行中:

{%- if fields_mapping[field]['type'] in ['date', 'time', 'datetime'] %}

应该借助数组fields_mapping来实现这一点。

通过一些快速而简单的解决方法,我试图找出fields_mapping中隐藏的内容。这是我的模型的结果:

任务

{
    id => {
        id => 1,
        fieldName => id,
        type => integer,
        columnName => id
    },
    description => {
        fieldName => description,
        type => text,
        columnName => description
    }
}

当遍历任务的字段时,在最后一步中它会遍历 tags 字段。if 子句中的表达式看起来像这样:

fields_mapping['tags']['type']

正如我们在之前的例子中看到的那样,在任务(Task)的 fields_mapping 中没有键为 tags,只有 iddescription。由于键 tags 不存在,因此会抛出错误。

我将文件 form/FormType.php.twig 中相关行更改为以下内容:

{%- if fields_mapping[field] is defined and fields_mapping[field]['type'] in ['date', 'time', 'datetime'] %}

现在我们可以使用新功能并通过检查数组中是否存在该键来防止错误。

我不知道这是一个错误还是我的特殊情况出了问题。现在版本2.8.0和3.0.0已经发布一周了,因此可能有成千上万的用户正在使用它们。如果这是个错误,我不敢相信没有人会注意到。

编辑:

我在GitHub上发布了一个问题:

https://github.com/sensiolabs/SensioGeneratorBundle/issues/443

这是一个错误,已以我上面想到和写的方式解决:

https://github.com/Maff-/SensioGeneratorBundle/commit/205f64e96a94759f795271cb00fc86fb03b1fd4a


3

即使在更新了固定的捆绑包之后问题仍然存在,有时解决问题最简单的方法是删除 vendor 目录,并更新 composer。


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