mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-04-17 10:14:08 +00:00
14 KiB
14 KiB
Laravel Media Library Reference
Complete reference for spatie/laravel-medialibrary. Full documentation: https://spatie.be/docs/laravel-medialibrary
Model Setup
Implement HasMedia and use InteractsWithMedia:
use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
class BlogPost extends Model implements HasMedia
{
use InteractsWithMedia;
public function registerMediaCollections(): void
{
$this->addMediaCollection('images');
}
public function registerMediaConversions(?Media $media = null): void
{
$this->addMediaConversion('thumb')
->fit(Fit::Contain, 300, 300);
}
}
Adding Media
From uploaded file
$model->addMedia($request->file('image'))->toMediaCollection('images');
From request (shorthand)
$model->addMediaFromRequest('image')->toMediaCollection('images');
From URL
$model->addMediaFromUrl('https://example.com/image.jpg')->toMediaCollection('images');
From string content
$model->addMediaFromString('raw content')->usingFileName('file.txt')->toMediaCollection('files');
From base64
$model->addMediaFromBase64($base64Data)->usingFileName('photo.jpg')->toMediaCollection('images');
From stream
$model->addMediaFromStream($stream)->usingFileName('file.pdf')->toMediaCollection('files');
From existing disk
$model->addMediaFromDisk('path/to/file.jpg', 's3')->toMediaCollection('images');
Multiple files from request
$model->addMultipleMediaFromRequest(['images'])->each(function ($fileAdder) {
$fileAdder->toMediaCollection('images');
});
$model->addAllMediaFromRequest()->each(function ($fileAdder) {
$fileAdder->toMediaCollection('images');
});
Copy instead of move
$model->copyMedia($pathToFile)->toMediaCollection('images');
// or
$model->addMedia($pathToFile)->preservingOriginal()->toMediaCollection('images');
FileAdder Options
All methods are chainable before calling toMediaCollection():
$model->addMedia($file)
->usingName('Custom Name') // display name
->usingFileName('custom-name.jpg') // filename on disk
->setOrder(3) // order within collection
->withCustomProperties(['alt' => 'A landscape photo'])
->withManipulations(['thumb' => ['filter' => 'greyscale']])
->withResponsiveImages() // generate responsive variants
->storingConversionsOnDisk('s3') // put conversions on different disk
->addCustomHeaders(['CacheControl' => 'max-age=31536000'])
->toMediaCollection('images');
Store on cloud disk
$model->addMedia($file)->toMediaCollectionOnCloudDisk('images');
Media Collections
Define in registerMediaCollections():
public function registerMediaCollections(): void
{
// Basic collection
$this->addMediaCollection('images');
// Single file (replacing previous on new upload)
$this->addMediaCollection('avatar')
->singleFile();
// Keep only latest N items
$this->addMediaCollection('recent_photos')
->onlyKeepLatest(5);
// Specific disk
$this->addMediaCollection('downloads')
->useDisk('s3');
// With conversions disk
$this->addMediaCollection('photos')
->useDisk('s3')
->storeConversionsOnDisk('s3-thumbnails');
// MIME type restriction
$this->addMediaCollection('documents')
->acceptsMimeTypes(['application/pdf', 'application/zip']);
// Custom validation
$this->addMediaCollection('images')
->acceptsFile(function ($file) {
return $file->mimeType === 'image/jpeg';
});
// Fallback URL/path when collection is empty
$this->addMediaCollection('avatar')
->singleFile()
->useFallbackUrl('/images/default-avatar.jpg')
->useFallbackPath(public_path('/images/default-avatar.jpg'));
// Enable responsive images for entire collection
$this->addMediaCollection('hero_images')
->withResponsiveImages();
// Collection-specific conversions
$this->addMediaCollection('photos')
->registerMediaConversions(function () {
$this->addMediaConversion('card')
->fit(Fit::Crop, 400, 400);
});
}
Media Conversions
Define in registerMediaConversions():
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Spatie\Image\Enums\Fit;
public function registerMediaConversions(?Media $media = null): void
{
$this->addMediaConversion('thumb')
->fit(Fit::Contain, 300, 300)
->nonQueued();
$this->addMediaConversion('preview')
->fit(Fit::Crop, 500, 500)
->withResponsiveImages()
->queued();
$this->addMediaConversion('banner')
->fit(Fit::Max, 1200, 630)
->performOnCollections('images', 'headers')
->nonQueued()
->sharpen(10);
// Conditional conversion based on media properties
if ($media?->mime_type === 'image/png') {
$this->addMediaConversion('png-thumb')
->fit(Fit::Contain, 150, 150);
}
// Keep original format instead of converting to jpg
$this->addMediaConversion('web')
->fit(Fit::Max, 800, 800)
->keepOriginalImageFormat();
// PDF page rendering
$this->addMediaConversion('pdf-preview')
->pdfPageNumber(1)
->fit(Fit::Contain, 400, 400);
// Video frame extraction
$this->addMediaConversion('video-thumb')
->extractVideoFrameAtSecond(5)
->fit(Fit::Crop, 300, 300);
}
Image Manipulation Methods (via spatie/image)
Resizing and fitting:
width(int),height(int)— constrain dimensionsfit(Fit, int, int)— fit within bounds usingFit::Contain,Fit::Max,Fit::Fill,Fit::Stretch,Fit::Cropcrop(int, int)— crop to exact dimensions
Effects:
sharpen(int),blur(int),pixelate(int)greyscale(),sepia()brightness(int),contrast(int),colorize(int, int, int)
Orientation:
orientation(int),flip(string),rotate(int)
Format:
format(string)—'jpg','png','webp','avif'quality(int)— 1-100
Other:
border(int, string, string),watermark(string)optimize(),nonOptimized()
Conversion Configuration
performOnCollections('col1', 'col2')— limit to specific collectionsqueued()/nonQueued()— run async or syncwithResponsiveImages()— also generate responsive variants for this conversionkeepOriginalImageFormat()— preserve png/webp/gif instead of converting to jpgpdfPageNumber(int)— which PDF page to renderextractVideoFrameAtSecond(int)— video thumbnail timing
Retrieving Media
Getting media items
$media = $model->getMedia('images'); // all in collection
$first = $model->getFirstMedia('images'); // first item
$last = $model->getLastMedia('images'); // last item
$has = $model->hasMedia('images'); // boolean check
Getting URLs
$url = $model->getFirstMediaUrl('images'); // original URL
$thumbUrl = $model->getFirstMediaUrl('images', 'thumb'); // conversion URL
$lastUrl = $model->getLastMediaUrl('images', 'thumb');
Getting paths
$path = $model->getFirstMediaPath('images');
$thumbPath = $model->getFirstMediaPath('images', 'thumb');
Temporary URLs (S3)
$tempUrl = $model->getFirstTemporaryUrl(
now()->addMinutes(30),
'images',
'thumb'
);
Fallback URLs
$url = $model->getFallbackMediaUrl('avatar');
From the Media model
$media = $model->getFirstMedia('images');
$media->getUrl(); // original URL
$media->getUrl('thumb'); // conversion URL
$media->getPath(); // disk path
$media->getFullUrl(); // full URL with domain
$media->getTemporaryUrl(now()->addMinutes(30));
$media->hasGeneratedConversion('thumb'); // check if conversion exists
Filtering media
$media = $model->getMedia('images', function (Media $media) {
return $media->getCustomProperty('featured') === true;
});
$media = $model->getMedia('images', ['mime_type' => 'image/jpeg']);
Custom Properties
Store arbitrary metadata on media items:
// When adding
$model->addMedia($file)
->withCustomProperties([
'alt' => 'Descriptive text',
'credits' => 'Photographer Name',
])
->toMediaCollection('images');
// Get/set on existing media
$media->setCustomProperty('alt', 'Updated text');
$media->save();
$alt = $media->getCustomProperty('alt');
$has = $media->hasCustomProperty('alt');
$media->forgetCustomProperty('alt');
$media->save();
Responsive Images
Generate multiple sizes for optimal loading:
// On the FileAdder
$model->addMedia($file)
->withResponsiveImages()
->toMediaCollection('images');
// On a conversion
$this->addMediaConversion('hero')
->fit(Fit::Max, 1200, 800)
->withResponsiveImages();
// On a collection
$this->addMediaCollection('photos')
->withResponsiveImages();
Using in Blade
{{-- Renders img tag with srcset --}}
{{ $media->toHtml() }}
{{-- With attributes --}}
{{ $media->img()->attributes(['class' => 'w-full', 'alt' => 'Photo']) }}
{{-- Get srcset string --}}
<img src="{{ $media->getUrl() }}" srcset="{{ $media->getSrcset() }}" />
{{-- Responsive conversion --}}
<img src="{{ $media->getUrl('hero') }}" srcset="{{ $media->getSrcset('hero') }}" />
Placeholder SVG
$svg = $media->responsiveImages()->getPlaceholderSvg(); // tiny blurred base64 placeholder
Managing Media
Clear a collection
$model->clearMediaCollection('images');
Clear except specific items
$model->clearMediaCollectionExcept('images', $mediaToKeep);
Delete specific media
$model->deleteMedia($mediaId);
Delete all media
$model->deleteAllMedia();
Delete model but keep media files
$model->deletePreservingMedia();
Reorder media
Media::setNewOrder([3, 1, 2]); // media IDs in desired order
Move/copy media between models
$media->move($otherModel, 'images');
$media->copy($otherModel, 'images');
Events
use Spatie\MediaLibrary\MediaCollections\Events\MediaHasBeenAddedEvent;
use Spatie\MediaLibrary\Conversions\Events\ConversionWillStartEvent;
use Spatie\MediaLibrary\Conversions\Events\ConversionHasBeenCompletedEvent;
use Spatie\MediaLibrary\MediaCollections\Events\CollectionHasBeenClearedEvent;
Listen to these events to hook into the media lifecycle:
Event::listen(MediaHasBeenAddedEvent::class, function ($event) {
$event->media; // the added Media model
});
Event::listen(ConversionHasBeenCompletedEvent::class, function ($event) {
$event->media;
$event->conversion;
});
Configuration
Key config/media-library.php options:
return [
'disk_name' => 'public', // default disk
'max_file_size' => 1024 * 1024 * 10, // 10MB
'queue_connection_name' => '', // queue connection
'queue_name' => '', // queue name
'queue_conversions_by_default' => true, // queue conversions
'media_model' => Spatie\MediaLibrary\MediaCollections\Models\Media::class,
'file_namer' => Spatie\MediaLibrary\Support\FileNamer\DefaultFileNamer::class,
'path_generator' => Spatie\MediaLibrary\Support\PathGenerator\DefaultPathGenerator::class,
'url_generator' => Spatie\MediaLibrary\Support\UrlGenerator\DefaultUrlGenerator::class,
'image_driver' => 'gd', // 'gd', 'imagick', or 'vips'
'image_optimizers' => [/* optimizer config */],
'version_urls' => true, // cache busting
'default_loading_attribute_value' => null, // 'lazy' for lazy loading
];
Custom Path Generator
use Spatie\MediaLibrary\Support\PathGenerator\PathGenerator;
class CustomPathGenerator implements PathGenerator
{
public function getPath(Media $media): string
{
return md5($media->id) . '/';
}
public function getPathForConversions(Media $media): string
{
return $this->getPath($media) . 'conversions/';
}
public function getPathForResponsiveImages(Media $media): string
{
return $this->getPath($media) . 'responsive/';
}
}
Custom File Namer
use Spatie\MediaLibrary\Support\FileNamer\FileNamer;
class CustomFileNamer extends FileNamer
{
public function originalFileName(string $fileName): string
{
return Str::slug(pathinfo($fileName, PATHINFO_FILENAME));
}
public function conversionFileName(string $fileName, Conversion $conversion): string
{
return $this->originalFileName($fileName) . '-' . $conversion->getName();
}
public function responsiveFileName(string $fileName): string
{
return pathinfo($fileName, PATHINFO_FILENAME);
}
}
Custom Media Model
use Spatie\MediaLibrary\MediaCollections\Models\Media as BaseMedia;
class Media extends BaseMedia
{
// Add custom methods, scopes, or override behavior
}
Register in config: 'media_model' => App\Models\Media::class
Downloading Media
Single file
return $media->toResponse($request); // download
return $media->toInlineResponse($request); // display inline
return $media->stream(); // stream
ZIP download of collection
use Spatie\MediaLibrary\Support\MediaStream;
return MediaStream::create('photos.zip')
->addMedia($model->getMedia('images'));
Using with API Resources
class PostResource extends JsonResource
{
public function toArray($request): array
{
return [
'id' => $this->id,
'title' => $this->title,
'image' => $this->getFirstMediaUrl('images'),
'thumb' => $this->getFirstMediaUrl('images', 'thumb'),
'media' => $this->getMedia('images')->map(function ($media) {
return [
'id' => $media->id,
'url' => $media->getUrl(),
'thumb' => $media->getUrl('thumb'),
'name' => $media->name,
'size' => $media->size,
'type' => $media->mime_type,
];
}),
];
}
}