Skip to content

Commit d458fc9

Browse files
committed
split context builders and remove cache trait
1 parent dd46dcd commit d458fc9

32 files changed

+717
-551
lines changed

src/Symfony/Bundle/FrameworkBundle/CacheWarmer/SerDesCacheWarmer.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use Psr\Log\NullLogger;
1616
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
1717
use Symfony\Component\SerDes\Attribute\Serializable;
18-
use Symfony\Component\SerDes\Context\ContextBuilderInterface;
18+
use Symfony\Component\SerDes\Context\ContextBuilder\SerializeContextBuilderInterface;
1919
use Symfony\Component\SerDes\Exception\ExceptionInterface;
2020
use Symfony\Component\SerDes\SerializableResolverInterface;
2121
use Symfony\Component\VarExporter\ProxyHelper;
@@ -30,8 +30,8 @@
3030
final class SerDesCacheWarmer implements CacheWarmerInterface
3131
{
3232
/**
33-
* @param iterable<ContextBuilderInterface> $contextBuilders
34-
* @param list<string> $formats
33+
* @param iterable<SerializeContextBuilderInterface> $contextBuilders
34+
* @param list<string> $formats
3535
*/
3636
public function __construct(
3737
private readonly SerializableResolverInterface $serializableResolver,
@@ -84,10 +84,13 @@ private function warmClassTemplate(string $class, Serializable $attribute, strin
8484
}
8585

8686
try {
87-
$context = ['cache_dir' => $this->templateCacheDir];
87+
$context = [
88+
'cache_dir' => $this->templateCacheDir,
89+
'template_exists' => false,
90+
];
8891

8992
foreach ($this->contextBuilders as $contextBuilder) {
90-
$context = $contextBuilder->buildSerializeContext($context, true);
93+
$context = $contextBuilder->build($context, true);
9194
}
9295

9396
file_put_contents($path, serialize_generate($class, $format, $context));

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
use Http\Client\HttpAsyncClient;
1717
use Http\Client\HttpClient;
1818
use Symfony\Component\SerDes\Context\ContextBuilderInterface;
19+
use Symfony\Component\SerDes\Context\ContextBuilder\DeserializeContextBuilderInterface;
20+
use Symfony\Component\SerDes\Context\ContextBuilder\SerializeContextBuilderInterface;
1921
use Symfony\Component\SerDes\SerializerInterface as SerDesSerializerInterface;
2022
use phpDocumentor\Reflection\DocBlockFactoryInterface;
2123
use phpDocumentor\Reflection\Types\ContextFactory;
@@ -697,8 +699,10 @@ public function load(array $configs, ContainerBuilder $container)
697699
->addTag('mime.mime_type_guesser');
698700
$container->registerForAutoconfiguration(LoggerAwareInterface::class)
699701
->addMethodCall('setLogger', [new Reference('logger')]);
700-
$container->registerForAutoconfiguration(ContextBuilderInterface::class)
701-
->addTag('ser_des.context_builder');
702+
$container->registerForAutoconfiguration(SerializeContextBuilderInterface::class)
703+
->addTag('ser_des.context_builder.serialize');
704+
$container->registerForAutoconfiguration(DeserializeContextBuilderInterface::class)
705+
->addTag('ser_des.context_builder.deserialize');
702706

703707
$container->registerAttributeForAutoconfiguration(AsEventListener::class, static function (ChildDefinition $definition, AsEventListener $attribute, \ReflectionClass|\ReflectionMethod $reflector) {
704708
$tagAttributes = get_object_vars($attribute);

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

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313

1414
use Symfony\Bundle\FrameworkBundle\CacheWarmer\SerDesCacheWarmer;
1515
use Symfony\Component\SerDes\CachedSerializableResolver;
16-
use Symfony\Component\SerDes\Context\ContextBuilder\CachedContextBuilder;
17-
use Symfony\Component\SerDes\Context\ContextBuilder\FormatterAttributeContextBuilder;
18-
use Symfony\Component\SerDes\Context\ContextBuilder\HookContextBuilder;
19-
use Symfony\Component\SerDes\Context\ContextBuilder\InstantiatorContextBuilder;
20-
use Symfony\Component\SerDes\Context\ContextBuilder\NameAttributeContextBuilder;
16+
use Symfony\Component\SerDes\Context\ContextBuilder\Deserialize\DeserializeFormatterAttributeContextBuilder;
17+
use Symfony\Component\SerDes\Context\ContextBuilder\Deserialize\DeserializeHookContextBuilder;
18+
use Symfony\Component\SerDes\Context\ContextBuilder\Deserialize\DeserializeInstantiatorContextBuilder;
19+
use Symfony\Component\SerDes\Context\ContextBuilder\Deserialize\DeserializeNameAttributeContextBuilder;
20+
use Symfony\Component\SerDes\Context\ContextBuilder\Serialize\SerializeFormatterAttributeContextBuilder;
21+
use Symfony\Component\SerDes\Context\ContextBuilder\Serialize\SerializeHookContextBuilder;
22+
use Symfony\Component\SerDes\Context\ContextBuilder\Serialize\SerializeNameAttributeContextBuilder;
2123
use Symfony\Component\SerDes\Instantiator\LazyInstantiator;
2224
use Symfony\Component\SerDes\SerializableResolver;
2325
use Symfony\Component\SerDes\SerializableResolverInterface;
@@ -39,7 +41,8 @@
3941
// Serializer
4042
->set('ser_des.serializer', Serializer::class)
4143
->args([
42-
tagged_iterator('ser_des.context_builder'),
44+
tagged_iterator('ser_des.context_builder.serialize'),
45+
tagged_iterator('ser_des.context_builder.deserialize'),
4346
param('ser_des.cache_dir.template')
4447
])
4548
->alias(SerializerInterface::class, 'ser_des.serializer')
@@ -60,48 +63,47 @@
6063
->alias('ser_des.type_extractor', 'ser_des.type_extractor.reflection')
6164

6265
// Context builders
63-
->set('ser_des.context_builder.hook', HookContextBuilder::class)
66+
->set('ser_des.context_builder.serialize.hook', SerializeHookContextBuilder::class)
6467
->args([
6568
tagged_iterator('ser_des.hook.serialize', 'name'),
66-
tagged_iterator('ser_des.hook.deserialize', 'name'),
6769
])
68-
->tag('ser_des.context_builder', ['priority' => -1024])
70+
->tag('ser_des.context_builder.serialize', ['priority' => -1024])
6971

70-
->set('ser_des.context_builder.instantiator', InstantiatorContextBuilder::class)
72+
->set('ser_des.context_builder.serialize.name_attribute', SerializeNameAttributeContextBuilder::class)
7173
->args([
72-
service('ser_des.instantiator.lazy'),
74+
service('ser_des.serializable_resolver'),
7375
])
74-
->tag('ser_des.context_builder', ['priority' => -1024])
76+
->tag('ser_des.context_builder.serialize', ['priority' => -1024])
7577

76-
->set('ser_des.context_builder.name_attribute', NameAttributeContextBuilder::class)
78+
->set('ser_des.context_builder.serialize.formatter_attribute', SerializeFormatterAttributeContextBuilder::class)
7779
->args([
7880
service('ser_des.serializable_resolver'),
7981
])
80-
->tag('ser_des.context_builder', ['priority' => -1024])
82+
->tag('ser_des.context_builder.serialize', ['priority' => -1024])
8183

82-
->set('ser_des.context_builder.name_attribute.cached', CachedContextBuilder::class)
83-
->decorate('ser_des.context_builder.name_attribute')
84+
->set('ser_des.context_builder.deserialize.hook', DeserializeHookContextBuilder::class)
8485
->args([
85-
service('ser_des.context_builder.name_attribute.cached.inner'),
86-
'property_name',
87-
'ser_des.context.name_attribute',
88-
service('cache.ser_des')->ignoreOnInvalid(),
86+
tagged_iterator('ser_des.hook.deserialize', 'name'),
8987
])
88+
->tag('ser_des.context_builder.deserialize', ['priority' => -1024])
9089

91-
->set('ser_des.context_builder.formatter_attribute', FormatterAttributeContextBuilder::class)
90+
->set('ser_des.context_builder.deserialize.name_attribute', DeserializeNameAttributeContextBuilder::class)
9291
->args([
9392
service('ser_des.serializable_resolver'),
9493
])
95-
->tag('ser_des.context_builder', ['priority' => -1024])
94+
->tag('ser_des.context_builder.deserialize', ['priority' => -1024])
9695

97-
->set('ser_des.context_builder.formatter_attribute.cached', CachedContextBuilder::class)
98-
->decorate('ser_des.context_builder.formatter_attribute')
96+
->set('ser_des.context_builder.deserialize.formatter_attribute', DeserializeFormatterAttributeContextBuilder::class)
9997
->args([
100-
service('ser_des.context_builder.formatter_attribute.cached.inner'),
101-
'property_formatter',
102-
'ser_des.context.formatter_attribute',
103-
service('cache.ser_des')->ignoreOnInvalid(),
98+
service('ser_des.serializable_resolver'),
99+
])
100+
->tag('ser_des.context_builder.deserialize', ['priority' => -1024])
101+
102+
->set('ser_des.context_builder.deserialize.instantiator', DeserializeInstantiatorContextBuilder::class)
103+
->args([
104+
service('ser_des.instantiator.lazy'),
104105
])
106+
->tag('ser_des.context_builder.deserialize', ['priority' => -1024])
105107

106108
// Hooks
107109
->set('ser_des.hook.serialize.object', SerializeHook\ObjectHook::class)

src/Symfony/Component/SerDes/CachedSerializableResolver.php

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,14 @@
1111

1212
namespace Symfony\Component\SerDes;
1313

14+
use Psr\Cache\CacheException;
1415
use Psr\Cache\CacheItemPoolInterface;
15-
use Symfony\Component\SerDes\Util\CachedTrait;
1616

1717
/**
1818
* @author Mathias Arlaud <[email protected]>
1919
*/
2020
final class CachedSerializableResolver implements SerializableResolverInterface
2121
{
22-
use CachedTrait;
23-
2422
public function __construct(
2523
private readonly SerializableResolverInterface $resolver,
2624
private readonly CacheItemPoolInterface|null $cacheItemPool = null,
@@ -29,13 +27,24 @@ public function __construct(
2927

3028
public function resolve(): iterable
3129
{
32-
yield from $this->getCached('ser_des.serializable', function (): array {
33-
$serializables = [];
34-
foreach ($this->resolver->resolve() as $class => $serializable) {
35-
$serializables[$class] = $serializable;
36-
}
37-
38-
return $serializables;
39-
});
30+
if (null === $this->cacheItemPool) {
31+
yield from $this->resolver->resolve();
32+
33+
return;
34+
}
35+
36+
try {
37+
$item = $this->cacheItemPool->getItem('ser_des.serializable');
38+
} catch (CacheException) {
39+
yield from $this->resolver->resolve();
40+
41+
return;
42+
}
43+
44+
if (!$item->isHit()) {
45+
$item->set(iterator_to_array($this->resolver->resolve()));
46+
}
47+
48+
yield from $item->get();
4049
}
4150
}

src/Symfony/Component/SerDes/Context/ContextBuilder/CachedContextBuilder.php

Lines changed: 0 additions & 56 deletions
This file was deleted.

src/Symfony/Component/SerDes/Context/ContextBuilderInterface.php renamed to src/Symfony/Component/SerDes/Context/ContextBuilder/ContextBuilderInterface.php

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
namespace Symfony\Component\SerDes\Context;
12+
namespace Symfony\Component\SerDes\Context\ContextBuilder;
1313

1414
/**
1515
* @author Mathias Arlaud <[email protected]>
@@ -23,12 +23,5 @@ interface ContextBuilderInterface
2323
*
2424
* @return array<string, mixed>
2525
*/
26-
public function buildSerializeContext(array $context, bool $willGenerateTemplate): array;
27-
28-
/**
29-
* @param array<string, mixed> $context
30-
*
31-
* @return array<string, mixed>
32-
*/
33-
public function buildDeserializeContext(array $context): array;
26+
public function build(array $context): array;
3427
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\SerDes\Context\ContextBuilder\Deserialize;
13+
14+
use Symfony\Component\SerDes\Attribute\Formatter;
15+
use Symfony\Component\SerDes\Context\ContextBuilder\DeserializeContextBuilderInterface;
16+
use Symfony\Component\SerDes\SerializableResolverInterface;
17+
18+
/**
19+
* @author Mathias Arlaud <[email protected]>
20+
*
21+
* @experimental in 7.0
22+
*/
23+
final class DeserializeFormatterAttributeContextBuilder implements DeserializeContextBuilderInterface
24+
{
25+
/**
26+
* @var array<string, string|array{0: string, 1: string}>
27+
*/
28+
private static ?array $cache = null;
29+
30+
public function __construct(
31+
private readonly SerializableResolverInterface $serializableResolver,
32+
) {
33+
}
34+
35+
public function build(array $context): array
36+
{
37+
if (null === self::$cache) {
38+
$propertyFormatters = [];
39+
40+
foreach ($this->serializableResolver->resolve() as $className => $_) {
41+
$propertyFormatters += $this->propertyFormatters($className);
42+
}
43+
44+
self::$cache = $propertyFormatters;
45+
}
46+
47+
$context['_symfony']['property_formatter'] = self::$cache;
48+
49+
return $context;
50+
}
51+
52+
/**
53+
* @param class-string $className
54+
*
55+
* @return array<string, string|array{0: string, 1: string}>
56+
*/
57+
private function propertyFormatters(string $className): array
58+
{
59+
$propertyFormatters = [];
60+
61+
foreach ((new \ReflectionClass($className))->getProperties() as $property) {
62+
foreach ($property->getAttributes() as $attribute) {
63+
if (Formatter::class !== $attribute->getName()) {
64+
continue;
65+
}
66+
67+
/** @var Formatter $attributeInstance */
68+
$attributeInstance = $attribute->newInstance();
69+
70+
if (null === $attributeInstance->onDeserialize) {
71+
break;
72+
}
73+
74+
$propertyFormatters[sprintf('%s::$%s', $property->getDeclaringClass()->getName(), $property->getName())]['deserialize'] = $attributeInstance->onDeserialize;
75+
76+
break;
77+
}
78+
}
79+
80+
return $propertyFormatters;
81+
}
82+
}

0 commit comments

Comments
 (0)