Uploading files and images using Laravel Livewire in storage and in the public path

- Andrés Cruz

En español

File upload is nothing more than the term used to transfer or upload a file from a local device like a PC or smartphone to a server; in the case of Laravel, it would be the project in Laravel; this is always a very necessary feature to perform all kinds of operations such as uploading an avatar or image of the user, to upload personal files such as excels, pdfs or others...

Since this is a routine process, we are going to talk about how we can upload files or images, specifically the user's avatar using Laravel Livewire; for this we have to keep in mind some important points before going into detail about the development that we are going to carry out.

Livewire and the use of components

What is Laravel Livewire? It is nothing more than a package available for our Laravel as we mentioned before for the development of applications based on components that allow FullDuplex communication through websockets between the frontend and the backend; besides:

  1. Let's remember that ALL screens or at least most of them are based on components, instead of controllers.
  2. We have an existing user module with login, registration, retrieval and editing credentials for Livewire and this is thanks to JetStream.

Clarified the previous points, let's start.

We are going to create a component to perform operations on an entity called user; with this entity we want it to be able to upload or load files such as images or specifically the avatar, we have to use "multiple inheritance" in other words, using a trait that Livewire provides us in our component:

class SaveUser extends Component
{
    use WithFileUploads;
}

Validation rules

Now, how we are going to work with forms, we have to indicate the data that we are going to use, and with this its validation rules:

    protected $rules = [
        'name' => 'required|min:6',
        'email' => 'required|email|unique:users,email',
        'password' => 'required',
        'avatar' => 'Nullable|image|max:1024',
    ];

Nothing strange at this point, normal validations on text fields and what would be interesting would be the so-called avatar, which, as you can suppose and analyze the validations, we are going to use the same to validate the upload of images, that is, the user's avatar; in this field, we define typical, non-null, image, and maximum size.

Process the avatar or image of the user

When sending the http request through the form, we verify if we have the avatar, since it is NOT required and is completely optional, therefore, this step is optional and if you want it to be mandatory you can dispense with the conditional and place the required in the above rules:

public function submit()
    {
        // upload
        if($this->avatar){
            $imageName = $this->category->slug . '.' . $this->image->getClientOriginalExtension();
            $this->avatar->storeAs('images', $imageName,'public_upload');
    
            $this->category->update([
                'image'=> $imageName
            ]);
        }
    }

The key point here is that using the storeAs() method, we move the file to the public folder, the disk configuration is shown a bit later.

Store in public folder

For the rest, we simply store the avatar in our application on the corresponding disk that remembers has to be defined in/config/filessystems.php:

'public_upload' => [
    'driver' => 'local',
    'root' => public_path()
],

In this simple way, we already managed to upload; as you can see, it's exactly the same as what we do in basic Laravel; finally, from your view, you can define in your form, the field for the file upload:

<x-jet-label for="">Imagen</x-jet-label>
<x-jet-input-error for="image" />
<x-jet-input type="file" wire:model="image" />

Extra: Update user avatar

Already by default in Livewire we have an avatar management, and a disk (disk) to store it; already in the user model we have a function that is in charge of carrying out ALL this process:

   $this->user->updateProfilePhoto($this->avatar);
   Luce como la siguiente:
trait HasProfilePhoto
{
    /**
     * Update the user's profile photo.
     *
     * @param  \Illuminate\Http\UploadedFile  $photo
     * @return void
     */
    public function updateProfilePhoto(UploadedFile $photo)
    {
        tap($this->profile_photo_path, function ($previous) use ($photo) {
            $this->forceFill([
                'profile_photo_path' => $photo->storePublicly(
                    'profile-photos', ['disk' => $this->profilePhotoDisk()]
                ),
            ])->save();
 
            if ($previous) {
                Storage::disk($this->profilePhotoDisk())->delete($previous);
            }
        });
    }

For the rest, all the operation has been identical except that you no longer have to point to the disk where you are going to store the user's photo.

Remember that this material is part of my course and book on Laravel Livewire.

Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz en Udemy