laravel-medialibrary is a package that can help handle media in a Laravel application. It can organise your files across multiple filesystems, generate thumbnails, optimize images and much much more.

Like mentioned before on this blog my team and I are currently creating a new major version, v7, that adds a lot of awesome features such as responsive images, vue components to assist with uploading, ... Last week you got a preview of multi file downloads, ... This week we are going to look at some improvements to defining media collections.

What are media collections? #

Media collections already exist in the current version of the medialibrary. They allow you to put different types of files in their own collection.

Let's associate some media:

$newsItem = News::find(1);
$newsItem->addMedia($pathToImage)->toMediaCollection('images');
$newsItem->addMedia($pathToAnotherImage)->toMediaCollection('images');
$newsItem->addMedia($pathToPdfFile)->toMediaCollection('downloads');
$newsItem->addMedia($pathToAnExcelFile)->toMediaCollection('downloads');

All media in a specific collection can be retrieved like this:

// will return media instances for all files in the images collection
$newsItem->getMedia('images');

// will returns media instance for all files in the downloads collection
$newsItem->getMedia('downloads');

New functionalities in v7 #

In v7 a media collection can be more than just a name to group files. By defining a media collection in your model you can add certain behaviours to collections.

To get started with media collections add a function called registerMediaCollections to your prepared model. Inside that function you can use addMediaCollection to start a media collection.

// in your model

public function registerMediaCollections()
{
    $this->addMediaCollection('my-collection')
        //add options
        ...

    // you can define as much collections as needed
    $this->addMediaCollection('my-other-collection')
        //add options
        ...
}

Only allow certain files in a collection #

You can pass a callback to acceptsFile that will check if a file is allowed into the collection. In this example we only accept jpeg files:

use Spatie\MediaLibrary\File;
...
public function registerMediaCollections()
{
    $this
        ->addMediaCollection('only-jpegs-please')
        ->acceptsFile(function (File $file) {
            return $file->mimeType === 'image/jpeg';
        });
}

This will succeed:

$yourModel->addMedia('beautiful.jpg')->toMediaCollection('only-jpegs-please');

This will throw a Spatie\MediaLibrary\Exceptions\FileCannotBeAdded\FileUnacceptableForCollection exception:

$yourModel->addMedia('ugly.ppt')->toMediaCollection('only-jpegs-please');

Using a specific disk #

You can ensure that files added to a collection are automatically added to a certain disk.

// in your model

public function registerMediaCollections()
{
    $this
       ->addMediaCollection('big-files')
       ->useDisk('s3');
}

When adding a file to my-collection it will be stored on the s3 disk.

$yourModel->addMedia($pathToFile)->toMediaCollection('big-files');

You can still specify the disk name manually when adding media. In this example the file will be stored on alternative-disk instead of s3.

$yourModel->addMedia($pathToFile)->toMediaCollection('big-files', 'alternative-disk');

Single file collections #

If you want a collection to hold only one file you can use singleFile on the collection. A good use case for this would be an avatar collection on a User model. In most cases you'd want to have a user to only have one avatar.

// in your model

public function registerMediaCollections()
{
    $this
        ->addMediaCollection('avatar')
        ->singleFile();
}

The first time you add a file to the collection it will be stored as usual.

$yourModel->add($pathToImage)->toMediaCollection('avatar');
$yourModel->getMedia('avatar')->count(); // returns 1
$yourModel->getFirstUrl('avatar'); // will return an url to the `$pathToImage` file

When adding another file to a single file collection the first one will be deleted.

// this will remove other files in the collection
$yourModel->add($anotherPathToImage)->toMediaCollection('avatar');
$yourModel->getMedia('avatar')->count(); // returns 1
$yourModel->getFirstUrl('avatar'); // will return an url to the `$anotherPathToImage` file

Registering media conversions #

It's recommended that your first read the section on converting images before reading the following paragraphs.

Normally image conversions are registered inside the registerMediaConversions function on your model. However, images conversions can also be registered inside media collections.

public function registerMediaCollections()
{
    $this
        ->addMediaCollection('my-collection')
        ->registerMediaConversions(function (Media $media) {
            $this
                ->addMediaConversion('thumb')
                ->width(100)
                ->height(100);
        });
}

When adding an image to my-collection a thumbnail that fits inside 100x100 will be created.

$yourModel->add($pathToImage)->toMediaCollection('my-collection');

$yourModel->getFirstMediaUrl('thumb') // returns an url to a 100x100 version of the added image.

Take a look at the defining conversions section to learn all the functions you can tack on to addMediaConversion.

In closing #

These improvements are coming to v7 of laravel-medialibrary. v7 will probably be released around February - March 2018. Of course you can start using v6 of laravel-medialibrary right now.