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 Tool Laravel Package

sajadsdi/dto-tool

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require sajadsdi/dto-tool
    

    Ensure your project uses PHP 8.1+ and sajadsdi/php-reflection (≥1.0).

  2. First DTO Class: Create a class with DTOTrait and define private properties:

    use Sajadsdi\DtoTool\Concerns\DTOTrait;
    
    class UserDTO
    {
        use DTOTrait;
    
        private string $name;
        private int $age;
    }
    
  3. First Use Case: Initialize and populate a DTO:

    $user = new UserDTO();
    $user->init(['name' => 'John', 'age' => 30]); // Mass assignment
    $array = $user->toArray(); // Convert to array
    

Key Starting Points

  • DTOTrait: Auto-generates getters/setters for private properties.
  • init(): Hydrate DTO from an array.
  • toArray(): Convert DTO to an array.

Implementation Patterns

1. DTO as a Service Layer Boundary

Use DTOs to decouple API/input layers from business logic:

// API Request → DTO → Service
$requestData = $request->all();
$userDTO = new UserDTO();
$userDTO->init($requestData);
$userService->create($userDTO);

2. Validation Integration

Pair with Laravel’s Validator for input sanitization:

use Illuminate\Support\Facades\Validator;

$validator = Validator::make($request->all(), [
    'name' => 'required|string|max:255',
    'age' => 'integer|min:18',
]);

if ($validator->fails()) {
    return response()->json(['errors' => $validator->errors()], 422);
}

$userDTO->init($request->all());

3. Dynamic Property Handling

Leverage auto-generated methods for flexibility:

// Add a new property dynamically (if needed)
$userDTO->setEmail('john@example.com'); // Works even without explicit property

4. DTO in Collections

Useful for API responses or batch processing:

$users = collect([$userDTO1, $userDTO2])
    ->map(fn ($dto) => $dto->toArray());

5. Overriding Getters/Setters

Customize behavior for specific properties:

public function getName(): string
{
    return ucfirst($this->name); // Auto-capitalize names
}

public function setAge(int $age): void
{
    $this->age = max(18, $age); // Enforce minimum age
}

6. DTO Factories

Create reusable factory methods:

class UserDTOFactory
{
    public static function fromRequest(array $data): UserDTO
    {
        $dto = new UserDTO();
        $dto->init($data);
        return $dto;
    }
}

7. Nested DTOs

Compose DTOs for complex structures:

class AddressDTO
{
    use DTOTrait;
    private string $street;
    private string $city;
}

class UserDTO
{
    use DTOTrait;
    private string $name;
    private AddressDTO $address; // Nested DTO
}

Gotchas and Tips

Pitfalls

  1. Property Naming Conflicts: Avoid property names starting with get/set (e.g., getName as a property). The trait may misinterpret them. Fix: Rename or use explicit getters/setters.

  2. Visibility Changes: The trait auto-generates methods for private/protected properties. Changing visibility (e.g., to public) breaks auto-magic. Fix: Use explicit getters/setters or adjust visibility consistently.

  3. Circular References in toArray(): Nested DTOs with circular references (e.g., UserDTOOrderDTOUserDTO) cause infinite loops. Fix: Implement __toString() or use json_encode() with JSON_THROW_ON_ERROR.

  4. Type Safety: The trait does not enforce type hints in generated setters. Invalid types may slip through. Fix: Override setters or use PHP 8.2’s #[SensitiveParameter] for critical fields.

  5. Mass Assignment Risks: init() blindly assigns all array keys. Untrusted data (e.g., user input) can overwrite properties. Fix: Whitelist allowed fields or validate before init().


Debugging Tips

  1. Check Generated Methods: Use get_class_methods(UserDTO::class) to verify auto-generated methods.

  2. Reflection Inspection: Debug property access issues with:

    $reflection = new ReflectionClass(UserDTO::class);
    var_dump($reflection->getProperties());
    
  3. Override for Debugging: Temporarily override toArray() to log data:

    public function toArray(): array
    {
        $data = parent::toArray();
        \Log::debug('DTO Data:', $data);
        return $data;
    }
    

Extension Points

  1. Custom Initialization: Extend init() to support nested DTOs or default values:

    public function init(array $data): void
    {
        parent::init($data);
        $this->address ??= new AddressDTO(); // Default nested DTO
    }
    
  2. Serialization Hooks: Add JsonSerializable for custom JSON output:

    implements JsonSerializable {
        public function jsonSerialize(): array
        {
            return [
                'full_name' => $this->getName(),
                'age' => $this->getAge(),
            ];
        }
    }
    
  3. DTO Events: Use events (e.g., Laravel’s Observers) for pre/post-set hooks:

    // In a service or observer
    $dto->setName('John');
    event(new DTOUpdated($dto));
    
  4. Performance Optimization: Cache toArray() results if DTOs are immutable:

    private ?array $cachedArray = null;
    
    public function toArray(): array
    {
        return $this->cachedArray ??= parent::toArray();
    }
    

Configuration Quirks

  1. Trait Loading Order: Ensure DTOTrait is the last trait in your class to avoid method conflicts.

  2. PHP Reflection Dependencies: The package relies on sajadsdi/php-reflection. Ensure it’s updated if you encounter reflection errors.

  3. IDE Support: Some IDEs (e.g., PHPStorm) may not auto-detect generated methods. Use @method PHPDoc annotations:

    /**
     * @method string getName()
     * @method void setName(string $name)
     */
    class UserDTO { ... }
    
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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
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