jungi/framework-extra-bundle
A Symfony bundle that adds extra annotations and conveniences beyond SensioFrameworkExtraBundle, helping streamline controller configuration and common framework tasks with less boilerplate.
Reality check first. This is a Symfony bundle, not a Laravel package. There is no service provider, no config/ publish tag, and Composer will not auto-register anything in a Laravel app. Treat this assessment as: (a) how to use it if your team also runs Symfony services, and (b) which patterns are worth stealing for a Laravel codebase.
ValueResolverInterface, which only exists from Symfony 6.2. That effectively raises the floor: treat 6.2+ as the supported range and do not assume 5.4 still works without pinning an older tag. If you are 100% Laravel, skip to the exit-strategy note in Gotchas — the same problems are already solved by FormRequest + middleware.composer require jungi/framework-extra-bundle
Then add it to config/bundles.php:
Jungi\FrameworkExtraBundle\JungiFrameworkExtraBundle::class => ['all' => true],
Attributes/ directory — this is the entire public surface. Everything the package does is driven by PHP 8 attributes on controller actions/methods.ValueResolver/ (argument resolver) classes and the DependencyInjection/ extension — as of v2.1.0 these implement ValueResolverInterface, which tells you both when attributes are read and how to override them, and the DI config tells you the tag/service ids.Accept header. In Laravel terms, that is the equivalent of replacing a FormRequest + response()->json() boilerplate pair with declarative method-level metadata.First use case (Laravel side): read the attribute set as a design spec. The valuable idea is "request/response contract lives next to the handler, not in a separate FormRequest class or middleware file." You can reproduce this in Laravel with a custom Route::macro or a controller dispatcher that reflects over method attributes.
Symfony host application
Accept/Content-Type. Pair this with a serializer so negotiation and serialization don't drift. If a controller accepts application/vnd.api+json, the vendor media type has to be declared explicitly — the negotiator will not guess it from application/json.#[MapRequestPayload] and #[MapQueryString] (Symfony 6.3+). Do not enable both resolution mechanisms across the same controller set; pick one per bounded context. Note that the v2.1.0 change puts this bundle's resolvers in the same pipeline as Symfony's native ones, so the "pick one" rule now matters operationally, not just stylistically."jungi/framework-extra-bundle": "~2.1.0" rather than ^2.0 if you are on 6.2/6.3 — the older tags' resolvers will trigger deprecation notices about ArgumentValueResolverInterface.Laravel application (pattern harvesting)
Accept, picks a supported representation, and stores it on the request ($request->attributes->set('negotiated_format', ...)). Return 406 when nothing matches. This is ~60 lines and removes negotiation logic from every controller.$action method attributes and hydrates a DTO before the controller runs. This is the Laravel analogue of a Symfony value resolver and is the only piece of this bundle worth porting. Mirror the ValueResolverInterface contract from v2.1.0 while you're at it: a resolver that returns "nothing" to signal "not mine" is simpler to compose than a separate supports() method.Validator::make($dto->toArray(), $rules) inside the same resolver. This preserves the "contract next to the handler" benefit without giving up Laravel's validation ecosystem.ValueResolverInterface), not a revival. There are still no dependents filing bugs, and no evidence of Symfony 7 readiness testing. Pin the version and keep an owner; the release makes it installable on 6.2+ without deprecation noise, not supported.ValueResolverInterface is 6.2+. If you were running the bundle on 5.4, upgrading will break at runtime; stay on the previous tag or upgrade Symfony. Check your composer.json constraint against your Symfony version before bumping.ArgumentValueResolverInterface the container called supports() first; with ValueResolverInterface the resolver is invoked and signals "not mine" by returning an empty iterable. Consequences: (1) every resolver in the tag is now hit for every controller argument, so ordering and tag priority matter more; (2) a custom or overriding resolver that returns null/throws instead of [] will now break every action, not just its own. Return [] early and explicitly.#[Attribute] class with the correct TARGET_METHOD and that the use statement is present.q=), */* fallbacks, charset parameters, and vendor media types. Write a test for each before trusting the bundle's negotiation in production.kernel.controller listener and dump() the argument map. If an attribute resolves to null/no argument, debug:container --tag=controller.argument_value_resolver lists what is actually registered and in what order — that is the fastest way to spot a resolver that never ran. On the Laravel side, log the DTO after hydration in your resolver — most bugs are "field name mismatch," not logic.ValueResolverInterface implementations) and the negotiator service definition are the intended seams. To customize, either register your own resolver with a higher tag priority or decorate the bundle's service — both are safer than subclassing internals. If you write custom resolvers, implement ValueResolverInterface (not the deprecated ArgumentValueResolverInterface) so they survive Symfony 7.#[MapRequestPayload]/#[MapQueryString] and, historically, SensioFrameworkExtraBundle. For a Laravel team the true equivalents are FormRequest (binding + validation) and a negotiation middleware (content type). If you are adopting this bundle today, you are adopting a pattern, not a dependency — write the 100 lines yourself and keep the maintenance in-house.How can I help you explore Laravel packages today?