Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[Serializer] AdddefaultType toDiscriminatorMap#59828

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,12 +22,14 @@ class DiscriminatorMap
/**
* @param string $typeProperty The property holding the type discriminator
* @param array<string, class-string> $mapping The mapping between types and classes (i.e. ['admin_user' => AdminUser::class])
* @param ?string $defaultType The fallback value if nothing specified by $typeProperty
*
* @throws InvalidArgumentException
*/
public function __construct(
private readonly string $typeProperty,
private readonly array $mapping,
private readonly ?string $defaultType = null,
) {
if (!$typeProperty) {
throw new InvalidArgumentException(\sprintf('Parameter "typeProperty" given to "%s" cannot be empty.', static::class));
Expand All@@ -36,6 +38,10 @@ public function __construct(
if (!$mapping) {
throw new InvalidArgumentException(\sprintf('Parameter "mapping" given to "%s" cannot be empty.', static::class));
}

if (null !== $this->defaultType && !\array_key_exists($this->defaultType, $this->mapping)) {
throw new InvalidArgumentException(\sprintf('Default type "%s" given to "%s" must be present in "mapping" types.', $this->defaultType, static::class));
}
}

public function getTypeProperty(): string
Expand All@@ -47,6 +53,11 @@ public function getMapping(): array
{
return $this->mapping;
}

public function getDefaultType(): ?string
{
return $this->defaultType;
}
}

if (!class_exists(\Symfony\Component\Serializer\Annotation\DiscriminatorMap::class, false)) {
Expand Down
1 change: 1 addition & 0 deletionssrc/Symfony/Component/Serializer/CHANGELOG.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@ CHANGELOG
* Deprecate the `CompiledClassMetadataFactory` and `CompiledClassMetadataCacheWarmer` classes
* Register `NormalizerInterface` and `DenormalizerInterface` aliases for named serializers
* Add `NumberNormalizer` to normalize `BcMath\Number` and `GMP` as `string`
* Add `defaultType` to `DiscriminatorMap`

7.2
---
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,7 @@ class ClassDiscriminatorMapping
public function __construct(
private readonly string $typeProperty,
private array $typesMapping = [],
private readonly ?string $defaultType = null,
) {
uasort($this->typesMapping, static function (string $a, string $b): int {
if (is_a($a, $b, true)) {
Expand DownExpand Up@@ -61,4 +62,9 @@ public function getTypesMapping(): array
{
return $this->typesMapping;
}

public function getDefaultType(): ?string
{
return $this->defaultType;
}
}
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,6 +55,7 @@ private function generateDeclaredClassMetadata(array $classMetadatas): string
$classDiscriminatorMapping = $classMetadata->getClassDiscriminatorMapping() ? [
$classMetadata->getClassDiscriminatorMapping()->getTypeProperty(),
$classMetadata->getClassDiscriminatorMapping()->getTypesMapping(),
$classMetadata->getClassDiscriminatorMapping()->getDefaultType(),
] : null;

$compiled .= \sprintf("\n'%s' => %s,", $classMetadata->getName(), VarExporter::export([
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -59,7 +59,7 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool

foreach ($this->loadAttributes($reflectionClass) as $attribute) {
match (true) {
$attribute instanceof DiscriminatorMap => $classMetadata->setClassDiscriminatorMapping(new ClassDiscriminatorMapping($attribute->getTypeProperty(), $attribute->getMapping())),
$attribute instanceof DiscriminatorMap => $classMetadata->setClassDiscriminatorMapping(new ClassDiscriminatorMapping($attribute->getTypeProperty(), $attribute->getMapping(), $attribute->getDefaultType())),
$attribute instanceof Groups => $classGroups = $attribute->getGroups(),
$attribute instanceof Context => $classContextAttribute = $attribute,
default => null,
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -107,7 +107,8 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool

$classMetadata->setClassDiscriminatorMapping(new ClassDiscriminatorMapping(
(string) $xml->{'discriminator-map'}->attributes()->{'type-property'},
$mapping
$mapping,
$xml->{'discriminator-map'}->attributes()->{'default-type'} ?? null
));
}

Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -133,7 +133,8 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata): bool

$classMetadata->setClassDiscriminatorMapping(new ClassDiscriminatorMapping(
$yaml['discriminator_map']['type_property'],
$yaml['discriminator_map']['mapping']
$yaml['discriminator_map']['mapping'],
$yaml['discriminator_map']['default_type'] ?? null
));
}

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,6 +47,7 @@
<xsd:element name="mapping" type="discriminator-map-mapping" maxOccurs="unbounded" />
</xsd:choice>
<xsd:attribute name="type-property" type="xsd:string" use="required" />
<xsd:attribute name="default-type" type="xsd:string" />
</xsd:complexType>

<xsd:complexType name="discriminator-map-mapping">
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1179,7 +1179,7 @@ private function getMappedClass(array $data, string $class, array $context): str
return $class;
}

if (null === $type = $data[$mapping->getTypeProperty()] ??null) {
if (null === $type = $data[$mapping->getTypeProperty()] ??$mapping->getDefaultType()) {
throw NotNormalizableValueException::createForUnexpectedDataType(\sprintf('Type property "%s" not found for the abstract object "%s".', $mapping->getTypeProperty(), $class), null, ['string'], isset($context['deserialization_path']) ? $context['deserialization_path'].'.'.$mapping->getTypeProperty() : $mapping->getTypeProperty(), false);
}

Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,9 +40,16 @@ public function testExceptionWithEmptyTypeProperty()
new DiscriminatorMap(typeProperty: '', mapping: ['foo' => 'FooClass']);
}

public functiontestExceptionWitEmptyMappingProperty()
public functiontestExceptionWithEmptyMappingProperty()
{
$this->expectException(InvalidArgumentException::class);
new DiscriminatorMap(typeProperty: 'type', mapping: []);
}

public function testExceptionWithMissingDefaultTypeInMapping()
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(sprintf('Default type "bar" given to "%s" must be present in "mapping" types.', DiscriminatorMap::class));
new DiscriminatorMap(typeProperty: 'type', mapping: ['foo' => 'FooClass'], defaultType: 'bar');
}
}
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,7 +17,7 @@
'first' => AbstractDummyFirstChild::class,
'second' => AbstractDummySecondChild::class,
'third' => AbstractDummyThirdChild::class,
])]
], defaultType: 'third')]
abstract class AbstractDummy
{
public $foo;
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,7 +35,7 @@
</class>

<class name="Symfony\Component\Serializer\Tests\Fixtures\Attributes\AbstractDummy">
<discriminator-map type-property="type">
<discriminator-map type-property="type" default-type="second">
<mapping type="first" class="Symfony\Component\Serializer\Tests\Fixtures\Attributes\AbstractDummyFirstChild" />
<mapping type="second" class="Symfony\Component\Serializer\Tests\Fixtures\Attributes\AbstractDummySecondChild" />
</discriminator-map>
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,6 +32,7 @@
mapping:
first: 'Symfony\Component\Serializer\Tests\Fixtures\Attributes\AbstractDummyFirstChild'
second: 'Symfony\Component\Serializer\Tests\Fixtures\Attributes\AbstractDummySecondChild'
default_type: first
attributes:
foo: ~
'Symfony\Component\Serializer\Tests\Fixtures\Attributes\IgnoreDummy':
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,6 +15,10 @@
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryCompiler;
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\AbstractDummy;
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\AbstractDummyFirstChild;
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\AbstractDummySecondChild;
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\AbstractDummyThirdChild;
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\MaxDepthDummy;
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\SerializedNameDummy;
use Symfony\Component\Serializer\Tests\Fixtures\Attributes\SerializedPathDummy;
Expand All@@ -40,13 +44,15 @@ public function testItDumpMetadata()
$classMetatadataFactory = new ClassMetadataFactory(new AttributeLoader());

$dummyMetadata = $classMetatadataFactory->getMetadataFor(Dummy::class);
$abstractDummyMetadata = $classMetatadataFactory->getMetadataFor(AbstractDummy::class);
$maxDepthDummyMetadata = $classMetatadataFactory->getMetadataFor(MaxDepthDummy::class);
$serializedNameDummyMetadata = $classMetatadataFactory->getMetadataFor(SerializedNameDummy::class);
$serializedPathDummyMetadata = $classMetatadataFactory->getMetadataFor(SerializedPathDummy::class);
$serializedPathInConstructorDummyMetadata = $classMetatadataFactory->getMetadataFor(SerializedPathInConstructorDummy::class);

$code = (new ClassMetadataFactoryCompiler())->compile([
$dummyMetadata,
$abstractDummyMetadata,
$maxDepthDummyMetadata,
$serializedNameDummyMetadata,
$serializedPathDummyMetadata,
Expand All@@ -56,7 +62,7 @@ public function testItDumpMetadata()
file_put_contents($this->dumpPath, $code);
$compiledMetadata = require $this->dumpPath;

$this->assertCount(5, $compiledMetadata);
$this->assertCount(6, $compiledMetadata);

$this->assertArrayHasKey(Dummy::class, $compiledMetadata);
$this->assertEquals([
Expand All@@ -69,6 +75,22 @@ public function testItDumpMetadata()
null,
], $compiledMetadata[Dummy::class]);

$this->assertArrayHasKey(AbstractDummy::class, $compiledMetadata);
$this->assertEquals([
[
'foo' => [[], null, null, null],
],
[
'type',
[
'first' => AbstractDummyFirstChild::class,
'second' => AbstractDummySecondChild::class,
'third' => AbstractDummyThirdChild::class,
],
'third',
],
], $compiledMetadata[AbstractDummy::class]);

$this->assertArrayHasKey(MaxDepthDummy::class, $compiledMetadata);
$this->assertEquals([
[
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -85,7 +85,7 @@ public function testLoadDiscriminatorMap()
'first' => AbstractDummyFirstChild::class,
'second' => AbstractDummySecondChild::class,
'third' => AbstractDummyThirdChild::class,
]));
], 'third'));

