Skip to content

Commit b49cd29

Browse files
committed
Test a queued job can upload and resize an image
1 parent 4191243 commit b49cd29

File tree

9 files changed

+208
-9
lines changed

9 files changed

+208
-9
lines changed

app/Http/Controllers/MediaUploaderController.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,28 @@ public function download($filename)
9797
return response()->download($privateFilepath, $filename);
9898
}
9999

100+
public function uploader()
101+
{
102+
return view('upload.uploader');
103+
}
104+
100105
public function uploadAndResizing()
101106
{
107+
\request()->validate([
108+
'image' => ['required', 'mimes:jpg,png', 'max:1024'],
109+
]);
110+
102111
$image = request()->file('image');
103112

104113
if ($image instanceof UploadedFile) {
105114
ImageUploadAndResizingJob::dispatch($image->getMimeType(), base64_encode($image->getContent()))
106115
->delay(now()->addSeconds(5));
116+
117+
return redirect()->route('uploader')->with([
118+
'message' => 'Image upload and resizing may take few moments.'
119+
]);
107120
}
121+
122+
return redirect()->route('uploader')->with(['failed' => 'Could not upload the image.']);
108123
}
109124
}

app/Jobs/ImageUploadAndResizingJob.php

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,70 @@
88
use Illuminate\Foundation\Bus\Dispatchable;
99
use Illuminate\Queue\InteractsWithQueue;
1010
use Illuminate\Queue\SerializesModels;
11+
use Illuminate\Support\Facades\Storage;
12+
use Intervention\Image\Facades\Image;
1113

1214
class ImageUploadAndResizingJob implements ShouldQueue
1315
{
1416
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
1517

18+
public string $mimeType;
19+
20+
public string $imageContent;
21+
22+
public array $resolutions = [
23+
'50x50' => [50, 50],
24+
'640x480' => [640, 480],
25+
];
26+
1627
/**
1728
* Create a new job instance.
1829
*
1930
* @return void
2031
*/
21-
public function __construct()
32+
public function __construct(string $mimeType, string $imageContent)
2233
{
23-
//
34+
$this->mimeType = $mimeType;
35+
$this->imageContent = $imageContent;
2436
}
2537

2638
/**
2739
* Execute the job.
2840
*
29-
* @return void
41+
* @return array
3042
*/
3143
public function handle()
3244
{
33-
//
45+
$storage = Storage::disk('public');
46+
47+
$path = 'fake-image-name.jpg';
48+
49+
$storage->put($path, base64_decode($this->imageContent));
50+
51+
$paths = [];
52+
53+
foreach ($this->resolutions as $key => $resolution) {
54+
$image = Image::make($absolutePath = $storage->path($path))
55+
->resize($resolution[0], $resolution[1])
56+
->save($this->absolutePathWithResolutionKey($absolutePath, $key));
57+
58+
$paths[] = $image->basename;
59+
}
60+
61+
return $paths;
62+
}
63+
64+
/**
65+
* Modify an absolute path for renaming image name with resolution key
66+
*
67+
* @param string $absoluteFilePath
68+
* @param string $resolutionKey
69+
* @return string
70+
*/
71+
private function absolutePathWithResolutionKey(string $absoluteFilePath, string $resolutionKey)
72+
{
73+
[$path, $extension] = explode('.', $absoluteFilePath);
74+
75+
return $path . '-' . $resolutionKey . '.' . $extension;
3476
}
3577
}

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"laravel/framework": "^9.19",
1212
"laravel/sanctum": "^3.0",
1313
"laravel/tinker": "^2.7",
14-
"laravel/ui": "^4.1"
14+
"laravel/ui": "^4.1",
15+
"predis/predis": "^2.1"
1516
},
1617
"require-dev": {
1718
"fakerphp/faker": "^1.9.1",

composer.lock

Lines changed: 71 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/database.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@
121121

122122
'redis' => [
123123

124-
'client' => env('REDIS_CLIENT', 'phpredis'),
124+
'client' => env('REDIS_CLIENT', 'predis'),
125125

126126
'options' => [
127127
'cluster' => env('REDIS_CLUSTER', 'redis'),

resources/views/layouts/app.blade.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,15 @@
3030
<div class="collapse navbar-collapse" id="navbarSupportedContent">
3131
<!-- Left Side Of Navbar -->
3232
<ul class="navbar-nav me-auto">
33-
@if(\Illuminate\Support\Facades\Route::has('posts.index'))
33+
@if(Route::has('posts.index'))
3434
<a href="{{ route('posts.index') }}">{{ __('Posts') }}</a>
3535
@endif
36+
37+
&nbsp;&nbsp;
38+
39+
@if(Route::has('uploader'))
40+
<a href="{{ route('uploader') }}">{{ __('Uploader') }}</a>
41+
@endif
3642
</ul>
3743

3844
<!-- Right Side Of Navbar -->
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
@extends('layouts.app')
2+
3+
@section('content')
4+
<div class="container">
5+
<div class="row justify-content-center">
6+
<div class="col-md-8">
7+
<div class="card">
8+
<div class="card-header d-flex align-items-center justify-content-between">
9+
<div>{{ __('Image Uploader') }}</div>
10+
</div>
11+
12+
<div class="card-body">
13+
@if ($errors->any())
14+
<div class="alert alert-danger">
15+
<ul>
16+
@foreach ($errors->all() as $error)
17+
<li>{{ $error }}</li>
18+
@endforeach
19+
</ul>
20+
</div>
21+
@endif
22+
23+
@if (session('failed'))
24+
<div class="alert alert-warning">
25+
{{ session('failed') }}
26+
</div>
27+
@endif
28+
29+
@if (session('message'))
30+
<div class="alert alert-success">
31+
{{ session('message') }}
32+
</div>
33+
@endif
34+
35+
<form method="POST" action="{{ route('upload.resize.via.queue') }}" enctype="multipart/form-data" class="flex items-center space-x-6">
36+
@csrf
37+
38+
<div class="input-group">
39+
<input type="file" name="image" class="form-control" id="inputGroupFile04" aria-describedby="inputGroupFileAddon04" aria-label="Upload">
40+
<button class="btn btn-primary" type="submit" id="inputGroupFileAddon04">{{ __('Upload') }}</button>
41+
</div>
42+
</form>
43+
</div>
44+
</div>
45+
</div>
46+
</div>
47+
</div>
48+
@endsection

routes/web.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
Route::post('/upload/private', 'uploadPrivate')->name('upload.private');
6161

6262
Route::get('/upload/download/{filename}', 'download')->name('upload.download');
63+
64+
Route::get('/uploader', 'uploader')->name('uploader');
6365
});
6466

6567
Route::prefix('mailable')->group(function() {

tests/Feature/JobTest.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Illuminate\Foundation\Testing\WithFaker;
1010
use Illuminate\Http\UploadedFile;
1111
use Illuminate\Support\Facades\Queue;
12+
use Illuminate\Support\Facades\Storage;
1213
use Tests\TestCase;
1314

1415
class JobTest extends TestCase
@@ -23,7 +24,7 @@ public function a_job_is_dispatchable()
2324
$this->assertTrue(in_array(Dispatchable::class, $job->getTraitNames()));
2425

2526
$this->assertTrue(method_exists(
26-
app(ImageUploadAndResizingJob::class),
27+
app(ImageUploadAndResizingJob::class, ['mimeType' => 'image/jpeg', 'imageContent' => 'content']),
2728
'handle'
2829
));
2930
}
@@ -43,4 +44,18 @@ public function queue_api_can_be_instructed_to_dispatch_image_upload_and_resizin
4344

4445
Queue::assertPushed(ImageUploadAndResizingJob::class);
4546
}
47+
48+
/** @test */
49+
public function an_image_can_be_uploaded_and_resized_via_a_queued_job()
50+
{
51+
Storage::fake('public');
52+
53+
$image = UploadedFile::fake()
54+
->image('a-large-image.jpg', 1000, 1000) // Increase width and height to upload a large image
55+
->mimeType('image/jpeg');
56+
57+
$job = new ImageUploadAndResizingJob($image->getMimeType(), base64_encode($image->getContent()));
58+
59+
Storage::disk('public')->assertExists($job->handle());
60+
}
4661
}

0 commit comments

Comments
 (0)