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

Request Dto Resolver Laravel Package

macpaw/request-dto-resolver

macpaw/request-dto-resolver automatically maps incoming Laravel request data into typed DTOs, cutting boilerplate and keeping controllers clean. It resolves DTO constructor parameters, supports nested objects, and makes request handling more explicit, predictable, and easy to test.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install via Composer: composer require macpaw/request-dto-resolver. Pin to ^1.1.2 (see Gotchas — v1.1.1 regressed attribute lookup).
  • Enable the bundle if Symfony Flex does not auto-register it. Check the README or src/ for the exact bundle class name, then add it to config/bundles.php.
  • Look first at:
    • README.md for the public API and the attributes the resolver reads.
    • src/ for the argument resolver and bundle extension — specifically the attribute lookup logic touched by v1.1.2.
    • tests/ for working examples — with 1 star and 0 dependents, tests are likely the most reliable documentation.
  • First use case: replace manual $request->query->get(...) extraction in a controller with a typed DTO decorated with the resolver's attribute.
final class SearchRequest
{
    public function __construct(
        public readonly string $q = '',
        public readonly int $page = 1,
        public readonly int $perPage = 20,
    ) {}
}

#[Route('/search', methods: ['GET'])]
public function search(#[MapRequestDto] SearchRequest $request): JsonResponse
{
    // $request is populated from query parameters by the resolver
}

As of v1.1.2 the resolver performs route attribute lookup to decide how a DTO parameter is resolved. Do not rely on the bare controller type-hint alone: attach the package's attribute (or the route-level configuration it documents) and confirm in the README/tests which attribute name and target (parameter vs. class) is expected. Verify the attribute is picked up before adding validation or nested objects.

Implementation Patterns

  • One DTO per request shape. Use separate DTOs for query filters, JSON bodies, and path parameters. This keeps validation rules and serializer groups explicit.
  • Prefer immutable DTOs. Constructor promotion and readonly properties make the resolved object predictable and safe to pass to services.
  • Validate on the DTO. Add Symfony Validator constraints to DTO properties and confirm the resolver triggers validation. Handle validation failures through your normal exception listener to return a consistent error response.
  • Use the DTO as the controller boundary. Let the resolver handle hydration; keep controllers free of request-parsing logic.
final class CreateUserRequest
{
    public function __construct(
        #[Assert\NotBlank]
        #[Assert\Email]
        public readonly string $email,

        #[Assert\Length(min: 8)]
        public readonly string $password,
    ) {}
}

#[Route('/users', methods: ['POST'])]
public function create(#[MapRequestDto] CreateUserRequest $request): JsonResponse
{
    // validated DTO ready for the application layer
}
  • Keep the attribute on every DTO parameter. Since resolution is attribute-driven, a missing/renamed attribute is the most likely cause of an unhydrated argument. Put it on the controller parameter consistently across the codebase rather than mixing attribute and non-attribute controllers.
  • Map nested structures deliberately. For arrays of objects, enums, or DateTimeImmutable, check how the bundle uses the Symfony Serializer. You may need serializer normalizers, #[SerializedName], or custom denormalizers.
  • Separate GET query DTOs from POST body DTOs. Query strings are flat strings by default; JSON bodies support richer types. Do not assume the same DTO works equally well for both.
  • Integration with Symfony’s native resolver. On Symfony 6.3+, #[MapRequestPayload] / #[MapQueryString] exist. Compare behaviour before adopting this package broadly; this bundle may be useful for query DTOs or older Symfony versions, but avoid running two competing resolvers without understanding priority.
  • Test at the HTTP boundary. Use KernelBrowser functional tests to assert that query/body data reaches the controller as a populated DTO. Add a regression test that the attribute on the parameter is honoured — that is precisely the behaviour v1.1.2 restores.
  • Use DTOs as OpenAPI schemas. Keep property types and docblocks accurate so generated API docs match runtime hydration.

Gotchas and Tips

  • v1.1.1 broke attribute-driven resolution; fixed in v1.1.2. The changelog entry "fix: restore route attribute lookup for DTO parameter resolution" means attribute lookup was missing/broken in the previous patch and DTO parameters could arrive unhydrated. Require ^1.1.2 and re-test hydration after any upgrade in this line.
  • Resolution is attribute-based, not type-hint-based. If a DTO parameter is empty, first check that the package attribute is present and correctly named/imported, then check resolver priority.
  • Low adoption means limited real-world coverage. With 1 star and 0 dependents, inspect the source and tests before relying on edge-case behaviour. Pin the version in composer.json and review changelogs before upgrades.
  • Check Symfony and PHP version constraints. The library’s composer.json is the source of truth. Do not assume compatibility with older or newer Symfony releases.
  • Argument resolver priority matters. If the DTO is not populated, another resolver may be intercepting the argument. Use bin/console debug:container to confirm the resolver service is registered and inspect its priority.
  • Validation is not automatic unless configured. Ensure symfony/validator is installed and that the resolver actually validates the DTO. Without this, invalid payloads can reach your controller.
  • Nested mapping often needs serializer configuration. Enums, dates, arrays of DTOs, and snake_case/camelCase mismatches frequently require custom normalizers or naming strategies.
  • Do not bind entities directly. DTOs reduce mass-assignment risk, but only if you validate and explicitly map DTO fields to domain objects. Never let request data drive entity persistence directly.
  • Debugging tips:
    • Dump inside the resolver or controller argument to confirm hydration.
    • Confirm the attribute instance is visible on the parameter via ReflectionParameter::getAttributes().
    • Use debug:event-dispatcher and debug:container to trace resolver registration.
    • Check var/log/dev.log for serializer/validator exceptions.
  • Contributing to the package itself: run composer install, composer phpunit, and XDEBUG_MODE=coverage vendor/bin/phpunit for coverage. The repo does not commit composer.lock, so installs resolve fresh dependency versions.
  • Extension points to inspect: custom argument resolvers, serializer normalizers, validation groups, and bundle configuration under config/packages/. Prefer decorating or configuring these over forking the bundle.
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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib