Laravel-medialibrary: return default file, if there is none

Created on 12 May 2018  路  9Comments  路  Source: spatie/laravel-medialibrary

Hi,
Is it possible to return a default file (an image for example), if the media collection is empty?

I have a model with following config:

public function registerMediaCollections()
{
    $this->addMediaCollection('image')
         ->singleFile()
         ->registerMediaConversions(function (Media $media) {
             $this->addMediaConversion('resized')
                  ->fit(Manipulations::FIT_FILL, 256, 256)
                  ->background('white')
                  ->nonQueued();
         });
}

and I access the image with following code:

$model->getFirstMediaUrl('image', 'resized');

Works great.

I was thinking about a way to return a default image when there is no image in the collection.
It's quite useful, for example when you use a seeder and don't mind to seed the images, or when you have a model where the image is required for your html template but you don't want to force the user to upload its own.

I know I can manually check and use a default one with:

$model->getFirstMediaUrl('image', 'resized') ?? asset('path/to/img');

But I was thinking about a better way, like defining a default file in registerMediaCollections method.

enhancement good first issue help wanted

Most helpful comment

For anyone looking here for a [temporary] solution, add this method to your model (or use it as a trait):

public function getFirstOrDefaultMediaUrl(string $collectionName = 'default', string $conversionName = ''): string
{
    $url = $this->getFirstMediaUrl($collectionName, $conversionName);

    return $url ? $url : $this::$defaultImage ?? '';
}

And define a static property inside your model (You can skip this if you don't mind have a default image):

protected static $defaultImage = '/images/default/event.png';

And access the first media url, or the default one as simple as:

$model->getFirstOrDefaultMediaUrl('collection');

All 9 comments

Sounds like a solid request! Feel free to send a PR that implements this.

The fallback should be some sort of Media null object, could be tricky to pull through but we'll see what it looks like when implemented.

I've got an idea about how this could be implemented:

We set the default file for each collection (or maybe for each conversion as well) like this:

public function registerMediaCollections()
{
    $this->addMediaCollection('image')
        ->singleFile()
        ->defaultFile('path/to/file/which/will/be/returned/as/it/is')
        // This library won't touch the default file, it just get a file name
        // as string and return it exactly as it is
        // It doesn't care about file type, or if it exists or not
        // ->defaultFile('images/user/default.png')
        ->registerMediaConversions(function (Media $media) {
            $this->addMediaConversion('resized')
                ->fit(Manipulations::FIT_FILL, 256, 256)
                ->background('white')
                ->nonQueued();
        });
}

Then there will be a new set of methods to retrieve file:
->getMediaOrDefault()
->getFirstOrDefaultMedia()
->getFirstOrDefaultMediaUrl()

So, we can use this methods in our frontend code to get the media (or the default one if there is none), and we can continue to use current methods (getMedia, getFirstMedia, getFirstMediaUrl) in our admin panel because we don't need the default file in there.

I know it's not complete and can get better, just wanted to start.

Maybe we should stick with URL's and paths instead of actual default media.

$this
    ->addMediaCollection('image')
    ->defaultUrl('/url/to/image.jpg')
    ->defaultPath('/path/to/image.jpg');

I don't know, we could return a dummy Media object but that sounds complicated. Pinging @freekmurze

I'd rather not add to the public API for this, if you're setting a default, it should be used in the existing methods.

I'd also steer away from dummy media, that could become complicated real fast.

What @sebastiandedeyne suggests I his code example seem pretty good. I'd slightly rename the methods

$this
    ->addMediaCollection('image')
    ->withFallbackUrl('/url/to/image.jpg')
    ->withFallbackPath('/path/to/image.jpg');

Sounds cool.
There is only one more thing that should be considered.

There should be a way to tell whenever you want the fallback to be returned if there is no media. It shouldn't be the default behavior and even if it is, there should be a way to change it, something like:

$model->getMediaWithFallback()
$model->getFirstMediaWithFallback()
$model->getFirstMediaUrlWithFallback()

I don't want to add new methods on the model for now. Users can easily do that in their own app.

Let's start with adding withFallbackUrl and withFallbackPath.

OK, looking forward to it.

For anyone looking here for a [temporary] solution, add this method to your model (or use it as a trait):

public function getFirstOrDefaultMediaUrl(string $collectionName = 'default', string $conversionName = ''): string
{
    $url = $this->getFirstMediaUrl($collectionName, $conversionName);

    return $url ? $url : $this::$defaultImage ?? '';
}

And define a static property inside your model (You can skip this if you don't mind have a default image):

protected static $defaultImage = '/images/default/event.png';

And access the first media url, or the default one as simple as:

$model->getFirstOrDefaultMediaUrl('collection');

Closing this issue for now, we'll continue the conversation in the PR you'll potentially submit.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

stayallive picture stayallive  路  4Comments

Radiergummi picture Radiergummi  路  4Comments

Nks picture Nks  路  3Comments

Krato picture Krato  路  4Comments

netanelwebninja picture netanelwebninja  路  3Comments