Создание форм с помощью 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.
Ответы
Ответ 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
и обновить композитор.