2626use App \Responses \StorageFileResponse ;
2727use App \Responses \ZipFilesResponse ;
2828use Nette \Application \Application ;
29+ use Nette \Http \FileUpload ;
2930use Nette \Http \IResponse ;
3031use Tracy \ILogger ;
3132use ReflectionClass ;
@@ -213,7 +214,14 @@ private function processParams(ReflectionMethod $reflection)
213214 }
214215
215216 // handle loose parameters
216- $ paramData = MetaFormatHelper::extractRequestParamData ($ reflection );
217+
218+ // cache the data from the loose attributes to improve performance
219+ $ actionPath = get_class ($ this ) . $ reflection ->name ;
220+ if (!FormatCache::looseParametersCached ($ actionPath )) {
221+ $ newParamData = MetaFormatHelper::extractRequestParamData ($ reflection );
222+ FormatCache::cacheLooseParameters ($ actionPath , $ newParamData );
223+ }
224+ $ paramData = FormatCache::getLooseParameters ($ actionPath );
217225 $ this ->processParamsLoose ($ paramData );
218226 }
219227
@@ -279,7 +287,7 @@ private function processParamsFormat(string $format, ?array $valueDictionary): M
279287 }
280288
281289 // this throws if the value is invalid
282- $ formatInstance ->checkedAssign ( $ fieldName , $ value );
290+ $ formatInstance ->checkedAssignWithSchema ( $ requestParamData , $ fieldName , $ value );
283291 }
284292
285293 // validate structural constraints
@@ -305,6 +313,8 @@ private function getValueFromParamData(RequestParamData $paramData): mixed
305313 return $ this ->getQueryField ($ paramData ->name , required: $ paramData ->required );
306314 case Type::Path:
307315 return $ this ->getPathField ($ paramData ->name );
316+ case Type::File:
317+ return $ this ->getFileField (required: $ paramData ->required );
308318 default :
309319 throw new InternalServerException ("Unknown parameter type: {$ paramData ->type ->name }" );
310320 }
@@ -338,6 +348,30 @@ private function getPostField($param, $required = true)
338348 }
339349 }
340350
351+ /**
352+ * @param bool $required Whether the file field is required.
353+ * @throws BadRequestException Thrown when the number of files is not 1 (and the field is required).
354+ * @return FileUpload|null Returns a FileUpload object or null if the file was optional and not sent.
355+ */
356+ private function getFileField (bool $ required = true ): FileUpload | null
357+ {
358+ $ req = $ this ->getRequest ();
359+ $ files = $ req ->getFiles ();
360+
361+ if (count ($ files ) === 0 ) {
362+ if ($ required ) {
363+ throw new BadRequestException ("No file was uploaded " );
364+ } else {
365+ return null ;
366+ }
367+ } elseif (count ($ files ) > 1 ) {
368+ throw new BadRequestException ("Too many files were uploaded " );
369+ }
370+
371+ $ file = array_pop ($ files );
372+ return $ file ;
373+ }
374+
341375 private function getQueryField ($ param , $ required = true )
342376 {
343377 $ value = $ this ->getRequest ()->getParameter ($ param );
0 commit comments