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.
First I create a new Symfony project using the bash
under Linux Mint 17.2:
symfony new tasks lts
The new directory tasks
gets created with a new Symfony 2.8.0 project inside.
After adapting the database credentials in app/config/parameters.yml
I create the database:
app/console doctrine:database:create
and generate a new bundle:
app/console generate:bundle --namespace=Acme/TasksBundle --format=yml
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
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
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
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
After confirming few questions it generates the CRUD and prints out:
Generating the CRUD code: OK
and afterwards throws this error:
[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.
Generating the CRUD without write options works fine. The very same code works flawlessly with Symfony 2.7.7.
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
{%- 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 %}
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.
EDIT:
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.
As I mentioned above, the file
form/FormType.php.twig
has been changed since the version 2.8.0.Obviously the Symfony makers wanted to enhance the forms and automatically resolve the types
date
,time
anddatetime
. This happens in the line:This should be achieved with the help of the array
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:Task
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:As we see in the previous example, there is no key
tags
in thefields_mapping
for Task, onlyid
anddescription
. Since the keytags
doesn't exist, the error is thrown.I changed the concerned line in the file
form/FormType.php.twig
to look like this:Now we can use the new feature and we prevent an error by checking if the key exists in the array.
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.
EDIT:
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
Looks like a regression after datetime fix in the generator bundle.
A quick solution is to revert to v2.* in your
composer.json
:The best solution is to fork the repo, fix the bug and create a pull request to contribute back to the community.
Since you already did all the job to isolate the bug, the fix is trivial: check if
type
exists inResources/skeleton/form/FormType.php.twig
. Something likeunless the bug masks more hidden errors based on the same assumption.
Even if after updating fixed bundle the issue is still existing, sometimes the easiest way to solve the problem is to delete the
vendor
catalog, and update composer.