Skip to content

Commit d7d7bbc

Browse files
committed
added file support
1 parent 8c56741 commit d7d7bbc

File tree

13 files changed

+279
-15
lines changed

13 files changed

+279
-15
lines changed

app/V1Module/presenters/UploadedFilesPresenter.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
namespace App\V1Module\Presenters;
44

5+
use App\Helpers\MetaFormats\Attributes\File;
56
use App\Helpers\MetaFormats\Attributes\Post;
67
use App\Helpers\MetaFormats\Attributes\Query;
78
use App\Helpers\MetaFormats\Attributes\Path;
9+
use App\Helpers\MetaFormats\FileRequestType;
810
use App\Helpers\MetaFormats\Validators\VInt;
911
use App\Helpers\MetaFormats\Validators\VString;
1012
use App\Helpers\MetaFormats\Validators\VUuid;
@@ -321,6 +323,7 @@ public function checkUpload()
321323
* @throws CannotReceiveUploadedFileException
322324
* @throws InternalServerException
323325
*/
326+
#[File(FileRequestType::FormData, "The whole file to be uploaded")]
324327
public function actionUpload()
325328
{
326329
$user = $this->getCurrentUser();
@@ -440,6 +443,7 @@ public function checkAppendPartial(string $id)
440443
*/
441444
#[Query("offset", new VInt(), "Offset of the chunk for verification", required: true)]
442445
#[Path("id", new VUuid(), "Identifier of the partial file", required: true)]
446+
#[File(FileRequestType::OctetStream, "A chunk of the uploaded file")]
443447
public function actionAppendPartial(string $id, int $offset)
444448
{
445449
$partialFile = $this->uploadedPartialFiles->findOrThrow($id);

app/V1Module/presenters/base/BasePresenter.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ private function getValueFromParamData(RequestParamData $paramData): mixed
305305
return $this->getQueryField($paramData->name, required: $paramData->required);
306306
case Type::Path:
307307
return $this->getPathField($paramData->name);
308+
case Type::File:
309+
return $this->getFileField(required: $paramData->required);
308310
default:
309311
throw new InternalServerException("Unknown parameter type: {$paramData->type->name}");
310312
}
@@ -338,6 +340,25 @@ private function getPostField($param, $required = true)
338340
}
339341
}
340342

