Skip to content

Commit 1a371f8

Browse files
eceltovkrulis-martin
authored andcommitted
added support for nested formats
1 parent 049de89 commit 1a371f8

3 files changed

Lines changed: 95 additions & 8 deletions

File tree

app/V1Module/presenters/base/BasePresenter.php

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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
/**

app/helpers/MetaFormats/RequestParamData.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use App\Exceptions\InternalServerException;
66
use App\Exceptions\InvalidArgumentException;
77
use App\Helpers\MetaFormats\Validators\VArray;
8+
use App\Helpers\MetaFormats\Validators\VFormat;
89
use App\Helpers\Swagger\AnnotationParameterData;
910
use Exception;
1011

@@ -76,6 +77,23 @@ public function conformsToDefinition(mixed $value)
7677
}
7778
}
7879

80+
/**
81+
* Returns the format name if the parameter should be interpreted as a format and not as a primitive type.
82+
* @return ?string Returns the format name or null if the param represents a primitive type.
83+
*/
84+
public function getFormatName(): ?string
85+
{
86+
// all format params have to have a VFormat validator
87+
foreach ($this->validators as $validator) {
88+
if ($validator instanceof VFormat) {
89+
return $validator->format;
90+
}
91+
}
92+
93+
// return null for primitive types
94+
return null;
95+
}
96+
7997
private function hasValidators(): bool
8098
{
8199
if (is_array($this->validators)) {
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace App\Helpers\MetaFormats\Validators;
4+
5+
use App\Exceptions\InternalServerException;
6+
use App\Helpers\MetaFormats\FormatCache;
7+
use App\Helpers\MetaFormats\MetaFormat;
8+
9+
/**
10+
* Validates formats. Accepts any format derived of the base MetaFormat.
11+
* Format fields are validated by validators added to the fields.
12+
*/
13+
class VFormat
14+
{
15+
public const SWAGGER_TYPE = "object";
16+
public string $format;
17+
18+
public function __construct(string $format)
19+
{
20+
$this->format = $format;
21+
22+
// throw immediatelly if the format does not exist
23+
if (!FormatCache::formatExists($format)) {
24+
throw new InternalServerException("Format $format does not exist.");
25+
}
26+
}
27+
28+
public function getExampleValue()
29+
{
30+
///TODO
31+
return "0";
32+
}
33+
34+
public function validate(mixed $value)
35+
{
36+
// fine-grained checking is done in the properties
37+
return $value instanceof MetaFormat;
38+
}
39+
}

0 commit comments

Comments
 (0)