emaia/laravel-mediaman
Laravel MediaMan is a UI-agnostic media manager for Laravel. Upload files via a fluent MediaUploader, organize them into virtual collections, attach media to any model through polymorphic associations, tag by channels, and run automatic image conversions.
Installation (unchanged):
composer require emaia/laravel-mediaman
php artisan mediaman:publish-config
php artisan mediaman:publish-migration
php artisan migrate
php artisan storage:link
First Upload with Size Limit (new):
use Emaia\MediaMan\Facades\MediaUploader;
$media = MediaUploader::source($request->file('file'))
->maxFileSize(5 * 1024 * 1024) // 5MB
->upload();
Attach to Model (unchanged):
$post = Post::find(1);
$post->attachMedia($media, 'featured-image-channel');
config/mediaman.php (new max_file_size setting)app/Models/Media.php and app/Models/MediaCollection.php (static methods now)MediaUploader (new maxFileSize() method)FileSizeExceeded for upload validationUpload a file with size validation and attach to a model:
try {
$media = MediaUploader::source($request->file('image'))
->useCollection('Blog Posts')
->maxFileSize(config('mediaman.max_file_size')) // Respect config
->upload();
$post = Post::find(1);
$post->attachMedia($media, 'featured-image');
} catch (FileSizeExceeded $e) {
return back()->withError('File too large');
}
Size Validation:
// Config (config/mediaman.php)
'max_file_size' => 10 * 1024 * 1024, // 10MB default
// Runtime
$media = MediaUploader::source($file)
->maxFileSize(2 * 1024 * 1024) // Override
->upload();
Exception Handling:
try {
$media = MediaUploader::source($file)->upload();
} catch (FileSizeExceeded $e) {
// Handle error (e.g., return validation error)
}
Static Collection Lookup (breaking change):
// OLD (no longer works)
$collection = MediaCollection::with('media')->findByName('Gallery');
// NEW
$collection = MediaCollection::findByName('Gallery'); // Lazy-loads relations
$media = $collection->load('media')->media; // Explicit eager load
Batch Attachments (performance improvement):
$post->syncMedia($mediaArray, 'gallery'); // Single bulk INSERT
class CustomWidthCalculator implements WidthCalculator {
public function calculateWidthsFromBinary(string $binary): Collection {
// New required method
return collect([100, 200, 300]); // Example widths
}
// ... existing methods
}
$media->generateResponsiveImages(); // No temp dir writes
$request->validate([
'file' => [
'required',
'file',
'max:10240', // Laravel's max:kb
function ($attribute, $value, $fail) {
$maxSize = config('mediaman.max_file_size') ?? 0;
if ($maxSize > 0 && $value->getSize() > $maxSize) {
$fail('The '.$attribute.' may not be greater than '.byteToHuman($maxSize).'.');
}
}
],
]);
// Handle static method changes in tests
public function test_collection_lookup() {
$collection = MediaCollection::findByName('Test');
$this->assertNull($collection->media); // Not loaded
$collection->load('media'); // Explicit load
}
use Emaia\MediaMan\Events\MediaCreated;
MediaCreated::subscribe(function ($media) {
if ($media->size > config('mediaman.max_file_size')) {
// Log oversized uploads
}
});
# Cleanup (unchanged)
php artisan mediaman:cleanup
# Generate responsive images (faster now)
php artisan mediaman:generate-responsive
Static Method Changes (breaking):
findByName() is now static. Chained queries like with()->findByName() fail.$collection = MediaCollection::findByName('x')->load('media');
Width Calculator Contract (breaking):
calculateWidthsFromBinary().DefaultWidthCalculator.File Size Validation:
maxFileSize() throws FileSizeExceeded (not a validation error).Responsive Image Temp Files:
sys_get_temp_dir (performance fix).Bulk Attach Performance:
syncMedia() now uses bulk INSERT (1 query vs N).Null Returns:
findByName('non-existent') now returns null (was Builder).$collection = MediaCollection::findByName('x') ?? throw new NotFoundException();
File Size Issues:
// Log actual vs allowed size
$fileSize = $request->file('file')->getSize();
$maxSize = config('mediaman.max_file_size');
\Log::debug('File size', compact('fileSize', 'maxSize'));
Static Method Calls:
// Check if collection exists before chaining
if (!$collection = MediaCollection::findByName('x')) {
abort(404);
}
$collection->load('media');
Width Calculator:
// Test custom calculator
$calculator = new CustomWidthCalculator();
$widths = $calculator->calculateWidthsFromBinary(file_get_contents($media->path));
Bulk Attach:
// Verify syncMedia works
$post->syncMedia([$media1, $media2], 'gallery');
$this->assertCount(2, $post->getMedia('gallery'));
Configurable Size Limits:
// config/mediaman.php
'max_file_size' => env('MEDIAMAN_MAX_FILE_SIZE', 10 * 1024 * 1024),
Set via .env:
MEDIAMAN_MAX_FILE_SIZE=5242880 # 5MB
Human-Readable Size Validation:
use Emaia\MediaMan\Helpers\byteToHuman;
$request->validate([
'file' => [
'max:10240',
function ($attribute, $value, $fail) {
$max = config('mediaman.max_file_size');
if ($max > 0 && $value->getSize() > $max) {
$fail("File must be less than {$byteToHuman($max)}.");
}
}
]
]);
Lazy-Loading Collections:
// Avoid N+1 queries
$collections = MediaCollection::all()->load('media');
Custom Exceptions:
// Extend FileSizeExceeded for custom messages
class CustomFileSizeExceeded extends FileSizeExceeded {
public function __construct($maxSize) {
parent::__construct($maxSize);
$this->message = "Files must be under {$byteToHuman($maxSize)}.";
}
}
Testing Static Methods:
public function test_static_find_by_name() {
$collection = MediaCollection::findByName('Test');
$this->assertInstanceOf(MediaCollection::class, $collection);
$this->assertNull($collection->media);
How can I help you explore Laravel packages today?