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

Annotation Extra Bundle Laravel Package

swis/annotation-extra-bundle

Adds extra, ready-to-use annotations to Symfony applications, extending Doctrine's annotation support with convenient shortcuts for common controller and configuration tasks. A lightweight bundle that registers quickly and integrates cleanly with existing projects.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony-era bundle (Symfony 2/3 vintage, no recent releases, ~0 dependents) that layers extra Doctrine-style annotations on top of Symfony's DI/annotation plumbing. In practice it lets you move configuration that normally lives in services.yml or routing files onto the class itself, and have a compiler pass translate those annotations into container definitions, tags, or route entries at compile time.

Minimal setup:

composer require swis/annotation-extra-bundle
// app/AppKernel.php (or config/bundles.php in Symfony 3.4+)
$bundles = [
    // ...
    new Swis\AnnotationExtraBundle\SwisAnnotationExtraBundle(),
];

There is typically no bundle configuration to publish — behaviour is driven entirely by the annotations you place on classes. Verify Symfony version constraints in composer.json before installing; on a modern app you will likely need --ignore-platform-reqs or a fork.

Look here first, in this order:

  1. src/Annotation/ — the annotation classes the bundle actually understands. This is your real API documentation; the README is thin.
  2. DependencyInjection/CompilerPass/ — the pass that scans and consumes them. Reading it tells you exactly which directories get scanned and how conflicts are resolved.
  3. Tests/ (if present) — the fastest way to see a working annotated class end to end.

First use case: annotate a non-controller service so you don't have to declare it manually. Instead of

services:
    App\EventListener\AuditListener:
        tags: [{ name: kernel.event_subscriber }]

you write on the class:

use Swis\AnnotationExtraBundle\Annotation as Swis;

/**
 * @Swis\Service
 * @Swis\Tag("kernel.event_subscriber")
 */
class AuditListener implements EventSubscriberInterface { /* ... */ }

Then clear the container cache and confirm with debug:container.

Implementation Patterns

Annotation-as-service-registration. The highest-value pattern is using annotations for infrastructure classes that are pure plumbing: event subscribers, console commands, Twig extensions, Doctrine subscribers. These are the classes where a services.yml entry is boilerplate with no tuning. Annotate them, delete the YAML block, and the container stays declarative.

Tagging instead of _instanceof. If your app already uses _instanceof blocks to tag every implementor of an interface, per-class annotation tags are a more local alternative — the tag lives next to the code it affects, which survives refactors better. Pick one style per interface; mixing both produces duplicate tags.

Controller-as-service routing. Where the bundle supports route annotations on service methods, the pattern is: define the controller as a service (annotated), then put @Route on the action. This is how you get constructor injection into controllers without the AbstractController container-lookup shortcut. Keep routing annotations on the action only — class-level prefixes mixed across two systems get confusing fast.

Layer annotations over explicit config, not under it. Use annotations for the 80% of services with defaults, and keep explicit YAML for anything with constructor arguments, factory methods, or calls: blocks. Annotation DSLs age badly; explicit config is self-documenting for the tricky 20%.

Compiler-pass ordering. If you write your own pass that consumes or rewrites the same definitions, register it with an explicit priority and make sure it runs after the bundle's scanning pass. A common bug is a custom pass seeing zero definitions because it ran first.

Gradual migration path. Introduce the bundle on one namespace (App\Infrastructure\) at a time. The scanning pass usually takes a directory list; constraining it limits blast radius and keeps compile time sane while you evaluate whether the bundle is worth keeping.

When to prefer PHP 8 attributes. If you are on PHP 8 and Symfony 5.3+, skip this bundle entirely. #[AsEventListener], #[AsCommand], #[AutoconfigureTag], and route attributes cover nearly all of its surface with first-party support, static analysis, and no extra compiler pass.

Gotchas and Tips

Stale container cache is the #1 confusion. Annotations are read at compile time, so editing an annotation does nothing until the container rebuilds. bin/console cache:clear in dev; annotations are not re-read per-request in prod.

Failures are compile-time, not runtime. A malformed or unknown annotation throws during cache:warmup, often with a stack trace pointing at the compiler pass rather than your class. Run bin/console cache:clear --no-warmup && bin/console cache:warmup -vvv to isolate it, and bin/console lint:container for definition-level errors.

Annotation classes must be imported. @Service alone will be ignored or throw unless you use Swis\AnnotationExtraBundle\Annotation as Swis; (or register the namespace with the reader). Silent no-ops are usually a missing import, not a bundle bug.

YAML and annotations collide silently. If a service ID exists in both services.yml and an annotation, whichever definition is set last wins, which depends on compiler pass order — not on anything you declared. Never define the same class both ways during a migration; move a class and delete the YAML line in the same commit.

Doctrine annotations are deprecated, and this bundle predates attributes. On PHP 8.1+ with recent doctrine/annotations, you will see deprecation notices from the reader itself. Plan to port: the annotation classes are thin, so converting @Swis\Tag("x") to #[AutoconfigureTag('x')] is mechanical.

Abandonment risk is real. Zero dependents and no releases means no security backports and no Symfony 6/7 compatibility. Before adopting, check composer.json constraints against your Symfony version, and budget for vendoring or forking the two or three classes you actually need — the compiler pass is usually small enough to copy into src/.

Inspect the compiled output to learn the DSL. var/cache/dev/App_KernelDevDebugContainer.xml shows exactly what each annotation produced. This is faster than reading the pass, and it is the definitive answer when you need to know whether an annotation actually emitted a tag.

No IDE support. Annotations look like docblocks, so PHPStorm and PHPStan will not validate them. Add @see references above annotated classes pointing at the annotation class, and rely on debug:container --tag=your_tag in CI smoke tests rather than on static analysis.

Extension point. The clean way to add your own annotation is a new class in your app's Annotation/ namespace plus a small compiler pass that reads it — do not patch the vendor directory, since a composer update will erase it and there is no upstream to send fixes to.

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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package