diff --git a/src/JsonSchema/DefinitionNameFactory.php b/src/JsonSchema/DefinitionNameFactory.php index f70f3a37a6f..2396f9424d5 100644 --- a/src/JsonSchema/DefinitionNameFactory.php +++ b/src/JsonSchema/DefinitionNameFactory.php @@ -44,9 +44,10 @@ public function create(string $className, string $format = 'json', ?string $inpu } if (null !== $inputOrOutputClass && $className !== $inputOrOutputClass) { - $parts = explode('\\', $inputOrOutputClass); - $shortName = end($parts); - $prefix .= self::GLUE.$shortName; + // Use createPrefixFromClass so DTOs with identical short names but different + // FQCNs (e.g. App\...\Input\ThingCreate and App\...\Output\ThingCreate) get + // disambiguated suffixes instead of overwriting each other in the schema map. + $prefix .= self::GLUE.$this->createPrefixFromClass($inputOrOutputClass); } // TODO: remove in 5.0 diff --git a/src/JsonSchema/Tests/DefinitionNameFactoryTest.php b/src/JsonSchema/Tests/DefinitionNameFactoryTest.php index 6257c4da70b..b297b8fae9f 100644 --- a/src/JsonSchema/Tests/DefinitionNameFactoryTest.php +++ b/src/JsonSchema/Tests/DefinitionNameFactoryTest.php @@ -15,8 +15,11 @@ use ApiPlatform\JsonSchema\DefinitionNameFactory; use ApiPlatform\JsonSchema\SchemaFactory; +use ApiPlatform\JsonSchema\Tests\Fixtures\DefinitionNameFactory\InputOutputCollision\Input\ThingCreate as InputThingCreate; +use ApiPlatform\JsonSchema\Tests\Fixtures\DefinitionNameFactory\InputOutputCollision\Output\ThingCreate as OutputThingCreate; use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\Operation; +use ApiPlatform\Metadata\Post; use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\DtoOutput; use ApiPlatform\Tests\Fixtures\TestBundle\Entity\Dummy; use PHPUnit\Framework\Attributes\DataProvider; @@ -146,6 +149,35 @@ public function testCreateDifferentPrefixesForClassesWithTheSameShortName(): voi ); } + public function testCreateDistinctDefinitionNamesWhenInputAndOutputShareShortName(): void + { + $definitionNameFactory = new DefinitionNameFactory(); + + $operation = new Post(class: Dummy::class, shortName: 'Thing'); + + $inputName = $definitionNameFactory->create( + Dummy::class, + 'jsonld', + InputThingCreate::class, + $operation, + ['schema_type' => \ApiPlatform\JsonSchema\Schema::TYPE_INPUT] + ); + + $outputName = $definitionNameFactory->create( + Dummy::class, + 'jsonld', + OutputThingCreate::class, + $operation, + ['schema_type' => \ApiPlatform\JsonSchema\Schema::TYPE_OUTPUT] + ); + + self::assertNotSame( + $inputName, + $outputName, + 'Input and Output DTO classes sharing the same short name must produce distinct definition names.' + ); + } + public function testCreateDifferentPrefixesForClassesWithTheSameOperationShortName(): void { $definitionNameFactory = new DefinitionNameFactory(); diff --git a/src/JsonSchema/Tests/Fixtures/DefinitionNameFactory/InputOutputCollision/Input/ThingCreate.php b/src/JsonSchema/Tests/Fixtures/DefinitionNameFactory/InputOutputCollision/Input/ThingCreate.php new file mode 100644 index 00000000000..c0b771c904d --- /dev/null +++ b/src/JsonSchema/Tests/Fixtures/DefinitionNameFactory/InputOutputCollision/Input/ThingCreate.php @@ -0,0 +1,18 @@ + + * + * 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\JsonSchema\Tests\Fixtures\DefinitionNameFactory\InputOutputCollision\Input; + +class ThingCreate +{ +} diff --git a/src/JsonSchema/Tests/Fixtures/DefinitionNameFactory/InputOutputCollision/Output/ThingCreate.php b/src/JsonSchema/Tests/Fixtures/DefinitionNameFactory/InputOutputCollision/Output/ThingCreate.php new file mode 100644 index 00000000000..acebe21f36d --- /dev/null +++ b/src/JsonSchema/Tests/Fixtures/DefinitionNameFactory/InputOutputCollision/Output/ThingCreate.php @@ -0,0 +1,18 @@ + + * + * 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\JsonSchema\Tests\Fixtures\DefinitionNameFactory\InputOutputCollision\Output; + +class ThingCreate +{ +}