مرور اکشن بهینهسازی تصویر قابل استفاده مجدد0:00
If we only do this optimization in one place, I guess it's okay to have this in our PuppyController in the store method, but we might want to do it in other places. And actually we already kind of want to the CD images that we've looked at at the start of the lesson that are already a bit bigger than what we want. We probably want to run them through the same image optimization when we seed the data with the images.
Creating Image Action0:18
through the same image optimization when we seed the data with the images. So let's move that logic that we've just created in an action class. I will go php artisan make:class, and we want to place this in actions/ and let's call it OptimizeMyImageAction. Feel free to name it otherwise. Okay. We want our action to have one method. It's typically called handle or execute.
We want our action to have one method. It's typically called handle or execute. Here I'll go with handle. And so what we want our action to handle here is I guess to receive an image, scale it down if necessary, and then convert it to WebP and return that conversion. So maybe the action could be optimizeImage and convert to WebP action, but we'll keep it to that. So we will want to receive an image. And here, let's assume we always run
So we will want to receive an image. And here, let's assume we always run that function when we upload an image. So we can type it as UploadedFile from HTTP, and then we are going to copy a bunch of code. So here the uploaded image would be that. So we would pass that to the function. So we want to grab the read function, the scale and WebP export. And I think that this should leave outside the function.
and WebP export. And I think that this should leave outside the function because this is per case specific. We definitely don't want our image to always store in the puppies directory. So let's copy to this line and I will paste that code here. And so a couple of things. Let's call our parameter here, file instead to not get confused with the image. And then we need to import the Image facade. And so then we want to read that file.
And then we need to import the Image facade. And so then we want to read that file. I don't know why it's not auto imported, but let's use image and let's make sure it's the correct one. Laravel facades Image, that one. And so the action takes the file as the argument. And then we read this, we try to do the rescale and basically we return this. So this is going to be a web p file ified, and I'm sort of backpedaling on the action name.
So this is going to be a web P file ified, and I'm sort of backpedaling on the action name and I think maybe we can call it optimizeWebPImage action. So let's also change the file name here. optimizeWebPImage action. And I wanna do one more thing. I want to make sure, I wanna specify that we want a string return from that function. Alright, so let's go and see if we can use that optimizeWebPImage action.
Refactor Controller Upload2:54
Alright, so let's go and see if we can use that optimized WebP image action inside our PuppyController. All right, let's go and see if we can use this optimizeWebPImage action in our PuppyController. So at the top of the PuppyController, let's use optimizeWebPImage action, which is our freshly created action. And let's go down to the store method. So remember the action takes a file
And let's go down to the store method. So remember the action takes a file and returns an encoded webP image stream. So I think that we can delete all of that. And then we're going to keep the webEncoded variable because we wanna store the result of the action in there. And exactly like copilot suggests, we're going to initialize the action and call the handle method, passing it the file that it's expecting.
and call the handle method, passing it the file that it's expecting. Let's try this, huh? We could argue that we kind want the generation of the unique file name with the .webp extension in the function as well because we always going to need this. But let's first see if this works. I will save that file and we are going to upload one more time, Simon hoodie.
I will save that file and we are going to upload one more time, Simon hoodie. And we are going to select the image. Hopefully that still works and it sure looks like it does. And if we inspect the hoodie image, once again it should be around 114 kilobytes. Perfect. Alright, so as hinted just then, I think we should modify our action just a little bit. So it also gives us the file name with the WebP extension.
Return Filename and Data4:26
I think we should modify our action just a little bit. So it also gives us the file name with the WebP extension so we can grab the actual encoded data and the file name from that action. So let's go back into action and instead of returning a string, it's going to return an array. And so you can see that this now does not match the expected return type. So what we want to do is have an $uncoded variable.
the expected return type. So what we want to do is have an $webPiece variable that does not return but stores the web piece string. And then we want a file name. And basically we want to recreate this with a random string here so I can paste that and let's use that string helper. Okay. And now we can return both these things in an array return. Copilot is definitely going to know, well not quite,
array return. Copilot is definitely going to know, well not quite, we don't want the path here, but we want file name and I guess the encoded could be called webP string. Not sure if that's the optimal naming, but this should work. So you can see now that the array is satisfied. And so now here in the PuppyController in the store method, we can change our code a bit. Let's store this in optimized and then we're going to get rid
Let's store this in optimized and then we're going to get rid of this file name string random because this is done in the action. And as copilot suggests, we can now grab for the optimize bracket file name to construct a path. Let's accept that. And then when we try to store it, we will pass the web piece string returned from the action in the optimized variable like so. So that should still work,
returned from the action in the optimized $variable like so. So that should still work, but that means we don't have to create the file name manually anymore. So we can remove the import and also the Image facade. And so now our implementation is even a bit tighter. If we have an image upload, we try to optimize it with our action, we can then construct the path from the file name returned and try to store it in disk public by putting the path and the web piece string.
file name returned and try to store it in disc public by putting the path and the web piece string. Let's try it one more time. Simon Warm. Pretty warm in that hoodie. I can tell you that. And I'm gonna select this one more time and I am pretty confident that it is going to work again. And it does. Let's go. Alright, so with that abstraction in place, we should now go in the pu cedar where we generate nine puppies with an image
Apply Optimization in Seeder6:45
we should now go in the PuppySeeder where we generate uh, nine Puppy instances with an image and make sure that the image is also running through this optimization before being stored. I sort of forgot the setup, but let's go in the PuppySeeder. All right. And so here we actually not uh, uploading an image, we just have a file path or basically an existing file that is already stored. And that's a problem 'cause we've made the assumption that it would always be an uploaded file.
And that's a problem 'cause we've made the assumption that it would always be an uploaded file. So let's one more time slightly modify our function to receive a path instead. And that's going to be a string. And so we can update it here to path. And I believe that should still work fine because if I look at the Intervention Image docs for the read function, you can see that it can take a mixed input argument,
for the read function, you can see that it can take a mixed input argument, which can be a path in the file system or a lot of other things like an uploaded file. So we are now going to change it to be the path. And you know what? Because it is not really always a path, let's call that input, just like the actual package calls, the argument of the read function. Alright, that's probably better. Alright, so what we want to do here in a puppy seater,
Alright, that's probably better. Alright, so what we want to do here in a PuppySeeder, instead of just passing the path, we want to actually make an optimized WebP image and then store it and then pass that path to the creation of the Puppy. So before the foreach loop here, I will initialize a new optimizer by calling my OptimizeWebPImage action class. And then inside the foreach loop, before we create a Puppy, I wanna do a few things. I want to optimize the image, then I'm going to want
before we create a Puppy, I wanna do a few things. I want to optimize the image, then I'm going to want to store that image. And also we want to grab the path of the image. And the reason is we're going to set that path for the image URL here. Okay? So remember that to optimize an image, we need an input. And so we are going to do input equals, and here we'll pass the path to the image directly.
And so we are going to do input equals, and here we'll pass the path to the image directly. So we want the full path to the image for each puppy. And here we can use storage_path. And remember our images are in app/public/puppies. And then we can concatenate that with the puppy image, which is that field here. So basically that input should be storage/app/public/puppies/8.jpeg. And that is the input that we're going to pass.
public slash puppies slash eight.jpeg. And that is the input that we're going to pass to the image optimizer. So let's try to obtain an optimized image by calling the optimizerHandle function and passing the input path. Alright, next to store the image, I realize that we actually need first to grab the path because we need that to pass to the put method. And so let's construct a path for each image that is going
because we need that to pass to the put method. And so let's construct a path for each image that is going to be exactly what copilot suggests puppies, and then the random file name generated by the optimizer. And remember, this is exactly the same thing that we do in the PuppyController right here. Okay? And so now that we have the path and the optimized webp string, we can try to store that image. So stored equals, lemme scroll down a bit.
we can try to store that image. So $stored equals, lemme scroll down a bit. Once again, exactly like we've done before. Storage::disk('public'). And then we're going to try to put our image at the path defined here. So that procedure here is exactly the same than that procedure there in the PuppyController. And actually we don't need the $stored variable here. We should do some error handling, but
And actually we don't need the stored variable here. We should do some error handling, but because this is just a seeder, I'm fine with that here. And so the last thing that we need to change is the image URL here. Instead of being the path to the puppy image here, we are going to use our path instead, which remember is that here, let's reseed our database with php artisan migrate:fresh --seed.
Reseed and Verify Results10:40
with php, what migrate:fresh --seed. And hopefully it goes all right, it looks like it did. And so I should be logged out of the app and yes I am. And we should have all the seed puppies in place. As you can see, we have 14 pages, which indicates we have 109 puppies. Let's go verify that the images are actually generated as webp files. Let's check paisley here.
as web P files. Let's check paisley here. And yep, it's a web P file and you can see it's 200 kilobytes and let's check ginger next to it. Also web P and 223 kilobytes. And since we've changed our optimized web P image action to take an input string instead of an uploaded file, let's verify that we can still upload images. So I'll have to log in
let's verify that we can still upload images. So I'll have to log in and let's go to the bottom of the file and create one more test testy and we'll go with what we know. And hopefully we should still have a webp file that is 114 kilobytes and 1000 pixels wide. Let's verify this. And yes, we do, and I think this is super helpful because if a User happens to upload a five meg image, uh,
and I think this is super helpful because if a user happens to upload a five meg image, uh, we are gonna make sure that it's only a handful of kilobytes, maybe one, 200 max, which is a huge difference. So now user uploads will go through this, uh, action and also the seeds data. And so I'm pretty happy with that and we can finally move away from handling images. So let's keep going. See you in the next video.
and we can finally move away from handling images. So let's keep going. See you in the next video.
