Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Form] Deprecated FormTypeInterface::getName() and passing of type instances #15079

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

Merged
merged 1 commit into from
Aug 1, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 190 additions & 2 deletions UPGRADE-2.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Form
Before:

```php
$form = $this->createForm('form', $article, array('cascade_validation' => true))
$form = $this->createFormBuilder($article, array('cascade_validation' => true))
->add('author', new AuthorType())
->getForm();
```
Expand All @@ -22,7 +22,7 @@ Form
```php
use Symfony\Component\Validator\Constraints\Valid;

$form = $this->createForm('form', $article)
$form = $this->createFormBuilder($article)
->add('author', new AuthorType(), array(
'constraints' => new Valid(),
))
Expand All @@ -42,6 +42,194 @@ Form
private $author;
}
```

* Type names were deprecated and will be removed in Symfony 3.0. Instead of
referencing types by name, you should reference them by their
fully-qualified class name (FQCN) instead. With PHP 5.5 or later, you can
use the "class" constant for that:

Before:

```php
$form = $this->createFormBuilder()
->add('name', 'text')
->add('age', 'integer')
->getForm();
```

After:

```php
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextType;

$form = $this->createFormBuilder()
->add('name', TextType::class)
->add('age', IntegerType::class)
->getForm();
```

As a further consequence, the method `FormTypeInterface::getName()` was
deprecated and will be removed in Symfony 3.0. You should remove this method
from your form types.

If you want to customize the block prefix of a type in Twig, you should now
implement `FormTypeInterface::getBlockPrefix()` instead:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly does "block prefix of a type in Twig" mean?

I'm upgrading old Symfony projects and this line is a mystery for me. Can I remove the getName() or not?
I'd appreciated some Twig snippet example what exactly is meant here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This refers to how form fragment names are generated. By default, the value is derived from the class name (see e.g. https://symfony.com/doc/current/form/form_themes.html#form-fragment-naming where textarea is derived from TextareaType class). If you have your own TextareaType class, you will maybe want to override the getBlockPrefix() method to not reuse the blocks used by the core TextareaType.

Copy link
Contributor

@TomasVotruba TomasVotruba Jul 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never used such fragments and docs is very confusing for me. I don't see any twig sample for textarea_widget keyword. I also checked PRs referecing this PR when upgrading, but it seems nobody ever used it on custom types.

I look for 3 lines of twig sample, so I can just scan twig templates with regualar expression. There are no Twig tests that could tell us what broke.

{{ form_widget(form.age) }}

{{ textarea_widget(form.age) }}

So for custom:

class SomeType extends FormType
{
	public function getName()
    {
    	return 'yolo';
	}
}

{{ yolo_widget(form.age) }}

Like this?

So it's string from getName() + somehow _widget magically added?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you just looking for a way to automatically update the code of the form type class, I would compare the value returned in getName() with what the automatically computed name would be (see

return StringUtil::fqcnToBlockPrefix(static::class) ?: '';
). Only if both values differ, you will need to rename the getName() method to getBlockPrefix(). Otherwise it can be removed.

Copy link
Contributor

@TomasVotruba TomasVotruba Jul 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I already do with rectorphp/rector#3705 I made it just before reading your comment :D

I want to take it further and remove all the getBlockPrefix() that:

  • don't have standard name
  • are never used in the twig templates

That's why I ask how can I find it in the twig templates.

Any example for that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The special block names are *_row, *_label, *_widget and *_errors (nowadays there is also *_help, but I guess you are addressing 2.8 applications here). But you need to be careful as the block prefix is also used to build block names for CollectionType entries (see https://symfony.com/doc/2.8/form/form_customization.html#form-custom-prototype).


Before:

```php
class UserProfileType extends AbstractType
{
public function getName()
{
return 'profile';
}
}
```

After:

```php
class UserProfileType extends AbstractType
{
public function getBlockPrefix()
{
return 'profile';
}
}
```

If you don't customize `getBlockPrefix()`, it defaults to the class name
without "Type" suffix in underscore notation (here: "user_profile").

If you want to create types that are compatible with Symfony 2.3 up to 2.8
and don't trigger deprecation errors, implement *both* `getName()` and
`getBlockPrefix()`:

```php
class ProfileType extends AbstractType
{
public function getName()
{
return $this->getBlockPrefix();
}

public function getBlockPrefix()
{
return 'profile';
}
}
```

If you define your form types in the Dependency Injection configuration, you
should further remove the "alias" attribute:

Before:

```xml
<service id="my.type" class="Vendor\Type\MyType">
<tag name="form.type" alias="mytype" />
</service>
```

After:

```xml
<service id="my.type" class="Vendor\Type\MyType">
<tag name="form.type" />
</service>
```

Type extension should return the fully-qualified class name of the extended
type from `FormTypeExtensionInterface::getExtendedType()` now.

Before:

```php
class MyTypeExtension extends AbstractTypeExtension
{
public function getExtendedType()
{
return 'form';
}
}
```

After:

```php
use Symfony\Component\Form\Extension\Core\Type\FormType;

class MyTypeExtension extends AbstractTypeExtension
{
public function getExtendedType()
{
return FormType::class;
}
}
```

If your extension has to be compatible with Symfony 2.3-2.8, use the
following statement:

```php
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FormType;

class MyTypeExtension extends AbstractTypeExtension
{
public function getExtendedType()
{
method_exists(AbstractType::class, 'getBlockPrefix') ? FormType::class : 'form';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return is missing ;-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 8d049c5

}
}
```

* Returning type instances from `FormTypeInterface::getParent()` is deprecated
and will not be supported anymore in Symfony 3.0. Return the fully-qualified
class name of the parent type class instead.

Before:

```php
class MyType
{
public function getParent()
{
return new ParentType();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was more likely to return an alias though

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah sorry, I misread the deprecation message. I confused with the deprecation of type names (which is the main goal of this PR even though this other change went in)

Returning an instance in getParent was indeed a bad idea by forcing to resolve types again and again.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think stof missed that this is describing the deprecated way.

}
}
```

After:

```php
class MyType
{
public function getParent()
{
return ParentType::class;
}
}
```

* Passing type instances to `Form::add()`, `FormBuilder::add()` and the
`FormFactory::create*()` methods is deprecated and will not be supported
anymore in Symfony 3.0. Pass the fully-qualified class name of the type
instead.

Before:

```php
$form = $this->createForm(new MyType());
```

After:

```php
$form = $this->createForm(MyType::class);
```

Translator
----------
Expand Down
8 changes: 4 additions & 4 deletions src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,12 @@ public static function createChoiceName($choice, $key, $value)
* Gets important parts from QueryBuilder that will allow to cache its results.
* For instance in ORM two query builders with an equal SQL string and
* equal parameters are considered to be equal.
*
*
* @param object $queryBuilder
*
*
* @return array|false Array with important QueryBuilder parts or false if
* they can't be determined
*
*
* @internal This method is public to be usable as callback. It should not
* be used in user code.
*/
Expand Down Expand Up @@ -335,6 +335,6 @@ abstract public function getLoader(ObjectManager $manager, $queryBuilder, $class

public function getParent()
{
return 'choice';
return 'Symfony\Component\Form\Extension\Core\Type\ChoiceType';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This requires bumping the min version of the component in the bridge

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}
}
17 changes: 14 additions & 3 deletions src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,30 @@ public function getLoader(ObjectManager $manager, $queryBuilder, $class)
return new ORMQueryBuilderLoader($queryBuilder, $manager, $class);
}

/**
* {@inheritdoc}
*/
public function getName()
{
return $this->getBlockPrefix();
}

/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
return 'entity';
}

/**
* We consider two query builders with an equal SQL string and
* equal parameters to be equal.
*
*
* @param QueryBuilder $queryBuilder
*
*
* @return array
*
*
* @internal This method is public to be usable as callback. It should not
* be used in user code.
*/
Expand Down
Loading