All Blade, Vue and React components communicate with the server in the same way. After a user selects one or more files, they're immediately sent to the server and stored as temporary uploads. When the parent form is submitted, the media items can be attached to a model.
Plain HTML file <input>s have two major shortcomings: they only upload the file when the form is submitted, and they're unable to remember the file when a form fails to submit. Temporary uploads solve both these problems.
When a user selects or drops a file in one of the Media Library components, it gets uploaded to the server immediately. Problem number 1 solved!
If the form submission fails later on, Media Library will pass down the previously added temporary upload objects so it can prefill the component with the previously uploaded files. Problem number 2 solved too!
To set up temporary uploads, register the temporary uploads route with our handy macro.
// Probably routes/web.phpRoute::mediaLibrary();
This will register a route at /media-library-pro/uploads.
If use React or Vue components to handle uploads you must set the enable_vapor_uploads key in the media-library config file to true. When enabling this option, a route will be registered that will enable
the Media Library Pro Vue and React components to move uploaded files in an S3 bucket to their right place.
With the config option enabled, the Route::mediaLibrary(); will register a route at /media-library-pro/post-s3
instead of /media-library-pro/uploads.
After a user has added files and they've been stored as temporary uploads, the user will submit the form. At this point the form request will hit one of your application's controllers. This is where you can permanently attach the file to your models.
To illustrate, we'll set up a little profile screen where a user may upload their avatar.
// Back in routes/web.phpuseApp\Http\Controllers\ProfileController;
Route::get('profile', [ProfileController::class, 'edit']);
Route::post('profile', [ProfileController::class, 'store']);
Route::mediaLibrary();
The profile controller has a simple form that uses the Blade attachment component.
The ProfileController we built assumes users will only upload the exact file types we're looking for. Of course they won't! We need to validate the incoming media before attaching them to our models.
The Media Library components provide instant client-side validation. You'll read more about that in the component docs. First, we'll set up server-side validation.
To validate uploaded media, we'll use a custom form request.
Every component will pass data in a key of a request. The name of that key is the name you passed to the name prop of any of the components.
// data will get passed via the `avatar` key of the request.
<x-media-library-attachmentname="avatar" />
The content of that request key will be an array. For each file uploaded that array will hold an array with these keys.
name: the name of the uploaded file
uuid: the UUID of a Media model. For newly uploaded files that have not been associated to a model yet, the Media model will be associated with a TemporaryUpload model
order: the order in which this item should be stored in a media collection.
Even though the upload components do some client-side validation, we highly recommend always validating requests on the server as well.
You should handle validation in a form request. On the form request you should use the Spatie\MediaLibraryPro\Rules\Concerns\ValidatesMedia trait. This will give you access to the validateSingleMedia and validateMultipleMedia methods.
In this example we assume that a component was configured to use the images key of the request. We validate that there was at least one item uploaded, but no more than 5. Only pngs that are up to 1MB in size are allowed. All images should have a name.
These are the available validation methods on validateSingleMedia() and validateMultipleMedia
minSizeInKb($minSizeInKb): validates that a single upload is not smaller than the $minSizeInKb given.
maxSizeInKb($maxSizeInKb): validates that a single upload is not greater than the $minSizeInKb given.
extension($extension): this rule expects a single extension as a string or multiple extensions as an array. Under the hood, the rule will validate if the value has the mime type that corresponds with the given extension.
mime($mime): this rule expects a single mime type as a string or multiple mime types as an array.
itemName($rules): this rule accepts rules that should be used to validate the name of a media item.
customProperty($name, $rules): this rule accepts a custom property name and rules that should be used to validate the attribute.
dimensions($width, $height): validates that the image has a specific width and height (in pixels).
width($width): validates that the image has a specific width (in pixels). The height is not validated.
height($height): validates that the image has a specific height (in pixels). The width is not validated.
widthBetween($minWidth, $maxWidth): validates that the image width (in pixels) is between the $minWidth and $maxWidth given (inclusive)
heightBetween($minHeight, $maxHeight): validates that the image height (in pixels) is between the $minHeight and $maxHeight given (inclusive)
These rules can be used on validateMultipleMedia;
minTotalSizeInKb($maxTotalSizeInKb): validates that the combined size of uploads is not smaller than the $minTotalSizeInKb given.
maxTotalSizeInKb($maxTotalSizeInKb): validates that the combined size of uploads is not greater than the $maxTotalSizeInKb given.
If you're using custom properties, you can validate them with the customProperty function. The first argument should be the name of the custom property you are validating. The second argument should be a string or an array with rules you'd like to use.
Here's an example where we validate extra_property and another_extra_property.
After you've validated the request, you should persist the changes to the media library. The media library provides two methods for that: syncFromMediaLibraryRequest and addFromMediaLibraryRequest. Both these methods are available on all models that handle media. Either way call the method toMediaCollection to update your media-model in the database. This will also ensure that temporary uploads are converted to the appropriate model.
This method will add all media whose uuid is in the request to a media collection of a model. Existing media associated on the model will remain untouched.
You should probably use this method only when accepting new uploads.
// in a controllerpublicfunctionyourMethod(YourFormRequest $request)
{
// retrieve model $yourModel
->addFromMediaLibraryRequest($request->get('images'))
->toMediaCollection('images');
flash()->success('Your model has been saved.')
returnback();
}
You should use this method when you are using the x-media-library-collection Blade component (or equivalent Vue or React component).
Here is an example where we are going to sync the contents of the images key in the request to the media library.
In this example we use the images key, but of course you should use the name that you used.
All media associated with $yourModel whose uuid is not present in the images array of the request will be deleted.
// in a controllerpublicfunctionyourMethod(YourFormRequest $request)
{
// retrieve model $yourModel
->syncFromMediaLibraryRequest($request->images)
->toMediaCollection('images');
flash()->success('Your model has been saved.')
returnback();
}
After this code has been executed, the media, whose uuid is present in the images array of request, will be in the images collection of $yourModel`.
$yourModel->getMedia('images'); // the media that we just synced will be returned.
If you are using properties for your media items you should pass the names of the custom properties you expect to the withCustomProperties method. Only these custom properties will be accepted.
Alternatively, you can pass a callable to usingName. This callable accepts an instance of Spatie\MediaLibraryPro\MediaLibraryRequestItem which can be used to get properties of the uploaded file.
For this we have to add the editableName attribute to the component:
Alternatively, you can pass a callable to usingFileName. This callable accepts an instance of Spatie\MediaLibraryPro\MediaLibraryRequestItem which can be used to get properties of the uploaded file.
In this example we're going to lowercase the name of the uploaded file before adding it the media library.
All Blade, Vue and React components will display previews images that are generated by the preview conversion of
the TemporaryUpload model. This conversion will create a 500x500 representation of the image.
You can customize this by registering a preview manipulation. Typically, this would be done in a service provider.
Here's an example where we will create 300x300 previews
useSpatie\MediaLibraryPro\Models\TemporaryUpload;
useSpatie\MediaLibrary\Conversions\Conversion;
useSpatie\Image\Manipulations;
// in a service providerTemporaryUpload::previewManipulation(function(Conversion $conversion) {
$conversion->fit(Manipulations::FIT_CROP, 300, 300);
});
The components will use the preview conversion of models that have media associated to them. For example, if you have
a $blogPost model, and you use the components to display the media associated to that model, the components will
use preview conversion on the BlogPost model.
Make sure such a preview conversion exists for each model that handles media. We highly recommend to use nonQueued
so the image is immediately available.