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

2022-01-16 00:00:00 php symfony doctrine symfony-2.8

自从几天前(30.11.2015)发布了 Symfony 的最后一个 LTS 版本以来,我开始使用它.不幸的是,我无法使用在 Symfony 2.7.7 中运行良好的相同代码生成具有写入操作的 CRUD.

Since the last LTS version of Symfony was released few days ago (30.11.2015) I started playing with it. Unfortunately I can't generate a CRUD with write actions with the same code that works fine in Symfony 2.7.7.

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

First I create a new Symfony project using the bash under Linux Mint 17.2:

symfony new tasks lts

新目录 tasks 被创建,其中包含一个新的 Symfony 2.8.0 项目.

The new directory tasks gets created with a new Symfony 2.8.0 project inside.

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

After adapting the database credentials in app/config/parameters.yml I create the database:

app/console doctrine:database:create

并生成一个新包:

app/console generate:bundle --namespace=Acme/TasksBundle --format=yml

然后我创建一个新目录 src/Acme/TasksBundle/Resources/config/doctrine 并在其中放置我的模型的两个文件.它们是:

Then I create a new directory src/Acme/TasksBundle/Resources/config/doctrine and place two files for my models inside. These are:

Task.orm.yml

Task.orm.yml

AcmeTasksBundleEntityTask:
    type: entity
    repositoryClass: AcmeTasksBundleRepositoryTaskRepository
    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

标签.orm.yml

AcmeTasksBundleEntityTag:
    type: entity
    repositoryClass: AcmeTasksBundleRepositoryTagRepository
    table: tag
    id:
        id:
            type: integer
            generator: { strategy : AUTO }
    fields:
        name:
            type: string
            length: 50
    manyToMany:
        tasks:
            targetEntity: Task
            mappedBy: tags

数据库架构应该是这样的:

The database schema should like this:

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

现在我可以生成实体了:

Now I can generate the entities:

app/console generate:doctrine:entities AcmeTasksBundle

这很好,所以可以更新数据库:

This works fine, so the database can be updated:

app/console doctrine:schema:update --force

到目前为止一切正常.这些表在数据库中.现在我想用写操作生成 CRUD:

Everything ok till now. The tables are in the database. Now I want to generate CRUD with write actions:

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

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

After confirming few questions it generates the CRUD and prints out:

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

创建了控制器,但没有创建表单.

The controller gets created, but not the form.

在没有写入选项的情况下生成 CRUD 可以正常工作.相同的代码在 Symfony 2.7.7 中完美运行.

Generating the CRUD without write options works fine. The very same code works flawlessly with Symfony 2.7.7.

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

I checked the differences in the file form/FormType.php.twig between the versions and here are the relevant parts:

Symfony 2.7.7
vendor/sensio/generator-bundle/Sensio/Bundle/GeneratorBundle/Resources/skeleton/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

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.)

As I see the if condition in the for loop is the place where the error occurs. (I assume that the expression fields_mapping[field]['type'] causes the problem since the many to many field (tag) has no attribute type.)

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

What I am doing wrong? How can I solve this problem? Thank you very much for your help.

Symfony 3.0.0 也会出现同样的问题.文件 form/FormType.php.twig 自 2.8 版起已更改.

The same problem occurs with Symfony 3.0.0. The file form/FormType.php.twig has been changed since version 2.8.

推荐答案

我研究了一下,尝试调试错误.

I was researching a little bit and tried to debug the error.

如上所述,文件 form/FormType.php.twig 自 2.8.0 版本以来已更改.

As I mentioned above, the file form/FormType.php.twig has been changed since the version 2.8.0.

显然 Symfony 的开发者希望增强表单并自动解析 datetimedatetime 类型.这发生在以下行:

Obviously the Symfony makers wanted to enhance the forms and automatically resolve the types date, time and datetime. This happens in the line:

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

这应该借助数组fields_mapping来实现.

This should be achieved with the help of the array fields_mapping.

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

With some quick-and-dirty workarounds I tried to find out what is hidden inside of fields_mapping. This is the result for my model:

任务

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

当遍历Task的字段时,在最后一步遍历字段tags.if 子句中的表达式如下所示:

When iterating through the fields of Task, in the last step it goes through the field tags. The expression in the if clause looks like this:

fields_mapping['tags']['type']

我们在前面的例子中看到,Task的fields_mapping中没有关键的tags,只有iddescription.由于键 tags 不存在,因此抛出错误.

As we see in the previous example, there is no key tags in the fields_mapping for Task, only id and description. Since the key tags doesn't exist, the error is thrown.

我将文件 form/FormType.php.twig 中的相关行更改为如下所示:

I changed the concerned line in the file form/FormType.php.twig to look like this:

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

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

Now we can use the new feature and we prevent an error by checking if the key exists in the array.

我不知道这是一个错误还是在我的特定情况下有什么问题.现在距离 2.8.0 和 3.0.0 版本发布已经一周了,所以可能有成千上万的用户在玩它们.我不敢相信,如果它是一个错误,没有人会注意到这一点.

I don't know if this is a bug or there is something wrong in my particular case. Now it is already one week since the release of the versions 2.8.0 and 3.0.0, so probably many thousands users have been playing around with them. I couldn't believe that, if it is a bug, nobody would have noticed this.

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

I posted an issue on GitHub:

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

这是一个错误,已经以同样的方式解决了,正如我在上面所想和写的:

This was a bug, that has been solved in the same way, as I thought and wrote above:

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

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

相关文章