jooservices/dto 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

jooservices/dto

最新稳定版本:1.0.0

Composer 安装命令:

composer require jooservices/dto

包简介

Data Transfer Object (DTO)

README 文档

README

A powerful, lightweight Data Transfer Object (DTO) package for PHP 8.5+.

Latest Version PHP Version License Downloads

Developer Information

Developer: Viet VU
Email: jooservices@gmail.com
URL: jooservices.com

Why JOOservices DTO?

  • Zero Dependencies - Pure PHP 8.5+, no bloat
  • 🚀 High Performance - Reflection-based with opcache optimization
  • 🎯 Type Safe - Full type hinting and validation
  • 🔧 Extensible - Custom casts, transformers, normalizers
  • 📦 Framework Agnostic - Works everywhere
  • 🧩 Modular - Trait-based composition architecture

Comparison

Feature JOOservices DTO Spatie DTO Spatie Laravel Data
PHP 8.5+ Required
Zero Dependencies
Framework Agnostic ❌ (Laravel only)
Built-in Validation
Type Casting
Property Mapping
Output Transformers
JSON Serialization
Nested DTOs
Collections Support
Accessors/Mutators
Lightweight

💡 Tip: Choose JOOservices DTO if you need a lightweight, zero-dependency solution with modern PHP 8.5+ features and comprehensive validation.

Table of Contents

Features

  • Immutable by Default: Dto class is immutable (read-only) ensuring data integrity
  • Mutable Option: Data class provides mutable behavior for flexible use cases
  • Clean Architecture: Both Dto and Data extend AbstractDto as siblings (not parent-child)
  • Immutable Updates: Use with() method to create new instances with updated properties
  • Type Safety: Strongly typed properties with PHP 8.5+ type hints
  • Array Transformation: Easy conversion to/from arrays
  • JSON Serialization: Built-in JSON encoding support
  • Nested DTOs: Support for nested DTO objects
  • Array of DTOs: Handle collections of DTOs
  • Reflection-based: Automatic property mapping using reflection
  • Property Mapping: Map input keys to different property names with #[MapFrom]
  • Validation Rules: Built-in validation attributes (#[Email], #[Min], #[Max], #[Regex])
  • Output Transformers: Transform property values during serialization with #[WithTransformer]
  • Pipeline Processing: Process DTOs through multiple transformation steps with error handling and rollback
  • Zero Dependencies: Pure PHP, no external dependencies required
  • Framework Agnostic: Works with any PHP 8.5+ application

Quick Start

Installation

composer require jooservices/dto

📖 For detailed installation instructions, see Installation Guide

Basic Usage

📖 For comprehensive usage examples, see Getting Started Guide

Dto vs Data: Immutable vs Mutable

The package provides two base classes that are siblings (both extend AbstractDto):

  • Dto - Immutable (read-only after creation). Properties cannot be modified after creation. Use the with() method to create new instances with updated properties. Perfect for data transfer where immutability ensures data integrity.

  • Data - Mutable. Properties can be modified after creation using setProperty() or direct assignment. Use when you need to build or modify DTOs incrementally.

Architecture Note: Both Dto and Data extend AbstractDto as siblings, not in a parent-child relationship. This design complies with the Liskov Substitution Principle and eliminates code duplication through SharedBaseTrait.

Quick Comparison Table

Feature Dto (Immutable) Data (Mutable)
Mutability ❌ Read-only after creation ✅ Can be modified
Property Assignment $dto->prop = value throws exception $data->prop = value works
Update Method with() creates new instance ✅ Direct assignment or setProperty()
Accessors ✅ Supported (computed properties) ✅ Supported (computed properties)
Mutators ❌ Not supported ✅ Supported (transform on set)
Use Case API responses, DB results, configs Form data, user input, incremental building
Immutability Guarantee ✅ Strong (cannot modify after creation) ❌ Mutable (can modify anytime)
Thread Safety ✅ Safe (immutable) ⚠️ Not thread-safe (mutable)

When to use each:

  • Use Dto for: API responses, database results, configuration objects, or any scenario where data should remain unchanged after creation.
  • Use Data for: Form data, user input processing, or any scenario where you need to modify properties after creation.

📖 For detailed information on extending classes, see Extending Classes Guide

Creating a DTO

Extend the base Dto class and define your properties as public:

💡 Tip: Always use type hints for properties to enable automatic type casting and validation.

use JOOservices\Dto\Dto;

class UserDto extends Dto
{
    public function __construct(
        public string $name,
        public string $email,
        public ?int $age = null,
    ) {
    }
}

Creating DTO from Array

$user = UserDto::fromArray([
    'name' => 'John Doe',
    'email' => 'john@example.com',
    'age' => 30,
]);

Converting DTO to Array/JSON

$user = new UserDto('John Doe', 'john@example.com', 30);

// To array
$array = $user->toArray();
// ['name' => 'John Doe', 'email' => 'john@example.com', 'age' => 30]

// To JSON
$json = $user->toJson();
// {"name":"John Doe","email":"john@example.com","age":30}

Nested DTOs

use JOOservices\Dto\Dto;

class CategoryDto extends Dto
{
    public function __construct(
        public int $id,
        public string $name,
        public string $slug,
    ) {
    }
}

class ProductDto extends Dto
{
    public function __construct(
        public string $name,
        public float $price,
        public ?CategoryDto $category = null,
    ) {
    }
}

// Create with nested DTO
$product = ProductDto::fromArray([
    'name' => 'Laptop',
    'price' => 999.99,
    'category' => [
        'id' => 1,
        'name' => 'Electronics',
        'slug' => 'electronics',
    ],
]);

// Nested DTO is automatically converted
echo $product->category->name; // "Electronics"

Array of DTOs

For arrays of DTOs, use PHPDoc annotation:

use JOOservices\Dto\Dto;

class ProductDto extends Dto
{
    public function __construct(
        public string $name,
        public float $price,
    ) {
    }
}

class OrderDto extends Dto
{
    /**
     * @var array<ProductDto>
     */
    public array $items = [];

    public function __construct(
        public int $id,
        public float $total,
    ) {
    }
}

$order = OrderDto::fromArray([
    'id' => 1,
    'total' => 199.99,
    'items' => [
        ['name' => 'Product 1', 'price' => 99.99],
        ['name' => 'Product 2', 'price' => 100.00],
    ],
]);

Property Access (Dto - Immutable)

$user = new UserDto('John Doe', 'john@example.com', 30);

// Direct property access (read-only)
echo $user->name; // "John Doe"

// Check if property exists
$user->hasProperty('email'); // true

// Get property value
$email = $user->getProperty('email');

// Create new instance with updated property (immutable update)
$updatedUser = $user->with('age', 31);
// Or update multiple properties
$updatedUser = $user->with(['age' => 31, 'name' => 'Jane Doe']);

// Get all property names
$properties = $user->getPropertyNames();
// ['name', 'email', 'age']

Property Access (Data - Mutable)

use JOOservices\Dto\Data;

class UserData extends Data
{
    public function __construct(
        public string $name,
        public string $email,
        public ?int $age = null,
    ) {
    }
}

$user = new UserData('John Doe', 'john@example.com', 30);

// Direct property access
echo $user->name; // "John Doe"

// Modify properties (mutable)
$user->setProperty('age', 31);
// Or use direct assignment
$user->age = 31;
$user->name = 'Jane Doe';

💡 Note: Data and Dto are siblings (both extend AbstractDto), not parent-child. This design ensures both classes share common functionality through SharedBaseTrait while maintaining distinct behavioral contracts.

Property Mapping (MapFrom)

Map input array keys to different property names:

use JOOservices\Dto\Attributes\MapFrom;
use JOOservices\Dto\Dto;

class PostDto extends Dto
{
    public function __construct(
        #[MapFrom('post_title')]
        public string $title,
        
        #[MapFrom('user_name')]
        public string $author,
        
        public string $content,
    ) {
    }
}

// Input uses different key names
$post = PostDto::fromArray([
    'post_title' => 'My Post',
    'user_name' => 'John Doe',
    'content' => 'Post content',
]);

echo $post->title; // "My Post"
echo $post->author; // "John Doe"

Validation Rules

Add validation rules to properties using attributes:

use JOOservices\Dto\Attributes\Required;
use JOOservices\Dto\Attributes\Validation\Email;
use JOOservices\Dto\Attributes\Validation\Min;
use JOOservices\Dto\Attributes\Validation\Max;
use JOOservices\Dto\Attributes\Validation\Regex;
use JOOservices\Dto\Dto;

class RegistrationDto extends Dto
{
    public function __construct(
        #[Required]
        #[Email]
        public string $email,
        
        #[Required]
        #[Min(8)]
        #[Max(100)]
        public string $password,
        
        #[Regex('/^[A-Z]{2}\d{4}$/')]
        public ?string $code = null,
    ) {
    }
}

$dto = RegistrationDto::fromArray([
    'email' => 'user@example.com',
    'password' => 'password123',
]);

// Validate rules
$errors = $dto->validateRules();
// Returns: [] (empty if valid)

// Or validate and throw exception
$dto->validateOrFail(); // Throws ValidationException if invalid

Output Transformers

Transform property values during serialization:

use DateTime;
use JOOservices\Dto\Attributes\WithTransformer;
use JOOservices\Dto\Dto;
use JOOservices\Dto\Transformers\DateTimeTransformer;

class EventDto extends Dto
{
    public function __construct(
        #[WithTransformer(DateTimeTransformer::class, ['format' => 'Y-m-d'])]
        public DateTime $eventDate,
        
        public string $name,
    ) {
    }
}

$event = new EventDto(new DateTime('2024-01-15 14:30:00'), 'Conference');
$array = $event->toArray();
// ['eventDate' => '2024-01-15', 'name' => 'Conference']

Documentation

For detailed documentation, please refer to the Documentation Hub or browse by category:

🚀 Getting Started

📖 Core Concepts

🔧 Advanced Topics

🤝 Contributing

Requirements

  • PHP 8.5 or higher

License

MIT

Changelog

See CHANGELOG.md for a detailed list of changes.

Version

Current Version: 1.0.0
Release Date: 2025-01-16
PHP Requirement: 8.5 or higher

Support

For issues, questions, or contributions, please contact:

统计信息

  • 总下载量: 1
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 0
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-01-09