$expected->addAttributeMetadata(new AttributeMetadata('foo'));
$expected->getReflectionClass();
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -109,7 +109,7 @@ public function testLoadDiscriminatorMap()
$expected = new ClassMetadata(AbstractDummy::class, new ClassDiscriminatorMapping('type', [
'first' => AbstractDummyFirstChild::class,
'second' => AbstractDummySecondChild::class,
]));
], 'second'));

$expected->addAttributeMetadata(new AttributeMetadata('foo'));

Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -126,7 +126,7 @@ public function testLoadDiscriminatorMap()
$expected = new ClassMetadata(AbstractDummy::class, new ClassDiscriminatorMapping('type', [
'first' => AbstractDummyFirstChild::class,
'second' => AbstractDummySecondChild::class,
]));
], 'first'));

$expected->addAttributeMetadata(new AttributeMetadata('foo'));

Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -560,6 +560,41 @@ public function hasMetadataFor($value): bool
$this->assertInstanceOf(DummySecondChildQuux::class, $normalizedData->quux);
}

public function testDenormalizeWithDiscriminatorMapUsesCorrectClassnameWithDefaultType()
{
$factory = new ClassMetadataFactory(new AttributeLoader());

$loaderMock = new class implements ClassMetadataFactoryInterface {
public function getMetadataFor($value): ClassMetadataInterface
{
if (AbstractDummy::class === $value) {
return new ClassMetadata(
AbstractDummy::class,
new ClassDiscriminatorMapping('type', [
'first' => AbstractDummyFirstChild::class,
'second' => AbstractDummySecondChild::class,
], 'second')
);
}

throw new InvalidArgumentException(sprintf('"%s" is not handled.', $value));
}

public function hasMetadataFor($value): bool
{
return AbstractDummy::class === $value;
}
};

$discriminatorResolver = new ClassDiscriminatorFromClassMetadata($loaderMock);
$normalizer = new AbstractObjectNormalizerDummy($factory, null, new PhpDocExtractor(), $discriminatorResolver);
$serializer = new Serializer([$normalizer]);
$normalizer->setSerializer($serializer);
$normalizedData = $normalizer->denormalize(['foo' => 'foo', 'baz' => 'baz', 'quux' => ['value' => 'quux']], AbstractDummy::class);

$this->assertInstanceOf(DummySecondChildQuux::class, $normalizedData->quux);
}

public function testDenormalizeWithDiscriminatorMapAndObjectToPopulateUsesCorrectClassname()
{
$factory = new ClassMetadataFactory(new AttributeLoader());
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp