8000 [Serializer] Add support for auto generated custom normalizers · symfony/symfony@b91c59b · GitHub
[go: up one dir, main page]

Skip to content

Commit b91c59b

Browse files
committed
[Serializer] Add support for auto generated custom normalizers
1 parent dc330b0 commit b91c59b
  • NoTypeHints
  • Some content is hidden

    Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

    71 files changed

    +4908
    -4
    lines changed

    src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

    Lines changed: 34 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1115,6 +1115,40 @@ private function addSerializerSection(ArrayNodeDefinition $rootNode, callable $e
    11151115
    ->defaultValue([])
    11161116
    ->prototype('variable')->end()
    11171117
    ->end()
    1118+
    ->arrayNode('auto_normalizer')
    1119+
    ->addDefaultsIfNotSet()
    1120+
    ->fixXmlConfig('path')
    1121+
    ->children()
    1122+
    ->arrayNode('paths')
    11 8D67 23+
    ->validate()
    1124+
    ->ifTrue(function ($data): bool {
    1125+
    foreach ($data as $key => $value) {
    1126+
    if (!\is_string($key)) {
    1127+
    return true;
    1128+
    }
    1129+
    if (!\is_string($value)) {
    1130+
    return true;
    1131+
    }
    1132+
    }
    1133+
    1134+
    return false;
    1135+
    })
    1136+
    ->thenInvalid('The value must be an array with keys and values. Keys should be the start of a namespace and the values should be a file path.')
    1137+
    ->end()
    1138+
    ->info('Paths where we store classes we want to automatically create normalizers for.')
    1139+
    ->normalizeKeys(false)
    1140+
    ->defaultValue([])
    1141+
    ->example(['App\\Model' => 'src/Model', 'App\\Entity' => 'src/Entity'])
    1142+
    ->useAttributeAsKey('name')
    1143+
    ->variablePrototype()
    1144+
    ->validate()
    1145+
    ->ifTrue(fn ($value): bool => !\is_string($value))
    1146+
    ->thenInvalid('The value must be a string representing a path relative to the project root.')
    1147+
    ->end()
    1148+
    ->end()
    1149+
    ->end()
    1150+
    ->end()
    1151+
    ->end()
    11181152
    ->end()
    11191153
    ->end()
    11201154
    ->end()

    src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

    Lines changed: 4 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1861,6 +1861,8 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
    18611861
    $container->removeDefinition('serializer.normalizer.translatable');
    18621862
    }
    18631863

    1864+
    $container->getDefinition('serializer.custom_normalizer_helper')->replaceArgument(2, $config['auto_normalizer']['paths']);
    1865+
    18641866
    $serializerLoaders = [];
    18651867
    if (isset($config['enable_attributes']) && $config['enable_attributes']) {
    18661868
    $attributeLoader = new Definition(AttributeLoader::class);
    @@ -1938,12 +1940,14 @@ private function registerPropertyInfoConfiguration(ContainerBuilder $container,
    19381940
    ) {
    19391941
    $definition = $container->register('property_info.phpstan_extractor', PhpStanExtractor::class);
    19401942
    $definition->addTag('property_info.type_extractor', ['priority' => -1000]);
    1943+
    $definition->addTag('property_info.property_info.constructor_argument_type_extractor');
    19411944
    }
    19421945

    19431946
    if (ContainerBuilder::willBeAvailable('phpdocumentor/reflection-docblock', DocBlockFactoryInterface::class, ['symfony/framework-bundle', 'symfony/property-info'], true)) {
    19441947
    $definition = $container->register('property_info.php_doc_extractor', PhpDocExtractor::class);
    19451948
    $definition->addTag('property_info.description_extractor', ['priority' => -1000]);
    19461949
    $definition->addTag('property_info.type_extractor', ['priority' => -1001]);
    1950+
    $definition->addTag('property_info.property_info.constructor_argument_type_extractor');
    19471951
    }
    19481952

    19491953
    if ($container->getParameter('kernel.debug')) {

    src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -150,8 +150,8 @@ public function build(ContainerBuilder $container): void
    150150
    $this->addCompilerPassIfExists($container, TranslationExtractorPass::class);
    151151
    $this->addCompilerPassIfExists($container, TranslationDumperPass::class);
    152152
    $container->addCompilerPass(new FragmentRendererPass());
    153-
    $this->addCompilerPassIfExists($container, SerializerPass::class);
    154153
    $this->addCompilerPassIfExists($container, PropertyInfoPass::class);
    154+
    $this->addCompilerPassIfExists($container, SerializerPass::class);
    155155
    $container->addCompilerPass(new ControllerArgumentValueResolverPass());
    156156
    $container->addCompilerPass(new CachePoolPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 32);
    157157
    $container->addCompilerPass(new CachePoolClearerPass(), PassConfig::TYPE_AFTER_REMOVING);

    src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.php

    Lines changed: 8 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -11,6 +11,8 @@
    1111

    1212
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    1313

    14+
    use Symfony\Component\PropertyInfo\Extractor\ConstructorArgumentTypeExtractorAggregate;
    15+
    use Symfony\Component\PropertyInfo\Extractor\ConstructorArgumentTypeExtractorInterface;
    1416
    use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
    1517
    use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface;
    1618
    use Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface;
    @@ -45,8 +47,14 @@
    4547
    ->tag('property_info.type_extractor', ['priority' => -1002])
    4648
    ->tag('property_info.access_extractor', ['priority' => -1000])
    4749
    ->tag('property_info.initializable_extractor', ['priority' => -1000])
    50+
    ->tag('property_info.property_info.constructor_argument_type_extractor')
    4851

    4952
    ->alias(PropertyReadInfoExtractorInterface::class, 'property_info.reflection_extractor')
    5053
    ->alias(PropertyWriteInfoExtractorInterface::class, 'property_info.reflection_extractor')
    54+
    55+
    ->set('property_info.constructor_argument_type_extractor_aggregate', ConstructorArgumentTypeExtractorAggregate::class)
    56+
    ->args([tagged_iterator('property_info.constructor_argument_type_extractor')])
    57+
    ->alias(ConstructorArgumentTypeExtractorInterface::class, 'property_info.constructor_argument_type_extractor_aggregate')
    58+
    5159
    ;
    5260
    };

    src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php

    Lines changed: 26 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -16,7 +16,14 @@
    1616
    use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
    1717
    use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
    1818
    use Symfony\Component\ErrorHandler\ErrorRenderer\SerializerErrorRenderer;
    19+
    use Symfony\Component\PropertyInfo\Extractor\ConstructorArgumentTypeExtractorInterface;
    1920
    use Symfony\Component\PropertyInfo\Extractor\SerializerExtractor;
    21+
    use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
    22+
    use Symfony\Component\PropertyInfo\PropertyReadInfoExtractorInterface;
    23+
    use Symfony\Component\PropertyInfo\PropertyWriteInfoExtractorInterface;
    24+
    use Symfony\Component\Serializer\Builder\DefinitionExtractor;
    25+
    use Symfony\Component\Serializer\Builder\NormalizerBuilder;
    26+
    use Symfony\Component\Serializer\DependencyInjection\CustomNormalizerHelper;
    2027
    use Symfony\Component\Serializer\Encoder\CsvEncoder;
    2128
    use Symfony\Component\Serializer\Encoder\DecoderInterface;
    2229
    use Symfony\Component\Serializer\Encoder\EncoderInterface;
    @@ -169,6 +176,25 @@
    169176
    service('serializer.mapping.cache.symfony'),
    170177
    ])
    171178

    179+
    // Auto Normalizer Builder
    180+
    ->set('serializer.auto_normalizer.builder', NormalizerBuilder::class)
    181+
    ->set('serializer.auto_normalizer.definition_extractor', DefinitionExtractor::class)
    182+
    ->args([
    183+
    service(PropertyInfoExtractorInterface::class),
    184+
    service(PropertyReadInfoExtractorInterface::class),
    185+
    service(PropertyWriteInfoExtractorInterface::class),
    186+
    service(ConstructorArgumentTypeExtractorInterface::class),
    187+
    ])
    188+
    189+
    ->set('serializer.custom_normalizer_helper', CustomNormalizerHelper::class)
    190+
    ->args([
    191+
    service('serializer.auto_normalizer.builder'),
    192+
    service('serializer.auto_normalizer.definition_extractor'),
    193+
    [],
    194+
    param('kernel.project_dir'),
    195+
    service('logger')->nullOnInvalid(),
    196+
    ])
    197+
    172198
    // Encoders
    173199
    ->set('serializer.encoder.xml', XmlEncoder::class)
    174200
    ->tag('serializer.encoder')

    src/Symfony/Component/PropertyInfo/CHANGELOG.md

    Lines changed: 2 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -5,6 +5,8 @@ CHANGELOG
    55
    ---
    66

    77
    * Introduce `PropertyDocBlockExtractorInterface` to extract a property's doc block
    8+
    * Make ConstructorArgumentTypeExtractorInterface non-internal
    9+
    * Add `ConstructorArgumentTypeExtractorAggregate` to aggregate multiple `ConstructorArgumentTypeExtractorInterface` implementations
    810

    911
    6.4
    1012
    ---
    Lines changed: 43 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,43 @@
    1+
    <?php
    2+
    3+
    /*
    4+
    * This file is part of the Symfony package.
    5+
    *
    6+
    * (c) Fabien Potencier <fabien@symfony.com>
    7+
    *
    8+
    * For the full copyright and license information, please view the LICENSE
    9+
    * file that was distributed with this source code.
    10+
    */
    11+
    12+
    namespace Symfony\Component\PropertyInfo\Extractor;
    13+
    14+
    /**
    15+
    * @author Tobias Nyholm <tobias.nyholm@gmail.com>
    16+
    */
    17+
    class ConstructorArgumentTypeExtractorAggregate implements ConstructorArgumentTypeExtractorInterface
    18+
    {
    19+
    /**
    20+
    * @param iterable<int, ConstructorArgumentTypeExtractorInterface> $extractors
    21+
    */
    22+
    public function __construct(
    23+
    private readonly iterable $extractors = [],
    24+
    ) {
    25+
    }
    26+
    27+
    public function getTypesFromConstructor(string $class, string $property): ?array
    28+
    {
    29+
    $output = [];
    30+
    foreach ($this->extractors as $extractor) {
    31+
    $value = $extractor->getTypesFromConstructor($class, $property);
    32+
    if (null !== $value) {
    33+
    $output[] = $value;
    34+
    }
    35+
    }
    36+
    37+
    if ([] === $output) {
    38+
    return null;
    39+
    }
    40+
    41+
    return array_merge([], ...$output);
    42+
    }
    43+
    }

    src/Symfony/Component/PropertyInfo/Extractor/ConstructorArgumentTypeExtractorInterface.php

    Lines changed: 0 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -17,8 +17,6 @@
    1717
    * Infers the constructor argument type.
    1818
    *
    1919
    * @author Dmitrii Poddubnyi <dpoddubny@gmail.com>
    20-
    *
    21-
    * @internal
    2220
    */
    2321
    interface ConstructorArgumentTypeExtractorInterface
    2422
    {
    Lines changed: 9 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,9 @@
    1+
    # Ignore paths
    2+
    [Tests/CodeGenerator/Fixtures/**]
    3+
    trim_trailing_whitespace = false
    4+
    5+
    [Tests/Fixtures/CustomNormalizer/**/ExpectedNormalizer/**]
    6+
    trim_trailing_whitespace = false
    7+
    insert_final_newline = false
    8+
    indent_size = unset
    9+
    indent_style = unset
    Lines changed: 1 addition & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,3 +1,4 @@
    11
    vendor/
    22
    composer.lock
    33
    phpunit.xml
    4+
    Tests/_output

    0 commit comments

    Comments
     (0)
    0