Skip to content

[Form] Custom Form Type with the same name as its parent Symfony form type results in exception upon rednering #58825

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

Open
yyaremenko opened this issue Nov 10, 2024 · 6 comments

Comments

@yyaremenko
Copy link

Symfony version(s) affected

7.1.7

Description

What I do:
I create a custom form type for an emali field, which has a name colliding with a Symfony's form type, as following:

<?php

namespace App\Form\User;

use Symfony\Component\Form\Extension\Core\Type\EmailType as BaseEmailType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;

class EmailType extends AbstractType
{
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            // ... defaults are set here
        ]);
    }

    public function getParent(): string
    {
        return BaseEmailType::class;
    }
}

What I expect:
The form is rendered to the end user.

What I get:
An exception rendered to the end user:

An exception has been thrown during the rendering of a template ("Unable to render the form because the block names array contains duplicates: "_sign_up_email_row", "email_row", "email_row", "text_row", "form_row".").

Experiment:
If I change my form type class name from EmailType to anything else, e.g. MailType, the form is rendered successfully

How to reproduce

(see description)

Possible Solution

No response

Additional Context

No response

@n0rbyt3
Copy link
Contributor

n0rbyt3 commented Nov 10, 2024

Try overriding getBlockPrefix() and return a static value like app_email. By default the class name without namespace and type suffix is used to generate the block prefix: Symfony\Component\Form\Extension\Core\Type\EmailType and App\Form\Type\EmailType are both converted to email which causes the duplication.

Source: https://github.com/symfony/symfony/blob/7.1/src/Symfony/Component/Form/AbstractType.php#L59-L65 and https://github.com/symfony/symfony/blob/7.1/src/Symfony/Component/Form/Util/StringUtil.php#L47-L49

@yyaremenko
Copy link
Author

Thank you for the proposed solution norby. Currently though I decided to move on with just giving my class a non-coliding name, because the proposed workaround looks to me like an undocumented semi-hack, and this is the last thing I'd want to see in my code. Because undocumented features tend to be silently changed over time.

I still believe either this bug should be fixed, or, if the fix is too expensive, at least a warning must be added to the documentation.

@n0rbyt3
Copy link
Contributor

n0rbyt3 commented Nov 10, 2024

The feature is documented, even though a bit hidden: https://symfony.com/doc/current/form/create_custom_field_type.html#creating-the-form-type-template (5th paragraph)

@yyaremenko
Copy link
Author

Thank you, I see now there's a warning in the docs. But I still believe this is a bug not a feature. Imho a form type class name colliding with Symfony's form type class name must never result in an exception, especially on rendering stage.

@yyaremenko
Copy link
Author

yyaremenko commented Nov 10, 2024

Okay, so I just came across another (related) bug: in case if your custom form type class name collides with a Symfony's form type name, even if it does not use such class as parent - it simply does not render, at all, without any warning; an example of such class e.g.

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType as BasePasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\OptionsResolver\OptionsResolver;

class PasswordType extends AbstractType
{
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'type' => BasePasswordType::class,
            ...
        ]);
    }

    public function getParent(): string
    {
        return RepeatedType::class; // parent is not a PasswordType
    }

results in the form type never rendered (but if I change its name to anything else, it works just fine)

UPD (and, surely, using getBlockPrefix() to return a custom value solves the problem - but again, imho this looks like a hack-ish fix to an internal problem, not like a feature)

@carsonbot
Copy link

Hey, thanks for your report!
There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

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

3 participants