Permalink
Browse files

feature #24530 [Form] simplify the form type extension registration (…

…xabbuh)

This PR was merged into the 4.2-dev branch.

Discussion
----------

[Form] simplify the form type extension registration

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #22833, #27906
| License       | MIT
| Doc PR        |

Commits
-------

6a1d4c5 simplify the form type extension registration
  • Loading branch information...
fabpot committed Oct 10, 2018
2 parents c10d2c0 + 6a1d4c5 commit 52b7239154e8a36e6b1a885639e4c45a79f5707e
Showing with 474 additions and 82 deletions.
  1. +30 −1 UPGRADE-4.2.md
  2. +30 −0 UPGRADE-5.0.md
  3. +3 −0 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
  4. +3 −3 src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml
  5. +1 −1 src/Symfony/Bundle/FrameworkBundle/Resources/config/form_csrf.xml
  6. +1 −1 src/Symfony/Bundle/FrameworkBundle/Resources/config/form_debug.xml
  7. +2 −2 src/Symfony/Bundle/FrameworkBundle/composer.json
  8. +14 −2 src/Symfony/Component/Form/AbstractExtension.php
  9. +19 −0 src/Symfony/Component/Form/AbstractTypeExtension.php
  10. +30 −0 src/Symfony/Component/Form/CHANGELOG.md
  11. +20 −5 src/Symfony/Component/Form/DependencyInjection/FormPass.php
  12. +3 −2 src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php
  13. +3 −2 src/Symfony/Component/Form/Extension/DataCollector/Type/DataCollectorTypeExtension.php
  14. +13 −3 src/Symfony/Component/Form/Extension/DependencyInjection/DependencyInjectionExtension.php
  15. +3 −2 src/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php
  16. +3 −2 src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php
  17. +3 −2 src/Symfony/Component/Form/Extension/Validator/Type/RepeatedTypeValidatorExtension.php
  18. +4 −2 src/Symfony/Component/Form/Extension/Validator/Type/SubmitTypeValidatorExtension.php
  19. +3 −2 src/Symfony/Component/Form/Extension/Validator/Type/UploadValidatorExtension.php
  20. +8 −2 src/Symfony/Component/Form/FormFactoryBuilder.php
  21. +4 −0 src/Symfony/Component/Form/FormTypeExtensionInterface.php
  22. +8 −0 src/Symfony/Component/Form/PreloadedExtension.php
  23. +53 −0 src/Symfony/Component/Form/Tests/AbstractTypeExtensionTest.php
  24. +159 −6 src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php
  25. +4 −2 src/Symfony/Component/Form/Tests/Extension/Core/Type/ExtendedChoiceTypeTest.php
  26. +3 −0 src/Symfony/Component/Form/Tests/Extension/DataCollector/Type/DataCollectorTypeExtensionTest.php
  27. +32 −13 src/Symfony/Component/Form/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php
  28. +3 −9 src/Symfony/Component/Form/Tests/Fixtures/ChoiceTypeExtension.php
  29. +2 −2 src/Symfony/Component/Form/Tests/Fixtures/FooTypeBarExtension.php
  30. +2 −2 src/Symfony/Component/Form/Tests/Fixtures/FooTypeBazExtension.php
  31. +3 −9 src/Symfony/Component/Form/Tests/Fixtures/LazyChoiceTypeExtension.php
  32. +5 −5 src/Symfony/Component/Form/Tests/Fixtures/TestExtension.php
@@ -55,9 +55,38 @@ Finder
Form
----
* The `getExtendedType()` method of the `FormTypeExtensionInterface` is deprecated and will be removed in 5.0. Type
extensions must implement the static `getExtendedTypes()` method instead and return an iterable of extended types.
Before:
```php
class FooTypeExtension extends AbstractTypeExtension
{
public function getExtendedType()
{
return FormType::class;
}
// ...
}
```
After:
```php
class FooTypeExtension extends AbstractTypeExtension
{
public static function getExtendedTypes(): iterable
{
return array(FormType::class);
}
// ...
}
```
* The `scale` option of the `IntegerType` is deprecated.
* The `$scale` argument of the `IntegerToLocalizedStringTransformer` is deprecated.
* Deprecated calling `FormRenderer::searchAndRenderBlock` for fields which were already rendered.
Instead of expecting such calls to return empty strings, check if the field has already been rendered.
@@ -72,6 +72,36 @@ Finder
Form
----
* The `getExtendedType()` method was removed from the `FormTypeExtensionInterface`. It is replaced by the the static
`getExtendedTypes()` method which must return an iterable of extended types.
Before:
```php
class FooTypeExtension extends AbstractTypeExtension
{
public function getExtendedType()
{
return FormType::class;
}
// ...
}
```
After:
```php
class FooTypeExtension extends AbstractTypeExtension
{
public static function getExtendedTypes(): iterable
{
return array(FormType::class);
}
// ...
}
```
* The `scale` option was removed from the `IntegerType`.
* The `$scale` argument of the `IntegerToLocalizedStringTransformer` was removed.
@@ -52,6 +52,7 @@
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Form\FormTypeExtensionInterface;
use Symfony\Component\Form\FormTypeGuesserInterface;
use Symfony\Component\Form\FormTypeInterface;
use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface;
@@ -325,6 +326,8 @@ public function load(array $configs, ContainerBuilder $container)
->addTag('form.type');
$container->registerForAutoconfiguration(FormTypeGuesserInterface::class)
->addTag('form.type_guesser');
$container->registerForAutoconfiguration(FormTypeExtensionInterface::class)
->addTag('form.type_extension');
$container->registerForAutoconfiguration(CacheClearerInterface::class)
->addTag('kernel.cache_clearer');
$container->registerForAutoconfiguration(CacheWarmerInterface::class)
@@ -74,7 +74,7 @@
<!-- FormTypeHttpFoundationExtension -->
<service id="form.type_extension.form.http_foundation" class="Symfony\Component\Form\Extension\HttpFoundation\Type\FormTypeHttpFoundationExtension">
<argument type="service" id="form.type_extension.form.request_handler" />
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\FormType" />
<tag name="form.type_extension" />
</service>
<!-- HttpFoundationRequestHandler -->
@@ -92,13 +92,13 @@
<argument type="service" id="validator" />
</service>
<service id="form.type_extension.repeated.validator" class="Symfony\Component\Form\Extension\Validator\Type\RepeatedTypeValidatorExtension">
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\RepeatedType" />
<tag name="form.type_extension" />
</service>
<service id="form.type_extension.submit.validator" class="Symfony\Component\Form\Extension\Validator\Type\SubmitTypeValidatorExtension">
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\SubmitType" />
</service>
<service id="form.type_extension.upload.validator" class="Symfony\Component\Form\Extension\Validator\Type\UploadValidatorExtension">
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\FormType" />
<tag name="form.type_extension" />
<argument type="service" id="translator"/>
<argument type="string">%validator.translation_domain%</argument>
</service>
@@ -8,7 +8,7 @@
<defaults public="false" />
<service id="form.type_extension.csrf" class="Symfony\Component\Form\Extension\Csrf\Type\FormTypeCsrfExtension">
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\FormType" />
<tag name="form.type_extension" />
<argument type="service" id="security.csrf.token_manager" />
<argument>%form.type_extension.csrf.enabled%</argument>
<argument>%form.type_extension.csrf.field_name%</argument>
@@ -16,7 +16,7 @@
<!-- DataCollectorTypeExtension -->
<service id="form.type_extension.form.data_collector" class="Symfony\Component\Form\Extension\DataCollector\Type\DataCollectorTypeExtension">
<tag name="form.type_extension" extended-type="Symfony\Component\Form\Extension\Core\Type\FormType" />
<tag name="form.type_extension" />
<argument type="service" id="data_collector.form" />
</service>
@@ -39,7 +39,7 @@
"symfony/dom-crawler": "~3.4|~4.0",
"symfony/polyfill-intl-icu": "~1.0",
"symfony/security": "~3.4|~4.0",
"symfony/form": "^4.1",
"symfony/form": "^4.2",
"symfony/expression-language": "~3.4|~4.0",
"symfony/messenger": "^4.2",
"symfony/process": "~3.4|~4.0",
@@ -66,7 +66,7 @@
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
"symfony/asset": "<3.4",
"symfony/console": "<3.4",
"symfony/form": "<4.1",
"symfony/form": "<4.2",
"symfony/messenger": "<4.2",
"symfony/property-info": "<3.4",
"symfony/serializer": "<4.1",
@@ -175,9 +175,21 @@ private function initTypeExtensions()
throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormTypeExtensionInterface');
}
$type = $extension->getExtendedType();
if (method_exists($extension, 'getExtendedTypes')) {
$extendedTypes = array();
$this->typeExtensions[$type][] = $extension;
foreach ($extension::getExtendedTypes() as $extendedType) {
$extendedTypes[] = $extendedType;
}
} else {
@trigger_error(sprintf('Not implementing the static getExtendedTypes() method in %s when implementing the %s is deprecated since Symfony 4.2. The method will be added to the interface in 5.0.', \get_class($extension), FormTypeExtensionInterface::class), E_USER_DEPRECATED);
$extendedTypes = array($extension->getExtendedType());
}
foreach ($extendedTypes as $extendedType) {
$this->typeExtensions[$extendedType][] = $extension;
}
}
}
@@ -11,6 +11,7 @@
namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\LogicException;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
@@ -45,4 +46,22 @@ public function finishView(FormView $view, FormInterface $form, array $options)
public function configureOptions(OptionsResolver $resolver)
{
}
/**
* {@inheritdoc}
*
* @deprecated since Symfony 4.2, use getExtendedTypes() instead.
*/
public function getExtendedType()
{
if (!method_exists($this, 'getExtendedTypes')) {
throw new LogicException(sprintf('You need to implement the static getExtendedTypes() method when implementing the %s in %s.', FormTypeExtensionInterface::class, static::class));
}
@trigger_error(sprintf('The %s::getExtendedType() method is deprecated since Symfony 4.2 and will be removed in 5.0. Use getExtendedTypes() instead.', \get_class($this)), E_USER_DEPRECATED);
foreach (static::getExtendedTypes() as $extendedType) {
return $extendedType;
}
}
}
@@ -4,6 +4,36 @@ CHANGELOG
4.2.0
-----
* The `getExtendedType()` method of the `FormTypeExtensionInterface` is deprecated and will be removed in 5.0. Type
extensions must implement the static `getExtendedTypes()` method instead and return an iterable of extended types.
Before:
```php
class FooTypeExtension extends AbstractTypeExtension
{
public function getExtendedType()
{
return FormType::class;
}
// ...
}
```
After:
```php
class FooTypeExtension extends AbstractTypeExtension
{
public static function getExtendedTypes(): iterable
{
return array(FormType::class);
}
// ...
}
```
* deprecated the `$scale` argument of the `IntegerToLocalizedStringTransformer`
* added `Symfony\Component\Form\ClearableErrorsInterface`
* deprecated calling `FormRenderer::searchAndRenderBlock` for fields which were already rendered
@@ -18,6 +18,7 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Form\FormTypeExtensionInterface;
/**
* Adds all services with the tags "form.type", "form.type_extension" and
@@ -92,13 +93,27 @@ private function processFormTypeExtensions(ContainerBuilder $container)
$tag = $serviceDefinition->getTag($this->formTypeExtensionTag);
if (isset($tag[0]['extended_type'])) {
$extendedType = $tag[0]['extended_type'];
if (!method_exists($serviceDefinition->getClass(), 'getExtendedTypes')) {
@trigger_error(sprintf('Not implementing the static getExtendedTypes() method in %s when implementing the %s is deprecated since Symfony 4.2. The method will be added to the interface in 5.0.', $serviceDefinition->getClass(), FormTypeExtensionInterface::class), E_USER_DEPRECATED);
}
$typeExtensions[$tag[0]['extended_type']][] = new Reference($serviceId);
$typeExtensionsClasses[] = $serviceDefinition->getClass();
} elseif (method_exists($serviceDefinition->getClass(), 'getExtendedTypes')) {
$extendsTypes = false;
foreach ($serviceDefinition->getClass()::getExtendedTypes() as $extendedType) {
$typeExtensions[$extendedType][] = new Reference($serviceId);
$typeExtensionsClasses[] = $serviceDefinition->getClass();
$extendsTypes = true;
}
if (!$extendsTypes) {
throw new InvalidArgumentException(sprintf('The getExtendedTypes() method for service "%s" does not return any extended types.', $serviceId));
}
} else {
throw new InvalidArgumentException(sprintf('"%s" tagged services must have the extended type configured using the extended_type/extended-type attribute, none was configured for the "%s" service.', $this->formTypeExtensionTag, $serviceId));
throw new InvalidArgumentException(sprintf('"%s" tagged services have to implement the static getExtendedTypes() method. The class for service "%s" does not implement it.', $this->formTypeExtensionTag, $serviceId));
}
$typeExtensions[$extendedType][] = new Reference($serviceId);
$typeExtensionsClasses[] = $serviceDefinition->getClass();
}
foreach ($typeExtensions as $extendedType => $extensions) {
@@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Extension\Csrf\Type;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
@@ -114,8 +115,8 @@ public function configureOptions(OptionsResolver $resolver)
/**
* {@inheritdoc}
*/
public function getExtendedType()
public static function getExtendedTypes(): iterable
{
return 'Symfony\Component\Form\Extension\Core\Type\FormType';
return array(FormType::class);
}
}
@@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Extension\DataCollector\Type;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\DataCollector\EventListener\DataCollectorListener;
use Symfony\Component\Form\Extension\DataCollector\FormDataCollectorInterface;
use Symfony\Component\Form\FormBuilderInterface;
@@ -45,8 +46,8 @@ public function buildForm(FormBuilderInterface $builder, array $options)
/**
* {@inheritdoc}
*/
public function getExtendedType()
public static function getExtendedTypes(): iterable
{
return 'Symfony\Component\Form\Extension\Core\Type\FormType';
return array(FormType::class);
}
}
@@ -58,9 +58,19 @@ public function getTypeExtensions($name)
foreach ($this->typeExtensionServices[$name] as $serviceId => $extension) {
$extensions[] = $extension;
// validate result of getExtendedType() to ensure it is consistent with the service definition
if ($extension->getExtendedType() !== $name) {
throw new InvalidArgumentException(sprintf('The extended type specified for the service "%s" does not match the actual extended type. Expected "%s", given "%s".', $serviceId, $name, $extension->getExtendedType()));
if (method_exists($extension, 'getExtendedTypes')) {
$extendedTypes = array();
foreach ($extension::getExtendedTypes() as $extendedType) {
$extendedTypes[] = $extendedType;
}
} else {
$extendedTypes = array($extension->getExtendedType());
}
// validate the result of getExtendedTypes()/getExtendedType() to ensure it is consistent with the service definition
if (!\in_array($name, $extendedTypes, true)) {
throw new InvalidArgumentException(sprintf('The extended type specified for the service "%s" does not match the actual extended type. Expected "%s", given "%s".', $serviceId, $name, implode(', ', $extendedTypes)));
}
}
}
@@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Extension\HttpFoundation\Type;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\RequestHandlerInterface;
@@ -39,8 +40,8 @@ public function buildForm(FormBuilderInterface $builder, array $options)
/**
* {@inheritdoc}
*/
public function getExtendedType()
public static function getExtendedTypes(): iterable
{
return 'Symfony\Component\Form\Extension\Core\Type\FormType';
return array(FormType::class);
}
}
@@ -11,6 +11,7 @@
namespace Symfony\Component\Form\Extension\Validator\Type;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener;
use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper;
use Symfony\Component\Form\FormBuilderInterface;
@@ -67,8 +68,8 @@ public function configureOptions(OptionsResolver $resolver)
/**
* {@inheritdoc}
*/
public function getExtendedType()
public static function getExtendedTypes(): iterable
{
return 'Symfony\Component\Form\Extension\Core\Type\FormType';
return array(FormType::class);
}
}
Oops, something went wrong.

0 comments on commit 52b7239

Please sign in to comment.