Installation
composer require app-verk/media-bundle
Ensure app-verk/components (v2.0+) is also installed.
Register the Bundle
Add to config/bundles.php (Laravel 5.4+) or AppKernel.php:
AppVerk\MediaBundle\MediaBundle::class => ['all' => true],
Create a Media Entity
Extend BaseMedia in app/Models (Laravel) or src/Entity (Symfony):
namespace App\Models;
use AppVerk\MediaBundle\Entity\Media as BaseMedia;
use Illuminate\Database\Eloquent\Model;
class Media extends BaseMedia {}
Configure
Add to config/media.php (Laravel) or config.yml (Symfony):
media:
entities:
media_class: App\Models\Media
allowed_mime_types: ["image/jpeg", "image/png", "application/pdf"]
Publish Assets
php artisan vendor:publish --tag=media-assets
Include in your layout:
<link href="{{ asset('vendor/media/css/dropzone.min.css') }}" rel="stylesheet">
<script src="{{ asset('vendor/media/js/dropzone.min.js') }}"></script>
Run Migrations
php artisan migrate
Create a Form
use AppVerk\MediaBundle\Form\Type\MediaType;
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('image', MediaType::class);
}
Render in Blade/Twig
<img src="{{ $post->image->url }}" alt="Post Image">
Dropzone.autoDiscover = false;
new Dropzone("#dropzone", {
url: "{{ route('media_upload') }}",
maxFilesize: {{ config('media.max_file_size') / 1024 }}, // in MB
acceptedFiles: "{{ implode(',', config('media.allowed_mime_types')) }}",
});
/media/upload). No manual controller needed.// Post.php
public function media() {
return $this->morphToMany(Media::class, 'model');
}
morphToMany with model and model_type columns in the media table.media:
groups:
documents:
allowed_mime_types: ["application/pdf", "application/msword"]
max_file_size: 10000000
$builder->add('document', MediaType::class, [
'group' => 'documents',
'label' => 'Upload Document',
]);
media:
storage_path: 'storage/custom_media'
Media entity to override getUrl():
public function getUrl() {
return Storage::disk('s3')->url($this->path);
}
public function bulkUpload(Request $request) {
$validator = Validator::make($request->all(), [
'files.*' => 'required|file',
]);
if ($validator->fails()) return response()->json(['error' => $validator->errors()]);
foreach ($request->file('files') as $file) {
$media = new Media();
$media->upload($file);
$media->save();
}
return response()->json(['success' => true]);
}
Service Provider:
Register the bundle in AppServiceProvider:
public function boot() {
$this->loadViewsFrom(__DIR__.'/../../vendor/app-verk/media-bundle/Resources/views', 'media');
}
Blade Directives: Add a helper for Twig-like syntax:
Blade::directive('media', function ($expression) {
return "<?php echo app('media')->getUrl($expression); ?>";
});
Usage:
<img src="@media($post->image)">
Form Integration: Use Laravel Collective for forms:
use AppVerk\MediaBundle\Form\MediaType;
$form->add('thumbnail', MediaType::class, [
'attr' => ['class' => 'dropzone'],
]);
Twig Extensions:
Register the Twig extension in services.yml:
services:
media.twig.extension:
class: AppVerk\MediaBundle\Twig\MediaExtension
tags: ['twig.extension']
Event Listeners: Listen for upload events:
public function onMediaUpload(MediaEvent $event) {
if ($event->getMedia()->getMimeType() === 'image/jpeg') {
// Process JPEG specifically
}
}
Dropzone.js Conflicts:
$(document).ready(function() {
new Dropzone("#dropzone", { /* options */ });
});
Mime Type Validation:
max_file_size).group config to enforce rules per field.Polymorphic Relationships:
model_type and model_id can break queries.morphToMany or manually set:
$media->model()->associate($post);
$media->model_type = (new ReflectionClass($post))->getShortName();
Storage Permissions:
storage_path lacks write permissions.mkdir -p storage/custom_media && chmod -R 775 storage/custom_media
Deprecated Methods:
FormBuilder, which may not work seamlessly in Laravel.Form facade or wrap the bundle’s form types:
use AppVerk\MediaBundle\Form\MediaType as BaseMediaType;
class MediaType extends BaseMediaType {
public function buildForm(FormBuilder $builder, array $options) {
parent::buildForm($builder, $options);
// Laravel-specific adjustments
}
}
Log Upload Errors: Add a listener to log failed uploads:
public function onMediaUploadFailed(MediaEvent $event) {
\Log::error('Media upload failed', [
'message' => $event->getError(),
'file' => $event->getFile()->getClientOriginalName(),
]);
}
Check Mime Types: Verify mime types with:
$mime = mime_content_type($file->getPathname());
\Log::info("Detected mime type: $mime");
Validate Config:
Ensure media_class in config/media.php matches your extended Media class exactly (namespace included).
Custom Validators:
Extend the validator by overriding the Media entity’s validate() method:
public function validate($group = null) {
$validator = parent::validate($group);
$validator->add('width', 'numeric', ['min' => 100]);
return $validator;
}
Post-Upload Processing: Use events to process files after upload:
public function onMediaUploaded(MediaEvent $event) {
$media = $event->getMedia();
if ($media->getMimeType
How can I help you explore Laravel packages today?