gollumsf/controller-action-extractor-bundle
Symfony bundle for extracting the current controller and action from a request, making it easy to log, debug, or display which controller is handling each route. A lightweight helper for routing-aware applications.
Read this first: it is a Symfony bundle, not a Laravel package. There is no service provider, no facade, no config file published to config/, and Composer's Laravel auto-discovery will not find anything to register. composer require gollumsf/controller-action-extractor-bundle in a Laravel app will install files that are never autoloaded into the container. Treat it as a reference implementation rather than a dependency.
If you are working inside a Symfony codebase (or a Laravel app that has pulled in symfony/http-kernel for a specific subsystem), the minimal path is:
composer require gollumsf/controller-action-extractor-bundle — as of v2.0.2 the tracked branch is Symfony 8.1, so check the composer.json constraint against your own Symfony version before assuming it will resolve.config/bundles.php:
GollumSF\ControllerActionExtractorBundle\GollumSFControllerActionExtractorBundle::class => ['all' => true],
src/Extractor/ first — that is where the actual logic lives. Then src/DependencyInjection/ to find the service id/alias you should inject, and tests/ for the canonical call shape. The bundle is small enough that the test suite is the best documentation._controller request attribute into a stable Controller::action pair so you can derive permission names, metric labels, or breadcrumb keys without string-munging App\Controller\FooController::barAction at every call site.The Laravel equivalent you almost certainly want instead:
use Illuminate\Support\Facades\Route;
$action = Route::currentRouteAction(); // "App\Http\Controllers\FooController@bar"
[$controller, $method] = explode('@', $action);
// or, more robustly, from the route itself:
$route = request()->route();
$controller = $route?->getControllerClass();
$method = $route?->getActionMethod();
Note the delimiter difference: Symfony uses ::, Laravel uses @. Any mapping table you build between the two frameworks has to normalize this.
Permission / authorization strings. The classic use for this bundle: derive a voter or ACL subject from the current controller+action, e.g. app.foo.bar. Inject the extractor into an event listener on kernel.controller, normalize the class name (strip the namespace, snake_case the short name), and check it against your ACL. In Laravel the same pattern becomes a middleware that reads Route::currentRouteName() or the controller class and calls Gate::authorize().
Observability tagging. Attach controller and action as labels on request-duration metrics or as log context fields. This is where the extraction pays for itself: doing it once in a listener beats explode('::', ...) scattered across handlers. In Laravel, put it in a terminable middleware and push into Log::withContext().
Breadcrumbs and active-menu state. Map Controller::action to a menu key rather than hardcoding route names in templates. This survives route renames and keeps navigation logic out of Twig/Blade.
Route-name convention generation. If your project enforces {controller}.{action} naming, the extractor lets you generate the route name for redirects and url() calls from the controller you are already in, instead of duplicating string literals.
Migration mapping (the one genuinely useful Laravel case). If you are porting a Symfony app to Laravel, run the extractor across your Symfony routes and emit a table of Symfony\Controller::action -> laravel.route.name, then load it as a redirect map. That is a one-off script, not a runtime dependency — vendor the bundle's extractor class into app/Support/ under your own namespace rather than shipping a GPL dependency.
Wrap it. Never inject the bundle's concrete extractor directly into your domain code. Define your own ControllerActionResolver interface, adapt the bundle behind it (or implement it against Laravel's Route), and you keep the option of dropping the bundle later without a refactor.
_controller is not always a string. It can be a Closure, an array callable [object, 'method'], an invokable controller class name with no method, or a service id when controller.service_arguments is in play. Verify the extractor handles each shape before you trust it in a listener; write your own test cases for invokable controllers and closures._controller. Fragment/ESI rendering and forward() calls change the attribute mid-request. Capture the value early (a kernel.request-priority listener) if you are building audit logs or metrics, not lazily during rendering.Request::$attributes is hookable from Symfony 8.1 onward. The v2.0.2 release specifically had to stop assigning Request::$attributes on a PHPUnit double, because it is now a property with hooks. If you write your own test doubles for request-level extraction, you will hit the same wall — either construct a real Request via Request::create() or use a partial mock that does not touch attributes. Assertions that read $request->attributes still work; assignment in setUp() does not.composer.json. The maintainers found their own symfony_* CI jobs were silently installing the latest components instead of the targeted branch until they switched to Flex's SYMFONY_REQUIRE. Your app has the same failure mode: a floating symfony/* constraint will pull 8.1 components under a bundle that only advertises 8.1 by name. Set SYMFONY_REQUIRE (or explicit constraints) so the tested matrix and your installed matrix actually match.composer.json constraints on every upgrade.$event->getRequest()->attributes->all()) rather than guessing at the _controller shape. On the Symfony side the debug:router command shows the resolved controller for each route; on the Laravel side use php artisan route:list -v.decorates: key) rather than forking the class. That keeps your normalization rules — namespace stripping, __invoke handling — out of vendor code.How can I help you explore Laravel packages today?