Skip to content

Commit 5c474ab

Browse files
committed
Support for nested request data when using the ConvertsBase64ToFiles trait
2 parents 574bea9 + 41d521e commit 5c474ab

File tree

3 files changed

+121
-7
lines changed

3 files changed

+121
-7
lines changed

README.md

+19
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,25 @@ $jpgFile = $request->file('jpg_image');
324324
$jpgFile->getClientOriginalName();
325325
```
326326

327+
This trait supports nested data as well. You can either reference the keys by a nested array, or with a [dotted notation](https://laravel.com/docs/master/helpers#method-array-dot):
328+
329+
```php
330+
class ImageRequest extends FormRequest
331+
{
332+
use ConvertsBase64ToFiles;
333+
334+
protected function base64FileKeys(): array
335+
{
336+
return [
337+
'company.logo' => 'Logo.jpg',
338+
'user' => [
339+
'avatar' => 'Avatar.jpg',
340+
],
341+
];
342+
}
343+
}
344+
```
345+
327346
Want to know more about this trait? Check out the [blog post](https://protone.media/blog/convert-and-store-base64-encoded-files-in-laravel-use-validation-rules-and-access-the-decoded-files-from-the-request-instance).
328347

329348
### Testing

src/Request/ConvertsBase64ToFiles.php

+33-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
namespace ProtoneMedia\LaravelMixins\Request;
44

55
use Illuminate\Http\UploadedFile;
6+
use Illuminate\Support\Arr;
67
use Illuminate\Support\Collection;
78
use Illuminate\Support\Str;
9+
use Symfony\Component\HttpFoundation\FileBag;
10+
use Symfony\Component\HttpFoundation\ParameterBag;
811

912
trait ConvertsBase64ToFiles
1013
{
@@ -13,6 +16,26 @@ protected function base64FileKeys(): array
1316
return [];
1417
}
1518

19+
/**
20+
* Helper method to get the body parameters bag.
21+
*
22+
* @return \Symfony\Component\HttpFoundation\ParameterBag
23+
*/
24+
private function bodyParametersBag(): ParameterBag
25+
{
26+
return $this->request;
27+
}
28+
29+
/**
30+
* Helper method to get the uploaded files bag.
31+
*
32+
* @return FileBag
33+
*/
34+
private function uploadFilesBag(): FileBag
35+
{
36+
return $this->files;
37+
}
38+
1639
/**
1740
* Pulls the Base64 contents for each image key and creates
1841
* an UploadedFile instance from it and sets it on the
@@ -22,7 +45,9 @@ protected function base64FileKeys(): array
2245
*/
2346
protected function prepareForValidation()
2447
{
25-
Collection::make($this->base64FileKeys())->each(function ($filename, $key) {
48+
$flattened = Arr::dot($this->base64FileKeys());
49+
50+
Collection::make($flattened)->each(function ($filename, $key) {
2651
rescue(function () use ($key, $filename) {
2752
$base64Contents = $this->input($key);
2853

@@ -48,8 +73,13 @@ protected function prepareForValidation()
4873

4974
$uploadedFile = new UploadedFile($tempFilePath, $filename, null, null, true);
5075

51-
$this->request->remove($key);
52-
$this->files->set($key, $uploadedFile);
76+
$body = $this->bodyParametersBag()->all();
77+
Arr::forget($body, $key);
78+
$this->bodyParametersBag()->replace($body);
79+
80+
$files = $this->uploadFilesBag()->all();
81+
Arr::set($files, $key, $uploadedFile);
82+
$this->uploadFilesBag()->replace($files);
5383
}, null, false);
5484
});
5585
}

tests/Request/ConvertsBase64ToFilesTest.php

+69-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace ProtoneMedia\Mixins\Tests\Request;
44

55
use Illuminate\Foundation\Http\FormRequest;
6+
use Illuminate\Routing\Redirector;
67
use Orchestra\Testbench\TestCase;
78
use ProtoneMedia\LaravelMixins\Request\ConvertsBase64ToFiles;
89
use ZipArchive;
@@ -28,6 +29,30 @@ public function rules()
2829
}
2930
}
3031

32+
class NestedImageRequest extends FormRequest
33+
{
34+
use ConvertsBase64ToFiles;
35+
36+
protected function base64FileKeys(): array
37+
{
38+
return [
39+
'company' => [
40+
'logo' => 'company_logo.jpeg',
41+
],
42+
43+
'user.avatar' => 'user_avatar.png',
44+
];
45+
}
46+
47+
public function rules()
48+
{
49+
return [
50+
'company.logo' => ['required', 'file', 'image'],
51+
'user.avatar' => ['required', 'file', 'image'],
52+
];
53+
}
54+
}
55+
3156
class ZipRequest extends FormRequest
3257
{
3358
use ConvertsBase64ToFiles;
@@ -49,6 +74,13 @@ public function rules()
4974

5075
class ConvertsBase64ToFilesTest extends TestCase
5176
{
77+
private function validateRequest(FormRequest $request)
78+
{
79+
$request->setContainer($this->app);
80+
$request->setRedirector($this->app->make(Redirector::class));
81+
$request->validateResolved();
82+
}
83+
5284
/** @test */
5385
public function it_converts_the_base64_images_to_illuminate_file_uploads()
5486
{
@@ -57,8 +89,7 @@ public function it_converts_the_base64_images_to_illuminate_file_uploads()
5789
'jpeg_image' => file_get_contents(__DIR__ . '/base64_jpeg'),
5890
]);
5991

60-
$request->setContainer($this->app);
61-
$request->validateResolved();
92+
$this->validateRequest($request);
6293

6394
$pngFile = $request->file('png_image');
6495
$jpegFile = $request->file('jpeg_image');
@@ -81,15 +112,49 @@ public function it_converts_the_base64_images_to_illuminate_file_uploads()
81112
$this->assertEquals('width="300" height="300"', $jpegSize[3]);
82113
}
83114

115+
/** @test */
116+
public function it_handles_nested_files()
117+
{
118+
$request = NestedImageRequest::create('/', 'POST', [
119+
'company' => [
120+
'logo' => file_get_contents(__DIR__ . '/base64_jpeg'),
121+
],
122+
'user' => [
123+
'avatar' => file_get_contents(__DIR__ . '/base64_png'),
124+
],
125+
]);
126+
127+
$this->validateRequest($request);
128+
129+
$pngFile = $request->file('user.avatar');
130+
$jpegFile = $request->file('company.logo');
131+
132+
$this->assertNotNull($pngFile);
133+
$this->assertNotNull($jpegFile);
134+
135+
$this->assertEquals($pngFile, $request->validated()['user']['avatar']);
136+
$this->assertEquals($jpegFile, $request->validated()['company']['logo']);
137+
138+
//
139+
140+
$pngSize = getimagesize($pngFile->getRealPath());
141+
$jpegSize = getimagesize($jpegFile->getRealPath());
142+
143+
$this->assertEquals('user_avatar.png', $pngFile->getClientOriginalName());
144+
$this->assertEquals('company_logo.jpeg', $jpegFile->getClientOriginalName());
145+
146+
$this->assertEquals('width="300" height="300"', $pngSize[3]);
147+
$this->assertEquals('width="300" height="300"', $jpegSize[3]);
148+
}
149+
84150
/** @test */
85151
public function it_converts_a_base64_zip_to_an_illuminate_file_upload()
86152
{
87153
$request = ZipRequest::create('/', 'POST', [
88154
'zip' => file_get_contents(__DIR__ . '/base64_zip'),
89155
]);
90156

91-
$request->setContainer($this->app);
92-
$request->validateResolved();
157+
$this->validateRequest($request);
93158

94159
$zipFile = $request->file('zip');
95160

0 commit comments

Comments
 (0)