@@ -214,7 +214,7 @@ private function processParams(ReflectionMethod $reflection)
214214 // use a method specialized for formats if there is a format available
215215 $ format = MetaFormatHelper::extractFormatFromAttribute ($ reflection );
216216 if ($ format !== null ) {
217- $ this ->processParamsFormat ($ format );
217+ $ this ->requestFormatInstance = $ this -> processParamsFormat ($ format, null );
218218 return ;
219219 }
220220
@@ -239,7 +239,18 @@ private function processParamsLoose(array $paramData)
239239 }
240240 }
241241
242- private function processParamsFormat (string $ format )
242+ /**
243+ * Processes parameters defined by a format. Request parameters are validated and a format instance with
244+ * parameter values created.
245+ * @param string $format The format defining the parameters.
246+ * @param ?array $valueDictionary If not null, a nested format instance will be created. The values will be taken
247+ * from here instead of the request object. Format validation ignores parameter type (path, query or post).
248+ * A top-level format will be created if null.
249+ * @throws \App\Exceptions\InternalServerException Thrown when the format definition is corrupted/absent.
250+ * @throws \App\Exceptions\BadRequestException Thrown when the request parameter values do not conform to the definition.
251+ * @return MetaFormat Returns a format instance with values filled from the request object.
252+ */
253+ private function processParamsFormat (string $ format , ?array $ valueDictionary ): MetaFormat
243254 {
244255 // get the parsed attribute data from the format fields
245256 $ formatToFieldDefinitionsMap = FormatCache::getFormatToFieldDefinitionsMap ();
@@ -250,15 +261,34 @@ private function processParamsFormat(string $format)
250261 // maps field names to their attribute data
251262 $ nameToFieldDefinitionsMap = $ formatToFieldDefinitionsMap [$ format ];
252263
253- ///TODO: handle nested MetaFormat creation
254264 $ formatInstance = MetaFormatHelper::createFormatInstance ($ format );
255265 foreach ($ nameToFieldDefinitionsMap as $ fieldName => $ requestParamData ) {
256- ///TODO: path parameters are not checked yet
257- if ($ requestParamData ->type == Type::Path) {
258- continue ;
266+ $ value = null ;
267+ // top-level format
268+ if ($ valueDictionary === null ) {
269+ ///TODO: path parameters are not checked yet
270+ if ($ requestParamData ->type == Type::Path) {
271+ continue ;
272+ }
273+
274+ $ value = $ this ->getValueFromParamData ($ requestParamData );
275+ // nested format
276+ } else {
277+ // Instead of retrieving the values with the getRequest call, use the provided $valueDictionary.
278+ // This makes the nested format ignore the parameter type (path, query, post) which is intended.
279+ // The data for this nested format cannot be spread across multiple param types, but it could be
280+ // if this was not a nested format but the top level format.
281+ if (array_key_exists ($ requestParamData ->name , $ valueDictionary )) {
282+ $ value = $ valueDictionary [$ requestParamData ->name ];
283+ }
259284 }
260285
261- $ value = $ this ->getValueFromParamData ($ requestParamData );
286+ // handle nested format creation
287+ // replace the value dictionary stored in $value with a format instance
288+ $ nestedFormatName = $ requestParamData ->getFormatName ();
289+ if ($ nestedFormatName !== null ) {
290+ $ value = $ this ->processParamsFormat ($ nestedFormatName , $ value );
291+ }
262292
263293 // this throws if the value is invalid
264294 $ formatInstance ->checkedAssign ($ fieldName , $ value );
@@ -269,7 +299,7 @@ private function processParamsFormat(string $format)
269299 throw new BadRequestException ("All request fields are valid but additional structural constraints failed. " );
270300 }
271301
272- $ this -> requestFormatInstance = $ formatInstance ;
302+ return $ formatInstance ;
273303 }
274304
275305 /**
0 commit comments