Craftable

Media

Often you want to be able to assign some media to your Eloquent models.

Craftable provides you an option to do that. It uses Spatie's spatie/laravel-medialibrary, but it goes a bit further:

  • UI - provides you both the uploader and media viewer elements for media management
  • Collections definition - inspired by the conversions definition
  • Auto-Process - saving the eloquent model automatically processes and attaches media collections from the request
  • Authorization - controls, who has the permission to attach specific medium to specific model
  • Private access - controls, who has the permission to view specific medium

Basic Usage

There are two core concepts to understand - MediaCollections and MediaConversions.

If you have different types of files that you want to associate with your model (e.g. image gallery, list of PDFs), you can put them in their own MediaCollection.

When adding files to your media library, MediaConversions can automatically create derived versions such as thumbnails, optimized versions, etc.. You can register as many MediaConversions as you want.

Collection definition

First, we need to define the media collections for the specific model.

Let's imagine a Post model for following examples. You need to register media collection like this:

use Illuminate\Database\Eloquent\Model;
use Brackets\Media\HasMedia\ProcessMediaTrait;
use Brackets\Media\HasMedia\AutoProcessMediaTrait;
use Brackets\Media\HasMedia\HasMediaCollectionsTrait;
use Spatie\MediaLibrary\HasMedia;

class Post extends Model implements HasMedia {

    use ProcessMediaTrait;
    use AutoProcessMediaTrait;
    use HasMediaCollectionsTrait;

    public function registerMediaCollections(): void {
        $this->addMediaCollection('gallery');
    }

Here we have added new gallery media collection.

Saving media

If we use AutoProcessMediaTrait media are attached automatically from the request (on saving event hook). You just need to use our uploader element or attach a gallery data structure to your request data like this:

class PostsController extends Controller {
    ...
    public function store(StoreRequest $request)
    {
        // this will automatically attach $request->file('gallery') to the Post
        $post = Post::create($request->validated());
        ...
    }

The $request->gallery should be an array in following format:

[
    [
        'id' => null,
        'collection_name' => 'gallery',
        'path' => 'my_lovely_picture_1.jpg',
        'action' => 'add',
        'meta_data' => [ // or any other data
            'name' => 'test',
            'width' => 200,
            'height' => 200,
        ],
    ],
    [
        'id' => null,
        'collection_name' => 'gallery',
        'path' => 'my_lovely_picture_2.jpg',
        'action' => 'add',
        'meta_data' => [ // or any other data
            'name' => 'test',
            'width' => 200,
            'height' => 200,
        ],
    ],
    ...
];

If Auto Process is not convenient it can be turned off simply by not using AutoProcessMediaTrait.

Once turned-off you can still process media manually using processMedia() method on your model or you can use Spatie's way of attaching media (see https://docs.spatie.be/laravel-medialibrary/v9/basic-usage/associating-files).

Media Conversions

If you want to adjust media during handling (e.g. resize, crop, optimize, fine tune colors) you can do it by using Spatie's method registerMediaConversions as shown below.

use Illuminate\Database\Eloquent\Model;
use Brackets\Media\HasMedia\ProcessMediaTrait;
use Brackets\Media\HasMedia\AutoProcessMediaTrait;
use Brackets\Media\HasMedia\HasMediaCollectionsTrait;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Spatie\MediaLibrary\HasMedia;

class Post extends Model implements HasMedia {

    use ProcessMediaTrait;
    use AutoProcessMediaTrait;
    use HasMediaCollectionsTrait;

    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('gallery');
    }

    public function registerMediaConversions(Media $media = null): void
    {
        $this->addMediaConversion('detail_hd')
            ->width(1920)
            ->height(1080)
            ->performOnCollections('gallery');
    }

It uses Spatie's fluent API, so for more info, check out their docs at https://docs.spatie.be/laravel-medialibrary/v9/converting-images/defining-conversions.

UI elements

To use our uploader/viewer UI component, first you must define media collections in your resources/js/admin/post/Form.js:

import AppForm from '../app-components/Form/AppForm';

Vue.component('post-form', {
    mixins: [AppForm],
    data: function() {
        return {
            form: {
                //your regular form inputs
                title:  this.getLocalizedFormDefaults(),
                perex:  this.getLocalizedFormDefaults()
            },
            mediaCollections: ['gallery']
        }
    }

});

Now in your form blades you can use brackets/admin-ui::admin.includes.media-uploader blade component:

@include('brackets/admin-ui::admin.includes.media-uploader', [
    'mediaCollection' => app(App\Models\Post::class)->getMediaCollection('gallery'),
    'label' => 'Gallery'
])

You can also add media key in your edit form to preview the attached media directly in your form. We recommend use it with our handy trait Brackets\Media\HasMedia\HasMediaThumbsTrait in your Eloquent model:

<?php namespace App\Models;
...
use Brackets\Media\HasMedia\HasMediaThumbsTrait;

class Post extends Model implements HasMedia
{
    use ProcessMediaTrait;
    use AutoProcessMediaTrait;
    use HasMediaCollectionsTrait;
    use HasMediaThumbsTrait;

    ...

    public function registerMediaCollections(): void {
        $this->addMediaCollection('gallery')
            ->accepts('image/*')
            ->maxNumberOfFiles(20);
    }
    public function registerMediaConversions(Media $media = null): void
    {
        $this->autoRegisterThumb200();
    }
    ...
}

and in your form:

@include('brackets/admin-ui::admin.includes.media-uploader', [
    'mediaCollection' => app(App\Models\Post::class)->getMediaCollection('gallery'),
    'media' => $post->getThumbs200ForCollection('gallery'),
    'label' => 'Gallery'
])

Retrieve

To retrieve files you can use the getMedia method:

$mediaItems = $post->getMedia('nameOfTheCollection');
$publicUrl = $mediaItems[0]->getUrl();

// to retrieve media from any Media Conversion
$publicUrl = $mediaItems[0]->getUrl('nameOfTheConversion');

For more info check the Spatie's docs: https://docs.spatie.be/laravel-medialibrary/v9/basic-usage/retrieving-media

Advanced usage

There are following methods on Media Collections:

public function registerMediaCollections(): void
    {
        $this->addMediaCollection('gallery')
            ->disk('media') // Specify a disk where to store this collection
            ->private() // Alias to setting default private disk 
            ->maxNumberOfFiles(10) // Set the file count limit
            ->maxFilesize(2*1024*1024) // Set the file size limit
            ->accepts('image/*') // Set the accepted file types (in MIME type format)
            ->canView('media.view') // Set the ability (Gate) which is required to view the medium (in most cases you would want to call private())
            ->canUpload('media.upload') // Set the ability (Gate) which is required to upload & attach new files to the model
    }