diff --git a/src/Tempest/Http/src/IsRequest.php b/src/Tempest/Http/src/IsRequest.php index 55f4eeeff..8631c1f2e 100644 --- a/src/Tempest/Http/src/IsRequest.php +++ b/src/Tempest/Http/src/IsRequest.php @@ -27,6 +27,7 @@ public function __construct( ) { $this->path ??= $this->resolvePath(); $this->query ??= $this->resolveQuery(); + $this->files ??= []; } public function get(string $key, mixed $default = null): mixed diff --git a/src/Tempest/Http/src/Mappers/PsrRequestToRequestMapper.php b/src/Tempest/Http/src/Mappers/PsrRequestToRequestMapper.php index 7e8e40981..c66ae5399 100644 --- a/src/Tempest/Http/src/Mappers/PsrRequestToRequestMapper.php +++ b/src/Tempest/Http/src/Mappers/PsrRequestToRequestMapper.php @@ -54,6 +54,7 @@ public function map(mixed $from, mixed $to): array|object 'query' => $query, 'files' => $uploads, ...$data, + ...$uploads, ])->to($requestClass); $validator = new Validator(); diff --git a/src/Tempest/Http/src/Mappers/RequestToPsrRequestMapper.php b/src/Tempest/Http/src/Mappers/RequestToPsrRequestMapper.php index cb5baecde..40476aba6 100644 --- a/src/Tempest/Http/src/Mappers/RequestToPsrRequestMapper.php +++ b/src/Tempest/Http/src/Mappers/RequestToPsrRequestMapper.php @@ -27,6 +27,7 @@ public function map(mixed $from, mixed $to): PsrRequest cookieParams: $from->getCookies(), queryParams: $from->getQuery(), parsedBody: $from->getBody(), + uploadedFiles: $from->getFiles() ); } } diff --git a/src/Tempest/Mapper/src/Mappers/ArrayToObjectMapper.php b/src/Tempest/Mapper/src/Mappers/ArrayToObjectMapper.php index dfce572eb..78f59d84f 100644 --- a/src/Tempest/Mapper/src/Mappers/ArrayToObjectMapper.php +++ b/src/Tempest/Mapper/src/Mappers/ArrayToObjectMapper.php @@ -160,9 +160,9 @@ private function resolveValueFromArray( $caster = $this->casterFactory->forProperty($property); - foreach ($data as $item) { + foreach ($data as $key => $item) { if (! is_array($item)) { - $values[] = $caster?->cast($item) ?? $item; + $values[$key] = $caster?->cast($item) ?? $item; continue; } diff --git a/tests/Fixtures/Modules/Books/Requests/CreateBookRequest.php b/tests/Fixtures/Modules/Books/Requests/CreateBookRequest.php index 245cb9d9d..48db7fc94 100644 --- a/tests/Fixtures/Modules/Books/Requests/CreateBookRequest.php +++ b/tests/Fixtures/Modules/Books/Requests/CreateBookRequest.php @@ -6,10 +6,13 @@ use Tempest\Http\IsRequest; use Tempest\Http\Request; +use Tempest\Http\Upload; final class CreateBookRequest implements Request { use IsRequest; public string $title; + + public Upload $cover; } diff --git a/tests/Integration/Mapper/PsrRequestToRequestMapperTest.php b/tests/Integration/Mapper/PsrRequestToRequestMapperTest.php index 163a2d2b8..0a6c1f634 100644 --- a/tests/Integration/Mapper/PsrRequestToRequestMapperTest.php +++ b/tests/Integration/Mapper/PsrRequestToRequestMapperTest.php @@ -10,6 +10,8 @@ use Tempest\Http\Request; use Tempest\Http\Upload; use Tempest\Mapper\Exceptions\MissingValuesException; +use function Tempest\Support\arr; +use Tests\Tempest\Fixtures\Modules\Books\Requests\CreateBookRequest; use Tests\Tempest\Fixtures\Modules\Posts\PostRequest; use Tests\Tempest\Integration\FrameworkIntegrationTestCase; @@ -113,4 +115,32 @@ public function test_files(): void $this->assertSame('hello', $upload->getClientFilename()); $this->assertSame('application/octet-stream', $upload->getClientMediaType()); } + + public function test_map_upload_file_into_request_property(): void + { + $currentPath = __DIR__ . '/Fixtures/upload.txt'; + + $mapper = new PsrRequestToRequestMapper(); + + $psrRequest = $this->http->makePsrRequest( + uri: '/books', + body: ['title' => 'Timeline Taxi'], + files: ['cover' => new UploadedFile( + streamOrFile: $currentPath, + size: null, + errorStatus: UPLOAD_ERR_OK, + )] + ); + + $request = $mapper->map( + from: $psrRequest, + to: CreateBookRequest::class + ); + + $this->assertInstanceOf(CreateBookRequest::class, $request); + $this->assertInstanceOf(Upload::class, $request->cover); + + $this->assertEquals('cover', array_key_first($request->getFiles())); + $this->assertTrue(arr($request->getFiles())->isAssoc()); + } }