Weave Code
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

Symfony Request Dto Bundle Laravel Package

dualmedia/symfony-request-dto-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require dualmedia/symfony-request-dto-bundle
    

    Enable the bundle in config/bundles.php:

    return [
        // ...
        Dualmedia\SymfonyRequestDtoBundle\DualmediaSymfonyRequestDtoBundle::class => ['all' => true],
    ];
    
  2. First DTO Class Create a DTO class (e.g., src/Dto/CreateUserDto.php):

    use Dualmedia\SymfonyRequestDtoBundle\Annotation\Bag;
    use Dualmedia\SymfonyRequestDtoBundle\Annotation\FindOneBy;
    use Doctrine\ORM\Mapping as ORM;
    
    #[Bag("query")]
    class CreateUserDto
    {
        #[FindOneBy(targetEntity: User::class, property: "email")]
        public ?User $user;
    
        public string $name;
        public int $age;
    }
    
  3. First Controller Usage Inject the DTO directly into a controller method:

    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\Routing\Annotation\Route;
    
    class UserController
    {
        #[Route("/users", methods: ["POST"])]
        public function create(CreateUserDto $dto): Response
        {
            // $dto->user, $dto->name, $dto->age are automatically populated, validated, and typecast
            return new Response("User created!");
        }
    }
    
  4. Verify Auto-Wiring The bundle hooks into Symfony’s dependency injection. No manual extraction or validation wiring is needed.


Implementation Patterns

Common Workflows

1. Request Body DTOs (Default)

#[Bag("body")]
class LoginDto
{
    public string $email;
    public string $password;
}
  • Automatically resolves JSON payloads (e.g., POST /login with {"email": "...", "password": "..."}).

2. Nested DTOs

class AddressDto
{
    public string $street;
    public string $city;
}

class UserProfileDto
{
    public string $name;
    public AddressDto $address; // Nested DTO
}
  • Supports arbitrary nesting. Request payload:
    {
        "name": "John",
        "address": {
            "street": "123 Main",
            "city": "Metropolis"
        }
    }
    

3. Collections of DTOs

use Dualmedia\SymfonyRequestDtoBundle\Annotation\Collection;

class BulkUserDto
{
    #[Collection]
    public array $users; // Array of UserDto objects
}
  • Resolves arrays of DTOs (e.g., POST /users/bulk with [{...}, {...}]).

4. Flat Root DTOs

use Dualmedia\SymfonyRequestDtoBundle\Annotation\AsRoot;

#[AsRoot]
class FlatUserDto
{
    public string $name;
    public int $age;
}
  • Treats the DTO as the root of the request (e.g., POST /users with {"name": "...", "age": 10} instead of nested under a key).

5. Doctrine Entity Loading

use Dualmedia\SymfonyRequestDtoBundle\Annotation\FindOneBy;
use App\Entity\User;

class UserReferenceDto
{
    #[FindOneBy(targetEntity: User::class, property: "id")]
    public ?User $user;
}
  • Automatically loads User entities from request fields (e.g., POST /posts with {"userId": 1}).

6. Custom Actions

use Dualmedia\SymfonyRequestDtoBundle\Annotation\Action;

class CustomActionDto
{
    public string $field;

    #[Action("custom.action")]
    public function onResolve(): void
    {
        // Custom logic (e.g., logging, transformations)
    }
}
  • Trigger custom logic during DTO resolution via events or annotations.

7. Validation Integration

use Symfony\Component\Validator\Constraints as Assert;

class RegisterDto
{
    #[Assert\NotBlank]
    #[Assert\Email]
    public string $email;

    #[Assert\Length(min: 8)]
    public string $password;
}
  • Validates fields automatically (400 errors for invalid data).

8. Header/Query/Attribute Bags

#[Bag("headers")]
class ApiKeyDto
{
    public string $apiKey;
}
  • Resolves from headers (e.g., X-API-KEY), query params, or route attributes.

Integration Tips

Laravel-Specific Adaptations

  1. Symfony Bridge Use symfony/http-foundation-bundle and symfony/dependency-injection as Laravel dependencies:

    composer require symfony/http-foundation-bundle symfony/dependency-injection
    

    Configure Laravel to load Symfony bundles via config/app.php:

    'extra' => [
        'bundles' => [
            Dualmedia\SymfonyRequestDtoBundle\DualmediaSymfonyRequestDtoBundle::class,
        ],
    ],
    
  2. Request Conversion Convert Laravel’s Illuminate\Http\Request to Symfony’s Request in controllers:

    use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
    
    public function __construct(private SymfonyRequest $request)
    {
        $this->request = $request;
    }
    
  3. Doctrine Integration Ensure Doctrine ORM is installed and configured in Laravel:

    composer require doctrine/orm
    

    Configure config/packages/doctrine.php (Symfony-style) or use Laravel’s Doctrine bridge.

  4. Nelmio API Docs Install Nelmio’s bundle for OpenAPI/Swagger support:

    composer require nelmio/api-doc-bundle
    

    The DTO bundle auto-generates API docs for DTOs.

  5. Event Listeners Register Symfony events in Laravel’s EventServiceProvider:

    protected $listeners = [
        'kernel.request' => [
            \Dualmedia\SymfonyRequestDtoBundle\EventListener\DtoListener::class,
        ],
    ];
    

Gotchas and Tips

Pitfalls

  1. Circular References in DTOs

    • Avoid circular references (e.g., UserDto referencing PostDto which references UserDto). Use lazy loading or break cycles with IDs.
  2. Case Sensitivity in Enums

    • Enum values must match exactly (case-sensitive) with request payloads. Use #[BackedEnum] or #[Enum] annotations for clarity:
      use Dualmedia\SymfonyRequestDtoBundle\Annotation\Enum;
      
      class StatusDto
      {
          #[Enum]
          public string $status; // "ACTIVE", "INACTIVE" (case-sensitive)
      }
      
  3. Doctrine Entity Not Found

    • If #[FindOneBy] fails to load an entity, the DTO property becomes null. Handle this gracefully:
      if ($dto->user === null) {
          throw new \RuntimeException("User not found");
      }
      
  4. Validator Overrides

    • Custom validators may conflict with the bundle’s auto-validation. Use #[Assert\Valid] sparingly on nested DTOs.
  5. Profiler Panel Missing

    • The Symfony profiler panel requires the web_profiler bundle. Install it if debugging:
      composer require symfony/web-profiler-bundle
      
  6. File Uploads

    • File fields (e.g., UploadedFile $avatar) require #[Bag("files")] and proper Symfony Request configuration. Laravel’s file handling may need adaptation.
  7. Nested Collections

    • Deeply nested collections (e.g., array<array<Dto>>) may require explicit type hints:
      #[Collection(type: UserDto::class)]
      public array $users;
      

Debugging Tips

  1. Enable Verbose Logging Configure the bundle in config/packages/dualmedia_symfony_request_dto.yaml:

    dualmedia_symfony_request_dto:
        debug: true
    

    Logs resolution steps to var/log/dev.log.

  2. Check Resolution Events Listen to DtoResolveEvent for debugging:

    use Dualmedia\SymfonyRequestDtoBundle\Event\DtoResolveEvent;
    
    $eventDispatcher->addListener(DtoResolveEvent::class, function (DtoResolveEvent $event) {
        \Log::debug("Resolving DTO:", [
            'dtoClass' => $event->getDtoClass(),
            'source' => $event->getSource(),
            'errors' => $event->getErrors
    
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.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware