symfonyid/symfony-bundle-plugins
A Symfony bundle that adds a plugin system to your application, letting you discover, register, and manage plugins through dependency injection tags and compiler passes for a clean, modular architecture.
The package has essentially no public documentation, no releases of note, and zero dependents, so the first job is reconnaissance rather than reading a README. Treat every API in it as "infer from source" until proven otherwise.
Install and inspect before wiring anything up:
composer require symfonyid/symfony-bundle-plugins
Then immediately read src/ end to end. You are looking for three things:
PluginInterface or an abstract Plugin base class),DependencyInjection/Compiler/) that wires plugins into the container.Where to look first. Start at the bundle class (*Bundle.php) and its build() method. In Symfony bundle-extension packages, the compiler pass registration is almost always there. Then read the extension class (DependencyInjection/*Extension.php) to see whether plugins are loaded from configuration or from tagged services. That single decision determines your whole integration strategy.
Register the bundle in config/bundles.php:
return [
// ...
SymfonyId\BundlePlugins\BundlePluginsBundle::class => ['all' => true],
];
First real use case. Pick one internal bundle in your app that has grown a grab-bag of optional behaviours (an AdminBundle, a ReportingBundle). Convert one of those behaviours into a plugin: implement the package's plugin interface, mark the class as a service, and let the manager pick it up. Do not attempt this on a third-party bundle first — you want a codebase you can edit when the interface turns out to be awkward.
If, after an hour of reading, the package's plugin contract requires bundles to change their base class or override getContainerExtension(), stop and reconsider. That is a large blast radius for an unmaintained dependency.
Pattern 1 — Service-tagged plugins (preferred). The most common shape for this kind of package is a compiler pass that collects services with a tag:
// config/services.yaml in your bundle
services:
App\Reporting\CsvExportPlugin:
tags:
- { name: 'symfonyid.bundle_plugin', priority: 10 }
Then consume them from the manager service rather than instantiating plugins yourself. This keeps plugins lazy and testable and lets you swap implementations without touching the bundle.
Pattern 2 — Bundle-declared plugins. If plugins are declared by the bundle class (e.g. a plugins() or getPlugins() method returning class names), keep that list short and let each plugin own its own dependencies via the container. A bundle class should not become a second service container.
Pattern 3 — Priority-ordered pipeline. If the manager exposes priorities or an ordered iteration, use it for anything resembling a middleware chain: export formatters, notification channels, validation rules. Ordering is the whole value proposition — without deterministic order, plugins are just global state with extra steps.
Pattern 4 — Config-driven enablement. In config/packages/*.yaml, expose a per-plugin toggle in your bundle's extension configuration and filter the manager's collection based on it. This gives you an operational kill switch when a plugin misbehaves in production, which matters more than usual when the plugin framework itself is untested.
Pattern 5 — Decorating bundle services. Where the package only provides discovery and you need to change behaviour, register a decorator around the core service and have it delegate across the plugin collection. This sidesteps any gaps in the plugin contract.
Testing. Use KernelTestCase and boot a minimal kernel with only the bundles under test. Assert on the manager's resolved plugin list, not on container internals. If the package registers its compiler pass unconditionally, you may need a separate test kernel to isolate bundle interactions.
$container->addCompilerPass(..., PassConfig::TYPE_BEFORE_OPTIMIZATION, -10) or verify config/bundles.php ordering before assuming the package is broken.bin/console cache:clear; in dev, stale plugins silently missing is the number-one confusing symptom.bin/console debug:container --tag=<tag_name> and bin/console debug:container --show-private are your fastest route to confirming registration. Follow with debug:autowiring for the manager service.composer.json ("symfonyid/symfony-bundle-plugins": "dev-master#<commit>" or a locked tag) and consider vendoring the source into src/ if the plugin mechanism becomes load-bearing.PluginCollection service so you can replace the whole package with twenty lines of a compiler pass if it is abandoned.extra.laravel.providers ergonomics. Expect to do the registration wiring by hand, and expect failures to surface at container-compile time rather than at boot, which makes them easier to debug but noisier in output.How can I help you explore Laravel packages today?