343+
private function getFileField($required = true)
344+
{
345+
$req = $this->getRequest();
346+
$files = $req->getFiles();
347+
348+
if (count($files) === 0) {
349+
if ($required) {
350+
throw new BadRequestException("No file was uploaded");
351+
} else {
352+
return null;
353+
}
354+
} elseif (count($files) > 1) {
355+
throw new BadRequestException("Too many files were uploaded");
356+
}
357+
358+
$file = array_pop($files);
359+
return $file;
360+
}
361+
341362
private function getQueryField($param, $required = true)
342363
{
343364
$value = $this->getRequest()->getParameter($param);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace App\Helpers\MetaFormats\Attributes;
4+
5+
use App\Helpers\MetaFormats\FileRequestType;
6+
use App\Helpers\MetaFormats\Type;
7+
use App\Helpers\MetaFormats\Validators\VFile;
8+
use Attribute;
9+
10+
/**
11+
* Attribute used to annotate format definition properties representing a file parameter.
12+
*/
13+
#[Attribute(Attribute::TARGET_PROPERTY)]
14+
class FFile extends FormatParameterAttribute
15+
{
16+
/**
17+
* @param FileRequestType $fileRequestType How will the file be transmitted in the request.
18+
* @param string $description The description of the request parameter.
19+
* @param bool $required Whether the request parameter is required.
20+
*/
21+
public function __construct(
22+
FileRequestType $fileRequestType,
23+
string $description = "",
24+
bool $required = true,
25+
) {
26+
parent::__construct(Type::File, new VFile($fileRequestType), $description, $required, false);
27+
}
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace App\Helpers\MetaFormats\Attributes;
4+
5+
use App\Helpers\MetaFormats\FileRequestType;
6+
use App\Helpers\MetaFormats\Type;
7+
use App\Helpers\MetaFormats\Validators\VFile;
8+
use Attribute;
9+
10+
/**
11+
* Attribute used to specify that an endpoint expects a file.
12+
*/
13+
#[Attribute(Attribute::TARGET_METHOD)]
14+
class File extends Param
15+
{
16+
/**
17+
* @param FileRequestType $fileRequestType How will the file be transmitted in the request.
18+
* @param string $description The description of the request parameter.
19+
* @param bool $required Whether the request parameter is required.
20+
*/
21+
public function __construct(
22+
FileRequestType $fileRequestType,
23+
string $description = "",
24+
bool $required = true,
25+
) {
26+
parent::__construct(Type::File, "file", new VFile($fileRequestType), $description, $required, false);
27+
}
28+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace App\Helpers\MetaFormats;
4+
5+
// @codingStandardsIgnoreStart
6+
/**
7+
* An enumeration of types how files can be transmitted.
8+
*/
9+
enum FileRequestType
10+
{
11+
case OctetStream;
12+
case FormData;
13+
}
14+
// @codingStandardsIgnoreEnd

app/helpers/MetaFormats/MetaFormatHelper.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace App\Helpers\MetaFormats;
44

55
use App\Exceptions\InternalServerException;
6+
use App\Helpers\MetaFormats\Attributes\FFile;
7+
use App\Helpers\MetaFormats\Attributes\File;
68
use App\Helpers\MetaFormats\Attributes\Format;
79
use App\Helpers\MetaFormats\Attributes\FormatParameterAttribute;
810
use App\Helpers\MetaFormats\Attributes\FPath;
@@ -50,8 +52,9 @@ public static function getEndpointAttributes(ReflectionMethod $reflectionMethod)
5052
$path = $reflectionMethod->getAttributes(name: Path::class);
5153
$query = $reflectionMethod->getAttributes(name: Query::class);
5254
$post = $reflectionMethod->getAttributes(name: Post::class);
55+
$file = $reflectionMethod->getAttributes(name: File::class);
5356
$param = $reflectionMethod->getAttributes(name: Param::class);
54-
return array_merge($path, $query, $post, $param);
57+
return array_merge($path, $query, $post, $file, $param);
5558
}
5659

5760
/**
@@ -91,7 +94,14 @@ public static function extractFormatParameterData(ReflectionProperty $reflection
9194
$pathAttributes = $reflectionObject->getAttributes(FPath::class);
9295
$queryAttributes = $reflectionObject->getAttributes(FQuery::class);
9396
$postAttributes = $reflectionObject->getAttributes(FPost::class);
94-
$requestAttributes = array_merge($longAttributes, $pathAttributes, $queryAttributes, $postAttributes);
97+
$fileAttributes = $reflectionObject->getAttributes(FFile::class);
98+
$requestAttributes = array_merge(
99+
$longAttributes,
100+
$pathAttributes,
101+
$queryAttributes,
102+
$postAttributes,
103+
$fileAttributes
104+
);
95105

96106
// there should be only one attribute
97107
if (count($requestAttributes) == 0) {

app/helpers/MetaFormats/RequestParamData.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use App\Exceptions\InvalidApiArgumentException;
77
use App\Helpers\MetaFormats\Validators\BaseValidator;
88
use App\Helpers\MetaFormats\Validators\VArray;
9+
use App\Helpers\MetaFormats\Validators\VFile;
910
use App\Helpers\MetaFormats\Validators\VObject;
1011
use App\Helpers\Swagger\AnnotationParameterData;
1112

@@ -143,6 +144,12 @@ public function toAnnotationParameterData()
143144
}, $nestedRequestParmData);
144145
}
145146

147+
// get file request type if file
148+
$fileRequestType = null;
149+
if ($this->validators[0] instanceof VFile) {
150+
$fileRequestType = $this->validators[0]->fileRequestType;
151+
}
152+
146153
return new AnnotationParameterData(
147154
$swaggerType,
148155
$this->name,
@@ -155,6 +162,7 @@ public function toAnnotationParameterData()
155162
$arrayDepth,
156163
$nestedObjectParameterData,
157164
$constraints,
165+
$fileRequestType,
158166
);
159167
}
160168
}

app/helpers/MetaFormats/Type.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ enum Type
1111
case Post;
1212
case Query;
1313
case Path;
14+
case File;
1415
}
1516
// @codingStandardsIgnoreEnd
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace App\Helpers\MetaFormats\Validators;
4+
5+
use App\Helpers\MetaFormats\FileRequestType;
6+
7+
/**
8+
* Validates files. Currently, all files are valid.
9+
*/
10+
class VFile extends BaseValidator
11+
{
12+
public const SWAGGER_TYPE = "string";
13+
public readonly FileRequestType $fileRequestType;
14+
15+
public function __construct(FileRequestType $fileRequestType)
16+
{
17+
parent::__construct(strict: false);
18+
$this->fileRequestType = $fileRequestType;
19+
}
20+
21+
public function validate(mixed $value): bool
22+
{
23+
return true;
24+
}
25+
}

0 commit comments

Comments
 (0)