Latest Posts

Prefixing your medias storage paths with Spatie Media Library

Tutorials

I use Spatie Media Library - a lot - and one really useful technique is to have the same storage system, with environment prefixes


When deploying to staging and production, I tend to use Amazon S3. And, like a lot of other Laravel projects, I often leverage the power of Spatie Media Library to manage my assets.

Spatie Media Library

The problem

I like to use the same physical Amazon S3 'bucket' so I can isolate our client down to one storage system, but I don't want to mix up my environments. This technique also doesn't necessarily directly relate to S3 and can be used for other storage systems.

It's also worth noting that with this strategy in S3, I can still create separate IAM users restricted down to management control over that particular folder, maintaining isolation.

Spatie's default behaviour is to create a folder structure based on the media ID, e.g. /12/filename.png. That's great - until you're pushing production and staging assets with potentially conflicting IDs. You can also change this to use UUID's instead. That'll work, and the chance of conflict is extremely low, but I still like having an individual folder for each environment.

The solution

Spatie Media Library offers a lot of flexibility, and it's possible to write a simple class that'll allow us to override the default path generation functionality.

We can then prefix our storage paths with our environment name, so our folder structure would appear as /production/12/filename.png.

To do this, we'll extend the plugins existing Spatie\MediaLibrary\Support\PathGenerator\DefaultPathGenerator class with our own App\Media\SpatiePathGenerator class.

<?php

namespace App\Media;

use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Spatie\MediaLibrary\Support\PathGenerator\DefaultPathGenerator;

class SpatiePathGenerator extends DefaultPathGenerator
{
    protected function getBasePath(Media $media): string
    {
        return app()->environment() . '/' . parent::getBasePath($media);
    }
}

This class tells our system that we want to prefix the base path with our environment name (e.g. staging, production)

And rather than replace the existing functinonality, we're extending it by calling parent::getBasePath($media). This helps to future proof our code for any changes Spatie may make.

Once you've made this class (in my case inside app/Media), you can update the media library configuration file which exists under config/media-library.php. If that file isn't there yet, you can generate it by running a simple artisan command:

php artisan vendor:publish --tag=medialibrary-config

Now, find the path_generator array key and update it to point to your custom generator.

/*
 * This is the class that is responsible for naming generated files.
 */
'file_namer' => Spatie\MediaLibrary\Support\FileNamer\DefaultFileNamer::class,

/*
 * The class that contains the strategy for determining a media file's path.
 */
'path_generator' => App\Media\SpatiePathGenerator::class,

/*
 * The class that contains the strategy for determining how to remove files.
 */
'file_remover_class' => Spatie\MediaLibrary\Support\FileRemover\DefaultFileRemover::class,

And that's it, time to test your apps behaviour and make sure it's working as expected!

If you enjoyed this little tip, please consider subscribing for more tips and tricks!