Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Controller Extra Bundle Laravel Package

mmoreram/controller-extra-bundle

Symfony bundle that cuts controller boilerplate with annotations: inject request params, Doctrine entities, paginators, logged-in users, and cache or log behavior directly into controller actions. Keeps code small and declarative, with custom resolvers for extending it.

View on GitHub
Deep Wiki
Context7

Getting Started

First, a reality check: this is a Symfony2/Symfony3 bundle, not a Laravel package. There is no service provider, no facade, no config file Laravel will read. composer require mmoreram/controller-extra-bundle in a Laravel app will succeed (it pulls symfony/http-kernel, doctrine/annotations, etc.) but nothing will be wired up — the ControllerExtraBundle class extends Symfony\Component\HttpKernel\Bundle\Bundle, and Laravel never instantiates bundles. So your "getting started" depends on which of two situations you're in.

If you are actually in a legacy Symfony 2.3–3.x app

  1. composer require mmoreram/controller-extra-bundle
  2. Register it in app/AppKernel.php: new Mmoreram\ControllerExtraBundle\ControllerExtraBundle()
  3. Confirm annotations are enabled (framework.annotations: true, plus doctrine/annotations and sensio/framework-extra-bundle present), and that the routing.yml for the controller uses type: annotation.
  4. Look first at the bundle's Annotation/ directory — that is the authoritative API surface. The headline annotations are @Paginator, @Entity, @Cache and @Log (with a couple of smaller helpers depending on version). The README is thin; the annotation classes and their EventSubscriber//EventListener/ counterparts tell you exactly which request attributes and controller arguments they populate.
  5. First use case to try — replace a hand-rolled pagination block in one list action:
/**
 * @Paginator(
 *     entityManager = "doctrine.orm.default_entity_manager",
 *     query         = "SELECT u FROM AppBundle:User u",
 *     page          = "page",
 *     limit         = "limit"
 * )
 */
public function listAction($paginator)
{
    return ['paginator' => $paginator];
}

(Exact parameter names drift between versions — read Annotation/Paginator.php before copying snippets from blog posts.)

If you are a Laravel developer evaluating it

Don't install it. Read the README and the Annotation/ folder as a design checklist for controller boilerplate, then map each annotation to what Laravel already gives you:

Bundle annotation Laravel equivalent, out of the box
@Entity (request param → entity, 404 if missing) Implicit route model binding: Route::get('/users/{user}', ...)
@Paginator User::paginate(15) + $users->links()
@Cache (cache a controller response for a TTL) Cache::remember() around the query, or spatie/laravel-responsecache for whole-response caching
@Log A LogRequests middleware with Log::info(), or spatie/laravel-activitylog

Your first "use case" is therefore: pick the one action in your app with the most boilerplate (usually a filtered, paginated index), and confirm Laravel's native tools already cover it. They almost always do.

Implementation Patterns

Pattern 1: Annotation-driven controller, Symfony style

The bundle's whole value proposition is that a controller action declares its inputs and side effects in the docblock, and event listeners on kernel.controller / kernel.controller_arguments resolve them before your method body runs. A typical annotated action:

/**
 * @Entity(
 *     name    = "user",
 *     class   = "AppBundle:User",
 *     mapping = {"id" = "id"}
 * )
 * @Cache(ttl = 3600, key = "user_show")
 * @Log(message = "User profile viewed", level = "info")
 */
public function showAction(User $user)
{
    return ['user' => $user];
}

Workflow tip: keep these actions thin. The bundle is designed so the method body is 1–3 lines. If you find yourself unpacking the paginator and re-querying, you're fighting the abstraction.

Pattern 2: The Laravel translation of the same action

// routes/web.php
Route::get('/users/{user}', [UserController::class, 'show'])->name('users.show');

// app/Http/Controllers/UserController.php
public function show(User $user)
{
    return view('users.show', compact('user'));
}

Route model binding does @Entity's job; returning a view/JSON does the response shaping. Add ->middleware('cache.headers:public;max_age=3600') or wrap the payload in Cache::remember("user.{$user->id}", 3600, fn () => ...) for the @Cache behaviour.

Pattern 3: Middleware as the modern @Log

The bundle's @Log is a per-action cross-cutting concern. In Laravel, cross-cutting concerns belong in middleware, not annotations, because you get one place to change and it applies to whole route groups:

