@@ -21,6 +21,9 @@ final class DefinitionNameFactory implements DefinitionNameFactoryInterface
2121{
2222 use ResourceClassInfoTrait;
2323
24+ private const GLUE = '. ' ;
25+ private array $ prefixCache = [];
26+
2427 public function __construct (private ?array $ distinctFormats )
2528 {
2629 }
@@ -32,18 +35,18 @@ public function create(string $className, string $format = 'json', ?string $inpu
3235 }
3336
3437 if (!isset ($ prefix )) {
35- $ prefix = ( new \ ReflectionClass ( $ className ))-> getShortName ( );
38+ $ prefix = $ this -> createPrefixFromClass ( $ className );
3639 }
3740
3841 if (null !== $ inputOrOutputClass && $ className !== $ inputOrOutputClass ) {
3942 $ parts = explode ('\\' , $ inputOrOutputClass );
4043 $ shortName = end ($ parts );
41- $ prefix .= ' . ' .$ shortName ;
44+ $ prefix .= self :: GLUE .$ shortName ;
4245 }
4346
4447 if ('json ' !== $ format && ($ this ->distinctFormats [$ format ] ?? false )) {
4548 // JSON is the default, and so isn't included in the definition name
46- $ prefix .= ' . ' .$ format ;
49+ $ prefix .= self :: GLUE .$ format ;
4750 }
4851
4952 $ definitionName = $ serializerContext [SchemaFactory::OPENAPI_DEFINITION_NAME ] ?? null ;
@@ -61,4 +64,22 @@ private function encodeDefinitionName(string $name): string
6164 {
6265 return preg_replace ('/[^a-zA-Z0-9.\-_]/ ' , '. ' , $ name );
6366 }
67+
68+ private function createPrefixFromClass (string $ fullyQualifiedClassName , int $ namespaceParts = 1 ): string
69+ {
70+ $ parts = explode ('\\' , $ fullyQualifiedClassName );
71+ $ name = implode (self ::GLUE , \array_slice ($ parts , -$ namespaceParts ));
72+
73+ if (!isset ($ this ->prefixCache [$ name ])) {
74+ $ this ->prefixCache [$ name ] = $ fullyQualifiedClassName ;
75+
76+ return $ name ;
77+ }
78+
79+ if ($ this ->prefixCache [$ name ] !== $ fullyQualifiedClassName ) {
80+ $ name = $ this ->createPrefixFromClass ($ fullyQualifiedClassName , ++$ namespaceParts );
81+ }
82+
83+ return $ name ;
84+ }
6485}
0 commit comments