diff --git a/src/Maker/MakeSerializerNormalizer.php b/src/Maker/MakeSerializerNormalizer.php index c82a7b593..bf193a68a 100644 --- a/src/Maker/MakeSerializerNormalizer.php +++ b/src/Maker/MakeSerializerNormalizer.php @@ -17,11 +17,10 @@ use Symfony\Bundle\MakerBundle\Generator; use Symfony\Bundle\MakerBundle\InputConfiguration; use Symfony\Bundle\MakerBundle\Util\UseStatementGenerator; -use Symfony\Bundle\MakerBundle\Util\YamlSourceManipulator; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Serializer; @@ -30,8 +29,15 @@ */ final class MakeSerializerNormalizer extends AbstractMaker { - public function __construct(private FileManager $fileManager) + public function __construct(private ?FileManager $fileManager = null) { + if (null !== $this->fileManager) { + @trigger_deprecation( + 'symfony/maker-bundle', + '1.56.0', + sprintf('Initializing MakeSerializerNormalizer while providing an instance of "%s" is deprecated. The $fileManager param will be removed in a future version.', FileManager::class) + ); + } } public static function getCommandName(): string @@ -54,35 +60,41 @@ public function configureCommand(Command $command, InputConfiguration $inputConf public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator): void { - $nextSteps = []; - $normalizerClassNameDetails = $generator->createClassNameDetails( $input->getArgument('name'), 'Serializer\\Normalizer\\', \Normalizer::class ); - $this->generateNormalizer($normalizerClassNameDetails->getFullName(), $generator); + $useStatements = new UseStatementGenerator([ + NormalizerInterface::class, + Autowire::class, + sprintf('App\Entity\%s', str_replace('Normalizer', '', $normalizerClassNameDetails->getShortName())), + ]); + + $entityDetails = $generator->createClassNameDetails( + str_replace('Normalizer', '', $normalizerClassNameDetails->getShortName()), + 'Entity\\', + ); - try { - $this->configureNormalizerService($normalizerClassNameDetails->getFullName(), $generator); - } catch (\Throwable) { - $nextSteps[] = "Your services.yaml could not be updated automatically. You'll need to inject the \$objectNormalizer argument to manually."; + if ($entityExists = class_exists($entityDetails->getFullName())) { + $useStatements->addUseStatement($entityDetails->getFullName()); } + $generator->generateClass($normalizerClassNameDetails->getFullName(), 'serializer/Normalizer.tpl.php', [ + 'use_statements' => $useStatements, + 'entity_exists' => $entityExists, + 'entity_name' => $entityDetails->getShortName(), + ]); + $generator->writeChanges(); $this->writeSuccessMessage($io); - array_push( - $nextSteps, - 'Open your new serializer normalizer class and start customizing it.', - 'Find the documentation at https://symfony.com/doc/current/serializer/custom_normalizer.html', - ); - $io->text([ 'Next:', - ...array_map(static fn (string $s): string => sprintf(' - %s', $s), $nextSteps), + ' - Open your new serializer normalizer class and start customizing it.', + ' - Find the documentation at https://symfony.com/doc/current/serializer/custom_normalizer.html', ]); } @@ -93,35 +105,4 @@ public function configureDependencies(DependencyBuilder $dependencies): void 'serializer' ); } - - private function generateNormalizer(string $className, Generator $generator): void - { - $useStatements = new UseStatementGenerator([ - NormalizerInterface::class, - CacheableSupportsMethodInterface::class, - ]); - - $generator->generateClass($className, 'serializer/Normalizer.tpl.php', [ - 'use_statements' => $useStatements, - ]); - } - - private function configureNormalizerService(string $className, Generator $generator): void - { - $servicesFilePath = 'config/services.yaml'; - - $manipulator = new YamlSourceManipulator($this->fileManager->getFileContents($servicesFilePath)); - $servicesData = $manipulator->getData(); - - if (!isset($servicesData['services'][$className])) { - $servicesData['services'][$className] = [ - 'arguments' => [ - '$objectNormalizer' => '@serializer.normalizer.object', - ], - ]; - } - - $manipulator->setData($servicesData); - $generator->dumpFile($servicesFilePath, $manipulator->getContents()); - } } diff --git a/src/Resources/config/makers.xml b/src/Resources/config/makers.xml index 4c3a0e152..b3eee7745 100644 --- a/src/Resources/config/makers.xml +++ b/src/Resources/config/makers.xml @@ -97,7 +97,6 @@ - diff --git a/src/Resources/skeleton/serializer/Normalizer.tpl.php b/src/Resources/skeleton/serializer/Normalizer.tpl.php index af212e4af..8fdeee82b 100644 --- a/src/Resources/skeleton/serializer/Normalizer.tpl.php +++ b/src/Resources/skeleton/serializer/Normalizer.tpl.php @@ -4,10 +4,12 @@ -class implements NormalizerInterface, CacheableSupportsMethodInterface +class implements NormalizerInterface { - public function __construct(private NormalizerInterface $objectNormalizer) - { + public function __construct( + #[Autowire(service: 'serializer.normalizer.object')] + private NormalizerInterface $normalizer + ) { } public function normalize($object, string $format = null, array $context = []): array @@ -21,11 +23,19 @@ public function normalize($object, string $format = null, array $context = []): public function supportsNormalization($data, string $format = null, array $context = []): bool { - return $data instanceof \App\Entity\; + + return $data instanceof ; + + // TODO: return $data instanceof Object + } - public function hasCacheableSupportsMethod(): bool + public function getSupportedTypes(?string $format): array { - return true; + + return [::class => true]; + + // TODO: return [Object::class => true]; + } } diff --git a/tests/Maker/MakeSerializerNormalizerTest.php b/tests/Maker/MakeSerializerNormalizerTest.php index a27196d90..a9fee2feb 100644 --- a/tests/Maker/MakeSerializerNormalizerTest.php +++ b/tests/Maker/MakeSerializerNormalizerTest.php @@ -22,20 +22,36 @@ protected function getMakerClass(): string return MakeSerializerNormalizer::class; } - public function getTestDetails() + public function getTestDetails(): \Generator { yield 'it_makes_serializer_normalizer' => [$this->createMakerTest() - // serializer-pack 1.1 requires symfony/property-info >= 5.4 - // adding symfony/serializer-pack:* as an extra depends allows - // us to use serializer-pack < 1.1 which does not conflict with - // property-info < 5.4. E.g. Symfony 5.3 tests. See PR 1063 - ->addExtraDependencies('symfony/serializer-pack:*') ->run(function (MakerTestRunner $runner) { - $runner->runMaker( - [ - // normalizer class name - 'FooBarNormalizer', - ] + $output = $runner->runMaker( + ['FooBarNormalizer'] + ); + + $this->assertStringContainsString('Success', $output); + + self::assertFileEquals( + \dirname(__DIR__).'/fixtures/make-serializer-normalizer/FooBarNormalizer.php', + $runner->getPath('src/Serializer/Normalizer/FooBarNormalizer.php') + ); + }), + ]; + + yield 'it_makes_serializer_normalizer_with_existing_entity' => [$this->createMakerTest() + ->run(function (MakerTestRunner $runner) { + $runner->copy('make-serializer-normalizer/EntityFixture.php', 'src/Entity/EntityFixture.php'); + + $output = $runner->runMaker( + ['EntityFixture'] + ); + + $this->assertStringContainsString('Success', $output); + + self::assertFileEquals( + \dirname(__DIR__).'/fixtures/make-serializer-normalizer/EntityFixtureNormalizer.php', + $runner->getPath('src/Serializer/Normalizer/EntityFixtureNormalizer.php') ); }), ]; diff --git a/tests/fixtures/make-serializer-normalizer/EntityFixture.php b/tests/fixtures/make-serializer-normalizer/EntityFixture.php new file mode 100644 index 000000000..b9c95a990 --- /dev/null +++ b/tests/fixtures/make-serializer-normalizer/EntityFixture.php @@ -0,0 +1,7 @@ +normalizer->normalize($object, $format, $context); + + // TODO: add, edit, or delete some data + + return $data; + } + + public function supportsNormalization($data, ?string $format = null, array $context = []): bool + { + return $data instanceof EntityFixture; + } + + public function getSupportedTypes(?string $format): array + { + return [EntityFixture::class => true]; + } +} diff --git a/tests/fixtures/make-serializer-normalizer/FooBarNormalizer.php b/tests/fixtures/make-serializer-normalizer/FooBarNormalizer.php new file mode 100644 index 000000000..3f253fdbd --- /dev/null +++ b/tests/fixtures/make-serializer-normalizer/FooBarNormalizer.php @@ -0,0 +1,34 @@ +normalizer->normalize($object, $format, $context); + + // TODO: add, edit, or delete some data + + return $data; + } + + public function supportsNormalization($data, ?string $format = null, array $context = []): bool + { + // TODO: return $data instanceof Object + } + + public function getSupportedTypes(?string $format): array + { + // TODO: return [Object::class => true]; + } +}