From 1c94f7858a376566391e68ab755cce926790a025 Mon Sep 17 00:00:00 2001 From: Maxcastel Date: Mon, 2 Mar 2026 15:10:41 +0100 Subject: [PATCH 1/6] test --- src/Serializer/AbstractItemNormalizer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Serializer/AbstractItemNormalizer.php b/src/Serializer/AbstractItemNormalizer.php index 7b141132aa..70f0c34854 100644 --- a/src/Serializer/AbstractItemNormalizer.php +++ b/src/Serializer/AbstractItemNormalizer.php @@ -478,11 +478,11 @@ protected function getAllowedAttributes(string|object $classOrObject, array $con $resourceClass = $this->resourceClassResolver->getResourceClass(null, $context['resource_class']); // fix for abstract classes and interfaces $options = $this->getFactoryOptions($context); - $propertyNames = $this->propertyNameCollectionFactory->create($resourceClass, $options); + $propertyNames = $this->propertyNameCollectionFactory->create($context['resource_class'], $options); $allowedAttributes = []; foreach ($propertyNames as $propertyName) { - $propertyMetadata = $this->propertyMetadataFactory->create($resourceClass, $propertyName, $options); + $propertyMetadata = $this->propertyMetadataFactory->create($context['resource_class'], $propertyName, $options); if ( $this->isAllowedAttribute($classOrObject, $propertyName, null, $context) From dcfcd494e8c1a000fe908bd5a6d42b944af2d6c8 Mon Sep 17 00:00:00 2001 From: Maxcastel Date: Mon, 2 Mar 2026 16:22:58 +0100 Subject: [PATCH 2/6] fix --- features/hal/table_inheritance.feature | 1 + features/main/table_inheritance.feature | 3 +++ 2 files changed, 4 insertions(+) diff --git a/features/hal/table_inheritance.feature b/features/hal/table_inheritance.feature index 55ef27b7ca..24b8929c81 100644 --- a/features/hal/table_inheritance.feature +++ b/features/hal/table_inheritance.feature @@ -75,6 +75,7 @@ Feature: Table inheritance "href": "/dummy_table_inheritances/2" } }, + "swaggerThanParent": true, "id": 2, "name": "Foobarbaz inheritance" } diff --git a/features/main/table_inheritance.feature b/features/main/table_inheritance.feature index 1c3617f5f9..77c2bf48a2 100644 --- a/features/main/table_inheritance.feature +++ b/features/main/table_inheritance.feature @@ -548,6 +548,9 @@ Feature: Table inheritance "type": "string", "pattern": "^single item$" }, + "bar": { + "type": ["string", "null"] + }, "fooz": { "type": "string", "pattern": "fooz" From a6aba0571cf783ef1872a53b6721991e4915259c Mon Sep 17 00:00:00 2001 From: Maxcastel Date: Tue, 3 Mar 2026 15:02:38 +0100 Subject: [PATCH 3/6] refactor --- src/Serializer/AbstractItemNormalizer.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Serializer/AbstractItemNormalizer.php b/src/Serializer/AbstractItemNormalizer.php index 70f0c34854..ff00bbf8b9 100644 --- a/src/Serializer/AbstractItemNormalizer.php +++ b/src/Serializer/AbstractItemNormalizer.php @@ -472,17 +472,17 @@ protected function extractAttributes(object $object, ?string $format = null, arr */ protected function getAllowedAttributes(string|object $classOrObject, array $context, bool $attributesAsString = false): array|bool { - if (!$this->resourceClassResolver->isResourceClass($context['resource_class'])) { + $contextResourceClass = $context['resource_class']; + if (!$this->resourceClassResolver->isResourceClass($contextResourceClass)) { return parent::getAllowedAttributes($classOrObject, $context, $attributesAsString); } - $resourceClass = $this->resourceClassResolver->getResourceClass(null, $context['resource_class']); // fix for abstract classes and interfaces $options = $this->getFactoryOptions($context); - $propertyNames = $this->propertyNameCollectionFactory->create($context['resource_class'], $options); + $propertyNames = $this->propertyNameCollectionFactory->create($contextResourceClass, $options); $allowedAttributes = []; foreach ($propertyNames as $propertyName) { - $propertyMetadata = $this->propertyMetadataFactory->create($context['resource_class'], $propertyName, $options); + $propertyMetadata = $this->propertyMetadataFactory->create($contextResourceClass, $propertyName, $options); if ( $this->isAllowedAttribute($classOrObject, $propertyName, null, $context) From 710c96aec3db4b428db7653ae70cff36a9d86720 Mon Sep 17 00:00:00 2001 From: Maxcastel Date: Wed, 4 Mar 2026 11:07:17 +0100 Subject: [PATCH 4/6] AbstractItemNormalizerTest + entities --- .../Tests/AbstractItemNormalizerTest.php | 171 +++++++++++++++++- .../TestBundle/Entity/Polymorphism/Author.php | 52 ++++++ .../TestBundle/Entity/Polymorphism/Book.php | 95 ++++++++++ .../Entity/Polymorphism/FictionBook.php | 67 +++++++ .../Entity/Polymorphism/TechnicalBook.php | 84 +++++++++ 5 files changed, 468 insertions(+), 1 deletion(-) create mode 100644 tests/Fixtures/TestBundle/Entity/Polymorphism/Author.php create mode 100644 tests/Fixtures/TestBundle/Entity/Polymorphism/Book.php create mode 100644 tests/Fixtures/TestBundle/Entity/Polymorphism/FictionBook.php create mode 100644 tests/Fixtures/TestBundle/Entity/Polymorphism/TechnicalBook.php diff --git a/src/Serializer/Tests/AbstractItemNormalizerTest.php b/src/Serializer/Tests/AbstractItemNormalizerTest.php index 4926681433..48e6572b50 100644 --- a/src/Serializer/Tests/AbstractItemNormalizerTest.php +++ b/src/Serializer/Tests/AbstractItemNormalizerTest.php @@ -43,6 +43,10 @@ use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\PropertyCollectionIriOnlyRelation; use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\RelatedDummy; use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\SecuredDummy; +use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism\Author; +use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism\Book; +use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism\FictionBook; +use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism\TechnicalBook; use Doctrine\Common\Collections\ArrayCollection; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\TestCase; @@ -1979,6 +1983,171 @@ public function testDenormalizeReportsAllMissingConstructorArguments(): void $this->assertSame(['title', 'rating', 'comment'], $e->getMissingConstructorArguments()); } } + + public function testNormalizePolymorphicFictionBook(): void + { + $author = new Author(); + $author->setName('author name'); + + $fictionBook = new FictionBook(); + $fictionBook->setTitle('The Hobbit'); + $fictionBook->setAuthor($author); + $fictionBook->setIsbn('978-0-345-33312-1'); + $fictionBook->setGenre('Fantasy'); + $fictionBook->setPageCount(310); + + $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); + $propertyNameCollectionFactoryProphecy->create(FictionBook::class, Argument::type('array'))->willReturn(new PropertyNameCollection(['title', 'author', 'isbn', 'bookType', 'genre', 'pageCount'])); + + $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); + + if (!method_exists(PropertyInfoExtractor::class, 'getType')) { + $stringType = new LegacyType(LegacyType::BUILTIN_TYPE_STRING); + $intType = new LegacyType(LegacyType::BUILTIN_TYPE_INT); + $authorType = new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Author::class); + + $propertyMetadataFactoryProphecy->create(FictionBook::class, 'title', Argument::type('array'))->willReturn((new ApiProperty())->withBuiltinTypes([$stringType])->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(FictionBook::class, 'author', Argument::type('array'))->willReturn((new ApiProperty())->withBuiltinTypes([$authorType])->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(FictionBook::class, 'isbn', Argument::type('array'))->willReturn((new ApiProperty())->withBuiltinTypes([$stringType])->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(FictionBook::class, 'bookType', Argument::type('array'))->willReturn((new ApiProperty())->withBuiltinTypes([$stringType])->withReadable(true)->withWritable(false)); + $propertyMetadataFactoryProphecy->create(FictionBook::class, 'genre', Argument::type('array'))->willReturn((new ApiProperty())->withBuiltinTypes([$stringType])->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(FictionBook::class, 'pageCount', Argument::type('array'))->willReturn((new ApiProperty())->withBuiltinTypes([$intType])->withReadable(true)->withWritable(true)); + } else { + $propertyMetadataFactoryProphecy->create(FictionBook::class, 'title', Argument::type('array'))->willReturn((new ApiProperty())->withNativeType(Type::string())->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(FictionBook::class, 'author', Argument::type('array'))->willReturn((new ApiProperty())->withNativeType(Type::object(Author::class))->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(FictionBook::class, 'isbn', Argument::type('array'))->willReturn((new ApiProperty())->withNativeType(Type::string())->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(FictionBook::class, 'bookType', Argument::type('array'))->willReturn((new ApiProperty())->withNativeType(Type::string())->withReadable(true)->withWritable(false)); + $propertyMetadataFactoryProphecy->create(FictionBook::class, 'genre', Argument::type('array'))->willReturn((new ApiProperty())->withNativeType(Type::string())->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(FictionBook::class, 'pageCount', Argument::type('array'))->willReturn((new ApiProperty())->withNativeType(Type::int())->withReadable(true)->withWritable(true)); + } + + $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); + $iriConverterProphecy->getIriFromResource($fictionBook, Argument::cetera())->willReturn('/books/1'); + $iriConverterProphecy->getIriFromResource($author, Argument::cetera())->willReturn('/authors/1'); + + $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class); + $propertyAccessorProphecy->getValue($fictionBook, 'title')->willReturn('The Hobbit'); + $propertyAccessorProphecy->getValue($fictionBook, 'author')->willReturn($author); + $propertyAccessorProphecy->getValue($fictionBook, 'isbn')->willReturn('978-0-345-33312-1'); + $propertyAccessorProphecy->getValue($fictionBook, 'bookType')->willReturn('fiction'); + $propertyAccessorProphecy->getValue($fictionBook, 'genre')->willReturn('Fantasy'); + $propertyAccessorProphecy->getValue($fictionBook, 'pageCount')->willReturn(310); + + $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); + $resourceClassResolverProphecy->getResourceClass(null, FictionBook::class)->willReturn(Book::class); + $resourceClassResolverProphecy->getResourceClass($fictionBook, null)->willReturn(FictionBook::class); + $resourceClassResolverProphecy->getResourceClass($author, Author::class)->willReturn(Author::class); + $resourceClassResolverProphecy->isResourceClass(FictionBook::class)->willReturn(true); + $resourceClassResolverProphecy->isResourceClass(Author::class)->willReturn(true); + + $serializerProphecy = $this->prophesize(SerializerInterface::class); + $serializerProphecy->willImplement(NormalizerInterface::class); + $serializerProphecy->normalize('The Hobbit', null, Argument::type('array'))->willReturn('The Hobbit'); + $serializerProphecy->normalize('/authors/1', null, Argument::type('array'))->willReturn('/authors/1'); + $serializerProphecy->normalize('978-0-345-33312-1', null, Argument::type('array'))->willReturn('978-0-345-33312-1'); + $serializerProphecy->normalize('fiction', null, Argument::type('array'))->willReturn('fiction'); + $serializerProphecy->normalize('Fantasy', null, Argument::type('array'))->willReturn('Fantasy'); + $serializerProphecy->normalize(310, null, Argument::type('array'))->willReturn(310); + + $normalizer = new class($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $iriConverterProphecy->reveal(), $resourceClassResolverProphecy->reveal(), $propertyAccessorProphecy->reveal(), null, null, [], null, null) extends AbstractItemNormalizer {}; + $normalizer->setSerializer($serializerProphecy->reveal()); + + $expected = [ + 'title' => 'The Hobbit', + 'author' => '/authors/1', + 'isbn' => '978-0-345-33312-1', + 'bookType' => 'fiction', + 'genre' => 'Fantasy', + 'pageCount' => 310, + ]; + $result = $normalizer->normalize($fictionBook, null, ['resources' => []]); + $this->assertSame($expected, $result); + } + + public function testNormalizePolymorphicTechnicalBook(): void + { + $author = new Author(); + $author->setName('author name'); + + $technicalBook = new TechnicalBook(); + $technicalBook->setTitle('Design Patterns'); + $technicalBook->setAuthor($author); + $technicalBook->setIsbn('978-0-201-63361-0'); + $technicalBook->setProgrammingLanguage('C++'); + $technicalBook->setDifficultyLevel('advanced'); + $technicalBook->setTopic('Software Design'); + + $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); + $propertyNameCollectionFactoryProphecy->create(TechnicalBook::class, Argument::type('array'))->willReturn(new PropertyNameCollection(['title', 'author', 'isbn', 'bookType', 'programmingLanguage', 'difficultyLevel', 'topic'])); + + $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); + + if (!method_exists(PropertyInfoExtractor::class, 'getType')) { + $stringType = new LegacyType(LegacyType::BUILTIN_TYPE_STRING); + $authorType = new LegacyType(LegacyType::BUILTIN_TYPE_OBJECT, false, Author::class); + + $propertyMetadataFactoryProphecy->create(TechnicalBook::class, 'title', Argument::type('array'))->willReturn((new ApiProperty())->withBuiltinTypes([$stringType])->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(TechnicalBook::class, 'author', Argument::type('array'))->willReturn((new ApiProperty())->withBuiltinTypes([$authorType])->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(TechnicalBook::class, 'isbn', Argument::type('array'))->willReturn((new ApiProperty())->withBuiltinTypes([$stringType])->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(TechnicalBook::class, 'bookType', Argument::type('array'))->willReturn((new ApiProperty())->withBuiltinTypes([$stringType])->withReadable(true)->withWritable(false)); + $propertyMetadataFactoryProphecy->create(TechnicalBook::class, 'programmingLanguage', Argument::type('array'))->willReturn((new ApiProperty())->withBuiltinTypes([$stringType])->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(TechnicalBook::class, 'difficultyLevel', Argument::type('array'))->willReturn((new ApiProperty())->withBuiltinTypes([$stringType])->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(TechnicalBook::class, 'topic', Argument::type('array'))->willReturn((new ApiProperty())->withBuiltinTypes([$stringType])->withReadable(true)->withWritable(true)); + } else { + $propertyMetadataFactoryProphecy->create(TechnicalBook::class, 'title', Argument::type('array'))->willReturn((new ApiProperty())->withNativeType(Type::string())->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(TechnicalBook::class, 'author', Argument::type('array'))->willReturn((new ApiProperty())->withNativeType(Type::object(Author::class))->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(TechnicalBook::class, 'isbn', Argument::type('array'))->willReturn((new ApiProperty())->withNativeType(Type::string())->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(TechnicalBook::class, 'bookType', Argument::type('array'))->willReturn((new ApiProperty())->withNativeType(Type::string())->withReadable(true)->withWritable(false)); + $propertyMetadataFactoryProphecy->create(TechnicalBook::class, 'programmingLanguage', Argument::type('array'))->willReturn((new ApiProperty())->withNativeType(Type::string())->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(TechnicalBook::class, 'difficultyLevel', Argument::type('array'))->willReturn((new ApiProperty())->withNativeType(Type::string())->withReadable(true)->withWritable(true)); + $propertyMetadataFactoryProphecy->create(TechnicalBook::class, 'topic', Argument::type('array'))->willReturn((new ApiProperty())->withNativeType(Type::string())->withReadable(true)->withWritable(true)); + } + + $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); + $iriConverterProphecy->getIriFromResource($technicalBook, Argument::cetera())->willReturn('/books/2'); + $iriConverterProphecy->getIriFromResource($author, Argument::cetera())->willReturn('/authors/1'); + + $propertyAccessorProphecy = $this->prophesize(PropertyAccessorInterface::class); + $propertyAccessorProphecy->getValue($technicalBook, 'title')->willReturn('Design Patterns'); + $propertyAccessorProphecy->getValue($technicalBook, 'author')->willReturn($author); + $propertyAccessorProphecy->getValue($technicalBook, 'isbn')->willReturn('978-0-201-63361-0'); + $propertyAccessorProphecy->getValue($technicalBook, 'bookType')->willReturn('technical'); + $propertyAccessorProphecy->getValue($technicalBook, 'programmingLanguage')->willReturn('C++'); + $propertyAccessorProphecy->getValue($technicalBook, 'difficultyLevel')->willReturn('advanced'); + $propertyAccessorProphecy->getValue($technicalBook, 'topic')->willReturn('Software Design'); + + $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class); + $resourceClassResolverProphecy->getResourceClass(null, TechnicalBook::class)->willReturn(Book::class); + $resourceClassResolverProphecy->getResourceClass($technicalBook, null)->willReturn(TechnicalBook::class); + $resourceClassResolverProphecy->getResourceClass($author, Author::class)->willReturn(Author::class); + $resourceClassResolverProphecy->isResourceClass(TechnicalBook::class)->willReturn(true); + $resourceClassResolverProphecy->isResourceClass(Author::class)->willReturn(true); + + $serializerProphecy = $this->prophesize(SerializerInterface::class); + $serializerProphecy->willImplement(NormalizerInterface::class); + $serializerProphecy->normalize('Design Patterns', null, Argument::type('array'))->willReturn('Design Patterns'); + $serializerProphecy->normalize('/authors/1', null, Argument::type('array'))->willReturn('/authors/1'); + $serializerProphecy->normalize('978-0-201-63361-0', null, Argument::type('array'))->willReturn('978-0-201-63361-0'); + $serializerProphecy->normalize('technical', null, Argument::type('array'))->willReturn('technical'); + $serializerProphecy->normalize('C++', null, Argument::type('array'))->willReturn('C++'); + $serializerProphecy->normalize('advanced', null, Argument::type('array'))->willReturn('advanced'); + $serializerProphecy->normalize('Software Design', null, Argument::type('array'))->willReturn('Software Design'); + + $normalizer = new class($propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), $iriConverterProphecy->reveal(), $resourceClassResolverProphecy->reveal(), $propertyAccessorProphecy->reveal(), null, null, [], null, null) extends AbstractItemNormalizer {}; + $normalizer->setSerializer($serializerProphecy->reveal()); + + $expected = [ + 'title' => 'Design Patterns', + 'author' => '/authors/1', + 'isbn' => '978-0-201-63361-0', + 'bookType' => 'technical', + 'programmingLanguage' => 'C++', + 'difficultyLevel' => 'advanced', + 'topic' => 'Software Design', + ]; + $result = $normalizer->normalize($technicalBook, null, ['resources' => []]); + $this->assertSame($expected, $result); + } } class ObjectWithBasicProperties @@ -2018,4 +2187,4 @@ class ObjectWithBasicProperties /** @var float */ public $floatNegInf; -} +} \ No newline at end of file diff --git a/tests/Fixtures/TestBundle/Entity/Polymorphism/Author.php b/tests/Fixtures/TestBundle/Entity/Polymorphism/Author.php new file mode 100644 index 0000000000..df3ab2b82f --- /dev/null +++ b/tests/Fixtures/TestBundle/Entity/Polymorphism/Author.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism; + +use ApiPlatform\Metadata\ApiResource; +use Doctrine\ORM\Mapping as ORM; + +#[ApiResource] +#[ORM\Entity] +class Author +{ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column(type: 'integer')] + private ?int $id = null; + + #[ORM\Column(type: 'string', length: 255)] + private string $name; + + public function __construct(string $name = '') + { + $this->name = $name; + } + + public function getId(): ?int + { + return $this->id; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): self + { + $this->name = $name; + + return $this; + } +} diff --git a/tests/Fixtures/TestBundle/Entity/Polymorphism/Book.php b/tests/Fixtures/TestBundle/Entity/Polymorphism/Book.php new file mode 100644 index 0000000000..e9c2d3118c --- /dev/null +++ b/tests/Fixtures/TestBundle/Entity/Polymorphism/Book.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism; + +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\GetCollection; +use Doctrine\ORM\Mapping as ORM; + +#[ApiResource( + operations: [ + new GetCollection(), + ], +)] +#[ORM\Entity] +#[ORM\InheritanceType('SINGLE_TABLE')] +#[ORM\DiscriminatorColumn(name: 'book_type', type: 'string')] +#[ORM\DiscriminatorMap([ + 'fiction' => FictionBook::class, + 'technical' => TechnicalBook::class, +])] +abstract class Book +{ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column(type: 'integer')] + private ?int $id = null; + + #[ORM\Column(type: 'string', length: 255)] + private string $title; + + #[ORM\ManyToOne(targetEntity: Author::class)] + #[ORM\JoinColumn(nullable: false)] + private Author $author; + + #[ORM\Column(type: 'string', length: 20)] + private string $isbn; + + public function __construct(string $title = '', ?Author $author = null, string $isbn = '') + { + $this->title = $title; + $this->author = $author ?? new Author('Unknown'); + $this->isbn = $isbn; + } + + public function getId(): ?int + { + return $this->id; + } + + public function getTitle(): string + { + return $this->title; + } + + public function setTitle(string $title): self + { + $this->title = $title; + return $this; + } + + public function getAuthor(): Author + { + return $this->author; + } + + public function setAuthor(Author $author): self + { + $this->author = $author; + return $this; + } + + public function getIsbn(): string + { + return $this->isbn; + } + + public function setIsbn(string $isbn): self + { + $this->isbn = $isbn; + return $this; + } + + abstract public function getBookType(): string; +} diff --git a/tests/Fixtures/TestBundle/Entity/Polymorphism/FictionBook.php b/tests/Fixtures/TestBundle/Entity/Polymorphism/FictionBook.php new file mode 100644 index 0000000000..3d257b3d1f --- /dev/null +++ b/tests/Fixtures/TestBundle/Entity/Polymorphism/FictionBook.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism; + +use Doctrine\ORM\Mapping as ORM; + +#[ORM\Entity] +class FictionBook extends Book +{ + public const string BOOK_TYPE = 'fiction'; + + #[ORM\Column(type: 'string', length: 100, nullable: true)] + private ?string $genre = null; + + #[ORM\Column(type: 'integer', nullable: true)] + private ?int $pageCount = null; + + public function __construct( + string $title = '', + ?Author $author = null, + string $isbn = '', + ?string $genre = null, + ?int $pageCount = null + ) { + parent::__construct($title, $author, $isbn); + $this->genre = $genre; + $this->pageCount = $pageCount; + } + + public function getBookType(): string + { + return self::BOOK_TYPE; + } + + public function getGenre(): ?string + { + return $this->genre; + } + + public function setGenre(?string $genre): self + { + $this->genre = $genre; + return $this; + } + + public function getPageCount(): ?int + { + return $this->pageCount; + } + + public function setPageCount(?int $pageCount): self + { + $this->pageCount = $pageCount; + return $this; + } +} diff --git a/tests/Fixtures/TestBundle/Entity/Polymorphism/TechnicalBook.php b/tests/Fixtures/TestBundle/Entity/Polymorphism/TechnicalBook.php new file mode 100644 index 0000000000..a84bde3dfa --- /dev/null +++ b/tests/Fixtures/TestBundle/Entity/Polymorphism/TechnicalBook.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism; + +use Doctrine\ORM\Mapping as ORM; + +#[ORM\Entity] +class TechnicalBook extends Book +{ + public const string BOOK_TYPE = 'technical'; + + #[ORM\Column(type: 'string', length: 100, nullable: true)] + private ?string $programmingLanguage = null; + + #[ORM\Column(type: 'string', length: 50, nullable: true)] + private ?string $difficultyLevel = null; + + #[ORM\Column(type: 'string', length: 255, nullable: true)] + private ?string $topic = null; + + public function __construct( + string $title = '', + ?Author $author = null, + string $isbn = '', + ?string $programmingLanguage = null, + ?string $difficultyLevel = null, + ?string $topic = null + ) { + parent::__construct($title, $author, $isbn); + $this->programmingLanguage = $programmingLanguage; + $this->difficultyLevel = $difficultyLevel; + $this->topic = $topic; + } + + public function getBookType(): string + { + return self::BOOK_TYPE; + } + + public function getProgrammingLanguage(): ?string + { + return $this->programmingLanguage; + } + + public function setProgrammingLanguage(?string $programmingLanguage): self + { + $this->programmingLanguage = $programmingLanguage; + return $this; + } + + public function getDifficultyLevel(): ?string + { + return $this->difficultyLevel; + } + + public function setDifficultyLevel(?string $difficultyLevel): self + { + $this->difficultyLevel = $difficultyLevel; + return $this; + } + + public function getTopic(): ?string + { + return $this->topic; + } + + public function setTopic(?string $topic): self + { + $this->topic = $topic; + + return $this; + } +} From f2364a4f10aa32995a0cf8c1622146d6325ca3ca Mon Sep 17 00:00:00 2001 From: Maxcastel Date: Wed, 4 Mar 2026 11:28:24 +0100 Subject: [PATCH 5/6] fix --- src/Serializer/Tests/AbstractItemNormalizerTest.php | 2 +- tests/Fixtures/TestBundle/Entity/Polymorphism/Book.php | 3 +++ .../Fixtures/TestBundle/Entity/Polymorphism/FictionBook.php | 6 ++++-- .../TestBundle/Entity/Polymorphism/TechnicalBook.php | 6 ++++-- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Serializer/Tests/AbstractItemNormalizerTest.php b/src/Serializer/Tests/AbstractItemNormalizerTest.php index 48e6572b50..2253266b2f 100644 --- a/src/Serializer/Tests/AbstractItemNormalizerTest.php +++ b/src/Serializer/Tests/AbstractItemNormalizerTest.php @@ -2187,4 +2187,4 @@ class ObjectWithBasicProperties /** @var float */ public $floatNegInf; -} \ No newline at end of file +} diff --git a/tests/Fixtures/TestBundle/Entity/Polymorphism/Book.php b/tests/Fixtures/TestBundle/Entity/Polymorphism/Book.php index e9c2d3118c..96d08f3a6a 100644 --- a/tests/Fixtures/TestBundle/Entity/Polymorphism/Book.php +++ b/tests/Fixtures/TestBundle/Entity/Polymorphism/Book.php @@ -66,6 +66,7 @@ public function getTitle(): string public function setTitle(string $title): self { $this->title = $title; + return $this; } @@ -77,6 +78,7 @@ public function getAuthor(): Author public function setAuthor(Author $author): self { $this->author = $author; + return $this; } @@ -88,6 +90,7 @@ public function getIsbn(): string public function setIsbn(string $isbn): self { $this->isbn = $isbn; + return $this; } diff --git a/tests/Fixtures/TestBundle/Entity/Polymorphism/FictionBook.php b/tests/Fixtures/TestBundle/Entity/Polymorphism/FictionBook.php index 3d257b3d1f..09da81bcdd 100644 --- a/tests/Fixtures/TestBundle/Entity/Polymorphism/FictionBook.php +++ b/tests/Fixtures/TestBundle/Entity/Polymorphism/FictionBook.php @@ -18,7 +18,7 @@ #[ORM\Entity] class FictionBook extends Book { - public const string BOOK_TYPE = 'fiction'; + public const BOOK_TYPE = 'fiction'; #[ORM\Column(type: 'string', length: 100, nullable: true)] private ?string $genre = null; @@ -31,7 +31,7 @@ public function __construct( ?Author $author = null, string $isbn = '', ?string $genre = null, - ?int $pageCount = null + ?int $pageCount = null, ) { parent::__construct($title, $author, $isbn); $this->genre = $genre; @@ -51,6 +51,7 @@ public function getGenre(): ?string public function setGenre(?string $genre): self { $this->genre = $genre; + return $this; } @@ -62,6 +63,7 @@ public function getPageCount(): ?int public function setPageCount(?int $pageCount): self { $this->pageCount = $pageCount; + return $this; } } diff --git a/tests/Fixtures/TestBundle/Entity/Polymorphism/TechnicalBook.php b/tests/Fixtures/TestBundle/Entity/Polymorphism/TechnicalBook.php index a84bde3dfa..abc57a2289 100644 --- a/tests/Fixtures/TestBundle/Entity/Polymorphism/TechnicalBook.php +++ b/tests/Fixtures/TestBundle/Entity/Polymorphism/TechnicalBook.php @@ -18,7 +18,7 @@ #[ORM\Entity] class TechnicalBook extends Book { - public const string BOOK_TYPE = 'technical'; + public const BOOK_TYPE = 'technical'; #[ORM\Column(type: 'string', length: 100, nullable: true)] private ?string $programmingLanguage = null; @@ -35,7 +35,7 @@ public function __construct( string $isbn = '', ?string $programmingLanguage = null, ?string $difficultyLevel = null, - ?string $topic = null + ?string $topic = null, ) { parent::__construct($title, $author, $isbn); $this->programmingLanguage = $programmingLanguage; @@ -56,6 +56,7 @@ public function getProgrammingLanguage(): ?string public function setProgrammingLanguage(?string $programmingLanguage): self { $this->programmingLanguage = $programmingLanguage; + return $this; } @@ -67,6 +68,7 @@ public function getDifficultyLevel(): ?string public function setDifficultyLevel(?string $difficultyLevel): self { $this->difficultyLevel = $difficultyLevel; + return $this; } From 1c150de5986731b494a6b7be151448356406a417 Mon Sep 17 00:00:00 2001 From: Maxcastel Date: Wed, 4 Mar 2026 12:19:25 +0100 Subject: [PATCH 6/6] fix --- src/Serializer/Tests/AbstractItemNormalizerTest.php | 8 ++++---- .../Tests/Fixtures/Polymorphism/ApiResource}/Author.php | 2 +- .../Tests/Fixtures/Polymorphism/ApiResource}/Book.php | 4 +++- .../Tests/Fixtures/Polymorphism/Entity}/FictionBook.php | 4 +++- .../Tests/Fixtures/Polymorphism/Entity}/TechnicalBook.php | 4 +++- 5 files changed, 14 insertions(+), 8 deletions(-) rename {tests/Fixtures/TestBundle/Entity/Polymorphism => src/Serializer/Tests/Fixtures/Polymorphism/ApiResource}/Author.php (92%) rename {tests/Fixtures/TestBundle/Entity/Polymorphism => src/Serializer/Tests/Fixtures/Polymorphism/ApiResource}/Book.php (89%) rename {tests/Fixtures/TestBundle/Entity/Polymorphism => src/Serializer/Tests/Fixtures/Polymorphism/Entity}/FictionBook.php (86%) rename {tests/Fixtures/TestBundle/Entity/Polymorphism => src/Serializer/Tests/Fixtures/Polymorphism/Entity}/TechnicalBook.php (90%) diff --git a/src/Serializer/Tests/AbstractItemNormalizerTest.php b/src/Serializer/Tests/AbstractItemNormalizerTest.php index 2253266b2f..9fc8f3de6b 100644 --- a/src/Serializer/Tests/AbstractItemNormalizerTest.php +++ b/src/Serializer/Tests/AbstractItemNormalizerTest.php @@ -43,10 +43,10 @@ use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\PropertyCollectionIriOnlyRelation; use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\RelatedDummy; use ApiPlatform\Serializer\Tests\Fixtures\ApiResource\SecuredDummy; -use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism\Author; -use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism\Book; -use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism\FictionBook; -use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism\TechnicalBook; +use ApiPlatform\Serializer\Tests\Fixtures\Polymorphism\ApiResource\Author; +use ApiPlatform\Serializer\Tests\Fixtures\Polymorphism\ApiResource\Book; +use ApiPlatform\Serializer\Tests\Fixtures\Polymorphism\Entity\FictionBook; +use ApiPlatform\Serializer\Tests\Fixtures\Polymorphism\Entity\TechnicalBook; use Doctrine\Common\Collections\ArrayCollection; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\TestCase; diff --git a/tests/Fixtures/TestBundle/Entity/Polymorphism/Author.php b/src/Serializer/Tests/Fixtures/Polymorphism/ApiResource/Author.php similarity index 92% rename from tests/Fixtures/TestBundle/Entity/Polymorphism/Author.php rename to src/Serializer/Tests/Fixtures/Polymorphism/ApiResource/Author.php index df3ab2b82f..5bc79629a3 100644 --- a/tests/Fixtures/TestBundle/Entity/Polymorphism/Author.php +++ b/src/Serializer/Tests/Fixtures/Polymorphism/ApiResource/Author.php @@ -11,7 +11,7 @@ declare(strict_types=1); -namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism; +namespace ApiPlatform\Serializer\Tests\Fixtures\Polymorphism\ApiResource; use ApiPlatform\Metadata\ApiResource; use Doctrine\ORM\Mapping as ORM; diff --git a/tests/Fixtures/TestBundle/Entity/Polymorphism/Book.php b/src/Serializer/Tests/Fixtures/Polymorphism/ApiResource/Book.php similarity index 89% rename from tests/Fixtures/TestBundle/Entity/Polymorphism/Book.php rename to src/Serializer/Tests/Fixtures/Polymorphism/ApiResource/Book.php index 96d08f3a6a..96792ae1ab 100644 --- a/tests/Fixtures/TestBundle/Entity/Polymorphism/Book.php +++ b/src/Serializer/Tests/Fixtures/Polymorphism/ApiResource/Book.php @@ -11,10 +11,12 @@ declare(strict_types=1); -namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism; +namespace ApiPlatform\Serializer\Tests\Fixtures\Polymorphism\ApiResource; use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Serializer\Tests\Fixtures\Polymorphism\Entity\FictionBook; +use ApiPlatform\Serializer\Tests\Fixtures\Polymorphism\Entity\TechnicalBook; use Doctrine\ORM\Mapping as ORM; #[ApiResource( diff --git a/tests/Fixtures/TestBundle/Entity/Polymorphism/FictionBook.php b/src/Serializer/Tests/Fixtures/Polymorphism/Entity/FictionBook.php similarity index 86% rename from tests/Fixtures/TestBundle/Entity/Polymorphism/FictionBook.php rename to src/Serializer/Tests/Fixtures/Polymorphism/Entity/FictionBook.php index 09da81bcdd..2bc710a84c 100644 --- a/tests/Fixtures/TestBundle/Entity/Polymorphism/FictionBook.php +++ b/src/Serializer/Tests/Fixtures/Polymorphism/Entity/FictionBook.php @@ -11,8 +11,10 @@ declare(strict_types=1); -namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism; +namespace ApiPlatform\Serializer\Tests\Fixtures\Polymorphism\Entity; +use ApiPlatform\Serializer\Tests\Fixtures\Polymorphism\ApiResource\Author; +use ApiPlatform\Serializer\Tests\Fixtures\Polymorphism\ApiResource\Book; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] diff --git a/tests/Fixtures/TestBundle/Entity/Polymorphism/TechnicalBook.php b/src/Serializer/Tests/Fixtures/Polymorphism/Entity/TechnicalBook.php similarity index 90% rename from tests/Fixtures/TestBundle/Entity/Polymorphism/TechnicalBook.php rename to src/Serializer/Tests/Fixtures/Polymorphism/Entity/TechnicalBook.php index abc57a2289..b259a32d22 100644 --- a/tests/Fixtures/TestBundle/Entity/Polymorphism/TechnicalBook.php +++ b/src/Serializer/Tests/Fixtures/Polymorphism/Entity/TechnicalBook.php @@ -11,8 +11,10 @@ declare(strict_types=1); -namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Polymorphism; +namespace ApiPlatform\Serializer\Tests\Fixtures\Polymorphism\Entity; +use ApiPlatform\Serializer\Tests\Fixtures\Polymorphism\ApiResource\Author; +use ApiPlatform\Serializer\Tests\Fixtures\Polymorphism\ApiResource\Book; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity]