Note I'm going to be using sudo code here.
There isn't much on Laracasts about handling images beyond beginner methods of just storing images to a public directory and storing the path in the DB.
Post example
Post Table
id|title|content|thumbnail
The post controller saves an image when a route hits the store method on the controller:
public function store(Request $request)
{
$post = new Post($request->all());
if ($post->img_path == ! null ) {
//Gets image type from url
$info = getimagesize($post->img_path);
$extension = image_type_to_extension($info[2]);
// Creates file name
$filename = str_slug($post->title, '-') . time() . $extension;
//Makes image
Image::make($post->img_path)->save(public_path('images/post-thumbnails/'.$filename));
//Saves new image path to DB
$post->img_path = $filename;
}
$post->save();
}
The problem is none of that is scalable. First I'm not taking advantage of the Laravel file storage system. This becomes problematic when wanting to swap from storing on your server to a CDN like S3.
The second problem is that it becomes hard to have one plan for how to deal with responsive images. Using just CSS can lead to scaling an image down which will use a lot of bandwidth.
It seems like there are a few methods you can use to deal with this. For example you could use srcset on image tags and render a different image for each media breaking point:
First Method
<img srcset="public/images/thumbnail-576.jpg 1x, public/images/thumbnail-768jpg 2x " alt="…
And then use a one to many relationship with post and a thumbnails table for each media breaking point:
Tailwind breaking points
- 576px
- 768px
- 992px
- 1200px;
Post Table
id|title|content|
Tumbnail Table
|post_id|thumbnail_path
PostController
public function store(Request $request)
{
$post = new Post($request->all());
if ($post->thumbnail == ! null ) {
//Gets image type from url
$info = getimagesize($post->thumbnail);
$extension = image_type_to_extension($info[2]);
// Creates file name
$filename = str_slug($post->title, '-') . time() . $extension;
//Makes image
$image = Image::make($post->thumbnail)
$image->save(public_path('images/post-thumbnails/'.$filename));
$image->resize(576, null)->save(public_path('images/post-thumbnails/576-'.$filename));
$image->resize(768, null)->save(public_path('images/post-thumbnails/768-'.$filename));
$image->resize(992, null)->save(public_path('images/post-thumbnails/992-'.$filename));
$image->resize(1200, null)->save(public_path('images/post-thumbnails/1200-'.$filename));
//Saves new image path to DB
Thumbnail:Create::(['post_id'=>$post->id, 'thumbnail_path'=> '576-'.$filename]);
Thumbnail:Create::(['post_id'=>$post->id, 'thumbnail_path'=> '768-'.$filename]);
Thumbnail:Create::(['post_id'=>$post->id, 'thumbnail_path'=> '992-'.$filename]);
Thumbnail:Create::(['post_id'=>$post->id, 'thumbnail_path'=> '1200-'.$filename]);
}
$post->save();
}
Note: I haven't started using the laravel filesytem yet
Second method
Is just store each image into their own directory:
$image = Image::make($post->thumbnail)
$image->save(public_path('images/post-thumbnails/'.$filename));
$image->resize(576, null)->save(public_path('images/post-thumbnails/576/'.$filename));
$image->resize(768, null)->save(public_path('images/post-thumbnails/768/'.$filename));
$image->resize(992, null)->save(public_path('images/post-thumbnails/992/'.$filename));
$image->resize(1200, null)->save(public_path('images/post-thumbnails/1200/'.$filename));
Third method
The last option is to do it on-demand, by routing the image URLs to a script that dissects the URL path, finds the right image, scales it on the fly, and serves the scaled version from memory.
I have no idea where to even begin with this method.
I would just absolutely love if there was a guide or Laravel lessons diving deeper into scalability like this. More specifically images, the file system, and responsive image output. I'm a total noob when it comes to this stuff.