Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Form] Wrong template block used for a nested CollectionType element #37024

Closed
jbtronics opened this issue May 31, 2020 · 10 comments
Closed

[Form] Wrong template block used for a nested CollectionType element #37024

jbtronics opened this issue May 31, 2020 · 10 comments

Comments

@jbtronics
Copy link
Contributor

Symfony version(s) affected: 5.1

Description
When a CollectionType is a child element of a form type, that itself is used in a CollectionType, and both form types define a _widget block to override default rendering, then the block of the outer type is used for both (inner and outer form) types.
This will most likely produce an exception, as the inner form does not define the properties needed by the block of the outer form.

How to reproduce
A minimal reproducer can be found here: https://github.com/jbtronics/symfony_bug

Assume we have multiple forms:

  • Our inner form:
class Element2Type extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('name');
    }
}
  • A form which contains of a collection of Element2Type:
class Element1Type extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('id');

        $builder->add('elements', CollectionType::class, [
            'entry_type' => Element2Type::class,
        ]);
    }
}
  • And a form which contains Element1Type:
    $builder->add('elements', CollectionType::class, [
           'entry_type' => Element1Type::class
        ]);

If you now define custom styles for the elements

{% block element2_widget %}
    Inner Element
{% endblock %}

{% block element1_widget %}
    {# This block is called two times, one time for element1 (which is correct), and one time for element2 (which is wrong) #}

    Outer Element
    {{ form_widget(form.id) }}
    {{ form_widget(form.elements) }}
{% endblock %}

then the code will break on Symfony 5.1, as element1_widget block is used for rendering both Element1Type and Element2Type elements, which will throw an exception (Neither the property "id" nor one of the methods "id()", "getid()"/"isid()"/"hasid()" or "__call()" exist and have public access in class "Symfony\Component\Form\FormView").

Possible Solution
The bug was somehow introduced by pull #36088 (Added collectzion_entry block), and especially this line, as commenting this line, stops the wrong behavior.

@xorus
Copy link

xorus commented Jun 5, 2020

I have the same problem with form collections, and commenting the pointed line does stop it from happening for me too.

@rudyleclercq
Copy link

+1

@nkanzari
Copy link

Same problem here

@AcelisWeaven
Copy link

AcelisWeaven commented Jun 12, 2020

If anyone is having this issue and can't wait for a fix, here's a temporary one with an intermediate class.

Create this file somewhere:

<?php
// src\Form\MyCollectionType.php

namespace App\Form;

use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;

/**
 * TODO: Remove this class when issue #37024 is fixed.
 *
 * @see https://github.com/symfony/symfony/issues/37024
 */
class MyCollectionType extends CollectionType
{
    public function finishView(FormView $view, FormInterface $form, array $options)
    {
        trigger_deprecation('', '', "Don't forget to remove the class MyCollectionType");
        if ($form->getConfig()->hasAttribute('prototype') && $view->vars['prototype']->vars['multipart']) {
            $view->vars['multipart'] = true;
        }
    }
}

Now you can use it instead of CollectionType.

It basically overrides the finishView method to how it was before #36088.
Since it's a temporary fix I've added a deprecation, so you'll be reminded to change it later.

@yceruto
Copy link
Member

yceruto commented Jun 14, 2020

I can confirm this issue, and I'm trying to find the original cause to solve it.

I don't think #36088 is the root problem, but might be related to the fact there is no form theme defined for this new block prefix collection_entry and how the right block name is resolved when it does not exist (from afar).

Temporarily, I solved it by adding this theme to my project:

{%- block collection_entry_widget -%}
    {{ form_widget(form) }}
{%- endblock -%}

@yceruto
Copy link
Member

yceruto commented Jun 14, 2020

Yes, the block prefixes hierarchy was incorrect, the new collection_entry block prefix should be placed before all specific ones.

It should be fixed in #37276

@fabpot fabpot closed this as completed Jun 14, 2020
fabpot added a commit that referenced this issue Jun 14, 2020
…e (yceruto)

This PR was merged into the 5.1 branch.

Discussion
----------

[Form] Fixed block prefixes hierarchy of the CollectionType

| Q             | A
| ------------- | ---
| Branch?       | 5.1
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #37024
| License       | MIT
| Doc PR        | -

/cc @HeahDude

Commits
-------

a8f2c60 fixed block prefixes hierarchy of the CollectionType
fabpot added a commit that referenced this issue Jun 15, 2020
…lectionType (yceruto)

This PR was merged into the 5.1 branch.

Discussion
----------

[Form] Fixed prototype block prefixes hierarchy of the CollectionType

| Q             | A
| ------------- | ---
| Branch?       | 5.1
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #37024
| License       | MIT
| Doc PR        |

Following #37276

Commits
-------

65efc36 fixed prototype block prefixes hierarchy of the CollectionType
@toooni
Copy link
Contributor

toooni commented Jan 18, 2021

Hi @yceruto
I still have the same issue Symfony on v5.2.10 and your temporary fix (setting the collection_entry_widget block) does work for me. The fix from #37276 didn't solve my issue. I am pretty sure it is because I am extending the CollectionType:

class SortableCollectionType extends AbstractType
{
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['sortable'] = $options['sortable'];
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'sortable' => false,
        ]);
    }

    public function getBlockPrefix()
    {
        return 'sortable_collection';
    }

    public function getParent()
    {
        return CollectionType::class;
    }
}

Any Idea how this could be fixed?

@yceruto
Copy link
Member

yceruto commented Jan 18, 2021

Hi @toooni, could you please create/share a small app reproducing your issue? thanks!

@dmitrach
Copy link

dmitrach commented Dec 26, 2023

Hi. I still have this problem after migration to Symfony 5.4 from 4.4.
I have deep internal elements of the form including collections with collections.

A simple of the structure:

  • form
    • group1 ...
    • group2 ...
    • group3
      • custom element 3 with two collections of custom elements
        • custom collection 1 ...
        • custom collection 2
          • element 1
          • element 2
          • ...
          • collectionType with custom type of 'entry_type' - it causes the exception

I've changed an initial value in extended class of Symfony\Component\Form\Extension\Core\Type\CollectionType::finishView() to fix the bug locally.

use Symfony\Component\Form\Extension\Core\Type\CollectionType as SymfonyCollectionType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;

class CollectionType extends SymfonyCollectionType
{

    public function finishView(FormView $view, FormInterface $form, array $options)
    {
        $prefixOffset = -5; // $prefixOffset = -2;

        // next original code
    }
}

It solves the issue only when the value -5 or less (-6, -7, etc).

@xabbuh
Copy link
Member

xabbuh commented Dec 26, 2023

@dmitrach Please open a new issue and provide a small example application that allows to reproduce your issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests