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

Dto Param Converter Bundle Laravel Package

pfilsx/dto-param-converter-bundle

A Symfony bundle that converts request parameters into typed DTOs via a param converter, keeping controllers clean and making input handling more explicit, reusable, and testable.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the bundle and confirm what it actually supports in the installed version:

composer require pfilsx/dto-param-converter-bundle

If Flex does not auto-register it, add it to config/bundles.php:

return [
    // ...
    Pfilsx\DtoParamConverterBundle\DtoParamConverterBundle::class => ['all' => true],
];

Look first at:

  • README.md for the supported attribute/annotation syntax and converter options.
  • src/Attribute or src/Annotation and src/Converter to see exactly how request data is read and how DTOs are constructed.
  • composer.json for Symfony/Sensio/annotations constraints and whether the bundle depends on an abandoned ParamConverter stack.
  • bin/console debug:container --tag=request.param_converter to confirm the converter is registered.

The first useful use case is replacing manual query-string extraction with a typed filter DTO:

namespace App\Dto;

class UserFilterDto
{
    public string $q = '';
    public int $page = 1;
    public int $limit = 20;
}
use Pfilsx\DtoParamConverterBundle\Attribute\DtoParamConverter; // verify namespace in the installed version

#[Route('/api/users', methods: ['GET'])]
public function list(#[DtoParamConverter] UserFilterDto $filter): JsonResponse
{
    // $filter is populated from the request before the controller runs
    return $this->json($this->userRepository->search($filter));
}

Treat that as the “hello world” pattern: one DTO per endpoint/use case, type-hint the DTO in the controller, and let the bundle populate it. Do not start by binding entities or complex nested graphs.

Implementation Patterns

Use request DTOs as controller boundary objects. Keep DTOs under src/Dto/Request or similar, with scalar typed properties and safe defaults. This gives controllers a stable input object instead of scattered $request->query->get() calls.

class SearchOrdersDto
{
    public string $status = 'open';
    public ?string $customerId = null;
    public int $page = 1;
    public int $limit = 25;
}

Separate query filters from command/payload DTOs. A GET search filter and a POST create payload usually have different validation, security, and mapping needs. Do not reuse one DTO for both. For write endpoints, verify whether the bundle reads JSON body content or only request query/form data; if not, keep using Symfony’s native #[MapRequestPayload] for JSON bodies.

Validate explicitly unless the bundle proves otherwise. A ParamConverter-style bundle usually only constructs the DTO; it does not automatically run Symfony Validator constraints.

$errors = $this->validator->validate($filter);
if (count($errors) > 0) {
    throw new ValidationFailedException($errors);
}

Put constraints on the DTO:

use Symfony\Component\Validator\Constraints as Assert;

class SearchOrdersDto
{
    #[Assert\Choice(['open', 'paid', 'cancelled'])]
    public string $status = 'open';

    #[Assert\Range(min: 1, max: 100)]
    public int $limit = 25;
}

Use one DTO per endpoint until a shared base object is clearly stable. Shared pagination/filter DTOs are fine, but avoid deep inheritance. Composition is easier to validate and document.

Map naming deliberately. If your API uses snake_case query parameters and your DTO uses camelCase, use the serializer name converter or explicit serialized-name metadata supported by the installed version. Do not rely on accidental property-name matching.

Integrate with testing at the controller boundary. Functional tests should send real query strings and assert the HTTP result; unit tests should validate DTO constraints directly.

$client->request('GET', '/api/users?page=2&limit=50');
self::assertResponseIsSuccessful();

Consider a custom converter or serializer normalizer only for repeated parsing problems. Examples: custom date parsing, enum conversion, comma-separated IDs, or nested filter objects. Prefer fixing this at the DTO/serializer level before decorating the bundle’s converter.

Document parameters for OpenAPI manually. A type-hinted DTO is not automatically visible to NelmioApiDocBundle/OpenAPI as query parameters. Add explicit query-parameter annotations or migrate to #[MapQueryString], which has better native documentation support in newer Symfony versions.

Plan an exit path. Keep DTOs independent of the bundle so you can replace #[DtoParamConverter] with Symfony’s native #[MapQueryString] or #[MapRequestPayload] later. For Symfony 6.3+, native attributes cover most of this package’s use cases.

Gotchas and Tips

  • Maintenance risk is real. The package has very low adoption, no dependents, and no release since March 2023. Pin it, test Symfony upgrades, and avoid making it a core architectural dependency.
  • Check the ParamConverter/Sensio dependency. If the bundle relies on sensio/framework-extra-bundle or Doctrine annotations, it may be a legacy bridge. Symfony 7 removed annotation support; prefer attribute-based usage and verify compatibility before upgrading.
  • No automatic validation is the most common trap. The converter creates the DTO; your controller or a listener must run the validator and return a proper 422/Problem Details response.
  • Do not bind entities or sensitive fields. A request DTO should expose only intended input fields. Never let a query/body parameter populate isAdmin, ownership IDs, or entity relations directly.
  • JSON bodies are different from query/form data. Confirm whether the converter reads $request->query, $request->request, route attributes, or JSON content. If it does not decode JSON, use native MapRequestPayload for JSON APIs.
  • Type conversion errors can become 500s or 400s instead of validation errors. ?page=abc may fail during DTO construction before validation runs. Use nullable/string DTO properties with constraints if you need consistent 422 responses, or catch conversion exceptions.
  • Constructor DTOs need serializer-friendly signatures. Public properties with defaults are the lowest-friction pattern. Readonly/constructor-only DTOs can fail if the serializer cannot match parameter names or types.
  • Nested arrays and DTO collections are not free. ?filters[status]=open or ?ids[]=1&ids[]=2 may require serializer support, normalizers, or manual post-processing. Start with flat DTOs.
  • Debug registration with the container. If the converter is not invoked, run bin/console debug:container --tag=request.param_converter, clear cache, and verify the attribute namespace and bundle registration.
  • Route/argument names matter. Some ParamConverter configurations require the controller argument name to match the converter name or route parameter. Check the README example exactly.
  • Do not assume Flex recipe/config exists. With low adoption, you may need to register the bundle manually and there may be no published config recipe.
  • Enums and dates are version-sensitive. If native enum/date conversion fails, accept strings in the DTO and convert explicitly in the controller/service. That keeps errors predictable.
  • Keep it as an adapter, not a domain layer. The bundle should convert HTTP input into plain DTOs. Business rules belong in services, not in converter configuration.
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
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager