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

Dto Bundle Laravel Package

bujanov/dto-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require bujanov/dto-bundle
    

    Add to config/bundles.php:

    return [
        // ...
        Bujanov\DtoBundle\BujanovDtoBundle::class => ['all' => true],
    ];
    
  2. First DTO Class Create a class (e.g., src/Dto/UserDto.php) extending AbstractDto:

    namespace App\Dto;
    
    use Bujanov\DtoBundle\AbstractDto;
    
    class UserDto extends AbstractDto
    {
        /** @var int */
        public $id;
    
        /** @var string */
        public $name;
    }
    
  3. Instantiation & Usage

    use App\Dto\UserDto;
    
    $dto = new UserDto();
    $dto->id = 1;
    $dto->name = 'John Doe';
    
    // Hydrate from array
    $dto->hydrate(['id' => 2, 'name' => 'Jane Smith']);
    

Key Files to Review

  • src/AbstractDto.php (Core functionality)
  • src/DtoInterface.php (Contract)
  • src/DtoTrait.php (Optional trait for reusable logic)

Implementation Patterns

Common Workflows

  1. Request/Response DTOs

    // In a controller
    public function create(Request $request, UserDto $dto)
    {
        $dto->hydrate($request->all());
        $user = $this->userService->create($dto);
        return new JsonResponse($dto->toArray());
    }
    
  2. Validation Integration Combine with Symfony Validator:

    use Symfony\Component\Validator\Validator\ValidatorInterface;
    
    $errors = $validator->validate($dto);
    if (count($errors) > 0) {
        // Handle validation errors
    }
    
  3. Type Safety with PHP 8 Attributes

    use Bujanov\DtoBundle\Attributes\DtoProperty;
    
    class UserDto extends AbstractDto
    {
        #[DtoProperty(type: 'int')]
        public $id;
    
        #[DtoProperty(type: 'string', required: true)]
        public $name;
    }
    
  4. DTO Factories

    class UserDtoFactory
    {
        public static function fromEntity(User $user): UserDto
        {
            $dto = new UserDto();
            $dto->id = $user->getId();
            $dto->name = $user->getName();
            return $dto;
        }
    }
    
  5. Nested DTOs

    class AddressDto extends AbstractDto { /* ... */ }
    
    class UserDto extends AbstractDto
    {
        public $address; // Type: AddressDto
    }
    

Integration Tips

  • Symfony Forms: Use DTOs as form data classes.
  • API Platform: Leverage DTOs for serialization/deserialization.
  • Doctrine: Map DTOs to entities via hydrate/dehydrate methods.
  • Testing: Mock DTOs easily for unit tests.

Gotchas and Tips

Pitfalls

  1. No Built-in Validation

    • The bundle provides no validation out-of-the-box. Use Symfony Validator or libraries like symfony/validator separately.
    • Workaround: Extend AbstractDto and add validation logic.
  2. No Magic Methods

    • Properties are public by default. Avoid naming conflicts with methods (e.g., getName() vs. name property).
    • Tip: Use #[DtoProperty] attributes to document types and requirements.
  3. Limited Type Safety

    • PHP 8 attributes are supported but not enforced. Type hints are manual.
    • Tip: Use #[Assert\Type] from Symfony Validator for runtime checks.
  4. No Immutable Support

    • DTOs are mutable by default. For immutability, override hydrate() or use readonly properties (PHP 8.1+).
  5. Serialization Quirks

    • toArray() includes all public properties, even "private" ones (via visibility tricks).
    • Tip: Override toArray() to filter properties:
      public function toArray(): array
      {
          return array_filter($this->toArray(), fn($k) => !str_starts_with($k, '_'));
      }
      

Debugging Tips

  • Hydration Issues: Use var_dump($dto->hydrate($data, true)) (third param for strict mode).
  • Circular References: Avoid nested DTOs with circular references (e.g., UserDto->address->user).
  • Property Overrides: Check for typos in property names during hydration.

Extension Points

  1. Custom Hydration Override hydrate() to add logic:

    public function hydrate(array $data, bool $strict = false, bool $deep = false): void
    {
        parent::hydrate($data, $strict, $deep);
        $this->normalizeName(); // Custom logic
    }
    
  2. Custom Serialization Override toArray() or add JsonSerializable:

    public function jsonSerialize(): array
    {
        return $this->toArray();
    }
    
  3. Event Dispatching Integrate with Symfony Events:

    use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
    
    class UserDto extends AbstractDto
    {
        public function __construct(private EventDispatcherInterface $dispatcher) {}
    
        public function hydrate(array $data): void
        {
            $this->dispatcher->dispatch(new DtoHydrateEvent($this, $data));
            parent::hydrate($data);
        }
    }
    
  4. Doctrine Integration Use Hydrator to map DTOs to entities:

    $user = new User();
    $hydrator = new ObjectPropertyHydrator();
    $hydrator->hydrate($dto->toArray(), $user);
    

Configuration Quirks

  • No Bundle Config: The bundle has no config/packages/bujanov_dto.yaml; all settings are code-based.
  • Namespace Collisions: Ensure DTO classes are in a unique namespace (e.g., App\Dto\).

Performance Notes

  • Avoid Deep Cloning: Use clone sparingly; DTOs are lightweight but nested objects may not be.
  • Batch Processing: For bulk operations, hydrate DTOs in batches to avoid memory issues.
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.
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager