Technology Blog

Look deep into latest news and innovations happening in the Tech industry with our highly informational blog.

Laravel component Media Library

hkis

Media Library can associate files with Eloquent models. You can, for instance, associate images with a blog post model. In your Blade view, you can retrieve URLs to the associated images. It can handle multiple collections, work with multiple filesytems, create zips on the fly to download multiple files, use a customized directory structure, save bandwidth using responsive images and much more.

The problem with traditional uploads

Before exploring Media Library Pro, let’s first explained why we built it in the first place. Here’s how a traditional upload form might look like. It uses a regular input of type file.

Pic courtesy: laravel-news.com

<form method="POST" enctype="multipart/form-data">
    <x-grid>
        @csrf

        <x-field label="name">
            <x-input id="name" name="name" placeholder="Your first name" />
        </x-field>

        <x-field label="file">
            <input type="file" name="file">
            @error('file')
                {{ $message }}
            @enderror
        </x-field>

        <x-button dusk="submit">Submit</x-button>
    </x-grid>
</form>

There are two big problems with this standard upload element.

First, the upload process only starts when the form is submitted. For small files in small forms, this might not be a problem. But imagine you’re uploading a multi MB file in a form. When submitting the form, you now have to wait for the upload to complete before seeing the submission results.

The second problem is something that has bothered us for a long, long time. Imagine that the input field is part of a form of which some fields are required. You’re selecting a file, submitting the form, leaving some of the required fields empty. You get redirected back to the form where error messages are now displayed. Your previous file selection is gone, and you need to select the file again.

Media Library Pro

Media Library Pro is a paid add-on package that offers Blade, Vue, and React components to upload files to your application. It ships with two components. The first one is the attachment component. It is meant to be used on a public-facing page where you want users to upload one or multiple files.

introducing-media-library-pro-attachment

Pic courtesy: laravel-news.com

The second one is called the collection component. This one can manage the files in an existing collection. It is meant to be used in the admin part of your app.

Pic courtesy: laravel-news.com

Both of these components are available as Vue, React and Blade components. Under the hood, the Blade components are powered by Caleb’s excellent Livewire package.

These components are straightforward to install and are documented in great detail.

Let’s take a look at both the `Attachment` and `Collection` component. In the remainder of the blog post, we’ll use the Blade version of the examples, but rest assured that everything shown can also be done with the Vue and React counterparts.

The Attachment component

To get started with the Attachment Blade component you’ll have to use x-media-library-attachment in your view.

<form method="POST">
    @csrf

    <input id="name" name="name">

    <x-media-library-attachment name="avatar"/>

    <button type="submit">Submit</button>
</form>

Here’s how it looks like after we’ve selected a file but before submitting the form.

Pic courtesy: laravel-news.com

The x-media-library-attachment has taken care of the upload. The file is now stored as a temporary upload. In case there are validation errors when submitting the form, the x-media-library-attachment will display the temporary upload when you get redirected back to the form. There’s no need for the user to upload the file again.

Pic courtesy: laravel-news.com

Here’s the form request used to validate the uploaded.

namespace App\Http\Requests\Blade;

use Illuminate\Foundation\Http\FormRequest;
use Spatie\MediaLibraryPro\Rules\Concerns\ValidatesMedia;

class StoreBladeAttachmentRequest extends FormRequest
{
    use ValidatesMedia;

    public function rules()
    {
        return [
            'name' => 'required',
            'media' => ['required', $this->validateSingleMedia()
                ->maxItemSizeInKb(3000),
            ],
        ];
    }
}

By applying the ValidatesMedia trait, you get access to the validateSingleMedia, which allows you to validate the upload. You can chain on many validation methods, which are documented here.

In your controller, you can associate the upload file to any model you’d like.

$formSubmission
    ->addFromMediaLibraryRequest($request->media)
    ->toMediaCollection('images');

And that is all you need to do!

The attachment component can be used to handle multiple uploads as well. In this video, you’ll see how that is done.

The Collection component

You can manage the entire contents of a media library collection with x-media-library-collection component. This
component is intended to use in admin sections.

Here is an example where we will administer an images collection of a $formSubmission model.

<form method="POST">
    @csrf
    <x-field label="name">
        <x-input id="name" name="name" autocomplete="off" placeholder="Your name"
                 value="{{ old('name', $formSubmission->name) }}"/>
    </x-field>

    <x-field label="Images">
        <x-media-library-collection
            name="images"
            :model="$formSubmission"
            collection="images"
            max-items="3"
            rules="mimes:png,jpeg"
        />
    </x-field>

    <x-button dusk="submit" type="submit">Submit</x-button>
</form>

Here’s how that component looks like:

Pic courtesy: laravel-news.com

This component will display the contents of the entire collection. Files can be added, removed, updated, and reordered.

To validate the response of the form, a form request like this one can be used:

namespace App\Http\Requests\Blade;

use Illuminate\Foundation\Http\FormRequest;
use Spatie\MediaLibraryPro\Rules\Concerns\ValidatesMedia;

class StoreBladeCollectionRequest extends FormRequest
{
    use ValidatesMedia;

    public function rules()
    {
        return [
            'name' => 'required',
            'images' => [$this->validateMultipleMedia()
                ->maxItems(3)
                ->itemName('required'),
            ],
        ];
    }
}

Again, you need to ValidatesMedia trait. This time the validateMultipleMedia should be used. You can chain on the other validation methods, which are documented here.

In the controller, you can associate the media in the collection component with your model using the syncFromMediaLibraryRequest method.

Here’s the relevant code in the controller of the demo app.

$formSubmission
    ->syncFromMediaLibraryRequest($request->images)
    ->toMediaCollection('images');

Adding custom properties

When using the collection component, you probably want to add some extra fields to be displayed. We’ve made this a straightforward thing to do.

In the screenshot below, we added the Extra field field.

Pic courtesy: medium.com

You can achieve this by passing a blade view to the fields-view prop of the x-media-library-collection.

<x-media-library-collection
    name="images"
    :model="$formSubmission"
    collection="images"
    max-items="3"
    rules="mimes:png,jpeg"
    fields-view="uploads.blade.partials.custom-properties"
/>

In that custom-properties view, you can put anything that should be displayed in the right half of the collection component.

Here’s the content of that custom-propertiesview.

@include('media-library::livewire.partials.collection.fields')

<div class="media-library-field">
    <label class="media-library-label">Extra field</label>
    <input
        dusk="media-library-extra-field"
        class="media-library-input"
        type="text"
        {{ $mediaItem->customPropertyAttributes('extra_field')  }}
    />

    @error($mediaItem->customPropertyErrorName('extra_field'))
        <span class="media-library-text-error">
               {{ $message }}
        </span>
    @enderror
</div>

In the form request, you can use the customProperty to validate any extra custom attributes. The second argument of the function can take any validator in Laravel.

namespace App\Http\Requests\Blade;

use Illuminate\Foundation\Http\FormRequest;
use Spatie\MediaLibraryPro\Rules\Concerns\ValidatesMedia;

class StoreBladeCollectionCustomPropertyRequest extends FormRequest
{
    use ValidatesMedia;

    public function rules()
    {
        return [
            'name' => 'required',
            'images' => [$this->validateMultipleMedia()
                ->maxItems(3)
                ->itemName('required|max:30')
                ->customProperty('extra_field', 'required|max:30'),
            ],
        ];
    }
}

In the controller where you process the form submission, you should use the withCustomProperties method to whitelist any extra attributes that you want to sync with your media.

$formSubmission
    ->syncFromMediaLibraryRequest($request->images)
    ->withCustomProperties('extra_field')
    ->toMediaCollection('images');

Customizing the look and feel

By default, both the Attachment and Collection components already look good. Probably you’d like to adapt them so they match the look of your app.

Luckily, this is easy to do. The styles that ship with Media Library Pro can be used by importing or linking dist/styles.css. The styles were built with a default tailwind.config.js.

You can customize the styles by importing src/styles.css and run every @apply rule through your own tailwind.config.js

/* app.css */

@tailwind base;

@tailwind components;

@tailwind utilities;

@import "src/styles.css";

…

How temporary files are used

To achieve that behavior where uploaded files are preserved when a form validation error occurs, we use temporary uploads.

Testing the components

Inside the private spatie/laravel-medialibrary-pro repo, there are a lot of tests to make sure the back end integration and the Vue, React, and Blade front end components are working as expected.

We also wanted to have browser tests that ensure that front end components work perfectly with the back end and vice versa. That’s why we added Dusk tests in our demo application. You can see them here.

Let’s take a look at one of them:

/**
 * @test
 *
 * @dataProvider routeNames
 */
public function it_can_handle_a_single_upload(string $routeName)
{
    $this->browse(function (Browser $browser) use ($routeName) {
        $browser
            ->visit(route($routeName))
            ->type('name', 'My name')
            ->attach('@main-uploader', $this->getStubPath('space.png'))
            ->waitForText('Remove')
            ->waitUntilMissing('.media-library-progress-wrap.media-library-progress-wrap-loading')
            ->press('@submit')
            ->assertSee('Your form has been submitted');

        $this->assertCount(1, FormSubmission::get());

        $this->assertEquals('space.png', FormSubmission::first()->getFirstMedia('images')->file_name);
    });
}

This test will upload a file and make sure that the file is associated with a model after the form is submitted.

A thing to note here is that @dataProvider attribute. This will make PHPUnit run the test for each result returned by the routeNames function defined in the same file.

public function routeNames(): array
{
    return [
        ['vue.attachment'],
        ['react.attachment'],
        ['blade.attachment'],
    ];
}

You can see that in combination with the routeNames function, the it_can_handle_a_single_upload will run for the vue.attachment, react.attachment and blade.attachment routes. Visiting these routes will display the form that will use the Vue, React, or Blade component, respectively. So, this one test covers a lot of logic. It makes sure that the component work using any technology. This gives us a lot of confidence that all of the components are working correctly.

For more information and to develop web application using Laravel, Hire Laravel Developer from us as we give you a high-quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft”. To develop custom web apps using React JS, please visit our technology page.

Content Source:

  1. laravel-news.com