Подтвердить что ты не робот

Создание форм с помощью Symfony 2.8 приводит к тому, что Twig_Error_Runtime

Поскольку последняя версия LTS Symfony была выпущена несколько дней назад (30.11.2015), я начал играть с ней. К сожалению, я не могу создать CRUD с действиями записи с тем же кодом, который отлично работает в Symfony 2.7.7.

Сначала я создаю новый проект Symfony, используя bash в Linux Mint 17.2:

symfony new tasks lts

Новый каталог tasks создается с новым проектом Symfony 2.8.0 внутри.

После адаптации учетных данных базы данных в 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 %}

Как я вижу, условие if в цикле for - это место, где происходит ошибка. (Я предполагаю, что выражение fields_mapping[field]['type'] вызывает проблему, так как поле many to many (tag) не имеет атрибута type.)

Что я делаю неправильно? Как я могу решить эту проблему? Большое вам спасибо за вашу помощь.

EDIT: Аналогичная проблема возникает и с Symfony 3.0.0. Файл form/FormType.php.twig был изменен с версии 2.8.

4b9b3361

Ответ 1

Я немного разбирался и пытался отладить ошибку.

Как я уже упоминал выше, файл form/FormType.php.twig был изменен с версии 2.8.0.

Очевидно, производители Symfony хотели улучшить формы и автоматически разрешать типы date, time и datetime. Это происходит в строке:

{%- 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']

Как мы видим в предыдущем примере, в fields_mapping для задачи нет ключа tags, только id и description. Поскольку ключ 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, поэтому, вероятно, многие тысячи пользователей играли с ними. Я не мог поверить, что если это ошибка, никто бы этого не заметил.

EDIT:

Я опубликовал вопрос о GitHub:

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

Это была ошибка, которая была решена так же, как я думал и писал выше:

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

Ответ 2

Похоже на регрессию после datetime fix в комплекте с генератором.

Быстрое решение - вернуться к v2. * в composer.json:

"sensio/generator-bundle": "^2.5",

Лучшим решением является разветвление репо, исправление ошибки и создание запроса на перенос, чтобы внести свой вклад в сообщество.

Поскольку вы уже выполнили всю работу, чтобы изолировать ошибку, исправление тривиально: проверьте, существует ли type в Resources/skeleton/form/FormType.php.twig. Что-то вроде

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

если ошибка не маскирует более скрытые ошибки, основанные на том же предположении.

Ответ 3

Даже если после обновления фиксированного пакета проблема все еще существует, иногда самый простой способ решить проблему - удалить каталог vendor и обновить композитор.