Search code examples
laravellaravel-livewirefilepond

Handling File uploads and reorder with Laravel Livewire and Filepond


I have a form in my application that allows users to create posts and while doing so upload multiple images to the post being created.

I am using Laravel Livewire and Filepond to achieve this.

The problem I am having is I need to allow the user to reorder the images (as it is a gallery and the order is important), and save the order in the database when the form in submitted.

Another issue I am running into is allowing a user to edit their post later. I need their pre-existing post images loaded in filepond, and also allow them to upload more, delete, and/or reorder.

When the user saves the post I need to be able to update my database and file system.

All info online is how to upload files, but no info on how to reorder, or pre-populate with pre-existing files.

Here is my current code for reference:

<div
    x-data=""
    x-init="
       
        FilePond.setOptions({
            allowMultiple: true,
            allowReorder: true,
            itemInsertLocation: 'after',
            server: {
                process: (fieldName, file, metadata, load, error, progress, abort, transfer, options) => {
                    @this.upload('images', file, load, error, progress)
                },
                revert: (filename, load) => {
                    @this.removeUpload('images', filename, load)
                },
                load: (source, load, error, progress, abort, headers) => {
                    var myRequest = new Request(source);
                    fetch(myRequest).then(function(response) {
                      response.blob().then(function(myBlob) {
                        load(myBlob)
                      });
                    });
                },
            },
        });
        const pond = FilePond.create($refs.input, {
            acceptedFileTypes: ['image/png', 'image/jpeg'],
            maxFileSize: '7MB',
            allowImageCrop: true,
            allowReorder: true,
            allowImageResize: true,
            imageResizeTargetWidth: '1000px',
            imageResizeTargetHeight: '1000px',
            filePosterMaxHeight: '256px',
            files: {{ $existingImages }} // used for when editing a post and it already has images. see php component on how I set this variable
            
        });

    "
>
    <div wire:ignore wire:key="images">
        <div class="form-group text-center">
            <input
                id="image-upload"
                type="file"
                x-ref="input"
                multiple
                data-allow-reorder="true"
                data-max-file-size="3MB"
                data-max-files="10"
            >
        </div>
    </div>
</div>

My Livewire PHP component:

    public $images = [];
    public $existingImages;

    public function mountMedia($post) {
        if($post){
            $this->existingImages = $post->images->map(function ($image) use ($post) {
                return [
                    'source' => $image->id,
                    'options' => [
                        'type' => 'local',
                        'file' => [
                            'name' => $image->getUrl(),
                            'size' => $image->file_size,
                            'type' => $image->mime_type,
                        ],
                        'metadata' => [
                            'poster' => $image->getUrl(),
                            'position' => $image->position
                        ],
                    ],
                ];

            });
        }
    }
    public function saveImage($file, $post, $position) {
        // Create a unique random string
        $randString = Str::random(3);
        // Get time
        $time = time();
        // Set file name
        $filename = $time. '-' . $randString.'-'.auth()->user()->id;
        $extension = '.'.$file->getClientOriginalExtension();

        // Save images for gallery 
        $regImage = $file->storeAs('/'. $post->id, $filename.$extension, 'post_images');

           
        // Create a new image in db
        Image::create([
            'user_id'       => auth()->user()->id,
            'post_id'       => $post->id,
            'position'      => $position,
            'filename'      => $filename,
            'extension'     => $extension,
            'src'           => 'post_images',
            'mime_type'     => $file->getMimeType(),
            'file_size'     => $file->getSize(),
        ]);
    }

    public function saveMedia($post) {
        // Make sure user owns post
        abort_unless($post->user_id == auth()->user()->id, 403);

        // Set default position
        $position = 1;

        // Save each image
        foreach ($this->images as $file) {
           $this->saveImage($file, $post, $position);
            // Increment position for next image
            $position++;
        }
    }
}

Solution

  • For sorting items in Livewire I would use https://github.com/livewire/sortable. Sortable is very easy to use.

    For filepond if the original image should be used again later I would save that image as well with a relation to the edited version.