diff --git a/composer.json b/composer.json index 263117fc8ddc4..55c4d866a95ff 100644 --- a/composer.json +++ b/composer.json @@ -83,7 +83,7 @@ "symfony/http-foundation": "self.version", "symfony/http-kernel": "self.version", "symfony/intl": "self.version", - "symfony/json-encoder": "self.version", + "symfony/json-streamer": "self.version", "symfony/ldap": "self.version", "symfony/lock": "self.version", "symfony/mailer": "self.version", diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 3b9873591065e..17201aeaec284 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -6,7 +6,7 @@ CHANGELOG * Add support for assets pre-compression * Rename `TranslationUpdateCommand` to `TranslationExtractCommand` - * Add JsonEncoder services and configuration + * Add JsonStreamer services and configuration * Add new `framework.property_info.with_constructor_extractor` option to allow enabling or disabling the constructor extractor integration * Deprecate the `--show-arguments` option of the `container:debug` command, as arguments are now always shown * Add `RateLimiterFactoryInterface` as an alias of the `limiter` service diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php index c5191a6599dc4..c8271d46335cc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php @@ -53,7 +53,7 @@ class UnusedTagsPass implements CompilerPassInterface 'form.type_guesser', 'html_sanitizer', 'http_client.client', - 'json_encoder.value_transformer', + 'json_streamer.value_transformer', 'kernel.cache_clearer', 'kernel.cache_warmer', 'kernel.event_listener', diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index d4bf35257a0ed..ce77b50f8585f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -31,7 +31,7 @@ use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\IpUtils; -use Symfony\Component\JsonEncoder\EncoderInterface; +use Symfony\Component\JsonStreamer\StreamWriterInterface; use Symfony\Component\Lock\Lock; use Symfony\Component\Lock\Store\SemaphoreStore; use Symfony\Component\Mailer\Mailer; @@ -182,7 +182,7 @@ public function getConfigTreeBuilder(): TreeBuilder $this->addHtmlSanitizerSection($rootNode, $enableIfStandalone); $this->addWebhookSection($rootNode, $enableIfStandalone); $this->addRemoteEventSection($rootNode, $enableIfStandalone); - $this->addJsonEncoderSection($rootNode, $enableIfStandalone); + $this->addJsonStreamerSection($rootNode, $enableIfStandalone); return $treeBuilder; } @@ -2692,13 +2692,13 @@ private function addHtmlSanitizerSection(ArrayNodeDefinition $rootNode, callable ; } - private function addJsonEncoderSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone): void + private function addJsonStreamerSection(ArrayNodeDefinition $rootNode, callable $enableIfStandalone): void { $rootNode ->children() - ->arrayNode('json_encoder') - ->info('JSON encoder configuration') - ->{$enableIfStandalone('symfony/json-encoder', EncoderInterface::class)}() + ->arrayNode('json_streamer') + ->info('JSON streamer configuration') + ->{$enableIfStandalone('symfony/json-streamer', StreamWriterInterface::class)}() ->end() ->end() ; diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 73024eaf8abc4..6be0e2be72651 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -100,11 +100,11 @@ use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\HttpKernel\Log\DebugLoggerConfigurator; -use Symfony\Component\JsonEncoder\Attribute\JsonEncodable; -use Symfony\Component\JsonEncoder\DecoderInterface as JsonEncoderDecoderInterface; -use Symfony\Component\JsonEncoder\EncoderInterface as JsonEncoderEncoderInterface; -use Symfony\Component\JsonEncoder\JsonEncoder; -use Symfony\Component\JsonEncoder\ValueTransformer\ValueTransformerInterface; +use Symfony\Component\JsonStreamer\Attribute\JsonStreamable; +use Symfony\Component\JsonStreamer\JsonStreamWriter; +use Symfony\Component\JsonStreamer\StreamReaderInterface; +use Symfony\Component\JsonStreamer\StreamWriterInterface; +use Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface; use Symfony\Component\Lock\LockFactory; use Symfony\Component\Lock\LockInterface; use Symfony\Component\Lock\PersistingStoreInterface; @@ -436,12 +436,12 @@ public function load(array $configs, ContainerBuilder $container): void $this->registerPropertyInfoConfiguration($config['property_info'], $container, $loader); } - if ($this->readConfigEnabled('json_encoder', $container, $config['json_encoder'])) { + if ($this->readConfigEnabled('json_streamer', $container, $config['json_streamer'])) { if (!$typeInfoEnabled) { - throw new LogicException('JsonEncoder support cannot be enabled as the TypeInfo component is not '.(interface_exists(TypeResolverInterface::class) ? 'enabled.' : 'installed. Try running "composer require symfony/type-info".')); + throw new LogicException('JsonStreamer support cannot be enabled as the TypeInfo component is not '.(interface_exists(TypeResolverInterface::class) ? 'enabled.' : 'installed. Try running "composer require symfony/type-info".')); } - $this->registerJsonEncoderConfiguration($config['json_encoder'], $container, $loader); + $this->registerJsonStreamerConfiguration($config['json_streamer'], $container, $loader); } if ($this->readConfigEnabled('lock', $container, $config['lock'])) { @@ -755,8 +755,8 @@ static function (ChildDefinition $definition, AsPeriodicTask|AsCronTask $attribu } ); } - $container->registerAttributeForAutoconfiguration(JsonEncodable::class, static function (ChildDefinition $definition, JsonEncodable $attribute): void { - $definition->addTag('json_encoder.encodable', [ + $container->registerAttributeForAutoconfiguration(JsonStreamable::class, static function (ChildDefinition $definition, JsonStreamable $attribute): void { + $definition->addTag('json_streamer.streamable', [ 'object' => $attribute->asObject, 'list' => $attribute->asList, ]); @@ -2033,26 +2033,26 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder $container->setParameter('.serializer.named_serializers', $config['named_serializers'] ?? []); } - private function registerJsonEncoderConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader): void + private function registerJsonStreamerConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader): void { - if (!class_exists(JsonEncoder::class)) { - throw new LogicException('JsonEncoder support cannot be enabled as the JsonEncoder component is not installed. Try running "composer require symfony/json-encoder".'); + if (!class_exists(JsonStreamWriter::class)) { + throw new LogicException('JsonStreamer support cannot be enabled as the JsonStreamer component is not installed. Try running "composer require symfony/json-streamer".'); } $container->registerForAutoconfiguration(ValueTransformerInterface::class) - ->addTag('json_encoder.value_transformer'); + ->addTag('json_streamer.value_transformer'); - $loader->load('json_encoder.php'); + $loader->load('json_streamer.php'); - $container->registerAliasForArgument('json_encoder.encoder', JsonEncoderEncoderInterface::class, 'json.encoder'); - $container->registerAliasForArgument('json_encoder.decoder', JsonEncoderDecoderInterface::class, 'json.decoder'); + $container->registerAliasForArgument('json_streamer.stream_writer', StreamWriterInterface::class, 'json.stream_writer'); + $container->registerAliasForArgument('json_streamer.stream_reader', StreamReaderInterface::class, 'json.stream_reader'); - $container->setParameter('.json_encoder.encoders_dir', '%kernel.cache_dir%/json_encoder/encoder'); - $container->setParameter('.json_encoder.decoders_dir', '%kernel.cache_dir%/json_encoder/decoder'); - $container->setParameter('.json_encoder.lazy_ghosts_dir', '%kernel.cache_dir%/json_encoder/lazy_ghost'); + $container->setParameter('.json_streamer.stream_writers_dir', '%kernel.cache_dir%/json_streamer/stream_writer'); + $container->setParameter('.json_streamer.stream_readers_dir', '%kernel.cache_dir%/json_streamer/stream_reader'); + $container->setParameter('.json_streamer.lazy_ghosts_dir', '%kernel.cache_dir%/json_streamer/lazy_ghost'); if (\PHP_VERSION_ID >= 80400) { - $container->removeDefinition('.json_encoder.cache_warmer.lazy_ghost'); + $container->removeDefinition('.json_streamer.cache_warmer.lazy_ghost'); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 89d9744f514e4..faf2841f40105 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -54,7 +54,7 @@ use Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass; use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass; use Symfony\Component\HttpKernel\KernelEvents; -use Symfony\Component\JsonEncoder\DependencyInjection\EncodablePass; +use Symfony\Component\JsonStreamer\DependencyInjection\StreamablePass; use Symfony\Component\Messenger\DependencyInjection\MessengerPass; use Symfony\Component\Mime\DependencyInjection\AddMimeTypeGuesserPass; use Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoConstructorPass; @@ -189,7 +189,7 @@ public function build(ContainerBuilder $container): void $container->addCompilerPass(new ErrorLoggerCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32); $container->addCompilerPass(new VirtualRequestStackPass()); $container->addCompilerPass(new TranslationUpdateCommandPass(), PassConfig::TYPE_BEFORE_REMOVING); - $this->addCompilerPassIfExists($container, EncodablePass::class); + $this->addCompilerPassIfExists($container, StreamablePass::class); if ($container->getParameter('kernel.debug')) { $container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 2); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/json_encoder.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/json_encoder.php deleted file mode 100644 index f6fbd05e6f038..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/json_encoder.php +++ /dev/null @@ -1,119 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Loader\Configurator; - -use Symfony\Component\JsonEncoder\CacheWarmer\EncoderDecoderCacheWarmer; -use Symfony\Component\JsonEncoder\CacheWarmer\LazyGhostCacheWarmer; -use Symfony\Component\JsonEncoder\JsonDecoder; -use Symfony\Component\JsonEncoder\JsonEncoder; -use Symfony\Component\JsonEncoder\Mapping\Decode\AttributePropertyMetadataLoader as DecodeAttributePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\Decode\DateTimeTypePropertyMetadataLoader as DecodeDateTimeTypePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\Encode\AttributePropertyMetadataLoader as EncodeAttributePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\Encode\DateTimeTypePropertyMetadataLoader as EncodeDateTimeTypePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\GenericTypePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoader; -use Symfony\Component\JsonEncoder\ValueTransformer\DateTimeToStringValueTransformer; -use Symfony\Component\JsonEncoder\ValueTransformer\StringToDateTimeValueTransformer; - -return static function (ContainerConfigurator $container) { - $container->services() - // encoder/decoder - ->set('json_encoder.encoder', JsonEncoder::class) - ->args([ - tagged_locator('json_encoder.value_transformer'), - service('json_encoder.encode.property_metadata_loader'), - param('.json_encoder.encoders_dir'), - ]) - ->set('json_encoder.decoder', JsonDecoder::class) - ->args([ - tagged_locator('json_encoder.value_transformer'), - service('json_encoder.decode.property_metadata_loader'), - param('.json_encoder.decoders_dir'), - param('.json_encoder.lazy_ghosts_dir'), - ]) - ->alias(JsonEncoder::class, 'json_encoder.encoder') - ->alias(JsonDecoder::class, 'json_encoder.decoder') - - // metadata - ->set('json_encoder.encode.property_metadata_loader', PropertyMetadataLoader::class) - ->args([ - service('type_info.resolver'), - ]) - ->set('.json_encoder.encode.property_metadata_loader.generic', GenericTypePropertyMetadataLoader::class) - ->decorate('json_encoder.encode.property_metadata_loader') - ->args([ - service('.inner'), - service('type_info.type_context_factory'), - ]) - ->set('.json_encoder.encode.property_metadata_loader.date_time', EncodeDateTimeTypePropertyMetadataLoader::class) - ->decorate('json_encoder.encode.property_metadata_loader') - ->args([ - service('.inner'), - ]) - ->set('.json_encoder.encode.property_metadata_loader.attribute', EncodeAttributePropertyMetadataLoader::class) - ->decorate('json_encoder.encode.property_metadata_loader') - ->args([ - service('.inner'), - tagged_locator('json_encoder.value_transformer'), - service('type_info.resolver'), - ]) - - ->set('json_encoder.decode.property_metadata_loader', PropertyMetadataLoader::class) - ->args([ - service('type_info.resolver'), - ]) - ->set('.json_encoder.decode.property_metadata_loader.generic', GenericTypePropertyMetadataLoader::class) - ->decorate('json_encoder.decode.property_metadata_loader') - ->args([ - service('.inner'), - service('type_info.type_context_factory'), - ]) - ->set('.json_encoder.decode.property_metadata_loader.date_time', DecodeDateTimeTypePropertyMetadataLoader::class) - ->decorate('json_encoder.decode.property_metadata_loader') - ->args([ - service('.inner'), - ]) - ->set('.json_encoder.decode.property_metadata_loader.attribute', DecodeAttributePropertyMetadataLoader::class) - ->decorate('json_encoder.decode.property_metadata_loader') - ->args([ - service('.inner'), - tagged_locator('json_encoder.value_transformer'), - service('type_info.resolver'), - ]) - - // value transformers - ->set('json_encoder.value_transformer.date_time_to_string', DateTimeToStringValueTransformer::class) - ->tag('json_encoder.value_transformer') - - ->set('json_encoder.value_transformer.string_to_date_time', StringToDateTimeValueTransformer::class) - ->tag('json_encoder.value_transformer') - - // cache - ->set('.json_encoder.cache_warmer.encoder_decoder', EncoderDecoderCacheWarmer::class) - ->args([ - abstract_arg('encodable class names'), - service('json_encoder.encode.property_metadata_loader'), - service('json_encoder.decode.property_metadata_loader'), - param('.json_encoder.encoders_dir'), - param('.json_encoder.decoders_dir'), - service('logger')->ignoreOnInvalid(), - ]) - ->tag('kernel.cache_warmer') - - ->set('.json_encoder.cache_warmer.lazy_ghost', LazyGhostCacheWarmer::class) - ->args([ - abstract_arg('encodable class names'), - param('.json_encoder.lazy_ghosts_dir'), - ]) - ->tag('kernel.cache_warmer') - ; -}; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/json_streamer.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/json_streamer.php new file mode 100644 index 0000000000000..79fb25833e066 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/json_streamer.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Loader\Configurator; + +use Symfony\Component\JsonStreamer\CacheWarmer\LazyGhostCacheWarmer; +use Symfony\Component\JsonStreamer\CacheWarmer\StreamerCacheWarmer; +use Symfony\Component\JsonStreamer\JsonStreamReader; +use Symfony\Component\JsonStreamer\JsonStreamWriter; +use Symfony\Component\JsonStreamer\Mapping\GenericTypePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\Read\AttributePropertyMetadataLoader as ReadAttributePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\Read\DateTimeTypePropertyMetadataLoader as ReadDateTimeTypePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\Write\AttributePropertyMetadataLoader as WriteAttributePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\Write\DateTimeTypePropertyMetadataLoader as WriteDateTimeTypePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\ValueTransformer\DateTimeToStringValueTransformer; +use Symfony\Component\JsonStreamer\ValueTransformer\StringToDateTimeValueTransformer; + +return static function (ContainerConfigurator $container) { + $container->services() + // stream reader/writer + ->set('json_streamer.stream_writer', JsonStreamWriter::class) + ->args([ + tagged_locator('json_streamer.value_transformer'), + service('json_streamer.write.property_metadata_loader'), + param('.json_streamer.stream_writers_dir'), + ]) + ->set('json_streamer.stream_reader', JsonStreamReader::class) + ->args([ + tagged_locator('json_streamer.value_transformer'), + service('json_streamer.read.property_metadata_loader'), + param('.json_streamer.stream_readers_dir'), + param('.json_streamer.lazy_ghosts_dir'), + ]) + ->alias(JsonStreamWriter::class, 'json_streamer.stream_writer') + ->alias(JsonStreamReader::class, 'json_streamer.stream_reader') + + // metadata + ->set('json_streamer.write.property_metadata_loader', PropertyMetadataLoader::class) + ->args([ + service('type_info.resolver'), + ]) + ->set('.json_streamer.write.property_metadata_loader.generic', GenericTypePropertyMetadataLoader::class) + ->decorate('json_streamer.write.property_metadata_loader') + ->args([ + service('.inner'), + service('type_info.type_context_factory'), + ]) + ->set('.json_streamer.write.property_metadata_loader.date_time', WriteDateTimeTypePropertyMetadataLoader::class) + ->decorate('json_streamer.write.property_metadata_loader') + ->args([ + service('.inner'), + ]) + ->set('.json_streamer.write.property_metadata_loader.attribute', WriteAttributePropertyMetadataLoader::class) + ->decorate('json_streamer.write.property_metadata_loader') + ->args([ + service('.inner'), + tagged_locator('json_streamer.value_transformer'), + service('type_info.resolver'), + ]) + + ->set('json_streamer.read.property_metadata_loader', PropertyMetadataLoader::class) + ->args([ + service('type_info.resolver'), + ]) + ->set('.json_streamer.read.property_metadata_loader.generic', GenericTypePropertyMetadataLoader::class) + ->decorate('json_streamer.read.property_metadata_loader') + ->args([ + service('.inner'), + service('type_info.type_context_factory'), + ]) + ->set('.json_streamer.read.property_metadata_loader.date_time', ReadDateTimeTypePropertyMetadataLoader::class) + ->decorate('json_streamer.read.property_metadata_loader') + ->args([ + service('.inner'), + ]) + ->set('.json_streamer.read.property_metadata_loader.attribute', ReadAttributePropertyMetadataLoader::class) + ->decorate('json_streamer.read.property_metadata_loader') + ->args([ + service('.inner'), + tagged_locator('json_streamer.value_transformer'), + service('type_info.resolver'), + ]) + + // value transformers + ->set('json_streamer.value_transformer.date_time_to_string', DateTimeToStringValueTransformer::class) + ->tag('json_streamer.value_transformer') + + ->set('json_streamer.value_transformer.string_to_date_time', StringToDateTimeValueTransformer::class) + ->tag('json_streamer.value_transformer') + + // cache + ->set('.json_streamer.cache_warmer.streamer', StreamerCacheWarmer::class) + ->args([ + abstract_arg('streamable'), + service('json_streamer.write.property_metadata_loader'), + service('json_streamer.read.property_metadata_loader'), + param('.json_streamer.stream_writers_dir'), + param('.json_streamer.stream_readers_dir'), + service('logger')->ignoreOnInvalid(), + ]) + ->tag('kernel.cache_warmer') + + ->set('.json_streamer.cache_warmer.lazy_ghost', LazyGhostCacheWarmer::class) + ->args([ + abstract_arg('streamable class names'), + param('.json_streamer.lazy_ghosts_dir'), + ]) + ->tag('kernel.cache_warmer') + ; +}; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index b47de331a4775..ae69a5aa9a66c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -46,7 +46,7 @@ - + @@ -1041,7 +1041,7 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 6dbb0f0e39ed3..6842cf9e92705 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -22,7 +22,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HtmlSanitizer\HtmlSanitizer; use Symfony\Component\HttpClient\HttpClient; -use Symfony\Component\JsonEncoder\JsonEncoder; +use Symfony\Component\JsonStreamer\JsonStreamWriter; use Symfony\Component\Lock\Store\SemaphoreStore; use Symfony\Component\Mailer\Mailer; use Symfony\Component\Messenger\MessageBusInterface; @@ -1009,8 +1009,8 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor 'remote-event' => [ 'enabled' => !class_exists(FullStack::class) && class_exists(RemoteEvent::class), ], - 'json_encoder' => [ - 'enabled' => !class_exists(FullStack::class) && class_exists(JsonEncoder::class), + 'json_streamer' => [ + 'enabled' => !class_exists(FullStack::class) && class_exists(JsonStreamWriter::class), ], ]; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/json_encoder.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/json_streamer.php similarity index 91% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/json_encoder.php rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/json_streamer.php index 42204b2cbb1dd..844b72004d6a6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/json_encoder.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/json_streamer.php @@ -8,7 +8,7 @@ 'type_info' => [ 'enabled' => true, ], - 'json_encoder' => [ + 'json_streamer' => [ 'enabled' => true, ], ]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml index 23d325e61c7a4..07faf22ab2ef1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml @@ -46,6 +46,6 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/json_encoder.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/json_streamer.xml similarity index 93% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/json_encoder.xml rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/json_streamer.xml index a20f98567581a..5c79cb8401642 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/json_encoder.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/json_streamer.xml @@ -9,6 +9,6 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml index 28c4336d93872..8a1a3834ba719 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml @@ -71,4 +71,4 @@ framework: formats: csv: ['text/csv', 'text/plain'] pdf: 'application/pdf' - json_encoder: ~ + json_streamer: ~ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/json_encoder.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/json_streamer.yml similarity index 90% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/json_encoder.yml rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/json_streamer.yml index e09f7c7d368b0..8873fea97a8ef 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/json_encoder.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/json_streamer.yml @@ -6,5 +6,5 @@ framework: log: true type_info: enabled: true - json_encoder: + json_streamer: enabled: true diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php index d48dd6ad6dff9..8581e4c8b4f73 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php @@ -2551,10 +2551,10 @@ public function testSemaphoreWithService() self::assertEquals(new Reference('my_service'), $storeDef->getArgument(0)); } - public function testJsonEncoderEnabled() + public function testJsonStreamerEnabled() { - $container = $this->createContainerFromFile('json_encoder'); - $this->assertTrue($container->has('json_encoder.encoder')); + $container = $this->createContainerFromFile('json_streamer'); + $this->assertTrue($container->has('json_streamer.stream_writer')); } protected function createContainer(array $data = []) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/JsonEncoderTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/JsonEncoderTest.php deleted file mode 100644 index b5410e1e1127b..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/JsonEncoderTest.php +++ /dev/null @@ -1,67 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\FrameworkBundle\Tests\Functional; - -use Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonEncoder\Dto\Dummy; -use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\JsonEncoder\DecoderInterface; -use Symfony\Component\JsonEncoder\EncoderInterface; -use Symfony\Component\TypeInfo\Type; - -/** - * @author Mathias Arlaud - */ -class JsonEncoderTest extends AbstractWebTestCase -{ - protected function setUp(): void - { - static::bootKernel(['test_case' => 'JsonEncoder']); - } - - public function testEncode() - { - /** @var EncoderInterface $encoder */ - $encoder = static::getContainer()->get('json_encoder.encoder.alias'); - - $this->assertSame('{"@name":"DUMMY","range":"10..20"}', (string) $encoder->encode(new Dummy(), Type::object(Dummy::class))); - } - - public function testDecode() - { - /** @var DecoderInterface $decoder */ - $decoder = static::getContainer()->get('json_encoder.decoder.alias'); - - $expected = new Dummy(); - $expected->name = 'dummy'; - $expected->range = [0, 1]; - - $this->assertEquals($expected, $decoder->decode('{"@name": "DUMMY", "range": "0..1"}', Type::object(Dummy::class))); - } - - public function testWarmupEncodableClasses() - { - /** @var Filesystem $fs */ - $fs = static::getContainer()->get('filesystem'); - - $encodersDir = \sprintf('%s/json_encoder/encoder/', static::getContainer()->getParameter('kernel.cache_dir')); - - // clear already created encoders - if ($fs->exists($encodersDir)) { - $fs->remove($encodersDir); - } - - static::getContainer()->get('json_encoder.cache_warmer.encoder_decoder.alias')->warmUp(static::getContainer()->getParameter('kernel.cache_dir')); - - $this->assertFileExists($encodersDir); - $this->assertCount(2, glob($encodersDir.'/*')); - } -} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/JsonStreamerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/JsonStreamerTest.php new file mode 100644 index 0000000000000..9816015b4484e --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/JsonStreamerTest.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional; + +use Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonStreamer\Dto\Dummy; +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\JsonStreamer\StreamReaderInterface; +use Symfony\Component\JsonStreamer\StreamWriterInterface; +use Symfony\Component\TypeInfo\Type; + +/** + * @author Mathias Arlaud + */ +class JsonStreamerTest extends AbstractWebTestCase +{ + protected function setUp(): void + { + static::bootKernel(['test_case' => 'JsonStreamer']); + } + + public function testWrite() + { + /** @var StreamWriterInterface $writer */ + $writer = static::getContainer()->get('json_streamer.stream_writer.alias'); + + $this->assertSame('{"@name":"DUMMY","range":"10..20"}', (string) $writer->write(new Dummy(), Type::object(Dummy::class))); + } + + public function testRead() + { + /** @var StreamReaderInterface $reader */ + $reader = static::getContainer()->get('json_streamer.stream_reader.alias'); + + $expected = new Dummy(); + $expected->name = 'dummy'; + $expected->range = [0, 1]; + + $this->assertEquals($expected, $reader->read('{"@name": "DUMMY", "range": "0..1"}', Type::object(Dummy::class))); + } + + public function testWarmupStreamableClasses() + { + /** @var Filesystem $fs */ + $fs = static::getContainer()->get('filesystem'); + + $streamWritersDir = \sprintf('%s/json_streamer/stream_writer/', static::getContainer()->getParameter('kernel.cache_dir')); + + // clear already created stream writers + if ($fs->exists($streamWritersDir)) { + $fs->remove($streamWritersDir); + } + + static::getContainer()->get('json_streamer.cache_warmer.streamer.alias')->warmUp(static::getContainer()->getParameter('kernel.cache_dir')); + + $this->assertFileExists($streamWritersDir); + $this->assertCount(2, glob($streamWritersDir.'/*')); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonEncoder/Dto/Dummy.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonEncoder/Dto/Dummy.php deleted file mode 100644 index a6b4d8e91f9b0..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonEncoder/Dto/Dummy.php +++ /dev/null @@ -1,32 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonEncoder\Dto; - -use Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonEncoder\RangeToStringValueTransformer; -use Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonEncoder\StringToRangeValueTransformer; -use Symfony\Component\JsonEncoder\Attribute\EncodedName; -use Symfony\Component\JsonEncoder\Attribute\JsonEncodable; -use Symfony\Component\JsonEncoder\Attribute\ValueTransformer; - -/** - * @author Mathias Arlaud - */ -#[JsonEncodable] -class Dummy -{ - #[EncodedName('@name')] - #[ValueTransformer(toJsonValue: 'strtoupper', toNativeValue: 'strtolower')] - public string $name = 'dummy'; - - #[ValueTransformer(toJsonValue: RangeToStringValueTransformer::class, toNativeValue: StringToRangeValueTransformer::class)] - public array $range = [10, 20]; -} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonEncoder/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonEncoder/config.yml deleted file mode 100644 index 5eb5d49961110..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonEncoder/config.yml +++ /dev/null @@ -1,27 +0,0 @@ -imports: - - { resource: ../config/default.yml } - -framework: - http_method_override: false - type_info: ~ - json_encoder: ~ - -services: - _defaults: - autoconfigure: true - - json_encoder.encoder.alias: - alias: json_encoder.encoder - public: true - - json_encoder.decoder.alias: - alias: json_encoder.decoder - public: true - - json_encoder.cache_warmer.encoder_decoder.alias: - alias: .json_encoder.cache_warmer.encoder_decoder - public: true - - Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonEncoder\Dto\Dummy: ~ - Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonEncoder\StringToRangeValueTransformer: ~ - Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonEncoder\RangeToStringValueTransformer: ~ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonStreamer/Dto/Dummy.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonStreamer/Dto/Dummy.php new file mode 100644 index 0000000000000..d1f1ca67a2a9a --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonStreamer/Dto/Dummy.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonStreamer\Dto; + +use Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonStreamer\RangeToStringValueTransformer; +use Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonStreamer\StringToRangeValueTransformer; +use Symfony\Component\JsonStreamer\Attribute\JsonStreamable; +use Symfony\Component\JsonStreamer\Attribute\StreamedName; +use Symfony\Component\JsonStreamer\Attribute\ValueTransformer; + +/** + * @author Mathias Arlaud + */ +#[JsonStreamable] +class Dummy +{ + #[StreamedName('@name')] + #[ValueTransformer( + nativeToStream: 'strtoupper', + streamToNative: 'strtolower', + )] + public string $name = 'dummy'; + + #[ValueTransformer( + nativeToStream: RangeToStringValueTransformer::class, + streamToNative: StringToRangeValueTransformer::class, + )] + public array $range = [10, 20]; +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonEncoder/RangeToStringValueTransformer.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonStreamer/RangeToStringValueTransformer.php similarity index 82% rename from src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonEncoder/RangeToStringValueTransformer.php rename to src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonStreamer/RangeToStringValueTransformer.php index 93be1fad94a2d..6d21f2d2f834e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonEncoder/RangeToStringValueTransformer.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonStreamer/RangeToStringValueTransformer.php @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonEncoder; +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonStreamer; -use Symfony\Component\JsonEncoder\ValueTransformer\ValueTransformerInterface; +use Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\Type\BuiltinType; @@ -25,7 +25,7 @@ public function transform(mixed $value, array $options = []): string return $value[0].'..'.$value[1]; } - public static function getJsonValueType(): BuiltinType + public static function getStreamValueType(): BuiltinType { return Type::string(); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonEncoder/StringToRangeValueTransformer.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonStreamer/StringToRangeValueTransformer.php similarity index 83% rename from src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonEncoder/StringToRangeValueTransformer.php rename to src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonStreamer/StringToRangeValueTransformer.php index 46e3dd30590bb..398beb2ffab1d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonEncoder/StringToRangeValueTransformer.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonStreamer/StringToRangeValueTransformer.php @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonEncoder; +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonStreamer; -use Symfony\Component\JsonEncoder\ValueTransformer\ValueTransformerInterface; +use Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\Type\BuiltinType; @@ -25,7 +25,7 @@ public function transform(mixed $value, array $options = []): array return array_map(static fn (string $v): int => (int) $v, explode('..', $value)); } - public static function getJsonValueType(): BuiltinType + public static function getStreamValueType(): BuiltinType { return Type::string(); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonEncoder/bundles.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonStreamer/bundles.php similarity index 100% rename from src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonEncoder/bundles.php rename to src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonStreamer/bundles.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonStreamer/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonStreamer/config.yml new file mode 100644 index 0000000000000..188869b8269f6 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/JsonStreamer/config.yml @@ -0,0 +1,27 @@ +imports: + - { resource: ../config/default.yml } + +framework: + http_method_override: false + type_info: ~ + json_streamer: ~ + +services: + _defaults: + autoconfigure: true + + json_streamer.stream_writer.alias: + alias: json_streamer.stream_writer + public: true + + json_streamer.stream_reader.alias: + alias: json_streamer.stream_reader + public: true + + json_streamer.cache_warmer.streamer.alias: + alias: .json_streamer.cache_warmer.streamer + public: true + + Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonStreamer\Dto\Dummy: ~ + Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonStreamer\StringToRangeValueTransformer: ~ + Symfony\Bundle\FrameworkBundle\Tests\Functional\app\JsonStreamer\RangeToStringValueTransformer: ~ diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 03707eea39b5f..a39899d26f77d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -69,7 +69,7 @@ "symfony/workflow": "^6.4|^7.0", "symfony/yaml": "^6.4|^7.0", "symfony/property-info": "^6.4|^7.0", - "symfony/json-encoder": "7.3.*", + "symfony/json-streamer": "7.3.*", "symfony/uid": "^6.4|^7.0", "symfony/web-link": "^6.4|^7.0", "symfony/webhook": "^7.2", @@ -88,7 +88,7 @@ "symfony/dom-crawler": "<6.4", "symfony/http-client": "<6.4", "symfony/form": "<6.4", - "symfony/json-encoder": ">=7.4", + "symfony/json-streamer": ">=7.4", "symfony/lock": "<6.4", "symfony/mailer": "<6.4", "symfony/messenger": "<6.4", diff --git a/src/Symfony/Component/JsonEncoder/Attribute/ValueTransformer.php b/src/Symfony/Component/JsonEncoder/Attribute/ValueTransformer.php deleted file mode 100644 index 3c64817aea759..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Attribute/ValueTransformer.php +++ /dev/null @@ -1,63 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\JsonEncoder\Attribute; - -use Symfony\Component\JsonEncoder\Exception\LogicException; - -/** - * Defines a callable or a {@see \Symfony\Component\JsonEncoder\ValueTransformer\ValueTransformerInterface} service id - * that will be used to transform the property data during encoding and decoding. - * - * @author Mathias Arlaud - * - * @experimental - */ -#[\Attribute(\Attribute::TARGET_PROPERTY)] -class ValueTransformer -{ - private \Closure|string|null $toNativeValue; - private \Closure|string|null $toJsonValue; - - /** - * @param (callable(mixed, array=): mixed)|string|null $toNativeValue - * @param (callable(mixed, array=): mixed)|string|null $toJsonValue - */ - public function __construct( - callable|string|null $toNativeValue = null, - callable|string|null $toJsonValue = null, - ) { - if (!$toNativeValue && !$toJsonValue) { - throw new LogicException('#[ValueTransformer] attribute must declare either $toNativeValue or $toJsonValue.'); - } - - if (\is_callable($toNativeValue)) { - $toNativeValue = $toNativeValue(...); - } - - if (\is_callable($toJsonValue)) { - $toJsonValue = $toJsonValue(...); - } - - $this->toNativeValue = $toNativeValue; - $this->toJsonValue = $toJsonValue; - } - - public function getToNativeValueTransformer(): string|\Closure|null - { - return $this->toNativeValue; - } - - public function getToJsonValueTransformer(): string|\Closure|null - { - return $this->toJsonValue; - } -} diff --git a/src/Symfony/Component/JsonEncoder/CacheWarmer/EncoderDecoderCacheWarmer.php b/src/Symfony/Component/JsonEncoder/CacheWarmer/EncoderDecoderCacheWarmer.php deleted file mode 100644 index 5ea39b3b96d04..0000000000000 --- a/src/Symfony/Component/JsonEncoder/CacheWarmer/EncoderDecoderCacheWarmer.php +++ /dev/null @@ -1,99 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\JsonEncoder\CacheWarmer; - -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; -use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; -use Symfony\Component\JsonEncoder\Decode\DecoderGenerator; -use Symfony\Component\JsonEncoder\Encode\EncoderGenerator; -use Symfony\Component\JsonEncoder\Exception\ExceptionInterface; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoaderInterface; -use Symfony\Component\TypeInfo\Type; - -/** - * Generates encoders and decoders PHP files. - * - * @author Mathias Arlaud - * - * @internal - */ -final class EncoderDecoderCacheWarmer implements CacheWarmerInterface -{ - private EncoderGenerator $encoderGenerator; - private DecoderGenerator $decoderGenerator; - - /** - * @param iterable $encodable - */ - public function __construct( - private iterable $encodable, - PropertyMetadataLoaderInterface $encodePropertyMetadataLoader, - PropertyMetadataLoaderInterface $decodePropertyMetadataLoader, - string $encodersDir, - string $decodersDir, - private LoggerInterface $logger = new NullLogger(), - ) { - $this->encoderGenerator = new EncoderGenerator($encodePropertyMetadataLoader, $encodersDir); - $this->decoderGenerator = new DecoderGenerator($decodePropertyMetadataLoader, $decodersDir); - } - - public function warmUp(string $cacheDir, ?string $buildDir = null): array - { - foreach ($this->encodable as $className => $encodable) { - if ($encodable['object']) { - $type = Type::object($className); - - $this->warmUpEncoder($type); - $this->warmUpDecoders($type); - } - - if ($encodable['list']) { - $type = Type::list(Type::object($className)); - - $this->warmUpEncoder($type); - $this->warmUpDecoders($type); - } - } - - return []; - } - - public function isOptional(): bool - { - return true; - } - - private function warmUpEncoder(Type $type): void - { - try { - $this->encoderGenerator->generate($type); - } catch (ExceptionInterface $e) { - $this->logger->debug('Cannot generate "json" encoder for "{type}": {exception}', ['type' => (string) $type, 'exception' => $e]); - } - } - - private function warmUpDecoders(Type $type): void - { - try { - $this->decoderGenerator->generate($type, decodeFromStream: false); - } catch (ExceptionInterface $e) { - $this->logger->debug('Cannot generate "json" decoder for "{type}": {exception}', ['type' => (string) $type, 'exception' => $e]); - } - - try { - $this->decoderGenerator->generate($type, decodeFromStream: true); - } catch (ExceptionInterface $e) { - $this->logger->debug('Cannot generate "json" streaming decoder for "{type}": {exception}', ['type' => (string) $type, 'exception' => $e]); - } - } -} diff --git a/src/Symfony/Component/JsonEncoder/Encoded.php b/src/Symfony/Component/JsonEncoder/Encoded.php deleted file mode 100644 index cb9796820515e..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Encoded.php +++ /dev/null @@ -1,48 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\JsonEncoder; - -/** - * Represents an encoding result. - * Can be iterated or casted to string. - * - * @author Mathias Arlaud - * - * @experimental - * - * @implements \IteratorAggregate - */ -final class Encoded implements \IteratorAggregate, \Stringable -{ - /** - * @param \Traversable $chunks - */ - public function __construct( - private \Traversable $chunks, - ) { - } - - public function getIterator(): \Traversable - { - return $this->chunks; - } - - public function __toString(): string - { - $encoded = ''; - foreach ($this->chunks as $chunk) { - $encoded .= $chunk; - } - - return $encoded; - } -} diff --git a/src/Symfony/Component/JsonEncoder/Mapping/PropertyMetadata.php b/src/Symfony/Component/JsonEncoder/Mapping/PropertyMetadata.php deleted file mode 100644 index 0716d85cc0a78..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Mapping/PropertyMetadata.php +++ /dev/null @@ -1,108 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\JsonEncoder\Mapping; - -use Symfony\Component\TypeInfo\Type; - -/** - * Holds encoding/decoding metadata about a given property. - * - * @author Mathias Arlaud - * - * @experimental - */ -final class PropertyMetadata -{ - /** - * @param list $toJsonValueTransformers - * @param list $toNativeValueTransformers - */ - public function __construct( - private string $name, - private Type $type, - private array $toJsonValueTransformers = [], - private array $toNativeValueTransformers = [], - ) { - } - - public function getName(): string - { - return $this->name; - } - - public function withName(string $name): self - { - return new self($name, $this->type, $this->toJsonValueTransformers, $this->toNativeValueTransformers); - } - - public function getType(): Type - { - return $this->type; - } - - public function withType(Type $type): self - { - return new self($this->name, $type, $this->toJsonValueTransformers, $this->toNativeValueTransformers); - } - - /** - * @return list - */ - public function getToJsonValueTransformer(): array - { - return $this->toJsonValueTransformers; - } - - /** - * @param list $toJsonValueTransformers - */ - public function withToJsonValueTransformers(array $toJsonValueTransformers): self - { - return new self($this->name, $this->type, $toJsonValueTransformers, $this->toNativeValueTransformers); - } - - public function withAdditionalToJsonValueTransformer(string|\Closure $toJsonValueTransformer): self - { - $toJsonValueTransformers = $this->toJsonValueTransformers; - - $toJsonValueTransformers[] = $toJsonValueTransformer; - $toJsonValueTransformers = array_values(array_unique($toJsonValueTransformers)); - - return $this->withToJsonValueTransformers($toJsonValueTransformers); - } - - /** - * @return list - */ - public function getToNativeValueTransformers(): array - { - return $this->toNativeValueTransformers; - } - - /** - * @param list $toNativeValueTransformers - */ - public function withToNativeValueTransformers(array $toNativeValueTransformers): self - { - return new self($this->name, $this->type, $this->toJsonValueTransformers, $toNativeValueTransformers); - } - - public function withAdditionalToNativeValueTransformer(string|\Closure $toNativeValueTransformer): self - { - $toNativeValueTransformers = $this->toNativeValueTransformers; - - $toNativeValueTransformers[] = $toNativeValueTransformer; - $toNativeValueTransformers = array_values(array_unique($toNativeValueTransformers)); - - return $this->withToNativeValueTransformers($toNativeValueTransformers); - } -} diff --git a/src/Symfony/Component/JsonEncoder/Tests/CacheWarmer/EncoderDecoderCacheWarmerTest.php b/src/Symfony/Component/JsonEncoder/Tests/CacheWarmer/EncoderDecoderCacheWarmerTest.php deleted file mode 100644 index e0882365ba521..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/CacheWarmer/EncoderDecoderCacheWarmerTest.php +++ /dev/null @@ -1,82 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\JsonEncoder\Tests\CacheWarmer; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\CacheWarmer\EncoderDecoderCacheWarmer; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes; -use Symfony\Component\TypeInfo\TypeResolver\TypeResolver; - -class EncoderDecoderCacheWarmerTest extends TestCase -{ - private string $encodersDir; - private string $decodersDir; - - protected function setUp(): void - { - parent::setUp(); - - $this->encodersDir = \sprintf('%s/symfony_json_encoder_test/json_encoder/encoder', sys_get_temp_dir()); - $this->decodersDir = \sprintf('%s/symfony_json_encoder_test/json_encoder/decoder', sys_get_temp_dir()); - - if (is_dir($this->encodersDir)) { - array_map('unlink', glob($this->encodersDir.'/*')); - rmdir($this->encodersDir); - } - - if (is_dir($this->decodersDir)) { - array_map('unlink', glob($this->decodersDir.'/*')); - rmdir($this->decodersDir); - } - } - - public function testWarmUp() - { - $this->cacheWarmer([ - ClassicDummy::class => ['object' => true, 'list' => true], - DummyWithNameAttributes::class => ['object' => true, 'list' => false], - ])->warmUp('useless'); - - $this->assertSame([ - \sprintf('%s/5acb3571777e02a2712fb9a9126a338f.json.php', $this->encodersDir), - \sprintf('%s/d147026bb5d25e5012afcdc1543cf097.json.php', $this->encodersDir), - \sprintf('%s/de878efdd0bf652bdd72d1dc95f6d80d.json.php', $this->encodersDir), - ], glob($this->encodersDir.'/*')); - - $this->assertSame([ - \sprintf('%s/5acb3571777e02a2712fb9a9126a338f.json.php', $this->decodersDir), - \sprintf('%s/5acb3571777e02a2712fb9a9126a338f.json.stream.php', $this->decodersDir), - \sprintf('%s/d147026bb5d25e5012afcdc1543cf097.json.php', $this->decodersDir), - \sprintf('%s/d147026bb5d25e5012afcdc1543cf097.json.stream.php', $this->decodersDir), - \sprintf('%s/de878efdd0bf652bdd72d1dc95f6d80d.json.php', $this->decodersDir), - \sprintf('%s/de878efdd0bf652bdd72d1dc95f6d80d.json.stream.php', $this->decodersDir), - ], glob($this->decodersDir.'/*')); - } - - /** - * @param array $encodableClasses - */ - private function cacheWarmer(array $encodableClasses = []): EncoderDecoderCacheWarmer - { - $typeResolver = TypeResolver::create(); - - return new EncoderDecoderCacheWarmer( - $encodableClasses, - new PropertyMetadataLoader($typeResolver), - new PropertyMetadataLoader($typeResolver), - $this->encodersDir, - $this->decodersDir, - ); - } -} diff --git a/src/Symfony/Component/JsonEncoder/Tests/DependencyInjection/EncodablePassTest.php b/src/Symfony/Component/JsonEncoder/Tests/DependencyInjection/EncodablePassTest.php deleted file mode 100644 index 36a7938e66b5a..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/DependencyInjection/EncodablePassTest.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\JsonEncoder\Tests\DependencyInjection; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\JsonEncoder\DependencyInjection\EncodablePass; - -class EncodablePassTest extends TestCase -{ - public function testSetEncodableClassNames() - { - $container = new ContainerBuilder(); - - $container->register('json_encoder.encoder'); - $container->register('.json_encoder.cache_warmer.encoder_decoder')->setArguments([null]); - $container->register('.json_encoder.cache_warmer.lazy_ghost')->setArguments([null]); - - $container->register('encodable')->setClass('Foo')->addTag('json_encoder.encodable', ['object' => true, 'list' => true]); - $container->register('abstractEncodable')->setClass('Bar')->addTag('json_encoder.encodable', ['object' => true, 'list' => true])->setAbstract(true); - $container->register('notEncodable')->setClass('Baz'); - - $pass = new EncodablePass(); - $pass->process($container); - - $encoderDecoderCacheWarmer = $container->getDefinition('.json_encoder.cache_warmer.encoder_decoder'); - $lazyGhostCacheWarmer = $container->getDefinition('.json_encoder.cache_warmer.lazy_ghost'); - - $this->assertSame(['Foo' => ['object' => true, 'list' => true]], $encoderDecoderCacheWarmer->getArgument(0)); - $this->assertSame(['Foo'], $lazyGhostCacheWarmer->getArgument(0)); - } -} diff --git a/src/Symfony/Component/JsonEncoder/Tests/EncodedTest.php b/src/Symfony/Component/JsonEncoder/Tests/EncodedTest.php deleted file mode 100644 index cb194d7d40bb0..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/EncodedTest.php +++ /dev/null @@ -1,28 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\JsonEncoder\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Encoded; - -class EncodedTest extends TestCase -{ - public function testEncodedAsTraversable() - { - $this->assertSame(['foo', 'bar', 'baz'], iterator_to_array(new Encoded(new \ArrayIterator(['foo', 'bar', 'baz'])))); - } - - public function testEncodedAsString() - { - $this->assertSame('foobarbaz', (string) new Encoded(new \ArrayIterator(['foo', 'bar', 'baz']))); - } -} diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/Attribute/BooleanStringValueTransformer.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/Attribute/BooleanStringValueTransformer.php deleted file mode 100644 index 2549c34a65055..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/Attribute/BooleanStringValueTransformer.php +++ /dev/null @@ -1,16 +0,0 @@ - (int) $v, explode('..', $range)); - } -} diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/Model/SelfReferencingDummy.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/Model/SelfReferencingDummy.php deleted file mode 100644 index d8f1073a8ab10..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/Model/SelfReferencingDummy.php +++ /dev/null @@ -1,11 +0,0 @@ -instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { - return '_symfony_missing_value' !== $v; - })); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy|null'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - if (\is_array($data)) { - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($data); - } - if (null === $data) { - return null; - } - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy|null".', \get_debug_type($data))); - }; - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy|null'](\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeString((string) $string)); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object.stream.php deleted file mode 100644 index 6fd33c206d897..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object.stream.php +++ /dev/null @@ -1,27 +0,0 @@ -instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - match ($k) { - 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - default => null, - }; - } - }); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy|null'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length); - if (\is_array($data)) { - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($data); - } - if (null === $data) { - return null; - } - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy|null".', \get_debug_type($data))); - }; - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy|null']($stream, 0, null); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_dict.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_dict.php deleted file mode 100644 index 3ea9636ceb8e8..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_dict.php +++ /dev/null @@ -1,27 +0,0 @@ -'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - $iterable = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - yield $k => $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($v); - } - }; - return \iterator_to_array($iterable($data)); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { - return '_symfony_missing_value' !== $v; - })); - }; - $providers['array|null'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - if (\is_array($data)) { - return $providers['array']($data); - } - if (null === $data) { - return null; - } - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "array|null".', \get_debug_type($data))); - }; - return $providers['array|null'](\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeString((string) $string)); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_dict.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_dict.stream.php deleted file mode 100644 index 84abb98cdeb92..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_dict.stream.php +++ /dev/null @@ -1,36 +0,0 @@ -'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $iterable = static function ($stream, $data) use ($options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - yield $k => $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($stream, $v[0], $v[1]); - } - }; - return \iterator_to_array($iterable($stream, $data)); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - match ($k) { - 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - default => null, - }; - } - }); - }; - $providers['array|null'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length); - if (\is_array($data)) { - return $providers['array']($data); - } - if (null === $data) { - return null; - } - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "array|null".', \get_debug_type($data))); - }; - return $providers['array|null']($stream, 0, null); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_list.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_list.php deleted file mode 100644 index 4fd20bb5fda8a..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_list.php +++ /dev/null @@ -1,27 +0,0 @@ -'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - $iterable = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - yield $k => $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($v); - } - }; - return \iterator_to_array($iterable($data)); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { - return '_symfony_missing_value' !== $v; - })); - }; - $providers['array|null'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - if (\is_array($data) && \array_is_list($data)) { - return $providers['array']($data); - } - if (null === $data) { - return null; - } - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "array|null".', \get_debug_type($data))); - }; - return $providers['array|null'](\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeString((string) $string)); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_list.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_list.stream.php deleted file mode 100644 index ff9db52b53d87..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/nullable_object_list.stream.php +++ /dev/null @@ -1,36 +0,0 @@ -'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitList($stream, $offset, $length); - $iterable = static function ($stream, $data) use ($options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - yield $k => $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($stream, $v[0], $v[1]); - } - }; - return \iterator_to_array($iterable($stream, $data)); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - match ($k) { - 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - default => null, - }; - } - }); - }; - $providers['array|null'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length); - if (\is_array($data) && \array_is_list($data)) { - return $providers['array']($data); - } - if (null === $data) { - return null; - } - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "array|null".', \get_debug_type($data))); - }; - return $providers['array|null']($stream, 0, null); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object.php deleted file mode 100644 index 5ff0c2a0d0b5c..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object.php +++ /dev/null @@ -1,10 +0,0 @@ -instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { - return '_symfony_missing_value' !== $v; - })); - }; - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'](\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeString((string) $string)); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object.stream.php deleted file mode 100644 index 7942f34d1b073..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object.stream.php +++ /dev/null @@ -1,17 +0,0 @@ -instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - match ($k) { - 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - default => null, - }; - } - }); - }; - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($stream, 0, null); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_dict.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_dict.php deleted file mode 100644 index 8b841095ea394..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_dict.php +++ /dev/null @@ -1,18 +0,0 @@ -'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - $iterable = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - yield $k => $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($v); - } - }; - return \iterator_to_array($iterable($data)); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { - return '_symfony_missing_value' !== $v; - })); - }; - return $providers['array'](\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeString((string) $string)); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_dict.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_dict.stream.php deleted file mode 100644 index cd029e43f4cfb..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_dict.stream.php +++ /dev/null @@ -1,26 +0,0 @@ -'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $iterable = static function ($stream, $data) use ($options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - yield $k => $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($stream, $v[0], $v[1]); - } - }; - return \iterator_to_array($iterable($stream, $data)); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - match ($k) { - 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - default => null, - }; - } - }); - }; - return $providers['array']($stream, 0, null); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_in_object.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_in_object.php deleted file mode 100644 index a62c9de14a9e2..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_in_object.php +++ /dev/null @@ -1,20 +0,0 @@ -instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithOtherDummies::class, \array_filter(['name' => $data['name'] ?? '_symfony_missing_value', 'otherDummyOne' => \array_key_exists('otherDummyOne', $data) ? $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes']($data['otherDummyOne']) : '_symfony_missing_value', 'otherDummyTwo' => \array_key_exists('otherDummyTwo', $data) ? $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($data['otherDummyTwo']) : '_symfony_missing_value'], static function ($v) { - return '_symfony_missing_value' !== $v; - })); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes::class, \array_filter(['id' => $data['@id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { - return '_symfony_missing_value' !== $v; - })); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { - return '_symfony_missing_value' !== $v; - })); - }; - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithOtherDummies'](\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeString((string) $string)); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_in_object.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_in_object.stream.php deleted file mode 100644 index cae4d3fd36e1f..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_in_object.stream.php +++ /dev/null @@ -1,42 +0,0 @@ -instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithOtherDummies::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - match ($k) { - 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - 'otherDummyOne' => $object->otherDummyOne = $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes']($stream, $v[0], $v[1]), - 'otherDummyTwo' => $object->otherDummyTwo = $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($stream, $v[0], $v[1]), - default => null, - }; - } - }); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - match ($k) { - '@id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - default => null, - }; - } - }); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - match ($k) { - 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - default => null, - }; - } - }); - }; - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithOtherDummies']($stream, 0, null); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_iterable.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_iterable.php deleted file mode 100644 index 85d964fc89c7f..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_iterable.php +++ /dev/null @@ -1,18 +0,0 @@ -'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - $iterable = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - yield $k => $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($v); - } - }; - return $iterable($data); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { - return '_symfony_missing_value' !== $v; - })); - }; - return $providers['iterable'](\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeString((string) $string)); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_iterable.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_iterable.stream.php deleted file mode 100644 index 11942db9b632e..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_iterable.stream.php +++ /dev/null @@ -1,26 +0,0 @@ -'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - $iterable = static function ($stream, $data) use ($options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - yield $k => $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($stream, $v[0], $v[1]); - } - }; - return $iterable($stream, $data); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - match ($k) { - 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - default => null, - }; - } - }); - }; - return $providers['iterable']($stream, 0, null); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_list.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_list.php deleted file mode 100644 index e13597b2aff78..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_list.php +++ /dev/null @@ -1,18 +0,0 @@ -'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - $iterable = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - yield $k => $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($v); - } - }; - return \iterator_to_array($iterable($data)); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { - return '_symfony_missing_value' !== $v; - })); - }; - return $providers['array'](\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeString((string) $string)); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_list.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_list.stream.php deleted file mode 100644 index 5a5342c291d78..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_list.stream.php +++ /dev/null @@ -1,26 +0,0 @@ -'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitList($stream, $offset, $length); - $iterable = static function ($stream, $data) use ($options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - yield $k => $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy']($stream, $v[0], $v[1]); - } - }; - return \iterator_to_array($iterable($stream, $data)); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - match ($k) { - 'id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - default => null, - }; - } - }); - }; - return $providers['array']($stream, 0, null); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_nullable_properties.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_nullable_properties.php deleted file mode 100644 index 6f041f99fad36..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_nullable_properties.php +++ /dev/null @@ -1,22 +0,0 @@ -instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNullableProperties::class, \array_filter(['name' => $data['name'] ?? '_symfony_missing_value', 'enum' => \array_key_exists('enum', $data) ? $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null']($data['enum']) : '_symfony_missing_value'], static function ($v) { - return '_symfony_missing_value' !== $v; - })); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum'] = static function ($data) { - return \Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum::from($data); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - if (\is_int($data)) { - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum']($data); - } - if (null === $data) { - return null; - } - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null".', \get_debug_type($data))); - }; - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNullableProperties'](\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeString((string) $string)); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_nullable_properties.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_nullable_properties.stream.php deleted file mode 100644 index ed3b5b4ab381f..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_nullable_properties.stream.php +++ /dev/null @@ -1,30 +0,0 @@ -instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNullableProperties::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - match ($k) { - 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - 'enum' => $object->enum = $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null']($stream, $v[0], $v[1]), - default => null, - }; - } - }); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum'] = static function ($stream, $offset, $length) { - return \Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum::from(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length)); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length); - if (\is_int($data)) { - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum']($data); - } - if (null === $data) { - return null; - } - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null".', \get_debug_type($data))); - }; - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNullableProperties']($stream, 0, null); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_union.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_union.php deleted file mode 100644 index 567c335341460..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_union.php +++ /dev/null @@ -1,25 +0,0 @@ -instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithUnionProperties::class, \array_filter(['value' => \array_key_exists('value', $data) ? $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null|string']($data['value']) : '_symfony_missing_value'], static function ($v) { - return '_symfony_missing_value' !== $v; - })); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum'] = static function ($data) { - return \Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum::from($data); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null|string'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - if (\is_int($data)) { - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum']($data); - } - if (null === $data) { - return null; - } - if (\is_string($data)) { - return $data; - } - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null|string".', \get_debug_type($data))); - }; - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithUnionProperties'](\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeString((string) $string)); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_union.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_union.stream.php deleted file mode 100644 index 2526149c8b43b..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_union.stream.php +++ /dev/null @@ -1,32 +0,0 @@ -instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithUnionProperties::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - match ($k) { - 'value' => $object->value = $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null|string']($stream, $v[0], $v[1]), - default => null, - }; - } - }); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum'] = static function ($stream, $offset, $length) { - return \Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum::from(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length)); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null|string'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length); - if (\is_int($data)) { - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum']($data); - } - if (null === $data) { - return null; - } - if (\is_string($data)) { - return $data; - } - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum|null|string".', \get_debug_type($data))); - }; - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithUnionProperties']($stream, 0, null); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_value_transformer.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_value_transformer.php deleted file mode 100644 index a84a95463e626..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_value_transformer.php +++ /dev/null @@ -1,10 +0,0 @@ -instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithValueTransformerAttributes::class, \array_filter(['id' => $valueTransformers->get('Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\DivideStringAndCastToIntValueTransformer')->transform($data['id'] ?? '_symfony_missing_value', $options), 'active' => $valueTransformers->get('Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\StringToBooleanValueTransformer')->transform($data['active'] ?? '_symfony_missing_value', $options), 'name' => strtoupper($data['name'] ?? '_symfony_missing_value'), 'range' => Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithValueTransformerAttributes::explodeRange($data['range'] ?? '_symfony_missing_value', $options)], static function ($v) { - return '_symfony_missing_value' !== $v; - })); - }; - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithValueTransformerAttributes'](\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeString((string) $string)); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_value_transformer.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_value_transformer.stream.php deleted file mode 100644 index 6fb3fdab1a00c..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/object_with_value_transformer.stream.php +++ /dev/null @@ -1,19 +0,0 @@ -instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithValueTransformerAttributes::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - match ($k) { - 'id' => $object->id = $valueTransformers->get('Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\DivideStringAndCastToIntValueTransformer')->transform(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), $options), - 'active' => $object->active = $valueTransformers->get('Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\StringToBooleanValueTransformer')->transform(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), $options), - 'name' => $object->name = strtoupper(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1])), - 'range' => $object->range = Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithValueTransformerAttributes::explodeRange(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), $options), - default => null, - }; - } - }); - }; - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithValueTransformerAttributes']($stream, 0, null); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/scalar.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/scalar.php deleted file mode 100644 index b52d20ec575a9..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/scalar.php +++ /dev/null @@ -1,5 +0,0 @@ -'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - $iterable = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - yield $k => $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum']($v); - } - }; - return \iterator_to_array($iterable($data)); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum'] = static function ($data) { - return \Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum::from($data); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes::class, \array_filter(['id' => $data['@id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { - return '_symfony_missing_value' !== $v; - })); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes|array|int'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { - if (\is_array($data) && \array_is_list($data)) { - return $providers['array']($data); - } - if (\is_array($data)) { - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes']($data); - } - if (\is_int($data)) { - return $data; - } - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes|array|int".', \get_debug_type($data))); - }; - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes|array|int'](\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeString((string) $string)); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/union.stream.php b/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/union.stream.php deleted file mode 100644 index 8fe29d0707ab9..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/decoder/union.stream.php +++ /dev/null @@ -1,42 +0,0 @@ -'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitList($stream, $offset, $length); - $iterable = static function ($stream, $data) use ($options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - yield $k => $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum']($stream, $v[0], $v[1]); - } - }; - return \iterator_to_array($iterable($stream, $data)); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum'] = static function ($stream, $offset, $length) { - return \Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum::from(\Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length)); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); - return $instantiator->instantiate(\Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { - foreach ($data as $k => $v) { - match ($k) { - '@id' => $object->id = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - 'name' => $object->name = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]), - default => null, - }; - } - }); - }; - $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes|array|int'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $offset, $length); - if (\is_array($data) && \array_is_list($data)) { - return $providers['array']($data); - } - if (\is_array($data)) { - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes']($data); - } - if (\is_int($data)) { - return $data; - } - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes|array|int".', \get_debug_type($data))); - }; - return $providers['Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes|array|int']($stream, 0, null); -}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/JsonDecoderTest.php b/src/Symfony/Component/JsonEncoder/Tests/JsonDecoderTest.php deleted file mode 100644 index b39d3ec8a7fbb..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/JsonDecoderTest.php +++ /dev/null @@ -1,204 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\JsonEncoder\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\JsonDecoder; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithDateTimes; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNullableProperties; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithPhpDoc; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithValueTransformerAttributes; -use Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\DivideStringAndCastToIntValueTransformer; -use Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\StringToBooleanValueTransformer; -use Symfony\Component\TypeInfo\Type; -use Symfony\Component\TypeInfo\TypeIdentifier; - -class JsonDecoderTest extends TestCase -{ - private string $decodersDir; - private string $lazyGhostsDir; - - protected function setUp(): void - { - parent::setUp(); - - $this->decodersDir = \sprintf('%s/symfony_json_encoder_test/decoder', sys_get_temp_dir()); - $this->lazyGhostsDir = \sprintf('%s/symfony_json_encoder_test/lazy_ghost', sys_get_temp_dir()); - - if (is_dir($this->decodersDir)) { - array_map('unlink', glob($this->decodersDir.'/*')); - rmdir($this->decodersDir); - } - - if (is_dir($this->lazyGhostsDir)) { - array_map('unlink', glob($this->lazyGhostsDir.'/*')); - rmdir($this->lazyGhostsDir); - } - } - - public function testDecodeScalar() - { - $decoder = JsonDecoder::create(decodersDir: $this->decodersDir, lazyGhostsDir: $this->lazyGhostsDir); - - $this->assertDecoded($decoder, null, 'null', Type::nullable(Type::int())); - $this->assertDecoded($decoder, true, 'true', Type::bool()); - $this->assertDecoded($decoder, [['foo' => 1, 'bar' => 2], ['foo' => 3]], '[{"foo": 1, "bar": 2}, {"foo": 3}]', Type::builtin(TypeIdentifier::ARRAY)); - $this->assertDecoded($decoder, [['foo' => 1, 'bar' => 2], ['foo' => 3]], '[{"foo": 1, "bar": 2}, {"foo": 3}]', Type::builtin(TypeIdentifier::ITERABLE)); - $this->assertDecoded($decoder, (object) ['foo' => 'bar'], '{"foo": "bar"}', Type::object()); - $this->assertDecoded($decoder, DummyBackedEnum::ONE, '1', Type::enum(DummyBackedEnum::class, Type::string())); - } - - public function testDecodeCollection() - { - $decoder = JsonDecoder::create(decodersDir: $this->decodersDir, lazyGhostsDir: $this->lazyGhostsDir); - - $this->assertDecoded( - $decoder, - [true, false], - '{"0": true, "1": false}', - Type::array(Type::bool()), - ); - - $this->assertDecoded( - $decoder, - [true, false], - '[true, false]', - Type::list(Type::bool()), - ); - - $this->assertDecoded($decoder, function (mixed $decoded) { - $this->assertIsIterable($decoded); - $this->assertSame([true, false], iterator_to_array($decoded)); - }, '{"0": true, "1": false}', Type::iterable(Type::bool())); - - $this->assertDecoded($decoder, function (mixed $decoded) { - $this->assertIsIterable($decoded); - $this->assertSame([true, false], iterator_to_array($decoded)); - }, '{"0": true, "1": false}', Type::iterable(Type::bool(), Type::int())); - } - - public function testDecodeObject() - { - $decoder = JsonDecoder::create(decodersDir: $this->decodersDir, lazyGhostsDir: $this->lazyGhostsDir); - - $this->assertDecoded($decoder, function (mixed $decoded) { - $this->assertInstanceOf(ClassicDummy::class, $decoded); - $this->assertSame(10, $decoded->id); - $this->assertSame('dummy name', $decoded->name); - }, '{"id": 10, "name": "dummy name"}', Type::object(ClassicDummy::class)); - } - - public function testDecodeObjectWithEncodedName() - { - $decoder = JsonDecoder::create(decodersDir: $this->decodersDir, lazyGhostsDir: $this->lazyGhostsDir); - - $this->assertDecoded($decoder, function (mixed $decoded) { - $this->assertInstanceOf(DummyWithNameAttributes::class, $decoded); - $this->assertSame(10, $decoded->id); - }, '{"@id": 10}', Type::object(DummyWithNameAttributes::class)); - } - - public function testDecodeObjectWithValueTransformer() - { - $decoder = JsonDecoder::create( - valueTransformers: [ - StringToBooleanValueTransformer::class => new StringToBooleanValueTransformer(), - DivideStringAndCastToIntValueTransformer::class => new DivideStringAndCastToIntValueTransformer(), - ], - decodersDir: $this->decodersDir, - lazyGhostsDir: $this->lazyGhostsDir, - ); - - $this->assertDecoded($decoder, function (mixed $decoded) { - $this->assertInstanceOf(DummyWithValueTransformerAttributes::class, $decoded); - $this->assertSame(10, $decoded->id); - $this->assertTrue($decoded->active); - $this->assertSame('LOWERCASE NAME', $decoded->name); - $this->assertSame([0, 1], $decoded->range); - }, '{"id": "20", "active": "true", "name": "lowercase name", "range": "0..1"}', Type::object(DummyWithValueTransformerAttributes::class), ['scale' => 1]); - } - - public function testDecodeObjectWithPhpDoc() - { - $decoder = JsonDecoder::create(decodersDir: $this->decodersDir, lazyGhostsDir: $this->lazyGhostsDir); - - $this->assertDecoded($decoder, function (mixed $decoded) { - $this->assertInstanceOf(DummyWithPhpDoc::class, $decoded); - $this->assertIsArray($decoded->arrayOfDummies); - $this->assertContainsOnlyInstancesOf(DummyWithNameAttributes::class, $decoded->arrayOfDummies); - $this->assertArrayHasKey('key', $decoded->arrayOfDummies); - }, '{"arrayOfDummies":{"key":{"@id":10,"name":"dummy"}}}', Type::object(DummyWithPhpDoc::class)); - } - - public function testDecodeObjectWithNullableProperties() - { - $decoder = JsonDecoder::create(decodersDir: $this->decodersDir, lazyGhostsDir: $this->lazyGhostsDir); - - $this->assertDecoded($decoder, function (mixed $decoded) { - $this->assertInstanceOf(DummyWithNullableProperties::class, $decoded); - $this->assertNull($decoded->name); - $this->assertNull($decoded->enum); - }, '{"name":null,"enum":null}', Type::object(DummyWithNullableProperties::class)); - } - - public function testDecodeObjectWithDateTimes() - { - $decoder = JsonDecoder::create(decodersDir: $this->decodersDir, lazyGhostsDir: $this->lazyGhostsDir); - - $this->assertDecoded($decoder, function (mixed $decoded) { - $this->assertInstanceOf(DummyWithDateTimes::class, $decoded); - $this->assertEquals(new \DateTimeImmutable('2024-11-20'), $decoded->interface); - $this->assertEquals(new \DateTimeImmutable('2025-11-20'), $decoded->immutable); - }, '{"interface":"2024-11-20","immutable":"2025-11-20"}', Type::object(DummyWithDateTimes::class)); - } - - public function testCreateDecoderFile() - { - $decoder = JsonDecoder::create(decodersDir: $this->decodersDir, lazyGhostsDir: $this->lazyGhostsDir); - - $decoder->decode('true', Type::bool()); - - $this->assertFileExists($this->decodersDir); - $this->assertCount(1, glob($this->decodersDir.'/*')); - } - - public function testCreateDecoderFileOnlyIfNotExists() - { - $decoder = JsonDecoder::create(decodersDir: $this->decodersDir, lazyGhostsDir: $this->lazyGhostsDir); - - if (!file_exists($this->decodersDir)) { - mkdir($this->decodersDir, recursive: true); - } - - file_put_contents( - \sprintf('%s%s%s.json.php', $this->decodersDir, \DIRECTORY_SEPARATOR, hash('xxh128', (string) Type::bool())), - 'assertSame('CACHED', $decoder->decode('true', Type::bool())); - } - - private function assertDecoded(JsonDecoder $decoder, mixed $decodedOrAssert, string $encoded, Type $type, array $options = []): void - { - $assert = \is_callable($decodedOrAssert, syntax_only: true) ? $decodedOrAssert : fn (mixed $decoded) => $this->assertEquals($decodedOrAssert, $decoded); - - $assert($decoder->decode($encoded, $type, $options)); - - $resource = fopen('php://temp', 'w'); - fwrite($resource, $encoded); - rewind($resource); - $assert($decoder->decode($resource, $type, $options)); - } -} diff --git a/src/Symfony/Component/JsonEncoder/Tests/JsonEncoderTest.php b/src/Symfony/Component/JsonEncoder/Tests/JsonEncoderTest.php deleted file mode 100644 index 65bd91dbe6c0c..0000000000000 --- a/src/Symfony/Component/JsonEncoder/Tests/JsonEncoderTest.php +++ /dev/null @@ -1,229 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\JsonEncoder\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Exception\MaxDepthException; -use Symfony\Component\JsonEncoder\JsonEncoder; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithDateTimes; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNullableProperties; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithPhpDoc; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithUnionProperties; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithValueTransformerAttributes; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\SelfReferencingDummy; -use Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\BooleanToStringValueTransformer; -use Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\DoubleIntAndCastToStringValueTransformer; -use Symfony\Component\JsonEncoder\ValueTransformer\DateTimeToStringValueTransformer; -use Symfony\Component\JsonEncoder\ValueTransformer\ValueTransformerInterface; -use Symfony\Component\TypeInfo\Type; - -class JsonEncoderTest extends TestCase -{ - private string $encodersDir; - - protected function setUp(): void - { - parent::setUp(); - - $this->encodersDir = \sprintf('%s/symfony_json_encoder_test/encoder', sys_get_temp_dir()); - - if (is_dir($this->encodersDir)) { - array_map('unlink', glob($this->encodersDir.'/*')); - rmdir($this->encodersDir); - } - } - - public function testReturnTraversableStringableEncoded() - { - $encoder = JsonEncoder::create(encodersDir: $this->encodersDir); - - $this->assertSame(['true'], iterator_to_array($encoder->encode(true, Type::bool()))); - $this->assertSame('true', (string) $encoder->encode(true, Type::bool())); - } - - public function testEncodeScalar() - { - $this->assertEncoded('null', null, Type::null()); - $this->assertEncoded('true', true, Type::bool()); - $this->assertEncoded('[{"foo":1,"bar":2},{"foo":3}]', [['foo' => 1, 'bar' => 2], ['foo' => 3]], Type::list()); - $this->assertEncoded('{"foo":"bar"}', (object) ['foo' => 'bar'], Type::object()); - $this->assertEncoded('1', DummyBackedEnum::ONE, Type::enum(DummyBackedEnum::class)); - } - - public function testEncodeUnion() - { - $this->assertEncoded( - '[1,true,["foo","bar"]]', - [DummyBackedEnum::ONE, true, ['foo', 'bar']], - Type::list(Type::union(Type::enum(DummyBackedEnum::class), Type::bool(), Type::list(Type::string()))), - ); - - $dummy = new DummyWithUnionProperties(); - $dummy->value = DummyBackedEnum::ONE; - $this->assertEncoded('{"value":1}', $dummy, Type::object(DummyWithUnionProperties::class)); - - $dummy->value = 'foo'; - $this->assertEncoded('{"value":"foo"}', $dummy, Type::object(DummyWithUnionProperties::class)); - - $dummy->value = null; - $this->assertEncoded('{"value":null}', $dummy, Type::object(DummyWithUnionProperties::class)); - } - - public function testEncodeCollection() - { - $this->assertEncoded( - '{"0":{"id":1,"name":"dummy"},"1":{"id":1,"name":"dummy"}}', - [new ClassicDummy(), new ClassicDummy()], - Type::array(Type::object(ClassicDummy::class)), - ); - - $this->assertEncoded( - '[{"id":1,"name":"dummy"},{"id":1,"name":"dummy"}]', - [new ClassicDummy(), new ClassicDummy()], - Type::list(Type::object(ClassicDummy::class)), - ); - - $this->assertEncoded( - '{"0":{"id":1,"name":"dummy"},"1":{"id":1,"name":"dummy"}}', - new \ArrayObject([new ClassicDummy(), new ClassicDummy()]), - Type::iterable(Type::object(ClassicDummy::class)), - ); - - $this->assertEncoded( - '{"0":{"id":1,"name":"dummy"},"1":{"id":1,"name":"dummy"}}', - new \ArrayObject([new ClassicDummy(), new ClassicDummy()]), - Type::iterable(Type::object(ClassicDummy::class), Type::int()), - ); - } - - public function testEncodeObject() - { - $dummy = new ClassicDummy(); - $dummy->id = 10; - $dummy->name = 'dummy name'; - - $this->assertEncoded('{"id":10,"name":"dummy name"}', $dummy, Type::object(ClassicDummy::class)); - } - - public function testEncodeObjectWithEncodedName() - { - $dummy = new DummyWithNameAttributes(); - $dummy->id = 10; - $dummy->name = 'dummy name'; - - $this->assertEncoded('{"@id":10,"name":"dummy name"}', $dummy, Type::object(DummyWithNameAttributes::class)); - } - - public function testEncodeObjectWithValueTransformer() - { - $dummy = new DummyWithValueTransformerAttributes(); - $dummy->id = 10; - $dummy->active = true; - - $this->assertEncoded( - '{"id":"20","active":"true","name":"dummy","range":"10..20"}', - $dummy, - Type::object(DummyWithValueTransformerAttributes::class), - options: ['scale' => 1], - valueTransformers: [ - BooleanToStringValueTransformer::class => new BooleanToStringValueTransformer(), - DoubleIntAndCastToStringValueTransformer::class => new DoubleIntAndCastToStringValueTransformer(), - ], - ); - } - - public function testEncodeObjectWithPhpDoc() - { - $dummy = new DummyWithPhpDoc(); - $dummy->arrayOfDummies = ['key' => new DummyWithNameAttributes()]; - - $this->assertEncoded('{"arrayOfDummies":{"key":{"@id":1,"name":"dummy"}},"array":[]}', $dummy, Type::object(DummyWithPhpDoc::class)); - } - - public function testEncodeObjectWithNullableProperties() - { - $dummy = new DummyWithNullableProperties(); - - $this->assertEncoded('{"name":null,"enum":null}', $dummy, Type::object(DummyWithNullableProperties::class)); - } - - public function testEncodeObjectWithDateTimes() - { - $dummy = new DummyWithDateTimes(); - $dummy->interface = new \DateTimeImmutable('2024-11-20'); - $dummy->immutable = new \DateTimeImmutable('2025-11-20'); - - $this->assertEncoded( - '{"interface":"2024-11-20","immutable":"2025-11-20"}', - $dummy, - Type::object(DummyWithDateTimes::class), - options: [DateTimeToStringValueTransformer::FORMAT_KEY => 'Y-m-d'], - ); - } - - public function testThrowWhenMaxDepthIsReached() - { - $encoder = JsonEncoder::create(encodersDir: $this->encodersDir); - - $dummy = new SelfReferencingDummy(); - for ($i = 0; $i < 512; ++$i) { - $tmp = new SelfReferencingDummy(); - $tmp->self = $dummy; - - $dummy = $tmp; - } - - $this->expectException(MaxDepthException::class); - $this->expectExceptionMessage('Max depth of 512 has been reached.'); - - (string) $encoder->encode($dummy, Type::object(SelfReferencingDummy::class)); - } - - public function testCreateEncoderFile() - { - $encoder = JsonEncoder::create(encodersDir: $this->encodersDir); - - $encoder->encode(true, Type::bool()); - - $this->assertFileExists($this->encodersDir); - $this->assertCount(1, glob($this->encodersDir.'/*')); - } - - public function testCreateEncoderFileOnlyIfNotExists() - { - $encoder = JsonEncoder::create(encodersDir: $this->encodersDir); - - if (!file_exists($this->encodersDir)) { - mkdir($this->encodersDir, recursive: true); - } - - file_put_contents( - \sprintf('%s%s%s.json.php', $this->encodersDir, \DIRECTORY_SEPARATOR, hash('xxh128', (string) Type::bool())), - 'assertSame('CACHED', (string) $encoder->encode(true, Type::bool())); - } - - /** - * @param array $options - * @param array $valueTransformers - */ - private function assertEncoded(string $expected, mixed $data, Type $type, array $options = [], array $valueTransformers = []): void - { - $encoder = JsonEncoder::create(encodersDir: $this->encodersDir, valueTransformers: $valueTransformers); - $this->assertSame($expected, (string) $encoder->encode($data, $type, $options)); - } -} diff --git a/src/Symfony/Component/JsonEncoder/.gitattributes b/src/Symfony/Component/JsonStreamer/.gitattributes similarity index 100% rename from src/Symfony/Component/JsonEncoder/.gitattributes rename to src/Symfony/Component/JsonStreamer/.gitattributes diff --git a/src/Symfony/Component/JsonEncoder/.gitignore b/src/Symfony/Component/JsonStreamer/.gitignore similarity index 100% rename from src/Symfony/Component/JsonEncoder/.gitignore rename to src/Symfony/Component/JsonStreamer/.gitignore diff --git a/src/Symfony/Component/JsonEncoder/Attribute/JsonEncodable.php b/src/Symfony/Component/JsonStreamer/Attribute/JsonStreamable.php similarity index 85% rename from src/Symfony/Component/JsonEncoder/Attribute/JsonEncodable.php rename to src/Symfony/Component/JsonStreamer/Attribute/JsonStreamable.php index b03346be2e36b..4b1e70e4c6857 100644 --- a/src/Symfony/Component/JsonEncoder/Attribute/JsonEncodable.php +++ b/src/Symfony/Component/JsonStreamer/Attribute/JsonStreamable.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Attribute; +namespace Symfony\Component\JsonStreamer\Attribute; /** * @author Mathias Arlaud @@ -17,7 +17,7 @@ * @experimental */ #[\Attribute(\Attribute::TARGET_CLASS)] -final class JsonEncodable +final class JsonStreamable { public function __construct( public bool $asObject = true, diff --git a/src/Symfony/Component/JsonEncoder/Attribute/EncodedName.php b/src/Symfony/Component/JsonStreamer/Attribute/StreamedName.php similarity index 81% rename from src/Symfony/Component/JsonEncoder/Attribute/EncodedName.php rename to src/Symfony/Component/JsonStreamer/Attribute/StreamedName.php index 3da35bc9e0549..145c57a39eaac 100644 --- a/src/Symfony/Component/JsonEncoder/Attribute/EncodedName.php +++ b/src/Symfony/Component/JsonStreamer/Attribute/StreamedName.php @@ -9,17 +9,17 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Attribute; +namespace Symfony\Component\JsonStreamer\Attribute; /** - * Defines the encoded property name. + * Defines the streamed property name. * * @author Mathias Arlaud * * @experimental */ #[\Attribute(\Attribute::TARGET_PROPERTY)] -final class EncodedName +final class StreamedName { public function __construct( private string $name, diff --git a/src/Symfony/Component/JsonStreamer/Attribute/ValueTransformer.php b/src/Symfony/Component/JsonStreamer/Attribute/ValueTransformer.php new file mode 100644 index 0000000000000..790c075dcb833 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Attribute/ValueTransformer.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonStreamer\Attribute; + +use Symfony\Component\JsonStreamer\Exception\LogicException; + +/** + * Defines a callable or a {@see \Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface} service id + * that will be used to transform the property data during stream reading/writing. + * + * @author Mathias Arlaud + * + * @experimental + */ +#[\Attribute(\Attribute::TARGET_PROPERTY)] +class ValueTransformer +{ + private \Closure|string|null $streamToNative; + private \Closure|string|null $nativeToStream; + + /** + * @param (callable(mixed, array=): mixed)|string|null $streamToNative + * @param (callable(mixed, array=): mixed)|string|null $nativeToStream + */ + public function __construct( + callable|string|null $streamToNative = null, + callable|string|null $nativeToStream = null, + ) { + if (!$streamToNative && !$nativeToStream) { + throw new LogicException('#[ValueTransformer] attribute must declare either $streamToNative or $nativeToStream.'); + } + + if (\is_callable($streamToNative)) { + $streamToNative = $streamToNative(...); + } + + if (\is_callable($nativeToStream)) { + $nativeToStream = $nativeToStream(...); + } + + $this->streamToNative = $streamToNative; + $this->nativeToStream = $nativeToStream; + } + + public function getStreamToNative(): string|\Closure|null + { + return $this->streamToNative; + } + + public function getNativeToStream(): string|\Closure|null + { + return $this->nativeToStream; + } +} diff --git a/src/Symfony/Component/JsonEncoder/CHANGELOG.md b/src/Symfony/Component/JsonStreamer/CHANGELOG.md similarity index 100% rename from src/Symfony/Component/JsonEncoder/CHANGELOG.md rename to src/Symfony/Component/JsonStreamer/CHANGELOG.md diff --git a/src/Symfony/Component/JsonEncoder/CacheWarmer/LazyGhostCacheWarmer.php b/src/Symfony/Component/JsonStreamer/CacheWarmer/LazyGhostCacheWarmer.php similarity index 84% rename from src/Symfony/Component/JsonEncoder/CacheWarmer/LazyGhostCacheWarmer.php rename to src/Symfony/Component/JsonStreamer/CacheWarmer/LazyGhostCacheWarmer.php index 25a00e4c9f39e..99b651d26d9e2 100644 --- a/src/Symfony/Component/JsonEncoder/CacheWarmer/LazyGhostCacheWarmer.php +++ b/src/Symfony/Component/JsonStreamer/CacheWarmer/LazyGhostCacheWarmer.php @@ -9,16 +9,16 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\CacheWarmer; +namespace Symfony\Component\JsonStreamer\CacheWarmer; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmer; -use Symfony\Component\JsonEncoder\Exception\RuntimeException; +use Symfony\Component\JsonStreamer\Exception\RuntimeException; use Symfony\Component\VarExporter\ProxyHelper; /** * Generates lazy ghost {@see \Symfony\Component\VarExporter\LazyGhostTrait} - * PHP files for $encodable types. + * PHP files for $streamable types. * * @author Mathias Arlaud * @@ -29,10 +29,10 @@ final class LazyGhostCacheWarmer extends CacheWarmer private Filesystem $fs; /** - * @param iterable $encodableClassNames + * @param iterable $streamableClassNames */ public function __construct( - private iterable $encodableClassNames, + private iterable $streamableClassNames, private string $lazyGhostsDir, ) { $this->fs = new Filesystem(); @@ -44,7 +44,7 @@ public function warmUp(string $cacheDir, ?string $buildDir = null): array $this->fs->mkdir($this->lazyGhostsDir); } - foreach ($this->encodableClassNames as $className) { + foreach ($this->streamableClassNames as $className) { $this->warmClassLazyGhost($className); } diff --git a/src/Symfony/Component/JsonStreamer/CacheWarmer/StreamerCacheWarmer.php b/src/Symfony/Component/JsonStreamer/CacheWarmer/StreamerCacheWarmer.php new file mode 100644 index 0000000000000..232b592fbbd3f --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/CacheWarmer/StreamerCacheWarmer.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonStreamer\CacheWarmer; + +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; +use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; +use Symfony\Component\JsonStreamer\Exception\ExceptionInterface; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\Read\StreamReaderGenerator; +use Symfony\Component\JsonStreamer\Write\StreamWriterGenerator; +use Symfony\Component\TypeInfo\Type; + +/** + * Generates stream readers and stream writers PHP files. + * + * @author Mathias Arlaud + * + * @internal + */ +final class StreamerCacheWarmer implements CacheWarmerInterface +{ + private StreamWriterGenerator $streamWriterGenerator; + private StreamReaderGenerator $streamReaderGenerator; + + /** + * @param iterable $streamable + */ + public function __construct( + private iterable $streamable, + PropertyMetadataLoaderInterface $streamWriterPropertyMetadataLoader, + PropertyMetadataLoaderInterface $streamReaderPropertyMetadataLoader, + string $streamWritersDir, + string $streamReadersDir, + private LoggerInterface $logger = new NullLogger(), + ) { + $this->streamWriterGenerator = new StreamWriterGenerator($streamWriterPropertyMetadataLoader, $streamWritersDir); + $this->streamReaderGenerator = new StreamReaderGenerator($streamReaderPropertyMetadataLoader, $streamReadersDir); + } + + public function warmUp(string $cacheDir, ?string $buildDir = null): array + { + foreach ($this->streamable as $className => $streamable) { + if ($streamable['object']) { + $type = Type::object($className); + + $this->warmUpStreamWriter($type); + $this->warmUpStreamReaders($type); + } + + if ($streamable['list']) { + $type = Type::list(Type::object($className)); + + $this->warmUpStreamWriter($type); + $this->warmUpStreamReaders($type); + } + } + + return []; + } + + public function isOptional(): bool + { + return true; + } + + private function warmUpStreamWriter(Type $type): void + { + try { + $this->streamWriterGenerator->generate($type); + } catch (ExceptionInterface $e) { + $this->logger->debug('Cannot generate "json" stream writer for "{type}": {exception}', ['type' => (string) $type, 'exception' => $e]); + } + } + + private function warmUpStreamReaders(Type $type): void + { + try { + $this->streamReaderGenerator->generate($type, false); + } catch (ExceptionInterface $e) { + $this->logger->debug('Cannot generate "json" string stream reader for "{type}": {exception}', ['type' => (string) $type, 'exception' => $e]); + } + + try { + $this->streamReaderGenerator->generate($type, true); + } catch (ExceptionInterface $e) { + $this->logger->debug('Cannot generate "json" resource stream reader for "{type}": {exception}', ['type' => (string) $type, 'exception' => $e]); + } + } +} diff --git a/src/Symfony/Component/JsonEncoder/DataModel/DataAccessorInterface.php b/src/Symfony/Component/JsonStreamer/DataModel/DataAccessorInterface.php similarity index 91% rename from src/Symfony/Component/JsonEncoder/DataModel/DataAccessorInterface.php rename to src/Symfony/Component/JsonStreamer/DataModel/DataAccessorInterface.php index 807ea749f4421..99f3dbfd0e9b8 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/DataAccessorInterface.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/DataAccessorInterface.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel; +namespace Symfony\Component\JsonStreamer\DataModel; use PhpParser\Node\Expr; diff --git a/src/Symfony/Component/JsonEncoder/DataModel/FunctionDataAccessor.php b/src/Symfony/Component/JsonStreamer/DataModel/FunctionDataAccessor.php similarity index 95% rename from src/Symfony/Component/JsonEncoder/DataModel/FunctionDataAccessor.php rename to src/Symfony/Component/JsonStreamer/DataModel/FunctionDataAccessor.php index a52e179e9f6a1..f2e579787f6da 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/FunctionDataAccessor.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/FunctionDataAccessor.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel; +namespace Symfony\Component\JsonStreamer\DataModel; use PhpParser\BuilderFactory; use PhpParser\Node\Expr; diff --git a/src/Symfony/Component/JsonEncoder/DataModel/PhpExprDataAccessor.php b/src/Symfony/Component/JsonStreamer/DataModel/PhpExprDataAccessor.php similarity index 92% rename from src/Symfony/Component/JsonEncoder/DataModel/PhpExprDataAccessor.php rename to src/Symfony/Component/JsonStreamer/DataModel/PhpExprDataAccessor.php index ee8f15ef20ed6..9806b94ed0a9f 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/PhpExprDataAccessor.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/PhpExprDataAccessor.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel; +namespace Symfony\Component\JsonStreamer\DataModel; use PhpParser\Node\Expr; diff --git a/src/Symfony/Component/JsonEncoder/DataModel/PropertyDataAccessor.php b/src/Symfony/Component/JsonStreamer/DataModel/PropertyDataAccessor.php similarity index 93% rename from src/Symfony/Component/JsonEncoder/DataModel/PropertyDataAccessor.php rename to src/Symfony/Component/JsonStreamer/DataModel/PropertyDataAccessor.php index 69cf7aa13f14c..a9ca03e02a512 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/PropertyDataAccessor.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/PropertyDataAccessor.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel; +namespace Symfony\Component\JsonStreamer\DataModel; use PhpParser\BuilderFactory; use PhpParser\Node\Expr; diff --git a/src/Symfony/Component/JsonEncoder/DataModel/Decode/BackedEnumNode.php b/src/Symfony/Component/JsonStreamer/DataModel/Read/BackedEnumNode.php similarity index 93% rename from src/Symfony/Component/JsonEncoder/DataModel/Decode/BackedEnumNode.php rename to src/Symfony/Component/JsonStreamer/DataModel/Read/BackedEnumNode.php index 1f78edf309eb5..9c56c536c4303 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/Decode/BackedEnumNode.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/Read/BackedEnumNode.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel\Decode; +namespace Symfony\Component\JsonStreamer\DataModel\Read; use Symfony\Component\TypeInfo\Type\BackedEnumType; diff --git a/src/Symfony/Component/JsonEncoder/DataModel/Decode/CollectionNode.php b/src/Symfony/Component/JsonStreamer/DataModel/Read/CollectionNode.php similarity index 94% rename from src/Symfony/Component/JsonEncoder/DataModel/Decode/CollectionNode.php rename to src/Symfony/Component/JsonStreamer/DataModel/Read/CollectionNode.php index 72bf2dd2be276..d9be381960dc1 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/Decode/CollectionNode.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/Read/CollectionNode.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel\Decode; +namespace Symfony\Component\JsonStreamer\DataModel\Read; use Symfony\Component\TypeInfo\Type\CollectionType; diff --git a/src/Symfony/Component/JsonEncoder/DataModel/Decode/CompositeNode.php b/src/Symfony/Component/JsonStreamer/DataModel/Read/CompositeNode.php similarity index 94% rename from src/Symfony/Component/JsonEncoder/DataModel/Decode/CompositeNode.php rename to src/Symfony/Component/JsonStreamer/DataModel/Read/CompositeNode.php index b767451722fa9..a0c9c758937cf 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/Decode/CompositeNode.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/Read/CompositeNode.php @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel\Decode; +namespace Symfony\Component\JsonStreamer\DataModel\Read; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\Type\UnionType; diff --git a/src/Symfony/Component/JsonEncoder/DataModel/Decode/DataModelNodeInterface.php b/src/Symfony/Component/JsonStreamer/DataModel/Read/DataModelNodeInterface.php similarity index 78% rename from src/Symfony/Component/JsonEncoder/DataModel/Decode/DataModelNodeInterface.php rename to src/Symfony/Component/JsonStreamer/DataModel/Read/DataModelNodeInterface.php index b9e81c1889edd..4b0c3853a34fe 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/Decode/DataModelNodeInterface.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/Read/DataModelNodeInterface.php @@ -9,12 +9,12 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel\Decode; +namespace Symfony\Component\JsonStreamer\DataModel\Read; use Symfony\Component\TypeInfo\Type; /** - * Represents a node in the decoding data model graph representation. + * Represents a node in the stream reading data model graph representation. * * @author Mathias Arlaud * diff --git a/src/Symfony/Component/JsonEncoder/DataModel/Decode/ObjectNode.php b/src/Symfony/Component/JsonStreamer/DataModel/Read/ObjectNode.php similarity index 92% rename from src/Symfony/Component/JsonEncoder/DataModel/Decode/ObjectNode.php rename to src/Symfony/Component/JsonStreamer/DataModel/Read/ObjectNode.php index 01e081dcc635f..ca39a4cfee5a9 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/Decode/ObjectNode.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/Read/ObjectNode.php @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel\Decode; +namespace Symfony\Component\JsonStreamer\DataModel\Read; -use Symfony\Component\JsonEncoder\DataModel\DataAccessorInterface; +use Symfony\Component\JsonStreamer\DataModel\DataAccessorInterface; use Symfony\Component\TypeInfo\Type\ObjectType; use Symfony\Component\TypeInfo\Type\UnionType; diff --git a/src/Symfony/Component/JsonEncoder/DataModel/Decode/ScalarNode.php b/src/Symfony/Component/JsonStreamer/DataModel/Read/ScalarNode.php similarity index 93% rename from src/Symfony/Component/JsonEncoder/DataModel/Decode/ScalarNode.php rename to src/Symfony/Component/JsonStreamer/DataModel/Read/ScalarNode.php index ae2f572b38faa..5684c28a4430b 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/Decode/ScalarNode.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/Read/ScalarNode.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel\Decode; +namespace Symfony\Component\JsonStreamer\DataModel\Read; use Symfony\Component\TypeInfo\Type\BuiltinType; diff --git a/src/Symfony/Component/JsonEncoder/DataModel/ScalarDataAccessor.php b/src/Symfony/Component/JsonStreamer/DataModel/ScalarDataAccessor.php similarity index 92% rename from src/Symfony/Component/JsonEncoder/DataModel/ScalarDataAccessor.php rename to src/Symfony/Component/JsonStreamer/DataModel/ScalarDataAccessor.php index b5f7776a9d002..f60220dd82e7a 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/ScalarDataAccessor.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/ScalarDataAccessor.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel; +namespace Symfony\Component\JsonStreamer\DataModel; use PhpParser\BuilderFactory; use PhpParser\Node\Expr; diff --git a/src/Symfony/Component/JsonEncoder/DataModel/VariableDataAccessor.php b/src/Symfony/Component/JsonStreamer/DataModel/VariableDataAccessor.php similarity index 92% rename from src/Symfony/Component/JsonEncoder/DataModel/VariableDataAccessor.php rename to src/Symfony/Component/JsonStreamer/DataModel/VariableDataAccessor.php index 783ffba07bb86..0046f55b4e7e0 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/VariableDataAccessor.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/VariableDataAccessor.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel; +namespace Symfony\Component\JsonStreamer\DataModel; use PhpParser\BuilderFactory; use PhpParser\Node\Expr; diff --git a/src/Symfony/Component/JsonEncoder/DataModel/Encode/BackedEnumNode.php b/src/Symfony/Component/JsonStreamer/DataModel/Write/BackedEnumNode.php similarity index 87% rename from src/Symfony/Component/JsonEncoder/DataModel/Encode/BackedEnumNode.php rename to src/Symfony/Component/JsonStreamer/DataModel/Write/BackedEnumNode.php index 519f7b977078c..4cda4df831d28 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/Encode/BackedEnumNode.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/Write/BackedEnumNode.php @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel\Encode; +namespace Symfony\Component\JsonStreamer\DataModel\Write; -use Symfony\Component\JsonEncoder\DataModel\DataAccessorInterface; +use Symfony\Component\JsonStreamer\DataModel\DataAccessorInterface; use Symfony\Component\TypeInfo\Type\BackedEnumType; /** diff --git a/src/Symfony/Component/JsonEncoder/DataModel/Encode/CollectionNode.php b/src/Symfony/Component/JsonStreamer/DataModel/Write/CollectionNode.php similarity index 88% rename from src/Symfony/Component/JsonEncoder/DataModel/Encode/CollectionNode.php rename to src/Symfony/Component/JsonStreamer/DataModel/Write/CollectionNode.php index 2827eca9de241..276679db210ca 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/Encode/CollectionNode.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/Write/CollectionNode.php @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel\Encode; +namespace Symfony\Component\JsonStreamer\DataModel\Write; -use Symfony\Component\JsonEncoder\DataModel\DataAccessorInterface; +use Symfony\Component\JsonStreamer\DataModel\DataAccessorInterface; use Symfony\Component\TypeInfo\Type\CollectionType; /** diff --git a/src/Symfony/Component/JsonEncoder/DataModel/Encode/CompositeNode.php b/src/Symfony/Component/JsonStreamer/DataModel/Write/CompositeNode.php similarity index 91% rename from src/Symfony/Component/JsonEncoder/DataModel/Encode/CompositeNode.php rename to src/Symfony/Component/JsonStreamer/DataModel/Write/CompositeNode.php index 7e7ee4120b1cc..63eff63af7e5a 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/Encode/CompositeNode.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/Write/CompositeNode.php @@ -9,10 +9,10 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel\Encode; +namespace Symfony\Component\JsonStreamer\DataModel\Write; -use Symfony\Component\JsonEncoder\DataModel\DataAccessorInterface; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\DataModel\DataAccessorInterface; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\Type\UnionType; diff --git a/src/Symfony/Component/JsonEncoder/DataModel/Encode/DataModelNodeInterface.php b/src/Symfony/Component/JsonStreamer/DataModel/Write/DataModelNodeInterface.php similarity index 70% rename from src/Symfony/Component/JsonEncoder/DataModel/Encode/DataModelNodeInterface.php rename to src/Symfony/Component/JsonStreamer/DataModel/Write/DataModelNodeInterface.php index eed57a5dd2d79..9b72503af1a3c 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/Encode/DataModelNodeInterface.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/Write/DataModelNodeInterface.php @@ -9,13 +9,13 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel\Encode; +namespace Symfony\Component\JsonStreamer\DataModel\Write; -use Symfony\Component\JsonEncoder\DataModel\DataAccessorInterface; +use Symfony\Component\JsonStreamer\DataModel\DataAccessorInterface; use Symfony\Component\TypeInfo\Type; /** - * Represents a node in the encoding data model graph representation. + * Represents a node in the stream writing data model graph representation. * * @author Mathias Arlaud * diff --git a/src/Symfony/Component/JsonEncoder/DataModel/Encode/ExceptionNode.php b/src/Symfony/Component/JsonStreamer/DataModel/Write/ExceptionNode.php similarity index 84% rename from src/Symfony/Component/JsonEncoder/DataModel/Encode/ExceptionNode.php rename to src/Symfony/Component/JsonStreamer/DataModel/Write/ExceptionNode.php index e026199aebb00..2145f9061dfc7 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/Encode/ExceptionNode.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/Write/ExceptionNode.php @@ -9,12 +9,12 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel\Encode; +namespace Symfony\Component\JsonStreamer\DataModel\Write; use PhpParser\Node\Expr\New_; use PhpParser\Node\Name\FullyQualified; -use Symfony\Component\JsonEncoder\DataModel\DataAccessorInterface; -use Symfony\Component\JsonEncoder\DataModel\PhpExprDataAccessor; +use Symfony\Component\JsonStreamer\DataModel\DataAccessorInterface; +use Symfony\Component\JsonStreamer\DataModel\PhpExprDataAccessor; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\Type\ObjectType; diff --git a/src/Symfony/Component/JsonEncoder/DataModel/Encode/ObjectNode.php b/src/Symfony/Component/JsonStreamer/DataModel/Write/ObjectNode.php similarity index 89% rename from src/Symfony/Component/JsonEncoder/DataModel/Encode/ObjectNode.php rename to src/Symfony/Component/JsonStreamer/DataModel/Write/ObjectNode.php index 561fb48e59846..04bc16dab957a 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/Encode/ObjectNode.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/Write/ObjectNode.php @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel\Encode; +namespace Symfony\Component\JsonStreamer\DataModel\Write; -use Symfony\Component\JsonEncoder\DataModel\DataAccessorInterface; +use Symfony\Component\JsonStreamer\DataModel\DataAccessorInterface; use Symfony\Component\TypeInfo\Type\ObjectType; /** diff --git a/src/Symfony/Component/JsonEncoder/DataModel/Encode/ScalarNode.php b/src/Symfony/Component/JsonStreamer/DataModel/Write/ScalarNode.php similarity index 87% rename from src/Symfony/Component/JsonEncoder/DataModel/Encode/ScalarNode.php rename to src/Symfony/Component/JsonStreamer/DataModel/Write/ScalarNode.php index 4bf032eb193af..9f7e048faf86a 100644 --- a/src/Symfony/Component/JsonEncoder/DataModel/Encode/ScalarNode.php +++ b/src/Symfony/Component/JsonStreamer/DataModel/Write/ScalarNode.php @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DataModel\Encode; +namespace Symfony\Component\JsonStreamer\DataModel\Write; -use Symfony\Component\JsonEncoder\DataModel\DataAccessorInterface; +use Symfony\Component\JsonStreamer\DataModel\DataAccessorInterface; use Symfony\Component\TypeInfo\Type\BuiltinType; /** diff --git a/src/Symfony/Component/JsonEncoder/DependencyInjection/EncodablePass.php b/src/Symfony/Component/JsonStreamer/DependencyInjection/StreamablePass.php similarity index 53% rename from src/Symfony/Component/JsonEncoder/DependencyInjection/EncodablePass.php rename to src/Symfony/Component/JsonStreamer/DependencyInjection/StreamablePass.php index 7d0f2a3b27c45..babf962bfcdaa 100644 --- a/src/Symfony/Component/JsonEncoder/DependencyInjection/EncodablePass.php +++ b/src/Symfony/Component/JsonStreamer/DependencyInjection/StreamablePass.php @@ -9,34 +9,34 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\DependencyInjection; +namespace Symfony\Component\JsonStreamer\DependencyInjection; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; /** - * Sets the encodable metadata to the services that need them. + * Sets the streamable metadata to the services that need them. * * @author Mathias Arlaud */ -class EncodablePass implements CompilerPassInterface +class StreamablePass implements CompilerPassInterface { public function process(ContainerBuilder $container): void { - if (!$container->hasDefinition('json_encoder.encoder')) { + if (!$container->hasDefinition('json_streamer.stream_writer')) { return; } - $encodable = []; + $streamable = []; - // retrieve concrete services tagged with "json_encoder.encodable" tag + // retrieve concrete services tagged with "json_streamer.streamable" tag foreach ($container->getDefinitions() as $id => $definition) { - if (!$tag = ($definition->getTag('json_encoder.encodable')[0] ?? null)) { + if (!$tag = ($definition->getTag('json_streamer.streamable')[0] ?? null)) { continue; } if (($className = $container->getDefinition($id)->getClass()) && !$container->getDefinition($id)->isAbstract()) { - $encodable[$className] = [ + $streamable[$className] = [ 'object' => $tag['object'], 'list' => $tag['list'], ]; @@ -45,12 +45,12 @@ public function process(ContainerBuilder $container): void $container->removeDefinition($id); } - $container->getDefinition('.json_encoder.cache_warmer.encoder_decoder') - ->replaceArgument(0, $encodable); + $container->getDefinition('.json_streamer.cache_warmer.streamer') + ->replaceArgument(0, $streamable); - if ($container->hasDefinition('.json_encoder.cache_warmer.lazy_ghost')) { - $container->getDefinition('.json_encoder.cache_warmer.lazy_ghost') - ->replaceArgument(0, array_keys($encodable)); + if ($container->hasDefinition('.json_streamer.cache_warmer.lazy_ghost')) { + $container->getDefinition('.json_streamer.cache_warmer.lazy_ghost') + ->replaceArgument(0, array_keys($streamable)); } } } diff --git a/src/Symfony/Component/JsonEncoder/Exception/ExceptionInterface.php b/src/Symfony/Component/JsonStreamer/Exception/ExceptionInterface.php similarity index 87% rename from src/Symfony/Component/JsonEncoder/Exception/ExceptionInterface.php rename to src/Symfony/Component/JsonStreamer/Exception/ExceptionInterface.php index b14a6e33d9a94..e9eff4b75bbca 100644 --- a/src/Symfony/Component/JsonEncoder/Exception/ExceptionInterface.php +++ b/src/Symfony/Component/JsonStreamer/Exception/ExceptionInterface.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Exception; +namespace Symfony\Component\JsonStreamer\Exception; /** * @author Mathias Arlaud diff --git a/src/Symfony/Component/JsonEncoder/Exception/InvalidArgumentException.php b/src/Symfony/Component/JsonStreamer/Exception/InvalidArgumentException.php similarity index 88% rename from src/Symfony/Component/JsonEncoder/Exception/InvalidArgumentException.php rename to src/Symfony/Component/JsonStreamer/Exception/InvalidArgumentException.php index d4a98a8d4a130..19902ef86d5fa 100644 --- a/src/Symfony/Component/JsonEncoder/Exception/InvalidArgumentException.php +++ b/src/Symfony/Component/JsonStreamer/Exception/InvalidArgumentException.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Exception; +namespace Symfony\Component\JsonStreamer\Exception; /** * @author Mathias Arlaud diff --git a/src/Symfony/Component/JsonEncoder/Exception/InvalidStreamException.php b/src/Symfony/Component/JsonStreamer/Exception/InvalidStreamException.php similarity index 88% rename from src/Symfony/Component/JsonEncoder/Exception/InvalidStreamException.php rename to src/Symfony/Component/JsonStreamer/Exception/InvalidStreamException.php index f3cfb18f8cfcd..b42adac6a0679 100644 --- a/src/Symfony/Component/JsonEncoder/Exception/InvalidStreamException.php +++ b/src/Symfony/Component/JsonStreamer/Exception/InvalidStreamException.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Exception; +namespace Symfony\Component\JsonStreamer\Exception; /** * @author Mathias Arlaud diff --git a/src/Symfony/Component/JsonEncoder/Exception/LogicException.php b/src/Symfony/Component/JsonStreamer/Exception/LogicException.php similarity index 88% rename from src/Symfony/Component/JsonEncoder/Exception/LogicException.php rename to src/Symfony/Component/JsonStreamer/Exception/LogicException.php index 513f9451ad658..691fccdb372be 100644 --- a/src/Symfony/Component/JsonEncoder/Exception/LogicException.php +++ b/src/Symfony/Component/JsonStreamer/Exception/LogicException.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Exception; +namespace Symfony\Component\JsonStreamer\Exception; /** * @author Mathias Arlaud diff --git a/src/Symfony/Component/JsonEncoder/Exception/MaxDepthException.php b/src/Symfony/Component/JsonStreamer/Exception/MaxDepthException.php similarity index 90% rename from src/Symfony/Component/JsonEncoder/Exception/MaxDepthException.php rename to src/Symfony/Component/JsonStreamer/Exception/MaxDepthException.php index 10742c95277a9..98ac498d1b7ca 100644 --- a/src/Symfony/Component/JsonEncoder/Exception/MaxDepthException.php +++ b/src/Symfony/Component/JsonStreamer/Exception/MaxDepthException.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Exception; +namespace Symfony\Component\JsonStreamer\Exception; /** * @author Mathias Arlaud diff --git a/src/Symfony/Component/JsonEncoder/Exception/RuntimeException.php b/src/Symfony/Component/JsonStreamer/Exception/RuntimeException.php similarity index 88% rename from src/Symfony/Component/JsonEncoder/Exception/RuntimeException.php rename to src/Symfony/Component/JsonStreamer/Exception/RuntimeException.php index 747caee07a88c..9641e79347c7d 100644 --- a/src/Symfony/Component/JsonEncoder/Exception/RuntimeException.php +++ b/src/Symfony/Component/JsonStreamer/Exception/RuntimeException.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Exception; +namespace Symfony\Component\JsonStreamer\Exception; /** * @author Mathias Arlaud diff --git a/src/Symfony/Component/JsonEncoder/Exception/UnexpectedValueException.php b/src/Symfony/Component/JsonStreamer/Exception/UnexpectedValueException.php similarity index 88% rename from src/Symfony/Component/JsonEncoder/Exception/UnexpectedValueException.php rename to src/Symfony/Component/JsonStreamer/Exception/UnexpectedValueException.php index 40c2aae292ec8..33fb8ec6d7437 100644 --- a/src/Symfony/Component/JsonEncoder/Exception/UnexpectedValueException.php +++ b/src/Symfony/Component/JsonStreamer/Exception/UnexpectedValueException.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Exception; +namespace Symfony\Component\JsonStreamer\Exception; /** * @author Mathias Arlaud diff --git a/src/Symfony/Component/JsonEncoder/Exception/UnsupportedException.php b/src/Symfony/Component/JsonStreamer/Exception/UnsupportedException.php similarity index 88% rename from src/Symfony/Component/JsonEncoder/Exception/UnsupportedException.php rename to src/Symfony/Component/JsonStreamer/Exception/UnsupportedException.php index 9bd9710a44fce..efae15ae9fbc1 100644 --- a/src/Symfony/Component/JsonEncoder/Exception/UnsupportedException.php +++ b/src/Symfony/Component/JsonStreamer/Exception/UnsupportedException.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Exception; +namespace Symfony\Component\JsonStreamer\Exception; /** * @author Mathias Arlaud diff --git a/src/Symfony/Component/JsonEncoder/JsonDecoder.php b/src/Symfony/Component/JsonStreamer/JsonStreamReader.php similarity index 61% rename from src/Symfony/Component/JsonEncoder/JsonDecoder.php rename to src/Symfony/Component/JsonStreamer/JsonStreamReader.php index 304b01f28cde9..b2f2fabaa3dad 100644 --- a/src/Symfony/Component/JsonEncoder/JsonDecoder.php +++ b/src/Symfony/Component/JsonStreamer/JsonStreamReader.php @@ -9,20 +9,20 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder; +namespace Symfony\Component\JsonStreamer; use PHPStan\PhpDocParser\Parser\PhpDocParser; use Psr\Container\ContainerInterface; -use Symfony\Component\JsonEncoder\Decode\DecoderGenerator; -use Symfony\Component\JsonEncoder\Decode\Instantiator; -use Symfony\Component\JsonEncoder\Decode\LazyInstantiator; -use Symfony\Component\JsonEncoder\Mapping\Decode\AttributePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\Decode\DateTimeTypePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\GenericTypePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoaderInterface; -use Symfony\Component\JsonEncoder\ValueTransformer\StringToDateTimeValueTransformer; -use Symfony\Component\JsonEncoder\ValueTransformer\ValueTransformerInterface; +use Symfony\Component\JsonStreamer\Mapping\GenericTypePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\Mapping\Read\AttributePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\Read\DateTimeTypePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Read\Instantiator; +use Symfony\Component\JsonStreamer\Read\LazyInstantiator; +use Symfony\Component\JsonStreamer\Read\StreamReaderGenerator; +use Symfony\Component\JsonStreamer\ValueTransformer\StringToDateTimeValueTransformer; +use Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\TypeContext\TypeContextFactory; use Symfony\Component\TypeInfo\TypeResolver\StringTypeResolver; @@ -31,31 +31,31 @@ /** * @author Mathias Arlaud * - * @implements DecoderInterface> + * @implements StreamReaderInterface> * * @experimental */ -final class JsonDecoder implements DecoderInterface +final class JsonStreamReader implements StreamReaderInterface { - private DecoderGenerator $decoderGenerator; + private StreamReaderGenerator $streamReaderGenerator; private Instantiator $instantiator; private LazyInstantiator $lazyInstantiator; public function __construct( private ContainerInterface $valueTransformers, PropertyMetadataLoaderInterface $propertyMetadataLoader, - string $decodersDir, + string $streamReadersDir, string $lazyGhostsDir, ) { - $this->decoderGenerator = new DecoderGenerator($propertyMetadataLoader, $decodersDir); + $this->streamReaderGenerator = new StreamReaderGenerator($propertyMetadataLoader, $streamReadersDir); $this->instantiator = new Instantiator(); $this->lazyInstantiator = new LazyInstantiator($lazyGhostsDir); } - public function decode($input, Type $type, array $options = []): mixed + public function read($input, Type $type, array $options = []): mixed { $isStream = \is_resource($input); - $path = $this->decoderGenerator->generate($type, $isStream, $options); + $path = $this->streamReaderGenerator->generate($type, $isStream, $options); return (require $path)($input, $this->valueTransformers, $isStream ? $this->lazyInstantiator : $this->instantiator, $options); } @@ -63,12 +63,12 @@ public function decode($input, Type $type, array $options = []): mixed /** * @param array $valueTransformers */ - public static function create(array $valueTransformers = [], ?string $decodersDir = null, ?string $lazyGhostsDir = null): self + public static function create(array $valueTransformers = [], ?string $streamReadersDir = null, ?string $lazyGhostsDir = null): self { - $decodersDir ??= sys_get_temp_dir().'/json_encoder/decoder'; - $lazyGhostsDir ??= sys_get_temp_dir().'/json_encoder/lazy_ghost'; + $streamReadersDir ??= sys_get_temp_dir().'/json_streamer/read'; + $lazyGhostsDir ??= sys_get_temp_dir().'/json_streamer/lazy_ghost'; $valueTransformers += [ - 'json_encoder.value_transformer.string_to_date_time' => new StringToDateTimeValueTransformer(), + 'json_streamer.value_transformer.string_to_date_time' => new StringToDateTimeValueTransformer(), ]; $valueTransformersContainer = new class($valueTransformers) implements ContainerInterface { @@ -101,6 +101,6 @@ public function get(string $id): ValueTransformerInterface $typeContextFactory, ); - return new self($valueTransformersContainer, $propertyMetadataLoader, $decodersDir, $lazyGhostsDir); + return new self($valueTransformersContainer, $propertyMetadataLoader, $streamReadersDir, $lazyGhostsDir); } } diff --git a/src/Symfony/Component/JsonEncoder/JsonEncoder.php b/src/Symfony/Component/JsonStreamer/JsonStreamWriter.php similarity index 50% rename from src/Symfony/Component/JsonEncoder/JsonEncoder.php rename to src/Symfony/Component/JsonStreamer/JsonStreamWriter.php index cbeb6a7406b83..bbe31af9de57a 100644 --- a/src/Symfony/Component/JsonEncoder/JsonEncoder.php +++ b/src/Symfony/Component/JsonStreamer/JsonStreamWriter.php @@ -9,18 +9,18 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder; +namespace Symfony\Component\JsonStreamer; use PHPStan\PhpDocParser\Parser\PhpDocParser; use Psr\Container\ContainerInterface; -use Symfony\Component\JsonEncoder\Encode\EncoderGenerator; -use Symfony\Component\JsonEncoder\Mapping\Encode\AttributePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\Encode\DateTimeTypePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\GenericTypePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoaderInterface; -use Symfony\Component\JsonEncoder\ValueTransformer\DateTimeToStringValueTransformer; -use Symfony\Component\JsonEncoder\ValueTransformer\ValueTransformerInterface; +use Symfony\Component\JsonStreamer\Mapping\GenericTypePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\Mapping\Write\AttributePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\Write\DateTimeTypePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\ValueTransformer\DateTimeToStringValueTransformer; +use Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface; +use Symfony\Component\JsonStreamer\Write\StreamWriterGenerator; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\TypeContext\TypeContextFactory; use Symfony\Component\TypeInfo\TypeResolver\StringTypeResolver; @@ -29,37 +29,65 @@ /** * @author Mathias Arlaud * - * @implements EncoderInterface> + * @implements StreamWriterInterface> * * @experimental */ -final class JsonEncoder implements EncoderInterface +final class JsonStreamWriter implements StreamWriterInterface { - private EncoderGenerator $encoderGenerator; + private StreamWriterGenerator $streamWriterGenerator; public function __construct( private ContainerInterface $valueTransformers, PropertyMetadataLoaderInterface $propertyMetadataLoader, - string $encodersDir, + string $streamWritersDir, ) { - $this->encoderGenerator = new EncoderGenerator($propertyMetadataLoader, $encodersDir); + $this->streamWriterGenerator = new StreamWriterGenerator($propertyMetadataLoader, $streamWritersDir); } - public function encode(mixed $data, Type $type, array $options = []): \Traversable&\Stringable + public function write(mixed $data, Type $type, array $options = []): \Traversable&\Stringable { - $path = $this->encoderGenerator->generate($type, $options); + $path = $this->streamWriterGenerator->generate($type, $options); + $chunks = (require $path)($data, $this->valueTransformers, $options); - return new Encoded((require $path)($data, $this->valueTransformers, $options)); + return new + /** + * @implements \IteratorAggregate + */ + class($chunks) implements \IteratorAggregate, \Stringable { + /** + * @param \Traversable $chunks + */ + public function __construct( + private \Traversable $chunks, + ) { + } + + public function getIterator(): \Traversable + { + return $this->chunks; + } + + public function __toString(): string + { + $string = ''; + foreach ($this->chunks as $chunk) { + $string .= $chunk; + } + + return $string; + } + }; } /** * @param array $valueTransformers */ - public static function create(array $valueTransformers = [], ?string $encodersDir = null): self + public static function create(array $valueTransformers = [], ?string $streamWritersDir = null): self { - $encodersDir ??= sys_get_temp_dir().'/json_encoder/encoder'; + $streamWritersDir ??= sys_get_temp_dir().'/json_streamer/write'; $valueTransformers += [ - 'json_encoder.value_transformer.date_time_to_string' => new DateTimeToStringValueTransformer(), + 'json_streamer.value_transformer.date_time_to_string' => new DateTimeToStringValueTransformer(), ]; $valueTransformersContainer = new class($valueTransformers) implements ContainerInterface { @@ -92,6 +120,6 @@ public function get(string $id): ValueTransformerInterface $typeContextFactory, ); - return new self($valueTransformersContainer, $propertyMetadataLoader, $encodersDir); + return new self($valueTransformersContainer, $propertyMetadataLoader, $streamWritersDir); } } diff --git a/src/Symfony/Component/JsonEncoder/LICENSE b/src/Symfony/Component/JsonStreamer/LICENSE similarity index 95% rename from src/Symfony/Component/JsonEncoder/LICENSE rename to src/Symfony/Component/JsonStreamer/LICENSE index e374a5c8339d3..bc38d714ef697 100644 --- a/src/Symfony/Component/JsonEncoder/LICENSE +++ b/src/Symfony/Component/JsonStreamer/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2024-present Fabien Potencier +Copyright (c) 2025-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/JsonEncoder/Mapping/GenericTypePropertyMetadataLoader.php b/src/Symfony/Component/JsonStreamer/Mapping/GenericTypePropertyMetadataLoader.php similarity index 97% rename from src/Symfony/Component/JsonEncoder/Mapping/GenericTypePropertyMetadataLoader.php rename to src/Symfony/Component/JsonStreamer/Mapping/GenericTypePropertyMetadataLoader.php index 4604e96e1a7ac..ccc705e7c8e33 100644 --- a/src/Symfony/Component/JsonEncoder/Mapping/GenericTypePropertyMetadataLoader.php +++ b/src/Symfony/Component/JsonStreamer/Mapping/GenericTypePropertyMetadataLoader.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Mapping; +namespace Symfony\Component\JsonStreamer\Mapping; use Symfony\Component\TypeInfo\Exception\InvalidArgumentException; use Symfony\Component\TypeInfo\Type; @@ -22,7 +22,7 @@ use Symfony\Component\TypeInfo\TypeContext\TypeContextFactory; /** - * Enhances properties encoding/decoding metadata based on properties' generic type. + * Enhances properties metadata based on properties' generic type. * * @author Mathias Arlaud * diff --git a/src/Symfony/Component/JsonStreamer/Mapping/PropertyMetadata.php b/src/Symfony/Component/JsonStreamer/Mapping/PropertyMetadata.php new file mode 100644 index 0000000000000..0294bc41505d1 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Mapping/PropertyMetadata.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonStreamer\Mapping; + +use Symfony\Component\TypeInfo\Type; + +/** + * Holds stream reading/writing metadata about a given property. + * + * @author Mathias Arlaud + * + * @experimental + */ +final class PropertyMetadata +{ + /** + * @param list $nativeToStreamValueTransformers + * @param list $streamToNativeValueTransformers + */ + public function __construct( + private string $name, + private Type $type, + private array $nativeToStreamValueTransformers = [], + private array $streamToNativeValueTransformers = [], + ) { + } + + public function getName(): string + { + return $this->name; + } + + public function withName(string $name): self + { + return new self($name, $this->type, $this->nativeToStreamValueTransformers, $this->streamToNativeValueTransformers); + } + + public function getType(): Type + { + return $this->type; + } + + public function withType(Type $type): self + { + return new self($this->name, $type, $this->nativeToStreamValueTransformers, $this->streamToNativeValueTransformers); + } + + /** + * @return list + */ + public function getNativeToStreamValueTransformer(): array + { + return $this->nativeToStreamValueTransformers; + } + + /** + * @param list $nativeToStreamValueTransformers + */ + public function withNativeToStreamValueTransformers(array $nativeToStreamValueTransformers): self + { + return new self($this->name, $this->type, $nativeToStreamValueTransformers, $this->streamToNativeValueTransformers); + } + + public function withAdditionalNativeToStreamValueTransformer(string|\Closure $nativeToStreamValueTransformer): self + { + $nativeToStreamValueTransformers = $this->nativeToStreamValueTransformers; + + $nativeToStreamValueTransformers[] = $nativeToStreamValueTransformer; + $nativeToStreamValueTransformers = array_values(array_unique($nativeToStreamValueTransformers)); + + return $this->withNativeToStreamValueTransformers($nativeToStreamValueTransformers); + } + + /** + * @return list + */ + public function getStreamToNativeValueTransformers(): array + { + return $this->streamToNativeValueTransformers; + } + + /** + * @param list $streamToNativeValueTransformers + */ + public function withStreamToNativeValueTransformers(array $streamToNativeValueTransformers): self + { + return new self($this->name, $this->type, $this->nativeToStreamValueTransformers, $streamToNativeValueTransformers); + } + + public function withAdditionalStreamToNativeValueTransformer(string|\Closure $streamToNativeValueTransformer): self + { + $streamToNativeValueTransformers = $this->streamToNativeValueTransformers; + + $streamToNativeValueTransformers[] = $streamToNativeValueTransformer; + $streamToNativeValueTransformers = array_values(array_unique($streamToNativeValueTransformers)); + + return $this->withStreamToNativeValueTransformers($streamToNativeValueTransformers); + } +} diff --git a/src/Symfony/Component/JsonEncoder/Mapping/PropertyMetadataLoader.php b/src/Symfony/Component/JsonStreamer/Mapping/PropertyMetadataLoader.php similarity index 77% rename from src/Symfony/Component/JsonEncoder/Mapping/PropertyMetadataLoader.php rename to src/Symfony/Component/JsonStreamer/Mapping/PropertyMetadataLoader.php index 5658aa3fa40c3..97b89bcf1d6c1 100644 --- a/src/Symfony/Component/JsonEncoder/Mapping/PropertyMetadataLoader.php +++ b/src/Symfony/Component/JsonStreamer/Mapping/PropertyMetadataLoader.php @@ -9,13 +9,13 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Mapping; +namespace Symfony\Component\JsonStreamer\Mapping; -use Symfony\Component\JsonEncoder\Exception\RuntimeException; +use Symfony\Component\JsonStreamer\Exception\RuntimeException; use Symfony\Component\TypeInfo\TypeResolver\TypeResolverInterface; /** - * Loads basic properties encoding/decoding metadata for a given $className. + * Loads basic properties stream reading/writing metadata for a given $className. * * @author Mathias Arlaud * @@ -43,10 +43,10 @@ public function load(string $className, array $options = [], array $context = [] continue; } - $name = $encodedName = $reflectionProperty->getName(); + $name = $streamedName = $reflectionProperty->getName(); $type = $this->typeResolver->resolve($reflectionProperty); - $result[$encodedName] = new PropertyMetadata($name, $type); + $result[$streamedName] = new PropertyMetadata($name, $type); } return $result; diff --git a/src/Symfony/Component/JsonEncoder/Mapping/PropertyMetadataLoaderInterface.php b/src/Symfony/Component/JsonStreamer/Mapping/PropertyMetadataLoaderInterface.php similarity index 86% rename from src/Symfony/Component/JsonEncoder/Mapping/PropertyMetadataLoaderInterface.php rename to src/Symfony/Component/JsonStreamer/Mapping/PropertyMetadataLoaderInterface.php index a2d0ce8dc092d..d215b6f64d1bf 100644 --- a/src/Symfony/Component/JsonEncoder/Mapping/PropertyMetadataLoaderInterface.php +++ b/src/Symfony/Component/JsonStreamer/Mapping/PropertyMetadataLoaderInterface.php @@ -9,10 +9,10 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Mapping; +namespace Symfony\Component\JsonStreamer\Mapping; /** - * Loads properties encoding/decoding metadata for a given $className. + * Loads properties stream reading/writing metadata for a given $className. * * These metadata can be used by the DataModelBuilder to create * an appropriate ObjectNode. diff --git a/src/Symfony/Component/JsonEncoder/Mapping/Decode/AttributePropertyMetadataLoader.php b/src/Symfony/Component/JsonStreamer/Mapping/Read/AttributePropertyMetadataLoader.php similarity index 69% rename from src/Symfony/Component/JsonEncoder/Mapping/Decode/AttributePropertyMetadataLoader.php rename to src/Symfony/Component/JsonStreamer/Mapping/Read/AttributePropertyMetadataLoader.php index ac6d4c09f8415..f1037b85c4fa5 100644 --- a/src/Symfony/Component/JsonEncoder/Mapping/Decode/AttributePropertyMetadataLoader.php +++ b/src/Symfony/Component/JsonStreamer/Mapping/Read/AttributePropertyMetadataLoader.php @@ -9,19 +9,19 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Mapping\Decode; +namespace Symfony\Component\JsonStreamer\Mapping\Read; use Psr\Container\ContainerInterface; -use Symfony\Component\JsonEncoder\Attribute\EncodedName; -use Symfony\Component\JsonEncoder\Attribute\ValueTransformer; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; -use Symfony\Component\JsonEncoder\Exception\RuntimeException; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoaderInterface; -use Symfony\Component\JsonEncoder\ValueTransformer\ValueTransformerInterface; +use Symfony\Component\JsonStreamer\Attribute\StreamedName; +use Symfony\Component\JsonStreamer\Attribute\ValueTransformer; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\Exception\RuntimeException; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface; use Symfony\Component\TypeInfo\TypeResolver\TypeResolverInterface; /** - * Enhances properties decoding metadata based on properties' attributes. + * Enhances properties stream reading metadata based on properties' attributes. * * @author Mathias Arlaud * @@ -41,7 +41,7 @@ public function load(string $className, array $options = [], array $context = [] $initialResult = $this->decorated->load($className, $options, $context); $result = []; - foreach ($initialResult as $initialEncodedName => $initialMetadata) { + foreach ($initialResult as $initialStreamedName => $initialMetadata) { try { $propertyReflection = new \ReflectionProperty($className, $initialMetadata->getName()); } catch (\ReflectionException $e) { @@ -49,10 +49,10 @@ public function load(string $className, array $options = [], array $context = [] } $attributesMetadata = $this->getPropertyAttributesMetadata($propertyReflection); - $encodedName = $attributesMetadata['name'] ?? $initialEncodedName; + $streamedName = $attributesMetadata['name'] ?? $initialStreamedName; - if (null === $valueTransformer = $attributesMetadata['toNativeValueTransformer'] ?? null) { - $result[$encodedName] = $initialMetadata; + if (null === $valueTransformer = $attributesMetadata['streamToNativeValueTransformer'] ?? null) { + $result[$streamedName] = $initialMetadata; continue; } @@ -60,9 +60,9 @@ public function load(string $className, array $options = [], array $context = [] if (\is_string($valueTransformer)) { $valueTransformerService = $this->getAndValidateValueTransformerService($valueTransformer); - $result[$encodedName] = $initialMetadata - ->withType($valueTransformerService::getJsonValueType()) - ->withAdditionalToNativeValueTransformer($valueTransformer); + $result[$streamedName] = $initialMetadata + ->withType($valueTransformerService::getStreamValueType()) + ->withAdditionalStreamToNativeValueTransformer($valueTransformer); continue; } @@ -74,32 +74,32 @@ public function load(string $className, array $options = [], array $context = [] } if (null === ($parameterReflection = $valueTransformerReflection->getParameters()[0] ?? null)) { - throw new InvalidArgumentException(\sprintf('"%s" property\'s toNativeValue callable has no parameter.', $initialEncodedName)); + throw new InvalidArgumentException(\sprintf('"%s" property\'s streamToNative callable has no parameter.', $initialStreamedName)); } - $result[$encodedName] = $initialMetadata + $result[$streamedName] = $initialMetadata ->withType($this->typeResolver->resolve($parameterReflection)) - ->withAdditionalToNativeValueTransformer($valueTransformer); + ->withAdditionalStreamToNativeValueTransformer($valueTransformer); } return $result; } /** - * @return array{name?: string, toNativeValueTransformer?: string|\Closure} + * @return array{name?: string, streamToNativeValueTransformer?: string|\Closure} */ private function getPropertyAttributesMetadata(\ReflectionProperty $reflectionProperty): array { $metadata = []; - $reflectionAttribute = $reflectionProperty->getAttributes(EncodedName::class, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null; + $reflectionAttribute = $reflectionProperty->getAttributes(StreamedName::class, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null; if (null !== $reflectionAttribute) { $metadata['name'] = $reflectionAttribute->newInstance()->getName(); } $reflectionAttribute = $reflectionProperty->getAttributes(ValueTransformer::class, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null; if (null !== $reflectionAttribute) { - $metadata['toNativeValueTransformer'] = $reflectionAttribute->newInstance()->getToNativeValueTransformer(); + $metadata['streamToNativeValueTransformer'] = $reflectionAttribute->newInstance()->getStreamToNative(); } return $metadata; diff --git a/src/Symfony/Component/JsonEncoder/Mapping/Decode/DateTimeTypePropertyMetadataLoader.php b/src/Symfony/Component/JsonStreamer/Mapping/Read/DateTimeTypePropertyMetadataLoader.php similarity index 76% rename from src/Symfony/Component/JsonEncoder/Mapping/Decode/DateTimeTypePropertyMetadataLoader.php rename to src/Symfony/Component/JsonStreamer/Mapping/Read/DateTimeTypePropertyMetadataLoader.php index b3c2ad878ed6b..11ce2b4f93962 100644 --- a/src/Symfony/Component/JsonEncoder/Mapping/Decode/DateTimeTypePropertyMetadataLoader.php +++ b/src/Symfony/Component/JsonStreamer/Mapping/Read/DateTimeTypePropertyMetadataLoader.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Mapping\Decode; +namespace Symfony\Component\JsonStreamer\Mapping\Read; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoaderInterface; -use Symfony\Component\JsonEncoder\ValueTransformer\StringToDateTimeValueTransformer; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\ValueTransformer\StringToDateTimeValueTransformer; use Symfony\Component\TypeInfo\Type\ObjectType; /** @@ -43,8 +43,8 @@ public function load(string $className, array $options = [], array $context = [] } $metadata = $metadata - ->withType(StringToDateTimeValueTransformer::getJsonValueType()) - ->withAdditionalToNativeValueTransformer('json_encoder.value_transformer.string_to_date_time'); + ->withType(StringToDateTimeValueTransformer::getStreamValueType()) + ->withAdditionalStreamToNativeValueTransformer('json_streamer.value_transformer.string_to_date_time'); } } diff --git a/src/Symfony/Component/JsonEncoder/Mapping/Encode/AttributePropertyMetadataLoader.php b/src/Symfony/Component/JsonStreamer/Mapping/Write/AttributePropertyMetadataLoader.php similarity index 69% rename from src/Symfony/Component/JsonEncoder/Mapping/Encode/AttributePropertyMetadataLoader.php rename to src/Symfony/Component/JsonStreamer/Mapping/Write/AttributePropertyMetadataLoader.php index 96af5f4a42495..a3922033fe403 100644 --- a/src/Symfony/Component/JsonEncoder/Mapping/Encode/AttributePropertyMetadataLoader.php +++ b/src/Symfony/Component/JsonStreamer/Mapping/Write/AttributePropertyMetadataLoader.php @@ -9,19 +9,19 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Mapping\Encode; +namespace Symfony\Component\JsonStreamer\Mapping\Write; use Psr\Container\ContainerInterface; -use Symfony\Component\JsonEncoder\Attribute\EncodedName; -use Symfony\Component\JsonEncoder\Attribute\ValueTransformer; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; -use Symfony\Component\JsonEncoder\Exception\RuntimeException; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoaderInterface; -use Symfony\Component\JsonEncoder\ValueTransformer\ValueTransformerInterface; +use Symfony\Component\JsonStreamer\Attribute\StreamedName; +use Symfony\Component\JsonStreamer\Attribute\ValueTransformer; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\Exception\RuntimeException; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface; use Symfony\Component\TypeInfo\TypeResolver\TypeResolverInterface; /** - * Enhances properties encoding metadata based on properties' attributes. + * Enhances properties stream writing metadata based on properties' attributes. * * @author Mathias Arlaud * @@ -41,7 +41,7 @@ public function load(string $className, array $options = [], array $context = [] $initialResult = $this->decorated->load($className, $options, $context); $result = []; - foreach ($initialResult as $initialEncodedName => $initialMetadata) { + foreach ($initialResult as $initialStreamedName => $initialMetadata) { try { $propertyReflection = new \ReflectionProperty($className, $initialMetadata->getName()); } catch (\ReflectionException $e) { @@ -49,10 +49,10 @@ public function load(string $className, array $options = [], array $context = [] } $attributesMetadata = $this->getPropertyAttributesMetadata($propertyReflection); - $encodedName = $attributesMetadata['name'] ?? $initialEncodedName; + $streamedName = $attributesMetadata['name'] ?? $initialStreamedName; - if (null === $valueTransformer = $attributesMetadata['toJsonValueTransformer'] ?? null) { - $result[$encodedName] = $initialMetadata; + if (null === $valueTransformer = $attributesMetadata['nativeToStreamValueTransformer'] ?? null) { + $result[$streamedName] = $initialMetadata; continue; } @@ -60,9 +60,9 @@ public function load(string $className, array $options = [], array $context = [] if (\is_string($valueTransformer)) { $valueTransformerService = $this->getAndValidateValueTransformerService($valueTransformer); - $result[$encodedName] = $initialMetadata - ->withType($valueTransformerService::getJsonValueType()) - ->withAdditionalToJsonValueTransformer($valueTransformer); + $result[$streamedName] = $initialMetadata + ->withType($valueTransformerService::getStreamValueType()) + ->withAdditionalNativeToStreamValueTransformer($valueTransformer); continue; } @@ -73,29 +73,29 @@ public function load(string $className, array $options = [], array $context = [] throw new RuntimeException($e->getMessage(), $e->getCode(), $e); } - $result[$encodedName] = $initialMetadata + $result[$streamedName] = $initialMetadata ->withType($this->typeResolver->resolve($valueTransformerReflection)) - ->withAdditionalToJsonValueTransformer($valueTransformer); + ->withAdditionalNativeToStreamValueTransformer($valueTransformer); } return $result; } /** - * @return array{name?: string, toJsonValueTransformer?: string|\Closure} + * @return array{name?: string, nativeToStreamValueTransformer?: string|\Closure} */ private function getPropertyAttributesMetadata(\ReflectionProperty $reflectionProperty): array { $metadata = []; - $reflectionAttribute = $reflectionProperty->getAttributes(EncodedName::class, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null; + $reflectionAttribute = $reflectionProperty->getAttributes(StreamedName::class, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null; if (null !== $reflectionAttribute) { $metadata['name'] = $reflectionAttribute->newInstance()->getName(); } $reflectionAttribute = $reflectionProperty->getAttributes(ValueTransformer::class, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null; if (null !== $reflectionAttribute) { - $metadata['toJsonValueTransformer'] = $reflectionAttribute->newInstance()->getToJsonValueTransformer(); + $metadata['nativeToStreamValueTransformer'] = $reflectionAttribute->newInstance()->getNativeToStream(); } return $metadata; diff --git a/src/Symfony/Component/JsonEncoder/Mapping/Encode/DateTimeTypePropertyMetadataLoader.php b/src/Symfony/Component/JsonStreamer/Mapping/Write/DateTimeTypePropertyMetadataLoader.php similarity index 76% rename from src/Symfony/Component/JsonEncoder/Mapping/Encode/DateTimeTypePropertyMetadataLoader.php rename to src/Symfony/Component/JsonStreamer/Mapping/Write/DateTimeTypePropertyMetadataLoader.php index 5edceb6c91545..859dcf7bcecbf 100644 --- a/src/Symfony/Component/JsonEncoder/Mapping/Encode/DateTimeTypePropertyMetadataLoader.php +++ b/src/Symfony/Component/JsonStreamer/Mapping/Write/DateTimeTypePropertyMetadataLoader.php @@ -9,10 +9,10 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Mapping\Encode; +namespace Symfony\Component\JsonStreamer\Mapping\Write; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoaderInterface; -use Symfony\Component\JsonEncoder\ValueTransformer\DateTimeToStringValueTransformer; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\ValueTransformer\DateTimeToStringValueTransformer; use Symfony\Component\TypeInfo\Type\ObjectType; /** @@ -38,8 +38,8 @@ public function load(string $className, array $options = [], array $context = [] if ($type instanceof ObjectType && is_a($type->getClassName(), \DateTimeInterface::class, true)) { $metadata = $metadata - ->withType(DateTimeToStringValueTransformer::getJsonValueType()) - ->withAdditionalToJsonValueTransformer('json_encoder.value_transformer.date_time_to_string'); + ->withType(DateTimeToStringValueTransformer::getStreamValueType()) + ->withAdditionalNativeToStreamValueTransformer('json_streamer.value_transformer.date_time_to_string'); } } diff --git a/src/Symfony/Component/JsonEncoder/README.md b/src/Symfony/Component/JsonStreamer/README.md similarity index 86% rename from src/Symfony/Component/JsonEncoder/README.md rename to src/Symfony/Component/JsonStreamer/README.md index 4b3de3ee0198a..b6628686ed256 100644 --- a/src/Symfony/Component/JsonEncoder/README.md +++ b/src/Symfony/Component/JsonStreamer/README.md @@ -1,7 +1,7 @@ -JsonEncoder component +JsonStreamer component ==================== -Provides powerful methods to encode/decode data structures into/from JSON. +Provides powerful methods to read/write data structures from/into JSON streams. **This Component is experimental**. [Experimental features](https://symfony.com/doc/current/contributing/code/experimental.html) diff --git a/src/Symfony/Component/JsonEncoder/Decode/NativeDecoder.php b/src/Symfony/Component/JsonStreamer/Read/Decoder.php similarity index 66% rename from src/Symfony/Component/JsonEncoder/Decode/NativeDecoder.php rename to src/Symfony/Component/JsonStreamer/Read/Decoder.php index 2898f32070588..16d4fe4dd1253 100644 --- a/src/Symfony/Component/JsonEncoder/Decode/NativeDecoder.php +++ b/src/Symfony/Component/JsonStreamer/Read/Decoder.php @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Decode; +namespace Symfony\Component\JsonStreamer\Read; -use Symfony\Component\JsonEncoder\Exception\UnexpectedValueException; +use Symfony\Component\JsonStreamer\Exception\UnexpectedValueException; /** * Decodes string or stream using the native "json_decode" PHP function. @@ -20,7 +20,7 @@ * * @internal */ -final class NativeDecoder +final class Decoder { public static function decodeString(string $json): mixed { @@ -31,15 +31,11 @@ public static function decodeString(string $json): mixed } } + /** + * @param resource $stream + */ public static function decodeStream($stream, int $offset = 0, ?int $length = null): mixed { - if (\is_resource($stream)) { - $json = stream_get_contents($stream, $length ?? -1, $offset); - } else { - $stream->seek($offset); - $json = $stream->read($length); - } - - return self::decodeString($json); + return self::decodeString(stream_get_contents($stream, $length ?? -1, $offset)); } } diff --git a/src/Symfony/Component/JsonEncoder/Decode/Instantiator.php b/src/Symfony/Component/JsonStreamer/Read/Instantiator.php similarity index 90% rename from src/Symfony/Component/JsonEncoder/Decode/Instantiator.php rename to src/Symfony/Component/JsonStreamer/Read/Instantiator.php index 6b4e986551e96..57506a133f730 100644 --- a/src/Symfony/Component/JsonEncoder/Decode/Instantiator.php +++ b/src/Symfony/Component/JsonStreamer/Read/Instantiator.php @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Decode; +namespace Symfony\Component\JsonStreamer\Read; -use Symfony\Component\JsonEncoder\Exception\UnexpectedValueException; +use Symfony\Component\JsonStreamer\Exception\UnexpectedValueException; /** * Instantiates a new $className eagerly, then sets the given properties. diff --git a/src/Symfony/Component/JsonEncoder/Decode/LazyInstantiator.php b/src/Symfony/Component/JsonStreamer/Read/LazyInstantiator.php similarity index 89% rename from src/Symfony/Component/JsonEncoder/Decode/LazyInstantiator.php rename to src/Symfony/Component/JsonStreamer/Read/LazyInstantiator.php index 285793c75bd4f..a9bd55553ad9d 100644 --- a/src/Symfony/Component/JsonEncoder/Decode/LazyInstantiator.php +++ b/src/Symfony/Component/JsonStreamer/Read/LazyInstantiator.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Decode; +namespace Symfony\Component\JsonStreamer\Read; use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; -use Symfony\Component\JsonEncoder\Exception\RuntimeException; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\Exception\RuntimeException; use Symfony\Component\VarExporter\ProxyHelper; /** @@ -85,7 +85,7 @@ public function instantiate(string $className, callable $initializer): object $this->fs->mkdir($this->lazyGhostsDir); } - file_put_contents($path, \sprintf('fs->dumpFile($path, \sprintf(' 0)) { - $chunk = stream_get_contents($stream, $infiniteLength ? $chunkLength : min($chunkLength, $toReadLength), $offset); + if (false === $chunk = stream_get_contents($stream, $infiniteLength ? $chunkLength : min($chunkLength, $toReadLength), $offset)) { + throw new RuntimeException('Failed to read JSON stream.'); + } + $toReadLength -= $l = \strlen($chunk); $offset += $l; diff --git a/src/Symfony/Component/JsonEncoder/Decode/PhpAstBuilder.php b/src/Symfony/Component/JsonStreamer/Read/PhpAstBuilder.php similarity index 92% rename from src/Symfony/Component/JsonEncoder/Decode/PhpAstBuilder.php rename to src/Symfony/Component/JsonStreamer/Read/PhpAstBuilder.php index fcc738efa4bcf..0189c7987d81e 100644 --- a/src/Symfony/Component/JsonEncoder/Decode/PhpAstBuilder.php +++ b/src/Symfony/Component/JsonStreamer/Read/PhpAstBuilder.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Decode; +namespace Symfony\Component\JsonStreamer\Read; use PhpParser\BuilderFactory; use PhpParser\Node; @@ -41,23 +41,24 @@ use PhpParser\Node\Stmt\If_; use PhpParser\Node\Stmt\Return_; use Psr\Container\ContainerInterface; -use Symfony\Component\JsonEncoder\DataModel\Decode\BackedEnumNode; -use Symfony\Component\JsonEncoder\DataModel\Decode\CollectionNode; -use Symfony\Component\JsonEncoder\DataModel\Decode\CompositeNode; -use Symfony\Component\JsonEncoder\DataModel\Decode\DataModelNodeInterface; -use Symfony\Component\JsonEncoder\DataModel\Decode\ObjectNode; -use Symfony\Component\JsonEncoder\DataModel\Decode\ScalarNode; -use Symfony\Component\JsonEncoder\DataModel\PhpExprDataAccessor; -use Symfony\Component\JsonEncoder\Exception\LogicException; -use Symfony\Component\JsonEncoder\Exception\UnexpectedValueException; +use Symfony\Component\JsonStreamer\DataModel\PhpExprDataAccessor; +use Symfony\Component\JsonStreamer\DataModel\Read\BackedEnumNode; +use Symfony\Component\JsonStreamer\DataModel\Read\CollectionNode; +use Symfony\Component\JsonStreamer\DataModel\Read\CompositeNode; +use Symfony\Component\JsonStreamer\DataModel\Read\DataModelNodeInterface; +use Symfony\Component\JsonStreamer\DataModel\Read\ObjectNode; +use Symfony\Component\JsonStreamer\DataModel\Read\ScalarNode; +use Symfony\Component\JsonStreamer\Exception\LogicException; +use Symfony\Component\JsonStreamer\Exception\UnexpectedValueException; use Symfony\Component\TypeInfo\Type\BackedEnumType; +use Symfony\Component\TypeInfo\Type\BuiltinType; use Symfony\Component\TypeInfo\Type\CollectionType; use Symfony\Component\TypeInfo\Type\ObjectType; use Symfony\Component\TypeInfo\Type\WrappingTypeInterface; use Symfony\Component\TypeInfo\TypeIdentifier; /** - * Builds a PHP syntax tree that decodes JSON. + * Builds a PHP syntax tree that reads JSON stream. * * @author Mathias Arlaud * @@ -94,7 +95,7 @@ public function build(DataModelNodeInterface $dataModel, bool $decodeFromStream, ...$this->buildProvidersStatements($dataModel, $decodeFromStream, $context), new Return_( $this->nodeOnlyNeedsDecode($dataModel, $decodeFromStream) - ? $this->builder->staticCall(new FullyQualified(NativeDecoder::class), 'decodeStream', [ + ? $this->builder->staticCall(new FullyQualified(Decoder::class), 'decodeStream', [ $this->builder->var('stream'), $this->builder->val(0), $this->builder->val(null), @@ -122,9 +123,9 @@ public function build(DataModelNodeInterface $dataModel, bool $decodeFromStream, ...$this->buildProvidersStatements($dataModel, $decodeFromStream, $context), new Return_( $this->nodeOnlyNeedsDecode($dataModel, $decodeFromStream) - ? $this->builder->staticCall(new FullyQualified(NativeDecoder::class), 'decodeString', [new StringCast($this->builder->var('string'))]) + ? $this->builder->staticCall(new FullyQualified(Decoder::class), 'decodeString', [new StringCast($this->builder->var('string'))]) : $this->builder->funcCall(new ArrayDimFetch($this->builder->var('providers'), $this->builder->val($dataModel->getIdentifier())), [ - $this->builder->staticCall(new FullyQualified(NativeDecoder::class), 'decodeString', [new StringCast($this->builder->var('string'))]), + $this->builder->staticCall(new FullyQualified(Decoder::class), 'decodeString', [new StringCast($this->builder->var('string'))]), ]), ), ], @@ -153,7 +154,7 @@ private function buildProvidersStatements(DataModelNodeInterface $node, bool $de $node instanceof CompositeNode => $this->buildCompositeNodeStatements($node, $decodeFromStream, $context), $node instanceof CollectionNode => $this->buildCollectionNodeStatements($node, $decodeFromStream, $context), $node instanceof ObjectNode => $this->buildObjectNodeStatements($node, $decodeFromStream, $context), - default => throw new LogicException(\sprintf('Unexpected "%s" data model node', $node::class)), + default => throw new LogicException(\sprintf('Unexpected "%s" data model node.', $node::class)), }; } @@ -163,7 +164,7 @@ private function buildProvidersStatements(DataModelNodeInterface $node, bool $de private function buildLeafProviderStatements(ScalarNode|BackedEnumNode $node, bool $decodeFromStream): array { $accessor = $decodeFromStream - ? $this->builder->staticCall(new FullyQualified(NativeDecoder::class), 'decodeStream', [ + ? $this->builder->staticCall(new FullyQualified(Decoder::class), 'decodeStream', [ $this->builder->var('stream'), $this->builder->var('offset'), $this->builder->var('length'), @@ -188,13 +189,17 @@ private function buildLeafProviderStatements(ScalarNode|BackedEnumNode $node, bo private function buildFormatValueStatement(DataModelNodeInterface $node, Expr $accessor): Node { - $type = $node->getType(); - if ($node instanceof BackedEnumNode) { + /** @var ObjectType $type */ + $type = $node->getType(); + return $this->builder->staticCall(new FullyQualified($type->getClassName()), 'from', [$accessor]); } if ($node instanceof ScalarNode) { + /** @var BuiltinType $type */ + $type = $node->getType(); + return match (true) { TypeIdentifier::NULL === $type->getTypeIdentifier() => $this->builder->val(null), TypeIdentifier::OBJECT === $type->getTypeIdentifier() => new ObjectCast($accessor), @@ -213,7 +218,7 @@ private function buildFormatValueStatement(DataModelNodeInterface $node, Expr $a private function buildCompositeNodeStatements(CompositeNode $node, bool $decodeFromStream, array &$context): array { $prepareDataStmts = $decodeFromStream ? [ - new Expression(new Assign($this->builder->var('data'), $this->builder->staticCall(new FullyQualified(NativeDecoder::class), 'decodeStream', [ + new Expression(new Assign($this->builder->var('data'), $this->builder->staticCall(new FullyQualified(Decoder::class), 'decodeStream', [ $this->builder->var('stream'), $this->builder->var('offset'), $this->builder->var('length'), @@ -260,7 +265,11 @@ private function buildCompositeNodeStatements(CompositeNode $node, bool $decodeF return $this->builder->funcCall('\is_array', [$this->builder->var('data')]); } - return $this->builder->funcCall('\is_'.$type->getTypeIdentifier()->value, [$this->builder->var('data')]); + if ($type instanceof BuiltinType) { + return $this->builder->funcCall('\is_'.$type->getTypeIdentifier()->value, [$this->builder->var('data')]); + } + + throw new LogicException(\sprintf('Unexpected "%s" type.', $type::class)); }; foreach ($node->getNodes() as $n) { @@ -318,7 +327,7 @@ private function buildCollectionNodeStatements(CollectionNode $node, bool $decod $itemValueStmt = $this->nodeOnlyNeedsDecode($node->getItemNode(), $decodeFromStream) ? $this->buildFormatValueStatement( $node->getItemNode(), - $this->builder->staticCall(new FullyQualified(NativeDecoder::class), 'decodeStream', [ + $this->builder->staticCall(new FullyQualified(Decoder::class), 'decodeStream', [ $this->builder->var('stream'), new ArrayDimFetch($this->builder->var('v'), $this->builder->val(0)), new ArrayDimFetch($this->builder->var('v'), $this->builder->val(1)), @@ -420,7 +429,7 @@ private function buildObjectNodeStatements(ObjectNode $node, bool $decodeFromStr $stringPropertiesValuesStmts = []; $streamPropertiesValuesStmts = []; - foreach ($node->getProperties() as $encodedName => $property) { + foreach ($node->getProperties() as $streamedName => $property) { $propertyValueProvidersStmts = [ ...$propertyValueProvidersStmts, ...($this->nodeOnlyNeedsDecode($property['value'], $decodeFromStream) ? [] : $this->buildProvidersStatements($property['value'], $decodeFromStream, $context)), @@ -430,7 +439,7 @@ private function buildObjectNodeStatements(ObjectNode $node, bool $decodeFromStr $propertyValueStmt = $this->nodeOnlyNeedsDecode($property['value'], $decodeFromStream) ? $this->buildFormatValueStatement( $property['value'], - $this->builder->staticCall(new FullyQualified(NativeDecoder::class), 'decodeStream', [ + $this->builder->staticCall(new FullyQualified(Decoder::class), 'decodeStream', [ $this->builder->var('stream'), new ArrayDimFetch($this->builder->var('v'), $this->builder->val(0)), new ArrayDimFetch($this->builder->var('v'), $this->builder->val(1)), @@ -444,18 +453,18 @@ private function buildObjectNodeStatements(ObjectNode $node, bool $decodeFromStr ], ); - $streamPropertiesValuesStmts[] = new MatchArm([$this->builder->val($encodedName)], new Assign( + $streamPropertiesValuesStmts[] = new MatchArm([$this->builder->val($streamedName)], new Assign( $this->builder->propertyFetch($this->builder->var('object'), $property['name']), $property['accessor'](new PhpExprDataAccessor($propertyValueStmt))->toPhpExpr(), )); } else { $propertyValueStmt = $this->nodeOnlyNeedsDecode($property['value'], $decodeFromStream) - ? new Coalesce(new ArrayDimFetch($this->builder->var('data'), $this->builder->val($encodedName)), $this->builder->val('_symfony_missing_value')) + ? new Coalesce(new ArrayDimFetch($this->builder->var('data'), $this->builder->val($streamedName)), $this->builder->val('_symfony_missing_value')) : new Ternary( - $this->builder->funcCall('\array_key_exists', [$this->builder->val($encodedName), $this->builder->var('data')]), + $this->builder->funcCall('\array_key_exists', [$this->builder->val($streamedName), $this->builder->var('data')]), $this->builder->funcCall( new ArrayDimFetch($this->builder->var('providers'), $this->builder->val($property['value']->getIdentifier())), - [new ArrayDimFetch($this->builder->var('data'), $this->builder->val($encodedName))], + [new ArrayDimFetch($this->builder->var('data'), $this->builder->val($streamedName))], ), $this->builder->val('_symfony_missing_value'), ); diff --git a/src/Symfony/Component/JsonEncoder/Decode/Splitter.php b/src/Symfony/Component/JsonStreamer/Read/Splitter.php similarity index 97% rename from src/Symfony/Component/JsonEncoder/Decode/Splitter.php rename to src/Symfony/Component/JsonStreamer/Read/Splitter.php index 186d58241eb2f..0230fd98f7859 100644 --- a/src/Symfony/Component/JsonEncoder/Decode/Splitter.php +++ b/src/Symfony/Component/JsonStreamer/Read/Splitter.php @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Decode; +namespace Symfony\Component\JsonStreamer\Read; -use Symfony\Component\JsonEncoder\Exception\UnexpectedValueException; +use Symfony\Component\JsonStreamer\Exception\UnexpectedValueException; /** * Splits collections to retrieve the offset and length of each element. diff --git a/src/Symfony/Component/JsonEncoder/Decode/DecoderGenerator.php b/src/Symfony/Component/JsonStreamer/Read/StreamReaderGenerator.php similarity index 76% rename from src/Symfony/Component/JsonEncoder/Decode/DecoderGenerator.php rename to src/Symfony/Component/JsonStreamer/Read/StreamReaderGenerator.php index 3d58ceaf2a1ea..77f34ffef142b 100644 --- a/src/Symfony/Component/JsonEncoder/Decode/DecoderGenerator.php +++ b/src/Symfony/Component/JsonStreamer/Read/StreamReaderGenerator.php @@ -9,26 +9,26 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Decode; +namespace Symfony\Component\JsonStreamer\Read; use PhpParser\PhpVersion; use PhpParser\PrettyPrinter; use PhpParser\PrettyPrinter\Standard; use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\JsonEncoder\DataModel\DataAccessorInterface; -use Symfony\Component\JsonEncoder\DataModel\Decode\BackedEnumNode; -use Symfony\Component\JsonEncoder\DataModel\Decode\CollectionNode; -use Symfony\Component\JsonEncoder\DataModel\Decode\CompositeNode; -use Symfony\Component\JsonEncoder\DataModel\Decode\DataModelNodeInterface; -use Symfony\Component\JsonEncoder\DataModel\Decode\ObjectNode; -use Symfony\Component\JsonEncoder\DataModel\Decode\ScalarNode; -use Symfony\Component\JsonEncoder\DataModel\FunctionDataAccessor; -use Symfony\Component\JsonEncoder\DataModel\ScalarDataAccessor; -use Symfony\Component\JsonEncoder\DataModel\VariableDataAccessor; -use Symfony\Component\JsonEncoder\Exception\RuntimeException; -use Symfony\Component\JsonEncoder\Exception\UnsupportedException; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\DataModel\DataAccessorInterface; +use Symfony\Component\JsonStreamer\DataModel\FunctionDataAccessor; +use Symfony\Component\JsonStreamer\DataModel\Read\BackedEnumNode; +use Symfony\Component\JsonStreamer\DataModel\Read\CollectionNode; +use Symfony\Component\JsonStreamer\DataModel\Read\CompositeNode; +use Symfony\Component\JsonStreamer\DataModel\Read\DataModelNodeInterface; +use Symfony\Component\JsonStreamer\DataModel\Read\ObjectNode; +use Symfony\Component\JsonStreamer\DataModel\Read\ScalarNode; +use Symfony\Component\JsonStreamer\DataModel\ScalarDataAccessor; +use Symfony\Component\JsonStreamer\DataModel\VariableDataAccessor; +use Symfony\Component\JsonStreamer\Exception\RuntimeException; +use Symfony\Component\JsonStreamer\Exception\UnsupportedException; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\Type\BackedEnumType; use Symfony\Component\TypeInfo\Type\BuiltinType; @@ -38,13 +38,13 @@ use Symfony\Component\TypeInfo\Type\UnionType; /** - * Generates and writes decoders PHP files. + * Generates and writes stream readers PHP files. * * @author Mathias Arlaud * * @internal */ -final class DecoderGenerator +final class StreamReaderGenerator { private ?PhpAstBuilder $phpAstBuilder = null; private ?PrettyPrinter $phpPrinter = null; @@ -52,12 +52,12 @@ final class DecoderGenerator public function __construct( private PropertyMetadataLoaderInterface $propertyMetadataLoader, - private string $decodersDir, + private string $streamReadersDir, ) { } /** - * Generates and writes a decoder PHP file and return its path. + * Generates and writes a stream reader PHP file and return its path. * * @param array $options */ @@ -76,8 +76,8 @@ public function generate(Type $type, bool $decodeFromStream, array $options = [] $nodes = $this->phpAstBuilder->build($dataModel, $decodeFromStream, $options); $content = $this->phpPrinter->prettyPrintFile($nodes)."\n"; - if (!$this->fs->exists($this->decodersDir)) { - $this->fs->mkdir($this->decodersDir); + if (!$this->fs->exists($this->streamReadersDir)) { + $this->fs->mkdir($this->streamReadersDir); } $tmpFile = $this->fs->tempnam(\dirname($path), basename($path)); @@ -87,7 +87,7 @@ public function generate(Type $type, bool $decodeFromStream, array $options = [] $this->fs->rename($tmpFile, $path); $this->fs->chmod($path, 0666 & ~umask()); } catch (IOException $e) { - throw new RuntimeException(\sprintf('Failed to write "%s" decoder file.', $path), previous: $e); + throw new RuntimeException(\sprintf('Failed to write "%s" stream reader file.', $path), previous: $e); } return $path; @@ -95,7 +95,7 @@ public function generate(Type $type, bool $decodeFromStream, array $options = [] private function getPath(Type $type, bool $decodeFromStream): string { - return \sprintf('%s%s%s.json%s.php', $this->decodersDir, \DIRECTORY_SEPARATOR, hash('xxh128', (string) $type), $decodeFromStream ? '.stream' : ''); + return \sprintf('%s%s%s.json%s.php', $this->streamReadersDir, \DIRECTORY_SEPARATOR, hash('xxh128', (string) $type), $decodeFromStream ? '.stream' : ''); } /** @@ -131,12 +131,12 @@ public function createDataModel(Type $type, array $options = [], array $context $propertiesMetadata = $this->propertyMetadataLoader->load($className, $options, $context); - foreach ($propertiesMetadata as $encodedName => $propertyMetadata) { - $propertiesNodes[$encodedName] = [ + foreach ($propertiesMetadata as $streamedName => $propertyMetadata) { + $propertiesNodes[$streamedName] = [ 'name' => $propertyMetadata->getName(), 'value' => $this->createDataModel($propertyMetadata->getType(), $options, $context), 'accessor' => function (DataAccessorInterface $accessor) use ($propertyMetadata): DataAccessorInterface { - foreach ($propertyMetadata->getToNativeValueTransformers() as $valueTransformer) { + foreach ($propertyMetadata->getStreamToNativeValueTransformers() as $valueTransformer) { if (\is_string($valueTransformer)) { $valueTransformerServiceAccessor = new FunctionDataAccessor('get', [new ScalarDataAccessor($valueTransformer)], new VariableDataAccessor('valueTransformers')); $accessor = new FunctionDataAccessor('transform', [$accessor, new VariableDataAccessor('options')], $valueTransformerServiceAccessor); diff --git a/src/Symfony/Component/JsonEncoder/DecoderInterface.php b/src/Symfony/Component/JsonStreamer/StreamReaderInterface.php similarity index 69% rename from src/Symfony/Component/JsonEncoder/DecoderInterface.php rename to src/Symfony/Component/JsonStreamer/StreamReaderInterface.php index 6639e5e638ecc..de39236b7f6bd 100644 --- a/src/Symfony/Component/JsonEncoder/DecoderInterface.php +++ b/src/Symfony/Component/JsonStreamer/StreamReaderInterface.php @@ -9,12 +9,12 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder; +namespace Symfony\Component\JsonStreamer; use Symfony\Component\TypeInfo\Type; /** - * Decodes an $input into a given $type according to $options. + * Reads an $input and convert it to given $type according to $options. * * @author Mathias Arlaud * @@ -22,11 +22,11 @@ * * @template T of array */ -interface DecoderInterface +interface StreamReaderInterface { /** * @param resource|string $input * @param T $options */ - public function decode($input, Type $type, array $options = []): mixed; + public function read($input, Type $type, array $options = []): mixed; } diff --git a/src/Symfony/Component/JsonEncoder/EncoderInterface.php b/src/Symfony/Component/JsonStreamer/StreamWriterInterface.php similarity index 61% rename from src/Symfony/Component/JsonEncoder/EncoderInterface.php rename to src/Symfony/Component/JsonStreamer/StreamWriterInterface.php index ae6f4d200b8db..99181360b79ee 100644 --- a/src/Symfony/Component/JsonEncoder/EncoderInterface.php +++ b/src/Symfony/Component/JsonStreamer/StreamWriterInterface.php @@ -9,12 +9,12 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder; +namespace Symfony\Component\JsonStreamer; use Symfony\Component\TypeInfo\Type; /** - * Encodes $data into a specific format according to $options. + * Writes $data into a specific format according to $options. * * @author Mathias Arlaud * @@ -22,12 +22,12 @@ * * @template T of array */ -interface EncoderInterface +interface StreamWriterInterface { /** * @param T $options * - * @return \Traversable&\Stringable + * @return \Traversable&\Stringable */ - public function encode(mixed $data, Type $type, array $options = []): \Traversable&\Stringable; + public function write(mixed $data, Type $type, array $options = []): \Traversable&\Stringable; } diff --git a/src/Symfony/Component/JsonEncoder/Tests/Attribute/ValueTransformerTest.php b/src/Symfony/Component/JsonStreamer/Tests/Attribute/ValueTransformerTest.php similarity index 68% rename from src/Symfony/Component/JsonEncoder/Tests/Attribute/ValueTransformerTest.php rename to src/Symfony/Component/JsonStreamer/Tests/Attribute/ValueTransformerTest.php index f3b30e48a5609..193e3301a0f88 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Attribute/ValueTransformerTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Attribute/ValueTransformerTest.php @@ -9,18 +9,18 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\Attribute; +namespace Symfony\Component\JsonStreamer\Tests\Attribute; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Attribute\ValueTransformer; -use Symfony\Component\JsonEncoder\Exception\LogicException; +use Symfony\Component\JsonStreamer\Attribute\ValueTransformer; +use Symfony\Component\JsonStreamer\Exception\LogicException; class ValueTransformerTest extends TestCase { public function testCannotCreateWithoutAnything() { $this->expectException(LogicException::class); - $this->expectExceptionMessage('#[ValueTransformer] attribute must declare either $toNativeValue or $toJsonValue.'); + $this->expectExceptionMessage('#[ValueTransformer] attribute must declare either $streamToNative or $nativeToStream.'); new ValueTransformer(); } diff --git a/src/Symfony/Component/JsonEncoder/Tests/CacheWarmer/LazyGhostCacheWarmerTest.php b/src/Symfony/Component/JsonStreamer/Tests/CacheWarmer/LazyGhostCacheWarmerTest.php similarity index 75% rename from src/Symfony/Component/JsonEncoder/Tests/CacheWarmer/LazyGhostCacheWarmerTest.php rename to src/Symfony/Component/JsonStreamer/Tests/CacheWarmer/LazyGhostCacheWarmerTest.php index f4544f3762671..86f2f9d4964f7 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/CacheWarmer/LazyGhostCacheWarmerTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/CacheWarmer/LazyGhostCacheWarmerTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\CacheWarmer; +namespace Symfony\Component\JsonStreamer\Tests\CacheWarmer; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\CacheWarmer\LazyGhostCacheWarmer; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy; +use Symfony\Component\JsonStreamer\CacheWarmer\LazyGhostCacheWarmer; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy; class LazyGhostCacheWarmerTest extends TestCase { @@ -23,7 +23,7 @@ protected function setUp(): void { parent::setUp(); - $this->lazyGhostsDir = \sprintf('%s/symfony_json_encoder_test/json_encoder/lazy_ghost', sys_get_temp_dir()); + $this->lazyGhostsDir = \sprintf('%s/symfony_json_streamer_test/lazy_ghost', sys_get_temp_dir()); if (is_dir($this->lazyGhostsDir)) { array_map('unlink', glob($this->lazyGhostsDir.'/*')); diff --git a/src/Symfony/Component/JsonStreamer/Tests/CacheWarmer/StreamerCacheWarmerTest.php b/src/Symfony/Component/JsonStreamer/Tests/CacheWarmer/StreamerCacheWarmerTest.php new file mode 100644 index 0000000000000..8eb5a84893218 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/CacheWarmer/StreamerCacheWarmerTest.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonStreamer\Tests\CacheWarmer; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\JsonStreamer\CacheWarmer\StreamerCacheWarmer; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes; +use Symfony\Component\TypeInfo\TypeResolver\TypeResolver; + +class StreamerCacheWarmerTest extends TestCase +{ + private string $streamWritersDir; + private string $streamReadersDir; + + protected function setUp(): void + { + parent::setUp(); + + $this->streamWritersDir = \sprintf('%s/symfony_json_streamer_test/stream_writer', sys_get_temp_dir()); + $this->streamReadersDir = \sprintf('%s/symfony_json_streamer_test/stream_reader', sys_get_temp_dir()); + + if (is_dir($this->streamWritersDir)) { + array_map('unlink', glob($this->streamWritersDir.'/*')); + rmdir($this->streamWritersDir); + } + + if (is_dir($this->streamReadersDir)) { + array_map('unlink', glob($this->streamReadersDir.'/*')); + rmdir($this->streamReadersDir); + } + } + + public function testWarmUp() + { + $this->cacheWarmer([ + ClassicDummy::class => ['object' => true, 'list' => true], + DummyWithNameAttributes::class => ['object' => true, 'list' => false], + ])->warmUp('useless'); + + $this->assertSame([ + \sprintf('%s/13791ba3dc4369dc488ec78466326979.json.php', $this->streamWritersDir), + \sprintf('%s/3d6bea319060b50305c349746ac6cabc.json.php', $this->streamWritersDir), + \sprintf('%s/6f7c0ed338bb3b8730cc67686a91941b.json.php', $this->streamWritersDir), + ], glob($this->streamWritersDir.'/*')); + + $this->assertSame([ + \sprintf('%s/13791ba3dc4369dc488ec78466326979.json.php', $this->streamReadersDir), + \sprintf('%s/13791ba3dc4369dc488ec78466326979.json.stream.php', $this->streamReadersDir), + \sprintf('%s/3d6bea319060b50305c349746ac6cabc.json.php', $this->streamReadersDir), + \sprintf('%s/3d6bea319060b50305c349746ac6cabc.json.stream.php', $this->streamReadersDir), + \sprintf('%s/6f7c0ed338bb3b8730cc67686a91941b.json.php', $this->streamReadersDir), + \sprintf('%s/6f7c0ed338bb3b8730cc67686a91941b.json.stream.php', $this->streamReadersDir), + ], glob($this->streamReadersDir.'/*')); + } + + /** + * @param array $streamable + */ + private function cacheWarmer(array $streamable = []): StreamerCacheWarmer + { + $typeResolver = TypeResolver::create(); + + return new StreamerCacheWarmer( + $streamable, + new PropertyMetadataLoader($typeResolver), + new PropertyMetadataLoader($typeResolver), + $this->streamWritersDir, + $this->streamReadersDir, + ); + } +} diff --git a/src/Symfony/Component/JsonEncoder/Tests/DataModel/Decode/CompositeNodeTest.php b/src/Symfony/Component/JsonStreamer/Tests/DataModel/Read/CompositeNodeTest.php similarity index 79% rename from src/Symfony/Component/JsonEncoder/Tests/DataModel/Decode/CompositeNodeTest.php rename to src/Symfony/Component/JsonStreamer/Tests/DataModel/Read/CompositeNodeTest.php index 6a6899aa7e147..8385448c44e0b 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/DataModel/Decode/CompositeNodeTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/DataModel/Read/CompositeNodeTest.php @@ -9,14 +9,14 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\DataModel\Decode; +namespace Symfony\Component\JsonStreamer\Tests\DataModel\Read; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\DataModel\Decode\CollectionNode; -use Symfony\Component\JsonEncoder\DataModel\Decode\CompositeNode; -use Symfony\Component\JsonEncoder\DataModel\Decode\ObjectNode; -use Symfony\Component\JsonEncoder\DataModel\Decode\ScalarNode; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\DataModel\Read\CollectionNode; +use Symfony\Component\JsonStreamer\DataModel\Read\CompositeNode; +use Symfony\Component\JsonStreamer\DataModel\Read\ObjectNode; +use Symfony\Component\JsonStreamer\DataModel\Read\ScalarNode; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; use Symfony\Component\TypeInfo\Type; class CompositeNodeTest extends TestCase diff --git a/src/Symfony/Component/JsonEncoder/Tests/DataModel/Encode/CompositeNodeTest.php b/src/Symfony/Component/JsonStreamer/Tests/DataModel/Write/CompositeNodeTest.php similarity index 81% rename from src/Symfony/Component/JsonEncoder/Tests/DataModel/Encode/CompositeNodeTest.php rename to src/Symfony/Component/JsonStreamer/Tests/DataModel/Write/CompositeNodeTest.php index e8c19e215b7f7..9fb197d23c7f7 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/DataModel/Encode/CompositeNodeTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/DataModel/Write/CompositeNodeTest.php @@ -9,15 +9,15 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\DataModel\Encode; +namespace Symfony\Component\JsonStreamer\Tests\DataModel\Write; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\DataModel\Encode\CollectionNode; -use Symfony\Component\JsonEncoder\DataModel\Encode\CompositeNode; -use Symfony\Component\JsonEncoder\DataModel\Encode\ObjectNode; -use Symfony\Component\JsonEncoder\DataModel\Encode\ScalarNode; -use Symfony\Component\JsonEncoder\DataModel\VariableDataAccessor; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\DataModel\VariableDataAccessor; +use Symfony\Component\JsonStreamer\DataModel\Write\CollectionNode; +use Symfony\Component\JsonStreamer\DataModel\Write\CompositeNode; +use Symfony\Component\JsonStreamer\DataModel\Write\ObjectNode; +use Symfony\Component\JsonStreamer\DataModel\Write\ScalarNode; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; use Symfony\Component\TypeInfo\Type; class CompositeNodeTest extends TestCase diff --git a/src/Symfony/Component/JsonStreamer/Tests/DependencyInjection/StreamablePassTest.php b/src/Symfony/Component/JsonStreamer/Tests/DependencyInjection/StreamablePassTest.php new file mode 100644 index 0000000000000..f58bc9ce81998 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/DependencyInjection/StreamablePassTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonStreamer\Tests\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\JsonStreamer\DependencyInjection\StreamablePass; + +class StreamablePassTest extends TestCase +{ + public function testSetStreamable() + { + $container = new ContainerBuilder(); + + $container->register('json_streamer.stream_writer'); + $container->register('.json_streamer.cache_warmer.streamer')->setArguments([null]); + $container->register('.json_streamer.cache_warmer.lazy_ghost')->setArguments([null]); + + $container->register('streamable')->setClass('Foo')->addTag('json_streamer.streamable', ['object' => true, 'list' => true]); + $container->register('abstractStreamable')->setClass('Bar')->addTag('json_streamer.streamable', ['object' => true, 'list' => true])->setAbstract(true); + $container->register('notStreamable')->setClass('Baz'); + + $pass = new StreamablePass(); + $pass->process($container); + + $streamerCacheWarmer = $container->getDefinition('.json_streamer.cache_warmer.streamer'); + $lazyGhostCacheWarmer = $container->getDefinition('.json_streamer.cache_warmer.lazy_ghost'); + + $this->assertSame(['Foo' => ['object' => true, 'list' => true]], $streamerCacheWarmer->getArgument(0)); + $this->assertSame(['Foo'], $lazyGhostCacheWarmer->getArgument(0)); + } +} diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/Attribute/BooleanStringValueTransformer.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/Attribute/BooleanStringValueTransformer.php new file mode 100644 index 0000000000000..983a6dd95bd2e --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/Attribute/BooleanStringValueTransformer.php @@ -0,0 +1,19 @@ + (int) $v, explode('..', $range)); + } +} diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/Model/SelfReferencingDummy.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/Model/SelfReferencingDummy.php new file mode 100644 index 0000000000000..d25a7b533ae1a --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/Model/SelfReferencingDummy.php @@ -0,0 +1,11 @@ +'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitDict($stream, $offset, $length); + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitDict($stream, $offset, $length); $iterable = static function ($stream, $data) use ($options, $valueTransformers, $instantiator, &$providers) { foreach ($data as $k => $v) { - yield $k => \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); + yield $k => \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]); } }; return \iterator_to_array($iterable($stream, $data)); diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/iterable.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/iterable.php new file mode 100644 index 0000000000000..a6fedcbd99ba0 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/iterable.php @@ -0,0 +1,5 @@ + $v) { - yield $k => \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); + yield $k => \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]); } }; return $iterable($stream, $data); diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/list.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/list.php new file mode 100644 index 0000000000000..a6fedcbd99ba0 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/list.php @@ -0,0 +1,5 @@ +'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { - $data = \Symfony\Component\JsonEncoder\Decode\Splitter::splitList($stream, $offset, $length); + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitList($stream, $offset, $length); $iterable = static function ($stream, $data) use ($options, $valueTransformers, $instantiator, &$providers) { foreach ($data as $k => $v) { - yield $k => \Symfony\Component\JsonEncoder\Decode\NativeDecoder::decodeStream($stream, $v[0], $v[1]); + yield $k => \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]); } }; return \iterator_to_array($iterable($stream, $data)); diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/mixed.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/mixed.php new file mode 100644 index 0000000000000..a6fedcbd99ba0 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/mixed.php @@ -0,0 +1,5 @@ +instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { + return '_symfony_missing_value' !== $v; + })); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy|null'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + if (\is_array($data)) { + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($data); + } + if (null === $data) { + return null; + } + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy|null".', \get_debug_type($data))); + }; + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy|null'](\Symfony\Component\JsonStreamer\Read\Decoder::decodeString((string) $string)); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object.stream.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object.stream.php new file mode 100644 index 0000000000000..b6af2cc29630a --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object.stream.php @@ -0,0 +1,27 @@ +instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy|null'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $offset, $length); + if (\is_array($data)) { + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($data); + } + if (null === $data) { + return null; + } + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy|null".', \get_debug_type($data))); + }; + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy|null']($stream, 0, null); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object_dict.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object_dict.php new file mode 100644 index 0000000000000..34a2b8c0dacd6 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object_dict.php @@ -0,0 +1,27 @@ +'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + $iterable = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + yield $k => $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($v); + } + }; + return \iterator_to_array($iterable($data)); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { + return '_symfony_missing_value' !== $v; + })); + }; + $providers['array|null'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + if (\is_array($data)) { + return $providers['array']($data); + } + if (null === $data) { + return null; + } + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "array|null".', \get_debug_type($data))); + }; + return $providers['array|null'](\Symfony\Component\JsonStreamer\Read\Decoder::decodeString((string) $string)); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object_dict.stream.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object_dict.stream.php new file mode 100644 index 0000000000000..fe3be40f02c7e --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object_dict.stream.php @@ -0,0 +1,36 @@ +'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitDict($stream, $offset, $length); + $iterable = static function ($stream, $data) use ($options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + yield $k => $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($stream, $v[0], $v[1]); + } + }; + return \iterator_to_array($iterable($stream, $data)); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitDict($stream, $offset, $length); + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); + }; + $providers['array|null'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $offset, $length); + if (\is_array($data)) { + return $providers['array']($data); + } + if (null === $data) { + return null; + } + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "array|null".', \get_debug_type($data))); + }; + return $providers['array|null']($stream, 0, null); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object_list.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object_list.php new file mode 100644 index 0000000000000..031d3dc609fac --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object_list.php @@ -0,0 +1,27 @@ +'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + $iterable = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + yield $k => $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($v); + } + }; + return \iterator_to_array($iterable($data)); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { + return '_symfony_missing_value' !== $v; + })); + }; + $providers['array|null'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + if (\is_array($data) && \array_is_list($data)) { + return $providers['array']($data); + } + if (null === $data) { + return null; + } + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "array|null".', \get_debug_type($data))); + }; + return $providers['array|null'](\Symfony\Component\JsonStreamer\Read\Decoder::decodeString((string) $string)); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object_list.stream.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object_list.stream.php new file mode 100644 index 0000000000000..558e1eac1c4e1 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/nullable_object_list.stream.php @@ -0,0 +1,36 @@ +'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitList($stream, $offset, $length); + $iterable = static function ($stream, $data) use ($options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + yield $k => $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($stream, $v[0], $v[1]); + } + }; + return \iterator_to_array($iterable($stream, $data)); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitDict($stream, $offset, $length); + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); + }; + $providers['array|null'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $offset, $length); + if (\is_array($data) && \array_is_list($data)) { + return $providers['array']($data); + } + if (null === $data) { + return null; + } + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "array|null".', \get_debug_type($data))); + }; + return $providers['array|null']($stream, 0, null); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object.php new file mode 100644 index 0000000000000..4bfffaea57b8c --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object.php @@ -0,0 +1,10 @@ +instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { + return '_symfony_missing_value' !== $v; + })); + }; + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy'](\Symfony\Component\JsonStreamer\Read\Decoder::decodeString((string) $string)); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object.stream.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object.stream.php new file mode 100644 index 0000000000000..97489cf36f414 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object.stream.php @@ -0,0 +1,17 @@ +instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); + }; + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($stream, 0, null); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_dict.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_dict.php new file mode 100644 index 0000000000000..150493376b014 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_dict.php @@ -0,0 +1,18 @@ +'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + $iterable = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + yield $k => $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($v); + } + }; + return \iterator_to_array($iterable($data)); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { + return '_symfony_missing_value' !== $v; + })); + }; + return $providers['array'](\Symfony\Component\JsonStreamer\Read\Decoder::decodeString((string) $string)); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_dict.stream.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_dict.stream.php new file mode 100644 index 0000000000000..0baba407dc54b --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_dict.stream.php @@ -0,0 +1,26 @@ +'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitDict($stream, $offset, $length); + $iterable = static function ($stream, $data) use ($options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + yield $k => $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($stream, $v[0], $v[1]); + } + }; + return \iterator_to_array($iterable($stream, $data)); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitDict($stream, $offset, $length); + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); + }; + return $providers['array']($stream, 0, null); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_in_object.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_in_object.php new file mode 100644 index 0000000000000..bbba349a3ca93 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_in_object.php @@ -0,0 +1,20 @@ +instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithOtherDummies::class, \array_filter(['name' => $data['name'] ?? '_symfony_missing_value', 'otherDummyOne' => \array_key_exists('otherDummyOne', $data) ? $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes']($data['otherDummyOne']) : '_symfony_missing_value', 'otherDummyTwo' => \array_key_exists('otherDummyTwo', $data) ? $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($data['otherDummyTwo']) : '_symfony_missing_value'], static function ($v) { + return '_symfony_missing_value' !== $v; + })); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes::class, \array_filter(['id' => $data['@id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { + return '_symfony_missing_value' !== $v; + })); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { + return '_symfony_missing_value' !== $v; + })); + }; + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithOtherDummies'](\Symfony\Component\JsonStreamer\Read\Decoder::decodeString((string) $string)); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_in_object.stream.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_in_object.stream.php new file mode 100644 index 0000000000000..df1596179e8e1 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_in_object.stream.php @@ -0,0 +1,42 @@ +instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithOtherDummies::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'name' => $object->name = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + 'otherDummyOne' => $object->otherDummyOne = $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes']($stream, $v[0], $v[1]), + 'otherDummyTwo' => $object->otherDummyTwo = $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($stream, $v[0], $v[1]), + default => null, + }; + } + }); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitDict($stream, $offset, $length); + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + '@id' => $object->id = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitDict($stream, $offset, $length); + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); + }; + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithOtherDummies']($stream, 0, null); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_iterable.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_iterable.php new file mode 100644 index 0000000000000..f10533f03a84f --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_iterable.php @@ -0,0 +1,18 @@ +'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + $iterable = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + yield $k => $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($v); + } + }; + return $iterable($data); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { + return '_symfony_missing_value' !== $v; + })); + }; + return $providers['iterable'](\Symfony\Component\JsonStreamer\Read\Decoder::decodeString((string) $string)); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_iterable.stream.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_iterable.stream.php new file mode 100644 index 0000000000000..144749d14959b --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_iterable.stream.php @@ -0,0 +1,26 @@ +'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitDict($stream, $offset, $length); + $iterable = static function ($stream, $data) use ($options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + yield $k => $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($stream, $v[0], $v[1]); + } + }; + return $iterable($stream, $data); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitDict($stream, $offset, $length); + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); + }; + return $providers['iterable']($stream, 0, null); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_list.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_list.php new file mode 100644 index 0000000000000..a243d0c95a76f --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_list.php @@ -0,0 +1,18 @@ +'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + $iterable = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + yield $k => $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($v); + } + }; + return \iterator_to_array($iterable($data)); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, \array_filter(['id' => $data['id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { + return '_symfony_missing_value' !== $v; + })); + }; + return $providers['array'](\Symfony\Component\JsonStreamer\Read\Decoder::decodeString((string) $string)); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_list.stream.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_list.stream.php new file mode 100644 index 0000000000000..14bb63a2a1dfc --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_list.stream.php @@ -0,0 +1,26 @@ +'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitList($stream, $offset, $length); + $iterable = static function ($stream, $data) use ($options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + yield $k => $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy']($stream, $v[0], $v[1]); + } + }; + return \iterator_to_array($iterable($stream, $data)); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitDict($stream, $offset, $length); + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); + }; + return $providers['array']($stream, 0, null); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_nullable_properties.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_nullable_properties.php new file mode 100644 index 0000000000000..647a3aeb923bb --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_nullable_properties.php @@ -0,0 +1,22 @@ +instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNullableProperties::class, \array_filter(['name' => $data['name'] ?? '_symfony_missing_value', 'enum' => \array_key_exists('enum', $data) ? $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum|null']($data['enum']) : '_symfony_missing_value'], static function ($v) { + return '_symfony_missing_value' !== $v; + })); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum'] = static function ($data) { + return \Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum::from($data); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum|null'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + if (\is_int($data)) { + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum']($data); + } + if (null === $data) { + return null; + } + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum|null".', \get_debug_type($data))); + }; + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNullableProperties'](\Symfony\Component\JsonStreamer\Read\Decoder::decodeString((string) $string)); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_nullable_properties.stream.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_nullable_properties.stream.php new file mode 100644 index 0000000000000..9266447cd53f3 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_nullable_properties.stream.php @@ -0,0 +1,30 @@ +instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNullableProperties::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'name' => $object->name = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + 'enum' => $object->enum = $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum|null']($stream, $v[0], $v[1]), + default => null, + }; + } + }); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum'] = static function ($stream, $offset, $length) { + return \Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum::from(\Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $offset, $length)); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum|null'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $offset, $length); + if (\is_int($data)) { + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum']($data); + } + if (null === $data) { + return null; + } + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum|null".', \get_debug_type($data))); + }; + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNullableProperties']($stream, 0, null); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_union.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_union.php new file mode 100644 index 0000000000000..971f20a4489cb --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_union.php @@ -0,0 +1,25 @@ +instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithUnionProperties::class, \array_filter(['value' => \array_key_exists('value', $data) ? $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum|null|string']($data['value']) : '_symfony_missing_value'], static function ($v) { + return '_symfony_missing_value' !== $v; + })); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum'] = static function ($data) { + return \Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum::from($data); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum|null|string'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + if (\is_int($data)) { + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum']($data); + } + if (null === $data) { + return null; + } + if (\is_string($data)) { + return $data; + } + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum|null|string".', \get_debug_type($data))); + }; + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithUnionProperties'](\Symfony\Component\JsonStreamer\Read\Decoder::decodeString((string) $string)); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_union.stream.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_union.stream.php new file mode 100644 index 0000000000000..ef7dc5791c666 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_union.stream.php @@ -0,0 +1,32 @@ +instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithUnionProperties::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'value' => $object->value = $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum|null|string']($stream, $v[0], $v[1]), + default => null, + }; + } + }); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum'] = static function ($stream, $offset, $length) { + return \Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum::from(\Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $offset, $length)); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum|null|string'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $offset, $length); + if (\is_int($data)) { + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum']($data); + } + if (null === $data) { + return null; + } + if (\is_string($data)) { + return $data; + } + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum|null|string".', \get_debug_type($data))); + }; + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithUnionProperties']($stream, 0, null); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_value_transformer.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_value_transformer.php new file mode 100644 index 0000000000000..6f9257e4d93f4 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_value_transformer.php @@ -0,0 +1,10 @@ +instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueTransformerAttributes::class, \array_filter(['id' => $valueTransformers->get('Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\DivideStringAndCastToIntValueTransformer')->transform($data['id'] ?? '_symfony_missing_value', $options), 'active' => $valueTransformers->get('Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\StringToBooleanValueTransformer')->transform($data['active'] ?? '_symfony_missing_value', $options), 'name' => strtoupper($data['name'] ?? '_symfony_missing_value'), 'range' => Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueTransformerAttributes::explodeRange($data['range'] ?? '_symfony_missing_value', $options)], static function ($v) { + return '_symfony_missing_value' !== $v; + })); + }; + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueTransformerAttributes'](\Symfony\Component\JsonStreamer\Read\Decoder::decodeString((string) $string)); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_value_transformer.stream.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_value_transformer.stream.php new file mode 100644 index 0000000000000..a6898aeb9bf6e --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/object_with_value_transformer.stream.php @@ -0,0 +1,19 @@ +instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueTransformerAttributes::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + 'id' => $object->id = $valueTransformers->get('Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\DivideStringAndCastToIntValueTransformer')->transform(\Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), $options), + 'active' => $object->active = $valueTransformers->get('Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\StringToBooleanValueTransformer')->transform(\Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), $options), + 'name' => $object->name = strtoupper(\Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1])), + 'range' => $object->range = Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueTransformerAttributes::explodeRange(\Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), $options), + default => null, + }; + } + }); + }; + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueTransformerAttributes']($stream, 0, null); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/scalar.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/scalar.php new file mode 100644 index 0000000000000..a6fedcbd99ba0 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/scalar.php @@ -0,0 +1,5 @@ +'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + $iterable = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + yield $k => $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum']($v); + } + }; + return \iterator_to_array($iterable($data)); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum'] = static function ($data) { + return \Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum::from($data); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes::class, \array_filter(['id' => $data['@id'] ?? '_symfony_missing_value', 'name' => $data['name'] ?? '_symfony_missing_value'], static function ($v) { + return '_symfony_missing_value' !== $v; + })); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes|array|int'] = static function ($data) use ($options, $valueTransformers, $instantiator, &$providers) { + if (\is_array($data) && \array_is_list($data)) { + return $providers['array']($data); + } + if (\is_array($data)) { + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes']($data); + } + if (\is_int($data)) { + return $data; + } + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes|array|int".', \get_debug_type($data))); + }; + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes|array|int'](\Symfony\Component\JsonStreamer\Read\Decoder::decodeString((string) $string)); +}; diff --git a/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/union.stream.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/union.stream.php new file mode 100644 index 0000000000000..db8d2cffb283e --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_reader/union.stream.php @@ -0,0 +1,42 @@ +'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitList($stream, $offset, $length); + $iterable = static function ($stream, $data) use ($options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + yield $k => $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum']($stream, $v[0], $v[1]); + } + }; + return \iterator_to_array($iterable($stream, $data)); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum'] = static function ($stream, $offset, $length) { + return \Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum::from(\Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $offset, $length)); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Splitter::splitDict($stream, $offset, $length); + return $instantiator->instantiate(\Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes::class, static function ($object) use ($stream, $data, $options, $valueTransformers, $instantiator, &$providers) { + foreach ($data as $k => $v) { + match ($k) { + '@id' => $object->id = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + 'name' => $object->name = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $v[0], $v[1]), + default => null, + }; + } + }); + }; + $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes|array|int'] = static function ($stream, $offset, $length) use ($options, $valueTransformers, $instantiator, &$providers) { + $data = \Symfony\Component\JsonStreamer\Read\Decoder::decodeStream($stream, $offset, $length); + if (\is_array($data) && \array_is_list($data)) { + return $providers['array']($data); + } + if (\is_array($data)) { + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes']($data); + } + if (\is_int($data)) { + return $data; + } + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value for "Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes|array|int".', \get_debug_type($data))); + }; + return $providers['Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes|array|int']($stream, 0, null); +}; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/backed_enum.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/backed_enum.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/backed_enum.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/backed_enum.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/bool.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/bool.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/bool.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/bool.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/bool_list.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/bool_list.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/bool_list.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/bool_list.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/dict.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/dict.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/dict.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/dict.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/iterable.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/iterable.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/iterable.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/iterable.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/list.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/list.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/list.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/list.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/mixed.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/mixed.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/mixed.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/mixed.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/null.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/null.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/null.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/null.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/null_list.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/null_list.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/null_list.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/null_list.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/nullable_backed_enum.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/nullable_backed_enum.php similarity index 50% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/nullable_backed_enum.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/nullable_backed_enum.php index 7302d3afaea90..5959bb1eb2f6c 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/nullable_backed_enum.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/nullable_backed_enum.php @@ -1,11 +1,11 @@ value); } elseif (null === $data) { yield 'null'; } else { - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value.', \get_debug_type($data))); + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value.', \get_debug_type($data))); } }; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/nullable_object.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/nullable_object.php similarity index 58% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/nullable_object.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/nullable_object.php index f42e35601c5fa..ee372d7282657 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/nullable_object.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/nullable_object.php @@ -1,7 +1,7 @@ id); yield ',"name":'; @@ -10,6 +10,6 @@ } elseif (null === $data) { yield 'null'; } else { - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value.', \get_debug_type($data))); + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value.', \get_debug_type($data))); } }; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/nullable_object_dict.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/nullable_object_dict.php similarity index 81% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/nullable_object_dict.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/nullable_object_dict.php index a62d9b76f6bf6..dfebf6436bef0 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/nullable_object_dict.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/nullable_object_dict.php @@ -18,6 +18,6 @@ } elseif (null === $data) { yield 'null'; } else { - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value.', \get_debug_type($data))); + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value.', \get_debug_type($data))); } }; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/nullable_object_list.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/nullable_object_list.php similarity index 79% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/nullable_object_list.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/nullable_object_list.php index fcb5aa9932658..c36e3a6c318be 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/nullable_object_list.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/nullable_object_list.php @@ -17,6 +17,6 @@ } elseif (null === $data) { yield 'null'; } else { - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value.', \get_debug_type($data))); + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value.', \get_debug_type($data))); } }; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object_dict.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_dict.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object_dict.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_dict.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object_in_object.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_in_object.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object_in_object.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_in_object.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object_iterable.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_iterable.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object_iterable.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_iterable.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object_list.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_list.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object_list.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_list.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object_with_union.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_with_union.php similarity index 60% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object_with_union.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_with_union.php index b3bce12cf189f..1b47d6246f525 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object_with_union.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_with_union.php @@ -2,14 +2,14 @@ return static function (mixed $data, \Psr\Container\ContainerInterface $valueTransformers, array $options): \Traversable { yield '{"value":'; - if ($data->value instanceof \Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum) { + if ($data->value instanceof \Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum) { yield \json_encode($data->value->value); } elseif (null === $data->value) { yield 'null'; } elseif (\is_string($data->value)) { yield \json_encode($data->value); } else { - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value.', \get_debug_type($data->value))); + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value.', \get_debug_type($data->value))); } yield '}'; }; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object_with_value_transformer.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_with_value_transformer.php similarity index 51% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object_with_value_transformer.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_with_value_transformer.php index 3a9d5d182bc33..ecb3490600103 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/object_with_value_transformer.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_with_value_transformer.php @@ -2,12 +2,12 @@ return static function (mixed $data, \Psr\Container\ContainerInterface $valueTransformers, array $options): \Traversable { yield '{"id":'; - yield \json_encode($valueTransformers->get('Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\DoubleIntAndCastToStringValueTransformer')->transform($data->id, $options)); + yield \json_encode($valueTransformers->get('Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\DoubleIntAndCastToStringValueTransformer')->transform($data->id, $options)); yield ',"active":'; - yield \json_encode($valueTransformers->get('Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\BooleanToStringValueTransformer')->transform($data->active, $options)); + yield \json_encode($valueTransformers->get('Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\BooleanToStringValueTransformer')->transform($data->active, $options)); yield ',"name":'; yield \json_encode(strtolower($data->name)); yield ',"range":'; - yield \json_encode(Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithValueTransformerAttributes::concatRange($data->range, $options)); + yield \json_encode(Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueTransformerAttributes::concatRange($data->range, $options)); yield '}'; }; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/scalar.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/scalar.php similarity index 100% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/scalar.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/scalar.php diff --git a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/union.php b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/union.php similarity index 70% rename from src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/union.php rename to src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/union.php index dc56e3034e94b..c0a882935ecbc 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Fixtures/encoder/union.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/union.php @@ -10,7 +10,7 @@ $prefix = ','; } yield ']'; - } elseif ($data instanceof \Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes) { + } elseif ($data instanceof \Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes) { yield '{"@id":'; yield \json_encode($data->id); yield ',"name":'; @@ -19,6 +19,6 @@ } elseif (\is_int($data)) { yield \json_encode($data); } else { - throw new \Symfony\Component\JsonEncoder\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value.', \get_debug_type($data))); + throw new \Symfony\Component\JsonStreamer\Exception\UnexpectedValueException(\sprintf('Unexpected "%s" value.', \get_debug_type($data))); } }; diff --git a/src/Symfony/Component/JsonStreamer/Tests/JsonStreamReaderTest.php b/src/Symfony/Component/JsonStreamer/Tests/JsonStreamReaderTest.php new file mode 100644 index 0000000000000..f93dd8ba13ce4 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/JsonStreamReaderTest.php @@ -0,0 +1,204 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonStreamer\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\JsonStreamer\JsonStreamReader; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithDateTimes; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNullableProperties; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithPhpDoc; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueTransformerAttributes; +use Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\DivideStringAndCastToIntValueTransformer; +use Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\StringToBooleanValueTransformer; +use Symfony\Component\TypeInfo\Type; +use Symfony\Component\TypeInfo\TypeIdentifier; + +class JsonStreamReaderTest extends TestCase +{ + private string $streamReadersDir; + private string $lazyGhostsDir; + + protected function setUp(): void + { + parent::setUp(); + + $this->streamReadersDir = \sprintf('%s/symfony_json_streamer_test/stream_reader', sys_get_temp_dir()); + $this->lazyGhostsDir = \sprintf('%s/symfony_json_streamer_test/lazy_ghost', sys_get_temp_dir()); + + if (is_dir($this->streamReadersDir)) { + array_map('unlink', glob($this->streamReadersDir.'/*')); + rmdir($this->streamReadersDir); + } + + if (is_dir($this->lazyGhostsDir)) { + array_map('unlink', glob($this->lazyGhostsDir.'/*')); + rmdir($this->lazyGhostsDir); + } + } + + public function testReadScalar() + { + $reader = JsonStreamReader::create(streamReadersDir: $this->streamReadersDir, lazyGhostsDir: $this->lazyGhostsDir); + + $this->assertRead($reader, null, 'null', Type::nullable(Type::int())); + $this->assertRead($reader, true, 'true', Type::bool()); + $this->assertRead($reader, [['foo' => 1, 'bar' => 2], ['foo' => 3]], '[{"foo": 1, "bar": 2}, {"foo": 3}]', Type::builtin(TypeIdentifier::ARRAY)); + $this->assertRead($reader, [['foo' => 1, 'bar' => 2], ['foo' => 3]], '[{"foo": 1, "bar": 2}, {"foo": 3}]', Type::builtin(TypeIdentifier::ITERABLE)); + $this->assertRead($reader, (object) ['foo' => 'bar'], '{"foo": "bar"}', Type::object()); + $this->assertRead($reader, DummyBackedEnum::ONE, '1', Type::enum(DummyBackedEnum::class, Type::string())); + } + + public function testReadCollection() + { + $reader = JsonStreamReader::create(streamReadersDir: $this->streamReadersDir, lazyGhostsDir: $this->lazyGhostsDir); + + $this->assertRead( + $reader, + [true, false], + '{"0": true, "1": false}', + Type::array(Type::bool()), + ); + + $this->assertRead( + $reader, + [true, false], + '[true, false]', + Type::list(Type::bool()), + ); + + $this->assertRead($reader, function (mixed $read) { + $this->assertIsIterable($read); + $this->assertSame([true, false], iterator_to_array($read)); + }, '{"0": true, "1": false}', Type::iterable(Type::bool())); + + $this->assertRead($reader, function (mixed $read) { + $this->assertIsIterable($read); + $this->assertSame([true, false], iterator_to_array($read)); + }, '{"0": true, "1": false}', Type::iterable(Type::bool(), Type::int())); + } + + public function testReadObject() + { + $reader = JsonStreamReader::create(streamReadersDir: $this->streamReadersDir, lazyGhostsDir: $this->lazyGhostsDir); + + $this->assertRead($reader, function (mixed $read) { + $this->assertInstanceOf(ClassicDummy::class, $read); + $this->assertSame(10, $read->id); + $this->assertSame('dummy name', $read->name); + }, '{"id": 10, "name": "dummy name"}', Type::object(ClassicDummy::class)); + } + + public function testReadObjectWithStreamedName() + { + $reader = JsonStreamReader::create(streamReadersDir: $this->streamReadersDir, lazyGhostsDir: $this->lazyGhostsDir); + + $this->assertRead($reader, function (mixed $read) { + $this->assertInstanceOf(DummyWithNameAttributes::class, $read); + $this->assertSame(10, $read->id); + }, '{"@id": 10}', Type::object(DummyWithNameAttributes::class)); + } + + public function testReadObjectWithValueTransformer() + { + $reader = JsonStreamReader::create( + valueTransformers: [ + StringToBooleanValueTransformer::class => new StringToBooleanValueTransformer(), + DivideStringAndCastToIntValueTransformer::class => new DivideStringAndCastToIntValueTransformer(), + ], + streamReadersDir: $this->streamReadersDir, + lazyGhostsDir: $this->lazyGhostsDir, + ); + + $this->assertRead($reader, function (mixed $read) { + $this->assertInstanceOf(DummyWithValueTransformerAttributes::class, $read); + $this->assertSame(10, $read->id); + $this->assertTrue($read->active); + $this->assertSame('LOWERCASE NAME', $read->name); + $this->assertSame([0, 1], $read->range); + }, '{"id": "20", "active": "true", "name": "lowercase name", "range": "0..1"}', Type::object(DummyWithValueTransformerAttributes::class), ['scale' => 1]); + } + + public function testReadObjectWithPhpDoc() + { + $reader = JsonStreamReader::create(streamReadersDir: $this->streamReadersDir, lazyGhostsDir: $this->lazyGhostsDir); + + $this->assertRead($reader, function (mixed $read) { + $this->assertInstanceOf(DummyWithPhpDoc::class, $read); + $this->assertIsArray($read->arrayOfDummies); + $this->assertContainsOnlyInstancesOf(DummyWithNameAttributes::class, $read->arrayOfDummies); + $this->assertArrayHasKey('key', $read->arrayOfDummies); + }, '{"arrayOfDummies":{"key":{"@id":10,"name":"dummy"}}}', Type::object(DummyWithPhpDoc::class)); + } + + public function testReadObjectWithNullableProperties() + { + $reader = JsonStreamReader::create(streamReadersDir: $this->streamReadersDir, lazyGhostsDir: $this->lazyGhostsDir); + + $this->assertRead($reader, function (mixed $read) { + $this->assertInstanceOf(DummyWithNullableProperties::class, $read); + $this->assertNull($read->name); + $this->assertNull($read->enum); + }, '{"name":null,"enum":null}', Type::object(DummyWithNullableProperties::class)); + } + + public function testReadObjectWithDateTimes() + { + $reader = JsonStreamReader::create(streamReadersDir: $this->streamReadersDir, lazyGhostsDir: $this->lazyGhostsDir); + + $this->assertRead($reader, function (mixed $read) { + $this->assertInstanceOf(DummyWithDateTimes::class, $read); + $this->assertEquals(new \DateTimeImmutable('2024-11-20'), $read->interface); + $this->assertEquals(new \DateTimeImmutable('2025-11-20'), $read->immutable); + }, '{"interface":"2024-11-20","immutable":"2025-11-20"}', Type::object(DummyWithDateTimes::class)); + } + + public function testCreateStreamReaderFile() + { + $reader = JsonStreamReader::create(streamReadersDir: $this->streamReadersDir, lazyGhostsDir: $this->lazyGhostsDir); + + $reader->read('true', Type::bool()); + + $this->assertFileExists($this->streamReadersDir); + $this->assertCount(1, glob($this->streamReadersDir.'/*')); + } + + public function testCreateStreamReaderFileOnlyIfNotExists() + { + $reader = JsonStreamReader::create(streamReadersDir: $this->streamReadersDir, lazyGhostsDir: $this->lazyGhostsDir); + + if (!file_exists($this->streamReadersDir)) { + mkdir($this->streamReadersDir, recursive: true); + } + + file_put_contents( + \sprintf('%s%s%s.json.php', $this->streamReadersDir, \DIRECTORY_SEPARATOR, hash('xxh128', (string) Type::bool())), + 'assertSame('CACHED', $reader->read('true', Type::bool())); + } + + private function assertRead(JsonStreamReader $reader, mixed $readOrAssert, string $json, Type $type, array $options = []): void + { + $assert = \is_callable($readOrAssert, syntax_only: true) ? $readOrAssert : fn (mixed $read) => $this->assertEquals($readOrAssert, $read); + + $assert($reader->read($json, $type, $options)); + + $resource = fopen('php://temp', 'w'); + fwrite($resource, $json); + rewind($resource); + $assert($reader->read($resource, $type, $options)); + } +} diff --git a/src/Symfony/Component/JsonStreamer/Tests/JsonStreamWriterTest.php b/src/Symfony/Component/JsonStreamer/Tests/JsonStreamWriterTest.php new file mode 100644 index 0000000000000..b37820e5da215 --- /dev/null +++ b/src/Symfony/Component/JsonStreamer/Tests/JsonStreamWriterTest.php @@ -0,0 +1,229 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonStreamer\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\JsonStreamer\Exception\MaxDepthException; +use Symfony\Component\JsonStreamer\JsonStreamWriter; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithDateTimes; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNullableProperties; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithPhpDoc; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithUnionProperties; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueTransformerAttributes; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\SelfReferencingDummy; +use Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\BooleanToStringValueTransformer; +use Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\DoubleIntAndCastToStringValueTransformer; +use Symfony\Component\JsonStreamer\ValueTransformer\DateTimeToStringValueTransformer; +use Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface; +use Symfony\Component\TypeInfo\Type; + +class JsonStreamWriterTest extends TestCase +{ + private string $streamWritersDir; + + protected function setUp(): void + { + parent::setUp(); + + $this->streamWritersDir = \sprintf('%s/symfony_json_streamer_test/stream_writer', sys_get_temp_dir()); + + if (is_dir($this->streamWritersDir)) { + array_map('unlink', glob($this->streamWritersDir.'/*')); + rmdir($this->streamWritersDir); + } + } + + public function testReturnTraversableAndStringable() + { + $writer = JsonStreamWriter::create(streamWritersDir: $this->streamWritersDir); + + $this->assertSame(['true'], iterator_to_array($writer->write(true, Type::bool()))); + $this->assertSame('true', (string) $writer->write(true, Type::bool())); + } + + public function testWriteScalar() + { + $this->assertWritten('null', null, Type::null()); + $this->assertWritten('true', true, Type::bool()); + $this->assertWritten('[{"foo":1,"bar":2},{"foo":3}]', [['foo' => 1, 'bar' => 2], ['foo' => 3]], Type::list()); + $this->assertWritten('{"foo":"bar"}', (object) ['foo' => 'bar'], Type::object()); + $this->assertWritten('1', DummyBackedEnum::ONE, Type::enum(DummyBackedEnum::class)); + } + + public function testWriteUnion() + { + $this->assertWritten( + '[1,true,["foo","bar"]]', + [DummyBackedEnum::ONE, true, ['foo', 'bar']], + Type::list(Type::union(Type::enum(DummyBackedEnum::class), Type::bool(), Type::list(Type::string()))), + ); + + $dummy = new DummyWithUnionProperties(); + $dummy->value = DummyBackedEnum::ONE; + $this->assertWritten('{"value":1}', $dummy, Type::object(DummyWithUnionProperties::class)); + + $dummy->value = 'foo'; + $this->assertWritten('{"value":"foo"}', $dummy, Type::object(DummyWithUnionProperties::class)); + + $dummy->value = null; + $this->assertWritten('{"value":null}', $dummy, Type::object(DummyWithUnionProperties::class)); + } + + public function testWriteCollection() + { + $this->assertWritten( + '{"0":{"id":1,"name":"dummy"},"1":{"id":1,"name":"dummy"}}', + [new ClassicDummy(), new ClassicDummy()], + Type::array(Type::object(ClassicDummy::class)), + ); + + $this->assertWritten( + '[{"id":1,"name":"dummy"},{"id":1,"name":"dummy"}]', + [new ClassicDummy(), new ClassicDummy()], + Type::list(Type::object(ClassicDummy::class)), + ); + + $this->assertWritten( + '{"0":{"id":1,"name":"dummy"},"1":{"id":1,"name":"dummy"}}', + new \ArrayObject([new ClassicDummy(), new ClassicDummy()]), + Type::iterable(Type::object(ClassicDummy::class)), + ); + + $this->assertWritten( + '{"0":{"id":1,"name":"dummy"},"1":{"id":1,"name":"dummy"}}', + new \ArrayObject([new ClassicDummy(), new ClassicDummy()]), + Type::iterable(Type::object(ClassicDummy::class), Type::int()), + ); + } + + public function testWriteObject() + { + $dummy = new ClassicDummy(); + $dummy->id = 10; + $dummy->name = 'dummy name'; + + $this->assertWritten('{"id":10,"name":"dummy name"}', $dummy, Type::object(ClassicDummy::class)); + } + + public function testWriteObjectWithStreamedName() + { + $dummy = new DummyWithNameAttributes(); + $dummy->id = 10; + $dummy->name = 'dummy name'; + + $this->assertWritten('{"@id":10,"name":"dummy name"}', $dummy, Type::object(DummyWithNameAttributes::class)); + } + + public function testWriteObjectWithValueTransformer() + { + $dummy = new DummyWithValueTransformerAttributes(); + $dummy->id = 10; + $dummy->active = true; + + $this->assertWritten( + '{"id":"20","active":"true","name":"dummy","range":"10..20"}', + $dummy, + Type::object(DummyWithValueTransformerAttributes::class), + options: ['scale' => 1], + valueTransformers: [ + BooleanToStringValueTransformer::class => new BooleanToStringValueTransformer(), + DoubleIntAndCastToStringValueTransformer::class => new DoubleIntAndCastToStringValueTransformer(), + ], + ); + } + + public function testWriteObjectWithPhpDoc() + { + $dummy = new DummyWithPhpDoc(); + $dummy->arrayOfDummies = ['key' => new DummyWithNameAttributes()]; + + $this->assertWritten('{"arrayOfDummies":{"key":{"@id":1,"name":"dummy"}},"array":[]}', $dummy, Type::object(DummyWithPhpDoc::class)); + } + + public function testWriteObjectWithNullableProperties() + { + $dummy = new DummyWithNullableProperties(); + + $this->assertWritten('{"name":null,"enum":null}', $dummy, Type::object(DummyWithNullableProperties::class)); + } + + public function testWriteObjectWithDateTimes() + { + $dummy = new DummyWithDateTimes(); + $dummy->interface = new \DateTimeImmutable('2024-11-20'); + $dummy->immutable = new \DateTimeImmutable('2025-11-20'); + + $this->assertWritten( + '{"interface":"2024-11-20","immutable":"2025-11-20"}', + $dummy, + Type::object(DummyWithDateTimes::class), + options: [DateTimeToStringValueTransformer::FORMAT_KEY => 'Y-m-d'], + ); + } + + public function testThrowWhenMaxDepthIsReached() + { + $writer = JsonStreamWriter::create(streamWritersDir: $this->streamWritersDir); + + $dummy = new SelfReferencingDummy(); + for ($i = 0; $i < 512; ++$i) { + $tmp = new SelfReferencingDummy(); + $tmp->self = $dummy; + + $dummy = $tmp; + } + + $this->expectException(MaxDepthException::class); + $this->expectExceptionMessage('Max depth of 512 has been reached.'); + + (string) $writer->write($dummy, Type::object(SelfReferencingDummy::class)); + } + + public function testCreateStreamWriterFile() + { + $writer = JsonStreamWriter::create(streamWritersDir: $this->streamWritersDir); + + $writer->write(true, Type::bool()); + + $this->assertFileExists($this->streamWritersDir); + $this->assertCount(1, glob($this->streamWritersDir.'/*')); + } + + public function testCreateStreamWriterFileOnlyIfNotExists() + { + $writer = JsonStreamWriter::create(streamWritersDir: $this->streamWritersDir); + + if (!file_exists($this->streamWritersDir)) { + mkdir($this->streamWritersDir, recursive: true); + } + + file_put_contents( + \sprintf('%s%s%s.json.php', $this->streamWritersDir, \DIRECTORY_SEPARATOR, hash('xxh128', (string) Type::bool())), + 'assertSame('CACHED', (string) $writer->write(true, Type::bool())); + } + + /** + * @param array $options + * @param array $valueTransformers + */ + private function assertWritten(string $json, mixed $data, Type $type, array $options = [], array $valueTransformers = []): void + { + $writer = JsonStreamWriter::create(streamWritersDir: $this->streamWritersDir, valueTransformers: $valueTransformers); + $this->assertSame($json, (string) $writer->write($data, $type, $options)); + } +} diff --git a/src/Symfony/Component/JsonEncoder/Tests/Mapping/GenericTypePropertyMetadataLoaderTest.php b/src/Symfony/Component/JsonStreamer/Tests/Mapping/GenericTypePropertyMetadataLoaderTest.php similarity index 88% rename from src/Symfony/Component/JsonEncoder/Tests/Mapping/GenericTypePropertyMetadataLoaderTest.php rename to src/Symfony/Component/JsonStreamer/Tests/Mapping/GenericTypePropertyMetadataLoaderTest.php index 2bab9f1b04d57..1591ef0d4e1ec 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Mapping/GenericTypePropertyMetadataLoaderTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Mapping/GenericTypePropertyMetadataLoaderTest.php @@ -9,13 +9,13 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\Mapping; +namespace Symfony\Component\JsonStreamer\Tests\Mapping; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Mapping\GenericTypePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadata; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoaderInterface; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithGenerics; +use Symfony\Component\JsonStreamer\Mapping\GenericTypePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadata; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithGenerics; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\TypeContext\TypeContextFactory; use Symfony\Component\TypeInfo\TypeResolver\StringTypeResolver; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Mapping/PropertyMetadataLoaderTest.php b/src/Symfony/Component/JsonStreamer/Tests/Mapping/PropertyMetadataLoaderTest.php similarity index 74% rename from src/Symfony/Component/JsonEncoder/Tests/Mapping/PropertyMetadataLoaderTest.php rename to src/Symfony/Component/JsonStreamer/Tests/Mapping/PropertyMetadataLoaderTest.php index 00c8294ae701f..6d04ec7b8bc6c 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Mapping/PropertyMetadataLoaderTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Mapping/PropertyMetadataLoaderTest.php @@ -9,12 +9,12 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\Mapping; +namespace Symfony\Component\JsonStreamer\Tests\Mapping; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadata; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadata; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\TypeResolver\TypeResolver; diff --git a/src/Symfony/Component/JsonEncoder/Tests/Mapping/Decode/AttributePropertyMetadataLoaderTest.php b/src/Symfony/Component/JsonStreamer/Tests/Mapping/Read/AttributePropertyMetadataLoaderTest.php similarity index 77% rename from src/Symfony/Component/JsonEncoder/Tests/Mapping/Decode/AttributePropertyMetadataLoaderTest.php rename to src/Symfony/Component/JsonStreamer/Tests/Mapping/Read/AttributePropertyMetadataLoaderTest.php index 59affb8ea6709..b388f8cefde18 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Mapping/Decode/AttributePropertyMetadataLoaderTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Mapping/Read/AttributePropertyMetadataLoaderTest.php @@ -9,25 +9,25 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\Mapping\Decode; +namespace Symfony\Component\JsonStreamer\Tests\Mapping\Read; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; -use Symfony\Component\JsonEncoder\Mapping\Decode\AttributePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadata; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithValueTransformerAttributes; -use Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\DivideStringAndCastToIntValueTransformer; -use Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\StringToBooleanValueTransformer; -use Symfony\Component\JsonEncoder\Tests\ServiceContainer; -use Symfony\Component\JsonEncoder\ValueTransformer\ValueTransformerInterface; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadata; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\Read\AttributePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueTransformerAttributes; +use Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\DivideStringAndCastToIntValueTransformer; +use Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\StringToBooleanValueTransformer; +use Symfony\Component\JsonStreamer\Tests\ServiceContainer; +use Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\TypeResolver\TypeResolver; class AttributePropertyMetadataLoaderTest extends TestCase { - public function testRetrieveEncodedName() + public function testRetrieveStreamedName() { $loader = new AttributePropertyMetadataLoader(new PropertyMetadataLoader(TypeResolver::create()), new ServiceContainer(), TypeResolver::create()); diff --git a/src/Symfony/Component/JsonEncoder/Tests/Mapping/Decode/DateTimeTypePropertyMetadataLoaderTest.php b/src/Symfony/Component/JsonStreamer/Tests/Mapping/Read/DateTimeTypePropertyMetadataLoaderTest.php similarity index 81% rename from src/Symfony/Component/JsonEncoder/Tests/Mapping/Decode/DateTimeTypePropertyMetadataLoaderTest.php rename to src/Symfony/Component/JsonStreamer/Tests/Mapping/Read/DateTimeTypePropertyMetadataLoaderTest.php index fd94c1a73979c..c71189815be29 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Mapping/Decode/DateTimeTypePropertyMetadataLoaderTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Mapping/Read/DateTimeTypePropertyMetadataLoaderTest.php @@ -9,13 +9,13 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\Mapping\Decode; +namespace Symfony\Component\JsonStreamer\Tests\Mapping\Read; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; -use Symfony\Component\JsonEncoder\Mapping\Decode\DateTimeTypePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadata; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadata; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\Mapping\Read\DateTimeTypePropertyMetadataLoader; use Symfony\Component\TypeInfo\Type; class DateTimeTypePropertyMetadataLoaderTest extends TestCase @@ -29,8 +29,8 @@ public function testAddStringToDateTimeValueTransformer() ])); $this->assertEquals([ - 'interface' => new PropertyMetadata('interface', Type::string(), [], ['json_encoder.value_transformer.string_to_date_time']), - 'immutable' => new PropertyMetadata('immutable', Type::string(), [], ['json_encoder.value_transformer.string_to_date_time']), + 'interface' => new PropertyMetadata('interface', Type::string(), [], ['json_streamer.value_transformer.string_to_date_time']), + 'immutable' => new PropertyMetadata('immutable', Type::string(), [], ['json_streamer.value_transformer.string_to_date_time']), 'other' => new PropertyMetadata('other', Type::object(self::class)), ], $loader->load(self::class)); } diff --git a/src/Symfony/Component/JsonEncoder/Tests/Mapping/Encode/AttributePropertyMetadataLoaderTest.php b/src/Symfony/Component/JsonStreamer/Tests/Mapping/Write/AttributePropertyMetadataLoaderTest.php similarity index 77% rename from src/Symfony/Component/JsonEncoder/Tests/Mapping/Encode/AttributePropertyMetadataLoaderTest.php rename to src/Symfony/Component/JsonStreamer/Tests/Mapping/Write/AttributePropertyMetadataLoaderTest.php index db9c96cd11535..9e83b3e37a375 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Mapping/Encode/AttributePropertyMetadataLoaderTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Mapping/Write/AttributePropertyMetadataLoaderTest.php @@ -9,25 +9,25 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\Mapping\Encode; +namespace Symfony\Component\JsonStreamer\Tests\Mapping\Write; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; -use Symfony\Component\JsonEncoder\Mapping\Encode\AttributePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadata; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithValueTransformerAttributes; -use Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\BooleanToStringValueTransformer; -use Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\DoubleIntAndCastToStringValueTransformer; -use Symfony\Component\JsonEncoder\Tests\ServiceContainer; -use Symfony\Component\JsonEncoder\ValueTransformer\ValueTransformerInterface; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadata; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\Write\AttributePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueTransformerAttributes; +use Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\BooleanToStringValueTransformer; +use Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\DoubleIntAndCastToStringValueTransformer; +use Symfony\Component\JsonStreamer\Tests\ServiceContainer; +use Symfony\Component\JsonStreamer\ValueTransformer\ValueTransformerInterface; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\TypeResolver\TypeResolver; class AttributePropertyMetadataLoaderTest extends TestCase { - public function testRetrieveEncodedName() + public function testRetrieveStreamedName() { $loader = new AttributePropertyMetadataLoader(new PropertyMetadataLoader(TypeResolver::create()), new ServiceContainer(), TypeResolver::create()); diff --git a/src/Symfony/Component/JsonEncoder/Tests/Mapping/Encode/DateTimeTypePropertyMetadataLoaderTest.php b/src/Symfony/Component/JsonStreamer/Tests/Mapping/Write/DateTimeTypePropertyMetadataLoaderTest.php similarity index 82% rename from src/Symfony/Component/JsonEncoder/Tests/Mapping/Encode/DateTimeTypePropertyMetadataLoaderTest.php rename to src/Symfony/Component/JsonStreamer/Tests/Mapping/Write/DateTimeTypePropertyMetadataLoaderTest.php index 6f3078679671c..eef83e3b2554c 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Mapping/Encode/DateTimeTypePropertyMetadataLoaderTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Mapping/Write/DateTimeTypePropertyMetadataLoaderTest.php @@ -9,12 +9,12 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\Mapping\Encode; +namespace Symfony\Component\JsonStreamer\Tests\Mapping\Write; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Mapping\Encode\DateTimeTypePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadata; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadata; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\Mapping\Write\DateTimeTypePropertyMetadataLoader; use Symfony\Component\TypeInfo\Type; class DateTimeTypePropertyMetadataLoaderTest extends TestCase @@ -27,7 +27,7 @@ public function testAddDateTimeToStringValueTransformer() ])); $this->assertEquals([ - 'dateTime' => new PropertyMetadata('dateTime', Type::string(), ['json_encoder.value_transformer.date_time_to_string']), + 'dateTime' => new PropertyMetadata('dateTime', Type::string(), ['json_streamer.value_transformer.date_time_to_string']), 'other' => new PropertyMetadata('other', Type::object(self::class)), ], $loader->load(self::class)); } diff --git a/src/Symfony/Component/JsonEncoder/Tests/Decode/NativeDecoderTest.php b/src/Symfony/Component/JsonStreamer/Tests/Read/DecoderTest.php similarity index 72% rename from src/Symfony/Component/JsonEncoder/Tests/Decode/NativeDecoderTest.php rename to src/Symfony/Component/JsonStreamer/Tests/Read/DecoderTest.php index a5ea8b86de1b4..567b4bd54793f 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Decode/NativeDecoderTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Read/DecoderTest.php @@ -9,13 +9,13 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\Decode; +namespace Symfony\Component\JsonStreamer\Tests\Read; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Decode\NativeDecoder; -use Symfony\Component\JsonEncoder\Exception\UnexpectedValueException; +use Symfony\Component\JsonStreamer\Exception\UnexpectedValueException; +use Symfony\Component\JsonStreamer\Read\Decoder; -class NativeDecoderTest extends TestCase +class DecoderTest extends TestCase { public function testDecode() { @@ -32,7 +32,7 @@ public function testDecodeThrowOnInvalidJsonString() $this->expectException(UnexpectedValueException::class); $this->expectExceptionMessage('JSON is not valid: Syntax error'); - NativeDecoder::decodeString('foo"'); + Decoder::decodeString('foo"'); } public function testDecodeThrowOnInvalidJsonStream() @@ -44,19 +44,19 @@ public function testDecodeThrowOnInvalidJsonStream() fwrite($resource, 'foo"'); rewind($resource); - NativeDecoder::decodeStream($resource); + Decoder::decodeStream($resource); } private function assertDecoded(mixed $decoded, string $encoded, int $offset = 0, ?int $length = null): void { if (0 === $offset && null === $length) { - $this->assertEquals($decoded, NativeDecoder::decodeString($encoded)); + $this->assertEquals($decoded, Decoder::decodeString($encoded)); } $resource = fopen('php://temp', 'w'); fwrite($resource, $encoded); rewind($resource); - $this->assertEquals($decoded, NativeDecoder::decodeStream($resource, $offset, $length)); + $this->assertEquals($decoded, Decoder::decodeStream($resource, $offset, $length)); } } diff --git a/src/Symfony/Component/JsonEncoder/Tests/Decode/InstantiatorTest.php b/src/Symfony/Component/JsonStreamer/Tests/Read/InstantiatorTest.php similarity index 80% rename from src/Symfony/Component/JsonEncoder/Tests/Decode/InstantiatorTest.php rename to src/Symfony/Component/JsonStreamer/Tests/Read/InstantiatorTest.php index c51298ce6b734..48557879951fe 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Decode/InstantiatorTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Read/InstantiatorTest.php @@ -9,12 +9,12 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\Decode; +namespace Symfony\Component\JsonStreamer\Tests\Read; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Decode\Instantiator; -use Symfony\Component\JsonEncoder\Exception\UnexpectedValueException; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy; +use Symfony\Component\JsonStreamer\Exception\UnexpectedValueException; +use Symfony\Component\JsonStreamer\Read\Instantiator; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy; class InstantiatorTest extends TestCase { diff --git a/src/Symfony/Component/JsonEncoder/Tests/Decode/LazyInstantiatorTest.php b/src/Symfony/Component/JsonStreamer/Tests/Read/LazyInstantiatorTest.php similarity index 73% rename from src/Symfony/Component/JsonEncoder/Tests/Decode/LazyInstantiatorTest.php rename to src/Symfony/Component/JsonStreamer/Tests/Read/LazyInstantiatorTest.php index 13cd60f5d1884..90e5f498d9cd2 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Decode/LazyInstantiatorTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Read/LazyInstantiatorTest.php @@ -9,13 +9,12 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\Decode; +namespace Symfony\Component\JsonStreamer\Tests\Read; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Decode\LazyInstantiator; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithValueTransformerAttributes; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\Read\LazyInstantiator; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy; class LazyInstantiatorTest extends TestCase { @@ -25,7 +24,7 @@ protected function setUp(): void { parent::setUp(); - $this->lazyGhostsDir = \sprintf('%s/symfony_json_encoder_test/lazy_ghost', sys_get_temp_dir()); + $this->lazyGhostsDir = \sprintf('%s/symfony_json_streamer_test/lazy_ghost', sys_get_temp_dir()); if (is_dir($this->lazyGhostsDir)) { array_map('unlink', glob($this->lazyGhostsDir.'/*')); @@ -50,7 +49,8 @@ public function testCreateLazyGhostUsingVarExporter() */ public function testCreateCacheFile() { - (new LazyInstantiator($this->lazyGhostsDir))->instantiate(DummyWithValueTransformerAttributes::class, function (ClassicDummy $object): void {}); + // use DummyForLazyInstantiation class to be sure that the instantiated object is not already in cache. + (new LazyInstantiator($this->lazyGhostsDir))->instantiate(DummyForLazyInstantiation::class, function (DummyForLazyInstantiation $object): void {}); $this->assertCount(1, glob($this->lazyGhostsDir.'/*')); } @@ -76,3 +76,7 @@ public function testCreateLazyGhostUsingPhp() $this->assertSame(123, $ghost->id); } } + +class DummyForLazyInstantiation +{ +} diff --git a/src/Symfony/Component/JsonEncoder/Tests/Decode/LexerTest.php b/src/Symfony/Component/JsonStreamer/Tests/Read/LexerTest.php similarity index 99% rename from src/Symfony/Component/JsonEncoder/Tests/Decode/LexerTest.php rename to src/Symfony/Component/JsonStreamer/Tests/Read/LexerTest.php index 1ac997d62ed4f..0442e9816974b 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Decode/LexerTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Read/LexerTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\Decode; +namespace Symfony\Component\JsonStreamer\Tests\Read; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Decode\Lexer; -use Symfony\Component\JsonEncoder\Exception\InvalidStreamException; +use Symfony\Component\JsonStreamer\Exception\InvalidStreamException; +use Symfony\Component\JsonStreamer\Read\Lexer; class LexerTest extends TestCase { diff --git a/src/Symfony/Component/JsonEncoder/Tests/Decode/SplitterTest.php b/src/Symfony/Component/JsonStreamer/Tests/Read/SplitterTest.php similarity index 96% rename from src/Symfony/Component/JsonEncoder/Tests/Decode/SplitterTest.php rename to src/Symfony/Component/JsonStreamer/Tests/Read/SplitterTest.php index d7e4bbcbfb8f2..02cd23e2c6b49 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Decode/SplitterTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Read/SplitterTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\Decode; +namespace Symfony\Component\JsonStreamer\Tests\Read; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Decode\Splitter; -use Symfony\Component\JsonEncoder\Exception\InvalidStreamException; +use Symfony\Component\JsonStreamer\Exception\InvalidStreamException; +use Symfony\Component\JsonStreamer\Read\Splitter; class SplitterTest extends TestCase { diff --git a/src/Symfony/Component/JsonEncoder/Tests/Decode/DecoderGeneratorTest.php b/src/Symfony/Component/JsonStreamer/Tests/Read/StreamReaderGeneratorTest.php similarity index 61% rename from src/Symfony/Component/JsonEncoder/Tests/Decode/DecoderGeneratorTest.php rename to src/Symfony/Component/JsonStreamer/Tests/Read/StreamReaderGeneratorTest.php index b91fd9f091d66..7215f223598fe 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Decode/DecoderGeneratorTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Read/StreamReaderGeneratorTest.php @@ -9,52 +9,52 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\Decode; +namespace Symfony\Component\JsonStreamer\Tests\Read; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Decode\DecoderGenerator; -use Symfony\Component\JsonEncoder\Exception\UnsupportedException; -use Symfony\Component\JsonEncoder\Mapping\Decode\AttributePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\Decode\DateTimeTypePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\GenericTypePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoaderInterface; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyEnum; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNullableProperties; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithOtherDummies; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithUnionProperties; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithValueTransformerAttributes; -use Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\DivideStringAndCastToIntValueTransformer; -use Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\StringToBooleanValueTransformer; -use Symfony\Component\JsonEncoder\Tests\ServiceContainer; +use Symfony\Component\JsonStreamer\Exception\UnsupportedException; +use Symfony\Component\JsonStreamer\Mapping\GenericTypePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\Mapping\Read\AttributePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\Read\DateTimeTypePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Read\StreamReaderGenerator; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyEnum; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNullableProperties; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithOtherDummies; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithUnionProperties; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueTransformerAttributes; +use Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\DivideStringAndCastToIntValueTransformer; +use Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\StringToBooleanValueTransformer; +use Symfony\Component\JsonStreamer\Tests\ServiceContainer; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\TypeContext\TypeContextFactory; use Symfony\Component\TypeInfo\TypeResolver\StringTypeResolver; use Symfony\Component\TypeInfo\TypeResolver\TypeResolver; -class DecoderGeneratorTest extends TestCase +class StreamReaderGeneratorTest extends TestCase { - private string $decodersDir; + private string $streamReadersDir; protected function setUp(): void { parent::setUp(); - $this->decodersDir = \sprintf('%s/symfony_json_encoder_test/decoder', sys_get_temp_dir()); + $this->streamReadersDir = \sprintf('%s/symfony_json_streamer_test/stream_reader', sys_get_temp_dir()); - if (is_dir($this->decodersDir)) { - array_map('unlink', glob($this->decodersDir.'/*')); - rmdir($this->decodersDir); + if (is_dir($this->streamReadersDir)) { + array_map('unlink', glob($this->streamReadersDir.'/*')); + rmdir($this->streamReadersDir); } } /** - * @dataProvider generatedDecoderDataProvider + * @dataProvider generatedStreamReaderDataProvider */ - public function testGeneratedDecoder(string $fixture, Type $type) + public function testGeneratedStreamReader(string $fixture, Type $type) { $propertyMetadataLoader = new GenericTypePropertyMetadataLoader( new DateTimeTypePropertyMetadataLoader(new AttributePropertyMetadataLoader( @@ -68,15 +68,15 @@ public function testGeneratedDecoder(string $fixture, Type $type) new TypeContextFactory(new StringTypeResolver()), ); - $generator = new DecoderGenerator($propertyMetadataLoader, $this->decodersDir); + $generator = new StreamReaderGenerator($propertyMetadataLoader, $this->streamReadersDir); $this->assertStringEqualsFile( - \sprintf('%s/Fixtures/decoder/%s.php', \dirname(__DIR__), $fixture), + \sprintf('%s/Fixtures/stream_reader/%s.php', \dirname(__DIR__), $fixture), file_get_contents($generator->generate($type, false)), ); $this->assertStringEqualsFile( - \sprintf('%s/Fixtures/decoder/%s.stream.php', \dirname(__DIR__), $fixture), + \sprintf('%s/Fixtures/stream_reader/%s.stream.php', \dirname(__DIR__), $fixture), file_get_contents($generator->generate($type, true)), ); } @@ -84,7 +84,7 @@ public function testGeneratedDecoder(string $fixture, Type $type) /** * @return iterable */ - public static function generatedDecoderDataProvider(): iterable + public static function generatedStreamReaderDataProvider(): iterable { yield ['scalar', Type::int()]; yield ['mixed', Type::mixed()]; @@ -115,7 +115,7 @@ public static function generatedDecoderDataProvider(): iterable public function testDoNotSupportIntersectionType() { - $generator = new DecoderGenerator(new PropertyMetadataLoader(TypeResolver::create()), $this->decodersDir); + $generator = new StreamReaderGenerator(new PropertyMetadataLoader(TypeResolver::create()), $this->streamReadersDir); $this->expectException(UnsupportedException::class); $this->expectExceptionMessage('"Stringable&Traversable" type is not supported.'); @@ -125,7 +125,7 @@ public function testDoNotSupportIntersectionType() public function testDoNotSupportEnumType() { - $generator = new DecoderGenerator(new PropertyMetadataLoader(TypeResolver::create()), $this->decodersDir); + $generator = new StreamReaderGenerator(new PropertyMetadataLoader(TypeResolver::create()), $this->streamReadersDir); $this->expectException(UnsupportedException::class); $this->expectExceptionMessage(\sprintf('"%s" type is not supported.', DummyEnum::class)); @@ -146,7 +146,7 @@ public function testCallPropertyMetadataLoaderWithProperContext() ]) ->willReturn([]); - $generator = new DecoderGenerator($propertyMetadataLoader, $this->decodersDir); + $generator = new StreamReaderGenerator($propertyMetadataLoader, $this->streamReadersDir); $generator->generate($type, false); } } diff --git a/src/Symfony/Component/JsonEncoder/Tests/ServiceContainer.php b/src/Symfony/Component/JsonStreamer/Tests/ServiceContainer.php similarity index 93% rename from src/Symfony/Component/JsonEncoder/Tests/ServiceContainer.php rename to src/Symfony/Component/JsonStreamer/Tests/ServiceContainer.php index 27a7944bf688e..795b5259631e7 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/ServiceContainer.php +++ b/src/Symfony/Component/JsonStreamer/Tests/ServiceContainer.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests; +namespace Symfony\Component\JsonStreamer\Tests; use Psr\Container\ContainerInterface; diff --git a/src/Symfony/Component/JsonEncoder/Tests/ValueTransformer/DateTimeToStringValueTransformerTest.php b/src/Symfony/Component/JsonStreamer/Tests/ValueTransformer/DateTimeToStringValueTransformerTest.php similarity index 84% rename from src/Symfony/Component/JsonEncoder/Tests/ValueTransformer/DateTimeToStringValueTransformerTest.php rename to src/Symfony/Component/JsonStreamer/Tests/ValueTransformer/DateTimeToStringValueTransformerTest.php index cc0a501cf4871..8e2dd80e13059 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/ValueTransformer/DateTimeToStringValueTransformerTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/ValueTransformer/DateTimeToStringValueTransformerTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\ValueTransformer; +namespace Symfony\Component\JsonStreamer\Tests\ValueTransformer; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; -use Symfony\Component\JsonEncoder\ValueTransformer\DateTimeToStringValueTransformer; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\ValueTransformer\DateTimeToStringValueTransformer; class DateTimeToStringValueTransformerTest extends TestCase { diff --git a/src/Symfony/Component/JsonEncoder/Tests/ValueTransformer/StringToDateTimeValueTransformerTest.php b/src/Symfony/Component/JsonStreamer/Tests/ValueTransformer/StringToDateTimeValueTransformerTest.php similarity index 91% rename from src/Symfony/Component/JsonEncoder/Tests/ValueTransformer/StringToDateTimeValueTransformerTest.php rename to src/Symfony/Component/JsonStreamer/Tests/ValueTransformer/StringToDateTimeValueTransformerTest.php index 3340adb8fc3b3..cb2cc32e58db4 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/ValueTransformer/StringToDateTimeValueTransformerTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/ValueTransformer/StringToDateTimeValueTransformerTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\ValueTransformer; +namespace Symfony\Component\JsonStreamer\Tests\ValueTransformer; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; -use Symfony\Component\JsonEncoder\ValueTransformer\StringToDateTimeValueTransformer; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\ValueTransformer\StringToDateTimeValueTransformer; class StringToDateTimeValueTransformerTest extends TestCase { diff --git a/src/Symfony/Component/JsonEncoder/Tests/Encode/EncoderGeneratorTest.php b/src/Symfony/Component/JsonStreamer/Tests/Write/StreamWriterGeneratorTest.php similarity index 63% rename from src/Symfony/Component/JsonEncoder/Tests/Encode/EncoderGeneratorTest.php rename to src/Symfony/Component/JsonStreamer/Tests/Write/StreamWriterGeneratorTest.php index 1d7e1b326febc..c3ee755ecc810 100644 --- a/src/Symfony/Component/JsonEncoder/Tests/Encode/EncoderGeneratorTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Write/StreamWriterGeneratorTest.php @@ -9,51 +9,51 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Tests\Encode; +namespace Symfony\Component\JsonStreamer\Tests\Write; use PHPUnit\Framework\TestCase; -use Symfony\Component\JsonEncoder\Encode\EncoderGenerator; -use Symfony\Component\JsonEncoder\Exception\UnsupportedException; -use Symfony\Component\JsonEncoder\Mapping\Encode\AttributePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\Encode\DateTimeTypePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\GenericTypePropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoader; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoaderInterface; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyBackedEnum; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Enum\DummyEnum; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\ClassicDummy; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithNameAttributes; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithOtherDummies; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithUnionProperties; -use Symfony\Component\JsonEncoder\Tests\Fixtures\Model\DummyWithValueTransformerAttributes; -use Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\BooleanToStringValueTransformer; -use Symfony\Component\JsonEncoder\Tests\Fixtures\ValueTransformer\DoubleIntAndCastToStringValueTransformer; -use Symfony\Component\JsonEncoder\Tests\ServiceContainer; +use Symfony\Component\JsonStreamer\Exception\UnsupportedException; +use Symfony\Component\JsonStreamer\Mapping\GenericTypePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\Mapping\Write\AttributePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Mapping\Write\DateTimeTypePropertyMetadataLoader; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyEnum; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithOtherDummies; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithUnionProperties; +use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueTransformerAttributes; +use Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\BooleanToStringValueTransformer; +use Symfony\Component\JsonStreamer\Tests\Fixtures\ValueTransformer\DoubleIntAndCastToStringValueTransformer; +use Symfony\Component\JsonStreamer\Tests\ServiceContainer; +use Symfony\Component\JsonStreamer\Write\StreamWriterGenerator; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\TypeContext\TypeContextFactory; use Symfony\Component\TypeInfo\TypeResolver\StringTypeResolver; use Symfony\Component\TypeInfo\TypeResolver\TypeResolver; -class EncoderGeneratorTest extends TestCase +class StreamWriterGeneratorTest extends TestCase { - private string $encodersDir; + private string $streamWritersDir; protected function setUp(): void { parent::setUp(); - $this->encodersDir = \sprintf('%s/symfony_json_encoder_test/encoder', sys_get_temp_dir()); + $this->streamWritersDir = \sprintf('%s/symfony_json_streamer_test/stream_writer', sys_get_temp_dir()); - if (is_dir($this->encodersDir)) { - array_map('unlink', glob($this->encodersDir.'/*')); - rmdir($this->encodersDir); + if (is_dir($this->streamWritersDir)) { + array_map('unlink', glob($this->streamWritersDir.'/*')); + rmdir($this->streamWritersDir); } } /** - * @dataProvider generatedEncoderDataProvider + * @dataProvider generatedStreamWriterDataProvider */ - public function testGeneratedEncoder(string $fixture, Type $type) + public function testGeneratedStreamWriter(string $fixture, Type $type) { $propertyMetadataLoader = new GenericTypePropertyMetadataLoader( new DateTimeTypePropertyMetadataLoader(new AttributePropertyMetadataLoader( @@ -67,10 +67,10 @@ public function testGeneratedEncoder(string $fixture, Type $type) new TypeContextFactory(new StringTypeResolver()), ); - $generator = new EncoderGenerator($propertyMetadataLoader, $this->encodersDir); + $generator = new StreamWriterGenerator($propertyMetadataLoader, $this->streamWritersDir); $this->assertStringEqualsFile( - \sprintf('%s/Fixtures/encoder/%s.php', \dirname(__DIR__), $fixture), + \sprintf('%s/Fixtures/stream_writer/%s.php', \dirname(__DIR__), $fixture), file_get_contents($generator->generate($type)), ); } @@ -78,7 +78,7 @@ public function testGeneratedEncoder(string $fixture, Type $type) /** * @return iterable */ - public static function generatedEncoderDataProvider(): iterable + public static function generatedStreamWriterDataProvider(): iterable { yield ['scalar', Type::int()]; yield ['null', Type::null()]; @@ -111,7 +111,7 @@ public static function generatedEncoderDataProvider(): iterable public function testDoNotSupportIntersectionType() { - $generator = new EncoderGenerator(new PropertyMetadataLoader(TypeResolver::create()), $this->encodersDir); + $generator = new StreamWriterGenerator(new PropertyMetadataLoader(TypeResolver::create()), $this->streamWritersDir); $this->expectException(UnsupportedException::class); $this->expectExceptionMessage('"Stringable&Traversable" type is not supported.'); @@ -121,7 +121,7 @@ public function testDoNotSupportIntersectionType() public function testDoNotSupportEnumType() { - $generator = new EncoderGenerator(new PropertyMetadataLoader(TypeResolver::create()), $this->encodersDir); + $generator = new StreamWriterGenerator(new PropertyMetadataLoader(TypeResolver::create()), $this->streamWritersDir); $this->expectException(UnsupportedException::class); $this->expectExceptionMessage(\sprintf('"%s" type is not supported.', DummyEnum::class)); @@ -142,7 +142,7 @@ public function testCallPropertyMetadataLoaderWithProperContext() ]) ->willReturn([]); - $generator = new EncoderGenerator($propertyMetadataLoader, $this->encodersDir); + $generator = new StreamWriterGenerator($propertyMetadataLoader, $this->streamWritersDir); $generator->generate($type); } } diff --git a/src/Symfony/Component/JsonEncoder/ValueTransformer/DateTimeToStringValueTransformer.php b/src/Symfony/Component/JsonStreamer/ValueTransformer/DateTimeToStringValueTransformer.php similarity index 80% rename from src/Symfony/Component/JsonEncoder/ValueTransformer/DateTimeToStringValueTransformer.php rename to src/Symfony/Component/JsonStreamer/ValueTransformer/DateTimeToStringValueTransformer.php index 36e577d8f5cd2..2da8fd3acbf16 100644 --- a/src/Symfony/Component/JsonEncoder/ValueTransformer/DateTimeToStringValueTransformer.php +++ b/src/Symfony/Component/JsonStreamer/ValueTransformer/DateTimeToStringValueTransformer.php @@ -9,15 +9,15 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\ValueTransformer; +namespace Symfony\Component\JsonStreamer\ValueTransformer; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\Type\BuiltinType; use Symfony\Component\TypeInfo\TypeIdentifier; /** - * Transforms DateTimeInterface to string during encoding. + * Transforms DateTimeInterface to string during stream writing. * * @author Mathias Arlaud * @@ -39,7 +39,7 @@ public function transform(mixed $value, array $options = []): string /** * @return BuiltinType */ - public static function getJsonValueType(): BuiltinType + public static function getStreamValueType(): BuiltinType { return Type::string(); } diff --git a/src/Symfony/Component/JsonEncoder/ValueTransformer/StringToDateTimeValueTransformer.php b/src/Symfony/Component/JsonStreamer/ValueTransformer/StringToDateTimeValueTransformer.php similarity index 90% rename from src/Symfony/Component/JsonEncoder/ValueTransformer/StringToDateTimeValueTransformer.php rename to src/Symfony/Component/JsonStreamer/ValueTransformer/StringToDateTimeValueTransformer.php index 502f9b03e9269..263d56773e22e 100644 --- a/src/Symfony/Component/JsonEncoder/ValueTransformer/StringToDateTimeValueTransformer.php +++ b/src/Symfony/Component/JsonStreamer/ValueTransformer/StringToDateTimeValueTransformer.php @@ -9,15 +9,15 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\ValueTransformer; +namespace Symfony\Component\JsonStreamer\ValueTransformer; -use Symfony\Component\JsonEncoder\Exception\InvalidArgumentException; +use Symfony\Component\JsonStreamer\Exception\InvalidArgumentException; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\Type\BuiltinType; use Symfony\Component\TypeInfo\TypeIdentifier; /** - * Transforms string to DateTimeImmutable during decoding. + * Transforms string to DateTimeImmutable during stream reading. * * @author Mathias Arlaud * @@ -57,7 +57,7 @@ public function transform(mixed $value, array $options = []): \DateTimeImmutable /** * @return BuiltinType */ - public static function getJsonValueType(): BuiltinType + public static function getStreamValueType(): BuiltinType { return Type::string(); } diff --git a/src/Symfony/Component/JsonEncoder/ValueTransformer/ValueTransformerInterface.php b/src/Symfony/Component/JsonStreamer/ValueTransformer/ValueTransformerInterface.php similarity index 69% rename from src/Symfony/Component/JsonEncoder/ValueTransformer/ValueTransformerInterface.php rename to src/Symfony/Component/JsonStreamer/ValueTransformer/ValueTransformerInterface.php index 8aed47f0eab4a..915e626414ac2 100644 --- a/src/Symfony/Component/JsonEncoder/ValueTransformer/ValueTransformerInterface.php +++ b/src/Symfony/Component/JsonStreamer/ValueTransformer/ValueTransformerInterface.php @@ -9,13 +9,12 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\ValueTransformer; +namespace Symfony\Component\JsonStreamer\ValueTransformer; use Symfony\Component\TypeInfo\Type; /** - * Transforms a native value so it's ready to be JSON encoded during encoding - * and to other way around during decoding. + * Transforms a native value before stream writing and after stream reading. * * @author Mathias Arlaud * @@ -28,5 +27,5 @@ interface ValueTransformerInterface */ public function transform(mixed $value, array $options = []): mixed; - public static function getJsonValueType(): Type; + public static function getStreamValueType(): Type; } diff --git a/src/Symfony/Component/JsonEncoder/Encode/MergingStringVisitor.php b/src/Symfony/Component/JsonStreamer/Write/MergingStringVisitor.php similarity index 96% rename from src/Symfony/Component/JsonEncoder/Encode/MergingStringVisitor.php rename to src/Symfony/Component/JsonStreamer/Write/MergingStringVisitor.php index 4c045ba01afcb..289448ba465e8 100644 --- a/src/Symfony/Component/JsonEncoder/Encode/MergingStringVisitor.php +++ b/src/Symfony/Component/JsonStreamer/Write/MergingStringVisitor.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Encode; +namespace Symfony\Component\JsonStreamer\Write; use PhpParser\Node; use PhpParser\Node\Expr\Yield_; diff --git a/src/Symfony/Component/JsonEncoder/Encode/PhpAstBuilder.php b/src/Symfony/Component/JsonStreamer/Write/PhpAstBuilder.php similarity index 91% rename from src/Symfony/Component/JsonEncoder/Encode/PhpAstBuilder.php rename to src/Symfony/Component/JsonStreamer/Write/PhpAstBuilder.php index 36d054649d596..f6a4d9b6e7c2c 100644 --- a/src/Symfony/Component/JsonEncoder/Encode/PhpAstBuilder.php +++ b/src/Symfony/Component/JsonStreamer/Write/PhpAstBuilder.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Encode; +namespace Symfony\Component\JsonStreamer\Write; use PhpParser\BuilderFactory; use PhpParser\Node\Expr; @@ -34,22 +34,23 @@ use PhpParser\Node\Stmt\If_; use PhpParser\Node\Stmt\Return_; use Psr\Container\ContainerInterface; -use Symfony\Component\JsonEncoder\DataModel\Encode\BackedEnumNode; -use Symfony\Component\JsonEncoder\DataModel\Encode\CollectionNode; -use Symfony\Component\JsonEncoder\DataModel\Encode\CompositeNode; -use Symfony\Component\JsonEncoder\DataModel\Encode\DataModelNodeInterface; -use Symfony\Component\JsonEncoder\DataModel\Encode\ExceptionNode; -use Symfony\Component\JsonEncoder\DataModel\Encode\ObjectNode; -use Symfony\Component\JsonEncoder\DataModel\Encode\ScalarNode; -use Symfony\Component\JsonEncoder\Exception\LogicException; -use Symfony\Component\JsonEncoder\Exception\RuntimeException; -use Symfony\Component\JsonEncoder\Exception\UnexpectedValueException; +use Symfony\Component\JsonStreamer\DataModel\Write\BackedEnumNode; +use Symfony\Component\JsonStreamer\DataModel\Write\CollectionNode; +use Symfony\Component\JsonStreamer\DataModel\Write\CompositeNode; +use Symfony\Component\JsonStreamer\DataModel\Write\DataModelNodeInterface; +use Symfony\Component\JsonStreamer\DataModel\Write\ExceptionNode; +use Symfony\Component\JsonStreamer\DataModel\Write\ObjectNode; +use Symfony\Component\JsonStreamer\DataModel\Write\ScalarNode; +use Symfony\Component\JsonStreamer\Exception\LogicException; +use Symfony\Component\JsonStreamer\Exception\RuntimeException; +use Symfony\Component\JsonStreamer\Exception\UnexpectedValueException; +use Symfony\Component\TypeInfo\Type\BuiltinType; use Symfony\Component\TypeInfo\Type\ObjectType; use Symfony\Component\TypeInfo\Type\WrappingTypeInterface; use Symfony\Component\TypeInfo\TypeIdentifier; /** - * Builds a PHP syntax tree that encodes data to JSON. + * Builds a PHP syntax tree that writes data to JSON stream. * * @author Mathias Arlaud * @@ -155,7 +156,11 @@ private function buildClosureStatements(DataModelNodeInterface $dataModelNode, a return new Instanceof_($accessor, new FullyQualified($type->getClassName())); } - return $this->builder->funcCall('\is_'.$type->getTypeIdentifier()->value, [$accessor]); + if ($type instanceof BuiltinType) { + return $this->builder->funcCall('\is_'.$type->getTypeIdentifier()->value, [$accessor]); + } + + throw new LogicException(\sprintf('Unexpected "%s" type.', $type::class)); }; $stmtsAndConditions = array_map(fn (DataModelNodeInterface $n): array => [ diff --git a/src/Symfony/Component/JsonEncoder/Encode/PhpOptimizer.php b/src/Symfony/Component/JsonStreamer/Write/PhpOptimizer.php similarity index 95% rename from src/Symfony/Component/JsonEncoder/Encode/PhpOptimizer.php rename to src/Symfony/Component/JsonStreamer/Write/PhpOptimizer.php index 5202aa893e219..4dddaf47aac70 100644 --- a/src/Symfony/Component/JsonEncoder/Encode/PhpOptimizer.php +++ b/src/Symfony/Component/JsonStreamer/Write/PhpOptimizer.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Encode; +namespace Symfony\Component\JsonStreamer\Write; use PhpParser\Node; use PhpParser\NodeTraverser; diff --git a/src/Symfony/Component/JsonEncoder/Encode/EncoderGenerator.php b/src/Symfony/Component/JsonStreamer/Write/StreamWriterGenerator.php similarity index 75% rename from src/Symfony/Component/JsonEncoder/Encode/EncoderGenerator.php rename to src/Symfony/Component/JsonStreamer/Write/StreamWriterGenerator.php index 51a1eb0d79773..44e05c494cd03 100644 --- a/src/Symfony/Component/JsonEncoder/Encode/EncoderGenerator.php +++ b/src/Symfony/Component/JsonStreamer/Write/StreamWriterGenerator.php @@ -9,29 +9,29 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\JsonEncoder\Encode; +namespace Symfony\Component\JsonStreamer\Write; use PhpParser\PhpVersion; use PhpParser\PrettyPrinter; use PhpParser\PrettyPrinter\Standard; use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\JsonEncoder\DataModel\DataAccessorInterface; -use Symfony\Component\JsonEncoder\DataModel\Encode\BackedEnumNode; -use Symfony\Component\JsonEncoder\DataModel\Encode\CollectionNode; -use Symfony\Component\JsonEncoder\DataModel\Encode\CompositeNode; -use Symfony\Component\JsonEncoder\DataModel\Encode\DataModelNodeInterface; -use Symfony\Component\JsonEncoder\DataModel\Encode\ExceptionNode; -use Symfony\Component\JsonEncoder\DataModel\Encode\ObjectNode; -use Symfony\Component\JsonEncoder\DataModel\Encode\ScalarNode; -use Symfony\Component\JsonEncoder\DataModel\FunctionDataAccessor; -use Symfony\Component\JsonEncoder\DataModel\PropertyDataAccessor; -use Symfony\Component\JsonEncoder\DataModel\ScalarDataAccessor; -use Symfony\Component\JsonEncoder\DataModel\VariableDataAccessor; -use Symfony\Component\JsonEncoder\Exception\MaxDepthException; -use Symfony\Component\JsonEncoder\Exception\RuntimeException; -use Symfony\Component\JsonEncoder\Exception\UnsupportedException; -use Symfony\Component\JsonEncoder\Mapping\PropertyMetadataLoaderInterface; +use Symfony\Component\JsonStreamer\DataModel\DataAccessorInterface; +use Symfony\Component\JsonStreamer\DataModel\FunctionDataAccessor; +use Symfony\Component\JsonStreamer\DataModel\PropertyDataAccessor; +use Symfony\Component\JsonStreamer\DataModel\ScalarDataAccessor; +use Symfony\Component\JsonStreamer\DataModel\VariableDataAccessor; +use Symfony\Component\JsonStreamer\DataModel\Write\BackedEnumNode; +use Symfony\Component\JsonStreamer\DataModel\Write\CollectionNode; +use Symfony\Component\JsonStreamer\DataModel\Write\CompositeNode; +use Symfony\Component\JsonStreamer\DataModel\Write\DataModelNodeInterface; +use Symfony\Component\JsonStreamer\DataModel\Write\ExceptionNode; +use Symfony\Component\JsonStreamer\DataModel\Write\ObjectNode; +use Symfony\Component\JsonStreamer\DataModel\Write\ScalarNode; +use Symfony\Component\JsonStreamer\Exception\MaxDepthException; +use Symfony\Component\JsonStreamer\Exception\RuntimeException; +use Symfony\Component\JsonStreamer\Exception\UnsupportedException; +use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoaderInterface; use Symfony\Component\TypeInfo\Type; use Symfony\Component\TypeInfo\Type\BackedEnumType; use Symfony\Component\TypeInfo\Type\BuiltinType; @@ -41,13 +41,13 @@ use Symfony\Component\TypeInfo\Type\UnionType; /** - * Generates and write encoders PHP files. + * Generates and write stream writers PHP files. * * @author Mathias Arlaud * * @internal */ -final class EncoderGenerator +final class StreamWriterGenerator { private const MAX_DEPTH = 512; @@ -58,12 +58,12 @@ final class EncoderGenerator public function __construct( private PropertyMetadataLoaderInterface $propertyMetadataLoader, - private string $encodersDir, + private string $streamWritersDir, ) { } /** - * Generates and writes an encoder PHP file and return its path. + * Generates and writes an stream writer PHP file and return its path. * * @param array $options */ @@ -86,8 +86,8 @@ public function generate(Type $type, array $options = []): string $content = $this->phpPrinter->prettyPrintFile($nodes)."\n"; - if (!$this->fs->exists($this->encodersDir)) { - $this->fs->mkdir($this->encodersDir); + if (!$this->fs->exists($this->streamWritersDir)) { + $this->fs->mkdir($this->streamWritersDir); } $tmpFile = $this->fs->tempnam(\dirname($path), basename($path)); @@ -97,7 +97,7 @@ public function generate(Type $type, array $options = []): string $this->fs->rename($tmpFile, $path); $this->fs->chmod($path, 0666 & ~umask()); } catch (IOException $e) { - throw new RuntimeException(\sprintf('Failed to write "%s" encoder file.', $path), previous: $e); + throw new RuntimeException(\sprintf('Failed to write "%s" stream writer file.', $path), previous: $e); } return $path; @@ -105,7 +105,7 @@ public function generate(Type $type, array $options = []): string private function getPath(Type $type): string { - return \sprintf('%s%s%s.json.php', $this->encodersDir, \DIRECTORY_SEPARATOR, hash('xxh128', (string) $type)); + return \sprintf('%s%s%s.json.php', $this->streamWritersDir, \DIRECTORY_SEPARATOR, hash('xxh128', (string) $type)); } /** @@ -148,10 +148,10 @@ private function createDataModel(Type $type, DataAccessorInterface $accessor, ar $propertiesNodes = []; - foreach ($propertiesMetadata as $encodedName => $propertyMetadata) { + foreach ($propertiesMetadata as $streamedName => $propertyMetadata) { $propertyAccessor = new PropertyDataAccessor($accessor, $propertyMetadata->getName()); - foreach ($propertyMetadata->getToJsonValueTransformer() as $valueTransformer) { + foreach ($propertyMetadata->getNativeToStreamValueTransformer() as $valueTransformer) { if (\is_string($valueTransformer)) { $valueTransformerServiceAccessor = new FunctionDataAccessor('get', [new ScalarDataAccessor($valueTransformer)], new VariableDataAccessor('valueTransformers')); $propertyAccessor = new FunctionDataAccessor('transform', [$propertyAccessor, new VariableDataAccessor('options')], $valueTransformerServiceAccessor); @@ -173,7 +173,7 @@ private function createDataModel(Type $type, DataAccessorInterface $accessor, ar $propertyAccessor = new FunctionDataAccessor($functionName, $arguments); } - $propertiesNodes[$encodedName] = $this->createDataModel($propertyMetadata->getType(), $propertyAccessor, $options, $context); + $propertiesNodes[$streamedName] = $this->createDataModel($propertyMetadata->getType(), $propertyAccessor, $options, $context); } return new ObjectNode($accessor, $type, $propertiesNodes); diff --git a/src/Symfony/Component/JsonEncoder/composer.json b/src/Symfony/Component/JsonStreamer/composer.json similarity index 77% rename from src/Symfony/Component/JsonEncoder/composer.json rename to src/Symfony/Component/JsonStreamer/composer.json index 512dcea495113..ba02d9fbc9172 100644 --- a/src/Symfony/Component/JsonEncoder/composer.json +++ b/src/Symfony/Component/JsonStreamer/composer.json @@ -1,8 +1,8 @@ { - "name": "symfony/json-encoder", + "name": "symfony/json-streamer", "type": "library", - "description": "Provides powerful methods to encode/decode data structures into/from JSON.", - "keywords": ["encoding", "decoding", "json"], + "description": "Provides powerful methods to read/write data structures from/into JSON streams.", + "keywords": ["json", "stream"], "homepage": "https://symfony.com", "license": "MIT", "authors": [ @@ -30,7 +30,7 @@ "symfony/http-kernel": "^7.2" }, "autoload": { - "psr-4": { "Symfony\\Component\\JsonEncoder\\": "" }, + "psr-4": { "Symfony\\Component\\JsonStreamer\\": "" }, "exclude-from-classmap": [ "Tests/" ] }, "minimum-stability": "dev" diff --git a/src/Symfony/Component/JsonEncoder/phpunit.xml.dist b/src/Symfony/Component/JsonStreamer/phpunit.xml.dist similarity index 91% rename from src/Symfony/Component/JsonEncoder/phpunit.xml.dist rename to src/Symfony/Component/JsonStreamer/phpunit.xml.dist index 91cb9a7aaee58..403afcbb1d1bf 100644 --- a/src/Symfony/Component/JsonEncoder/phpunit.xml.dist +++ b/src/Symfony/Component/JsonStreamer/phpunit.xml.dist @@ -13,7 +13,7 @@ - + ./Tests/