symkit / media-bundle
A powerful, modern media management bundle for Symfony applications, designed for performance, flexibility, and a premium UI/UX.
Installs: 33
Dependents: 1
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
Type:symfony-bundle
pkg:composer/symkit/media-bundle
Requires
- php: >=8.2
- symfony/framework-bundle: ^7.0 || ^8.0
- symkit/crud-bundle: ~0.0.1
- symkit/form-bundle: ~0.0.1
- symkit/menu-bundle: ~0.0.1
- symkit/metadata-bundle: ~0.0.1
- symkit/search-bundle: ~0.0.1
Requires (Dev)
- deptrac/deptrac: ^4.6
- friendsofphp/php-cs-fixer: ^3.94
- infection/infection: ^0.32.5
- nyholm/symfony-bundle-test: ^3.0
- phpro/grumphp: ^2.0
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11.0
- symfony/asset-mapper: ^7.0 || ^8.0
- symfony/mime: ^7.0 || ^8.0
- symfony/ux-dropzone: ^2.0
- symkit/bundle-ai-kit: ~0.0.1
README
A powerful, modern media management bundle for Symfony applications, designed for performance, flexibility, and a premium UI/UX.
Features
- Async Uploads: Fast, asynchronous file uploads via dedicated API endpoint.
- Advanced Security Layer: Modular security strategy pattern to block threats (Magic Bytes, SVG sanitization, pixel/archive bomb protection, MIME consistency).
- File Processing: EXIF stripping, strict file permissions.
- Media Library: Grid-based library with search and pagination (Live Component).
- Media Picker: Form field for selecting and replacing media assets.
- SOLID & Configurable: Activable admin/API, configurable entity and repository, routes via YAML.
- Translations: FR and EN included; domain
SymkitMediaBundle. - Hotwired Stack: Symfony UX Live Components and Stimulus.
Installation
1. Install via Composer
composer require symkit/media-bundle
2. Register the Bundle
In config/bundles.php:
return [ // ... Symkit\MediaBundle\SymkitMediaBundle::class => ['all' => true], ];
3. Configuration
Create config/packages/symkit_media.yaml:
symkit_media: public_dir: '%kernel.project_dir%/public' media_prefix: '/uploads/media/' alt_text_strategy: 'Symkit\MediaBundle\Strategy\FilenameAltTextStrategy' admin: enabled: true route_prefix: 'admin' # URL prefix for admin routes (e.g. /admin/media) api: enabled: true # Async upload endpoint doctrine: entity: 'Symkit\MediaBundle\Entity\Media' repository: 'Symkit\MediaBundle\Repository\MediaRepository' search: enabled: true # Register MediaSearchProvider for symkit/search-bundle engine: 'default' # Search engine to attach the provider to
4. Routes
Include the bundle routes in config/routes.yaml:
# Admin (list, create, edit, delete) symkit_media_admin: resource: '@SymkitMediaBundle/config/routing_admin.yaml' prefix: '%symkit_media.admin.route_prefix%' # API (async upload) symkit_media_api: resource: '@SymkitMediaBundle/config/routing_api.yaml' prefix: /admin/medias/api
If admin.enabled or api.enabled is false, do not include the corresponding route block so that those URLs are not exposed.
5. Assets
The bundle prepends its Stimulus controllers to AssetMapper. Ensure your app discovers them (e.g. via assets/bootstrap.js and Stimulus).
Activation / Deactivation
- Disable admin: Set
admin.enabled: falseand remove or do not load thesymkit_media_adminroutes. - Disable API: Set
api.enabled: falseand remove or do not load thesymkit_media_apiroutes. - Disable search: Set
search.enabled: falseto avoid registering the media search provider with symkit/search-bundle. No attributes are used; the provider is registered via the bundle’s PHP config (tagsymkit_search.provider).
Only the controllers, routes, and search provider are conditional; core services (MediaManager, forms, Live Components, etc.) remain available when the bundle is enabled.
Custom Entity and Repository
You can use your own Media entity and repository:
- Create an entity (e.g. extend
Symkit\MediaBundle\Entity\Mediaor implement the same contract) and map it with Doctrine. - Create a repository that implements
Symkit\MediaBundle\Repository\MediaRepositoryInterface(or extendSymkit\MediaBundle\Repository\MediaRepositorywith a constructor acceptingManagerRegistryandstring $entityClass). - Configure:
symkit_media: doctrine: entity: 'App\Entity\Media' repository: 'App\Repository\MediaRepository'
Translations (FR / EN)
The bundle ships with English and French in translations/ (domain SymkitMediaBundle). The translation path is registered automatically.
- Set your app locale in
config/packages/framework.yaml(default_locale,enabled_locales) and use the translator as usual. - All admin labels, form labels, library and picker UI, and API error messages use this domain.
Usage
In Entities
use Symkit\MediaBundle\Entity\Media; #[ORM\ManyToOne(targetEntity: Media::class)] #[ORM\JoinColumn(onDelete: 'SET NULL')] private ?Media $image = null;
In Forms
use Symkit\MediaBundle\Form\MediaType; $builder->add('image', MediaType::class);
In Twig
<img src="{{ article.image|media_url }}" alt="{{ article.image.altText }}">
Architecture & SOLID
- MediaManager: Orchestrates upload (Security → Processing → Storage → Metadata).
- MediaRepositoryInterface: Implement or extend the default repository for custom entity/repository.
- SecurityRuleInterface: Tag with
symkit_media.security_rulefor custom security rules. - FileProcessorInterface: Tag with
symkit_media.processorfor custom processors. - StorageInterface: Swap storage backends (Local, S3, etc.).
- AltTextStrategyInterface: Customize alt text generation.
Testing
Bundle test suite
From the bundle root, run make test. After composer install, you can also run make quality for the full pipeline (cs-check, phpstan, deptrac, lint, test, infection).
The suite includes unit tests (services, form transformer, security rules, Live Components, search provider), integration tests (bundle boot, config, services), and functional tests (API upload).
Testing in an application
To validate the bundle in a real application (e.g. an app that uses this bundle via Composer):
- Run the application (e.g.
symfony serveorphp -S localhost:8000 -t publicfrom the app root). - Admin media
- Open the media list (e.g.
/admin/mediaifroute_prefixisadmin). - Check: list, create (upload), edit (replace file), delete.
- Open the media list (e.g.
- API upload
- POST a file to the async upload endpoint (e.g.
/admin/medias/api/uploadwithfile). - Expect JSON
{ "id", "url", "filename" }on success.
- POST a file to the async upload endpoint (e.g.
- Media Library / Picker
- Use a form that embeds the media library or picker Live Component; run search, pagination, and selection.
- Search
- If the app uses symkit/search-bundle, trigger global search and confirm media results appear.
These steps can be automated with E2E tools (e.g. Playwright, Mink) or run as a manual checklist.
Contributing
- Run the quality pipeline:
make quality(ormake cs-fix,make phpstan,make test).
License
MIT