Skip to content

Commit 64a926e

Browse files
committed
docs: update readme
1 parent b719f0a commit 64a926e

1 file changed

Lines changed: 63 additions & 30 deletions

File tree

README.md

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ A Laravel package that provides an elegant way to generate and use Actions and D
2828
## Features
2929

3030
- 🚀 **Simple Command Generation**: Generate Actions and DTOs with simple Artisan commands
31-
- 🔒 **Type Safety**: Built with PHP 8.2+ readonly classes for immutable data structures
31+
- 🔒 **Type Safety**: Built with PHP 8.3+ readonly classes for immutable data structures
3232
- 🏗️ **Clean Architecture**: Promotes separation of concerns and clean code practices
3333
- 🔄 **Automatic Data Mapping**: Seamless conversion between arrays, Form Requests, and Models
3434
-**Attribute-Based Validation**: Use PHP attributes for declarative validation rules
@@ -41,8 +41,8 @@ A Laravel package that provides an elegant way to generate and use Actions and D
4141

4242
## Requirements
4343

44-
- PHP 8.2 or higher
45-
- Laravel 11.0 or higher
44+
- PHP 8.3 or higher
45+
- Laravel 12.0 or 13.0
4646

4747
## Installation
4848

@@ -326,14 +326,10 @@ readonly class CreateUserData extends DataTransferObject
326326
}
327327

328328
// Validate using attributes
329-
try {
330-
$user = CreateUserData::resolve($data);
331-
$user->validateAttributes();
332-
// DTO is valid
333-
} catch (\InvalidArgumentException $e) {
334-
// Handle validation errors
335-
echo $e->getMessage();
336-
}
329+
$user = CreateUserData::resolve($data)->validateAttributes();
330+
331+
// If invalid, validateAttributes() throws Illuminate\Validation\ValidationException
332+
// with Laravel-standard per-field errors.
337333
```
338334

339335
**Available validation attributes:**
@@ -364,6 +360,29 @@ $user
364360
->validateAttributes(); // Combine with attribute validation
365361
```
366362

363+
#### Custom Validation Attributes
364+
365+
You can create your own PHP attributes by implementing `Holiq\ActionData\Contracts\Validator`:
366+
367+
```php
368+
use Attribute;
369+
use Holiq\ActionData\Contracts\Validator;
370+
371+
#[Attribute(Attribute::TARGET_PROPERTY)]
372+
class Positive implements Validator
373+
{
374+
public function validate(mixed $value, string $property): bool
375+
{
376+
return is_numeric($value) && $value > 0;
377+
}
378+
379+
public function getErrorMessage(string $property): string
380+
{
381+
return "'{$property}' must be a positive number.";
382+
}
383+
}
384+
```
385+
367386
### Nested DTOs
368387

369388
Laravel Action Data automatically resolves nested DTOs and arrays of DTOs:
@@ -389,7 +408,7 @@ readonly class UserData extends DataTransferObject
389408
) {}
390409
}
391410

392-
// Automatically resolves nested structure
411+
// Option 1: Using resolver (auto maps nested array → DTO)
393412
$user = UserData::resolve([
394413
'name' => 'John Doe',
395414
'email' => 'john@example.com',
@@ -400,6 +419,17 @@ $user = UserData::resolve([
400419
],
401420
]);
402421

422+
// Option 2: Manual instantiation (must pass AddressData object)
423+
$user = new UserData(
424+
name: 'John Doe',
425+
email: 'john@example.com',
426+
address: new AddressData(
427+
street: '123 Main St',
428+
city: 'Anytown',
429+
country: 'USA',
430+
),
431+
);
432+
403433
// Access nested data
404434
echo $user->address->street; // "123 Main St"
405435
```
@@ -624,28 +654,24 @@ class UserController extends Controller
624654
{
625655
public function store(CreateUserRequest $request): JsonResponse
626656
{
627-
try {
628-
// Resolve and validate DTO
629-
$userData = CreateUserData::resolve($request->validated())
630-
->validateAttributes();
631-
632-
// Execute action with validated DTO
633-
$user = CreateUserAction::resolve()->execute($userData);
634-
635-
return response()->json([
636-
'message' => 'User created successfully',
637-
'data' => $user
638-
], 201);
639-
} catch (\InvalidArgumentException $e) {
640-
return response()->json([
641-
'message' => 'Validation failed',
642-
'errors' => $e->getMessage()
643-
], 422);
644-
}
657+
// Resolve and validate DTO
658+
$userData = CreateUserData::resolve($request->validated())
659+
->validateAttributes();
660+
661+
// Execute action with validated DTO
662+
$user = CreateUserAction::resolve()->execute($userData);
663+
664+
return response()->json([
665+
'message' => 'User created successfully',
666+
'data' => $user
667+
], 201);
645668
}
646669
}
647670
```
648671

672+
When validation fails, Laravel will automatically convert the
673+
`ValidationException` to a standard `422 Unprocessable Entity` response.
674+
649675
#### Nested DTOs Example: Order Management
650676

651677
```php
@@ -783,6 +809,7 @@ Creates a DTO instance from various data sources.
783809
**`toArrayForCreate(): array`** - Excludes properties from `toExcludedPropertiesOnCreate()`
784810
**`toArrayForUpdate(): array`** - Excludes properties from `toExcludedPropertiesOnUpdate()`
785811
**`toJson(int $options = 0): string`** - Converts to JSON string
812+
**`toCamelJson(int $options = 0): string`** - Converts to camelCase JSON string
786813

787814
#### Validation
788815

@@ -797,6 +824,12 @@ Validates using PHP attributes.
797824
**`has(string $property): bool`** - Checks if property exists
798825
**`get(string $property, mixed $default = null): mixed`** - Gets property value
799826

827+
#### Immutable Update Helpers
828+
829+
**`with(mixed ...$values): static`** - Returns a cloned DTO with named-argument overrides
830+
**`withArray(array $overrides): static`** - Returns a cloned DTO with snake_case/camelCase key overrides
831+
**`without(string ...$properties): static`** - Returns a cloned DTO with nullable properties set to null
832+
800833
#### Utility Methods
801834

802835
**`clone(): static`** - Creates a clone

0 commit comments

Comments
 (0)