@@ -1225,7 +1225,7 @@ public static function getMimeTypes(string $format): array
1225
1225
/**
1226
1226
* Gets the format associated with the mime type.
1227
1227
*/
1228
- public function getFormat (?string $ mimeType ): ?string
1228
+ public function getFormat (?string $ mimeType, bool $ subtypeFallback = false ): ?string
1229
1229
{
1230
1230
$ canonicalMimeType = null ;
1231
1231
if ($ mimeType && false !== $ pos = strpos ($ mimeType , '; ' )) {
@@ -1245,6 +1245,27 @@ public function getFormat(?string $mimeType): ?string
1245
1245
}
1246
1246
}
1247
1247
1248
+ if (!$ canonicalMimeType ) {
1249
+ $ canonicalMimeType = $ mimeType ;
1250
+ }
1251
+
1252
+ if (str_starts_with ($ canonicalMimeType , 'application/ ' ) && str_contains ($ canonicalMimeType , '+ ' )) {
1253
+ $ suffix = substr (strrchr ($ canonicalMimeType , '+ ' ), 1 );
1254
+ if (isset (static ::getStructuredSuffixFormats ()[$ suffix ])) {
1255
+ return static ::getStructuredSuffixFormats ()[$ suffix ];
1256
+ }
1257
+ }
1258
+
1259
+ if ($ subtypeFallback && str_contains ($ canonicalMimeType , '/ ' )) {
1260
+ [, $ subtype ] = explode ('/ ' , $ canonicalMimeType , 2 );
1261
+ if (str_starts_with ($ subtype , 'x- ' )) {
1262
+ $ subtype = substr ($ subtype , 2 );
1263
+ }
1264
+ if (!str_contains ($ subtype , '+ ' )) {
1265
+ return $ subtype ;
1266
+ }
1267
+ }
1268
+
1248
1269
return null ;
1249
1270
}
1250
1271
@@ -1917,6 +1938,41 @@ protected static function initializeFormats(): void
1917
1938
'atom ' => ['application/atom+xml ' ],
1918
1939
'rss ' => ['application/rss+xml ' ],
1919
1940
'form ' => ['application/x-www-form-urlencoded ' , 'multipart/form-data ' ],
1941
+ 'soap ' => ['application/soap+xml ' ],
1942
+ 'problem ' => ['application/problem+json ' ],
1943
+ 'hal ' => ['application/hal+json ' , 'application/hal+xml ' ],
1944
+ 'jsonapi ' => ['application/vnd.api+json ' ],
1945
+ 'yaml ' => ['text/yaml ' , 'application/x-yaml ' ],
1946
+ 'wbxml ' => ['application/vnd.wap.wbxml ' ],
1947
+ 'pdf ' => ['application/pdf ' ],
1948
+ 'csv ' => ['text/csv ' ],
1949
+ ];
1950
+ }
1951
+
1952
+ /**
1953
+ * Structured MIME suffix fallback formats
1954
+ *
1955
+ * This mapping is used when no exact MIME match is found in $formats.
1956
+ * It enables handling of types like application/soap+xml → 'xml'.
1957
+ *
1958
+ * @see https://datatracker.ietf.org/doc/html/rfc6839
1959
+ * @see https://datatracker.ietf.org/doc/html/rfc7303
1960
+ *
1961
+ * @return list<string>
1962
+ */
1963
+ private static function getStructuredSuffixFormats (): array
1964
+ {
1965
+ return [
1966
+ 'json ' => 'json ' ,
1967
+ 'xml ' => 'xml ' ,
1968
+ 'xhtml ' => 'html ' ,
1969
+ 'cbor ' => 'cbor ' ,
1970
+ 'zip ' => 'zip ' ,
1971
+ 'ber ' => 'asn1 ' ,
1972
+ 'der ' => 'asn1 ' ,
1973
+ 'tlv ' => 'tlv ' ,
1974
+ 'wbxml ' => 'xml ' ,
1975
+ 'yaml ' => 'yaml ' ,
1920
1976
];
1921
1977
}
1922
1978
0 commit comments