// app/Http/Middleware/LogControllerAction.php
public function handle($request, Closure $next)
{
    Log::info('controller.action', [
        'route'  => $request->route()->getName(),
        'action' => $request->route()->getActionName(),
        'user'   => optional($request->user())->id,
    ]);

    return $next($request);
}

Register it globally in bootstrap/app.php (Laravel 11+) or Kernel::$middleware. This is the direct upgrade path from "annotate each action."

Pattern 4: If you must maintain the Symfony app

Integrate the bundle only where it replaces existing code — don't annotate new actions for the sake of it. The pragmatic migration order is:

  1. @Entity on detail/show actions (highest boilerplate savings, lowest risk).
  2. @Paginator on index actions.
  3. @Cache last, and only on read-only, non-authenticated-variant endpoints (see Gotchas).
  4. @Log never — use a Monolog channel or a kernel listener you control.

Pattern 5: Extract, don't depend

If you like the annotation ergonomics, the durable version is to write your own small kernel.controller_arguments listener (Symfony) or a FormRequest + policy (Laravel). The bundle is 151 stars, zero dependents, last released 2017 — treat it as a reference implementation of the pattern, not a runtime dependency.

Gotchas and Tips

It will not run on Symfony 4+ (Flex). Symfony 4 removed bundle registration from AppKernel, and the bundle predates the Flex recipe era — there is no recipe, no config/bundles.php entry, and its service definitions assume Symfony 2/3 container semantics. Installing it on a modern Symfony is a dead end. On Laravel it is a no-op.

Version drift in annotation parameters. The README on GitHub does not match every tagged release. The single most common time-waster is copying a @Paginator(query = "...") snippet that belongs to a different minor version. Always open vendor/mmoreram/controller-extra-bundle/Annotation/<Annotation>.php and read the public properties — those are the accepted argument names.

@Entity overlaps with @ParamConverter. If sensio/framework-extra-bundle is installed, both listeners may try to resolve the same controller argument. Whichever listener has the higher priority runs first, and the second may overwrite or 404 unexpectedly. Fix by using one or the other per action, and if debugging, dump $event->getRequest()->attributes->all() in a kernel.controller listener to see which one won.

@Cache caches the response, not the data — and it does not understand user context. An action that varies by logged-in user, by Accept header, or by query string can serve one user's response to another if the cache key is static. Always make key include the varying inputs (e.g. key = "user_show_" ~ id if the annotation supports expression keys in your version) or skip @Cache for authenticated endpoints entirely. In Laravel the equivalent trap is Cache::remember without the user id in the key.

Cache invalidation is manual. The bundle has no tag-based invalidation and no observer on Doctrine writes. You will be clearing the pool (cache:pool:clear, or cache:clear in older Symfony) after every content change. This is the main reason the pattern lost to HTTP-cache middleware (symfony/http-cache, or spatie/laravel-responsecache on the Laravel side), which can purge by tag.

@Log is synchronous and in-request. It writes during the request lifecycle; a slow log handler directly increases response time, and it logs before you know whether the action threw. For anything you actually rely on for audit, use a kernel.terminate listener or Laravel's terminable middleware.

Annotations are parsed on every request in dev, cached in prod. If you add an annotation and see no effect, you almost certainly need to clear the container/annotation cache (bin/console cache:clear --env=prod). This accounts for the majority of "the bundle is broken" reports.

No PHP 7.2+ / 8.x guarantees. Last release 2017-12-04 means it predates PHP 7.2's object type, PHP 7.4 typed properties, and PHP 8 attributes entirely. On PHP 8 you may hit deprecation noise from doctrine/annotations or reflection-based code. Pin your PHP version or run with E_DEPRECATED suppressed.

Extension points, if you're stuck on it: each annotation is paired with a listener that you can override by registering your own service with the same event and a higher priority in the tag (kernel.event_listener). You can also decorate the paginator factory if the bundle exposes one as a service — check Resources/config/services.yml for the service ids; that file is the real table of contents for the bundle.

For a Laravel team, the actionable takeaway: the four annotations map 1:1 onto route model binding, Eloquent pagination, response caching middleware, and logging middleware. There is nothing here you need to import. Re-derive the ergonomics, skip the dependency.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect