DEV Community

Ayako yk
Ayako yk

Posted on

A Practical Approach: Image Handling with Spatie

In my previous blog post, I explored the Spatie media management package. While working on a project, I managed to successfully implement the creation aspect of it but encountered challenges when it came to editing. Ultimately, my senior developer had to step in to resolve the issue. To learn from both my mistakes and my colleague's code, I decided to dive deeper into understanding the correct implementation.
In this article, I will delve into two key topics:

  1. Utilizing Livewire for thumbnail.
  2. Implementing create and edit functionality in Laravel.

Laravel 10
Livewire v2
Spatie v10

Livewire

Livewire is a full-stack framework for Laravel that makes building dynamic interfaces simple, without leaving the comfort of Laravel.

File Uploads
Livewire allows you to easily handle file uploads in web applications because it does a lot for us under the hood.

  1. To use file uploads with Livewire, you add the WithFileUploads trait to your component.
  2. You can use wire:model on file inputs just like with other input types, and Livewire will manage the file upload process.
  3. When a file is selected, Livewire's JavaScript initiates a request to the server to get a temporary signed upload URL. The file is then uploaded to this URL, and its unique hash ID is returned.
  4. After successful upload, Livewire's JavaScript informs the server to set the desired public property to the new temporary file.
  5. You can customize file storage options, including directory and storage disk, using Laravel's file storage APIs.

example.blade.php

<form wire:submit.prevent="save">
    <input type="file" wire:model="photo" />
    <button type="submit">Save</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Example.php

use Livewire\WithFileUploads;

class Example extends Component
 {
     use WithFileUploads;

     public $photo;

    public function save()
    {
        $this->validate([
            'photo' => 'image|max:1024',
        ]);

        $this->photo->store('photos');
    }
Enter fullscreen mode Exit fullscreen mode

You can provide temporary preview URLs for uploaded images using $photo->temporaryUrl().
To store an image temporarily, a signed URL is created for security reasons and it is a complicated way to expose the image URL. But Livewire takes care of everything, so we just use that method like this:

<form wire:submit.prevent="save">
    @if($photo)
        Thumbnail:
        <img src="{{ $phot->temporaryURL() }}">
    @endif

    <input type="file" wire:model="photo" />
    <button type="submit">Save</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Create and Edit in Laravel
During my experience working on profile creation and editing, I encountered several challenges, including:

  1. Understanding how images are stored in the database.
  2. Determining the appropriate conditions for handling the form and input fields. In my previous blog post, I discussed the first challenge regarding image storage. In this article, I will focus on how to effectively manage form and input fields using if-conditions.

Profile/CreatePage.php

class CreatePage extends Component { 
    use WithFileUploads; 
    public $photo; // Model containing "first_name" and "last_name" 
    public $file = null; // This is important 
    public array $form = [ 
        'last_name' => null, 
        'first_name' => null, 
    ]; 

    // ... mount, validate, render, etc. 

    public function handleSubmit() 
    { 
        ['form' => $inputs] = $this->validate(); 
        $photo = Photo::create($inputs); 
        if ($this->file) { 
            $photo->addMedia($this->file) 
            ->preservingOriginal() 
            ->toMediaCollection('photo'); 
        } 
        $photo->save(); 
        return route("profile.index", $photo); 
    } 
}
Enter fullscreen mode Exit fullscreen mode

Profile/index.blade.php

<form wire:submit.prevent="handleSubmit" >
    @if ($action === 'create')
        @if ($this->file)
            <div>
                <img src="{{ $this->file->temporaryUrl() }}" alt="">
            </div>
        @else
            <div>
                <label for="photo">Choose File</label>
                <input type="file" class="hidden" id="photo" wire:model="file">
            </div>
        @endif
...
Enter fullscreen mode Exit fullscreen mode

Here, public $file = null or $this->file can hold the value of the image. If we've chosen an image, we can display it as a thumbnail; otherwise, only the label, "Choose File" is shown.

Profile/EditPage.php

class EditPage extends Controller
{
    use WithFileUploads;
    public Photo $photo; 
    public $file = null; 

    // ...mount, validate, render, etc.

    public function handleSubmit()
    {
        ['form' => $inputs] = $this->validate();

       if ($this->file) {
           if ($this->photo->getMedia('photo')) {
               $this->photo->getMedia('photo')->first()->delete();
       }

       $this->photo->addMedia($this->file)
           ->preservingOriginal()
           ->toMediaCollection('photo');
    }


        $this->photo->update($inputs); 
        return route("profile.index", [$this->photo]);
    }
Enter fullscreen mode Exit fullscreen mode

Profile/index.blade.php

(right below the create part)

 @else
    <div>
    @if (!$this->file && $this->photo->getMedia('photo'))
        <img src="{{ $this->photo->getFirstMediaUrl('photo') }}" alt="">
        <div>
            <label for="photo">Choose File</label>
            <input type="file" class="hidden" id="photo" wire:mode="file">
        </div>
    @else
        <img src="{{ $this->file->temporaryUrl() }}" alt="">
    @endif
        </div>
@endif
Enter fullscreen mode Exit fullscreen mode

if
!$this->file: First, ensure that a temporary image has not been chosen.
$this->photo->getMedia('photo'): Display the stored image.
Choose File: Provide this option for the user to select another image.

else
When a new image is chosen, it is displayed as a thumbnail.

When dealing with conditional logic involving multiple values, it can be a valuable strategy to take a moment and sketch out your thoughts on pen and paper. While it may initially seem like a detour from coding, this approach often leads to simpler and more efficient solutions. Taking the time to carefully map out your logic can help you avoid errors and streamline your code, ultimately saving you time and effort in the long run.

Top comments (0)