Installation
Add the bundle to your composer.json:
composer require akuma/media-bundle
Register the bundle in config/bundles.php:
return [
// ...
Akuma\MediaBundle\AkumaMediaBundle::class => ['all' => true],
];
Configuration Publish the default config:
php artisan vendor:publish --tag=akuma-media-config
Update config/akuma_media.php with your storage paths (e.g., public/media, private/media).
First Use Case: Uploading Media
Inject the Akuma\MediaBundle\Service\MediaService into a controller:
use Akuma\MediaBundle\Service\MediaService;
class MediaController extends Controller
{
protected $mediaService;
public function __construct(MediaService $mediaService)
{
$this->mediaService = $mediaService;
}
public function upload(Request $request)
{
$file = $request->file('media');
$media = $this->mediaService->upload($file, 'public'); // 'public' or 'private'
return response()->json(['url' => $media->getUrl()]);
}
}
Routes & Views
Define a route in routes/web.php:
Route::post('/upload', [MediaController::class, 'upload']);
Use the media helper in Blade:
<img src="{{ media('public', $media->getFilename()) }}" alt="Media">
File Handling
MediaService::upload($file, $storageType) to store files in either public or private storage.MediaService::delete($mediaId).MediaService::find($mediaId).Storage Integration
public (web-accessible) and private (non-web-accessible) storage.config/akuma_media.php:
'storages' => [
'public' => [
'path' => 'public/media',
'url' => '/media',
],
'private' => [
'path' => 'private/media',
],
],
Model Integration
hasMany relationship:
use Akuma\MediaBundle\Entity\Media;
class Post extends Model
{
public function media()
{
return $this->hasMany(Media::class);
}
}
MediaService::attach($mediaId, $model) to link media to models.Validation
$request->validate([
'media' => 'required|file|mimes:jpg,png|max:2048',
]);
Batch Operations
$this->mediaService->deleteMany([$id1, $id2]);
media.uploaded or media.deleted events.Akuma\MediaBundle\Storage\StorageInterface.return response()->json([
'data' => $media->getUrl(),
'thumbnail' => $media->getThumbnailUrl(),
]);
Storage Permissions
public/media and private/media directories are writable:
chmod -R 775 storage/app/public/media
chmod -R 775 storage/app/private/media
php artisan storage:link if using public/media symlinks.Missing Config
404, verify config/akuma_media.php paths and storage:link.Private Storage Access
MediaService::getStream() for direct responses:
return response()->streamDownload(function () use ($media) {
echo $media->getStream();
}, $media->getFilename());
Dependency on Core Bundle
akuma/core-bundle (dev-master). Pin versions in composer.json to avoid instability:
"akuma/core-bundle": "dev-master#1234abc"
config/akuma_media.php:
'debug' => env('APP_DEBUG', false),
media.error events to catch upload failures:
Event::listen('media.error', function ($event) {
Log::error('Media error: ' . $event->getMessage());
});
Custom Storage Drivers
Override Akuma\MediaBundle\Storage\FilesystemStorage for S3/Cloud storage:
class CustomStorage implements StorageInterface
{
public function save($file, $path)
{
// Custom logic (e.g., AWS S3)
}
}
Register in config/akuma_media.php:
'storage_driver' => \App\Storage\CustomStorage::class,
Media Events
Extend core events (e.g., media.uploaded) in EventSubscriber:
class MediaSubscriber implements EventSubscriber
{
public static function getSubscribedEvents()
{
return [
'media.uploaded' => 'onMediaUploaded',
];
}
public function onMediaUploaded(MediaEvent $event)
{
// Post-upload logic (e.g., generate thumbnails)
}
}
Validation Rules
Add custom rules to config/akuma_media.php:
'validation' => [
'mimes' => ['jpg', 'png', 'pdf'],
'max_size' => '5120', // KB
],
MediaService::generateThumbnail() for on-the-fly resizing:
$thumbnail = $this->mediaService->generateThumbnail($mediaId, 200, 200);
class PostObserver
{
public function deleting(Post $post)
{
$post->media()->each(function ($media) {
app(MediaService::class)->delete($media->id);
});
}
}
$media = app(MediaService::class)->find($id, ['cache' => true]);
How can I help you explore Laravel packages today?