{"id":15090063,"url":"https://github.com/holiq/action-data","last_synced_at":"2026-02-09T01:31:41.409Z","repository":{"id":254080044,"uuid":"845411768","full_name":"holiq/action-data","owner":"holiq","description":"Simple way to use Actions and DTOs on your Laravel project","archived":false,"fork":false,"pushed_at":"2026-02-05T04:28:47.000Z","size":161,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-05T17:19:52.427Z","etag":null,"topics":["actions","data-transfer-object","dto","hacktoberfest","laravel","laravel-actions","laravel-dto"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/holiq.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-08-21T07:43:44.000Z","updated_at":"2026-02-05T04:27:15.000Z","dependencies_parsed_at":"2024-08-21T09:44:07.192Z","dependency_job_id":"ce9e34d7-7073-4810-ae5e-ea24849e313a","html_url":"https://github.com/holiq/action-data","commit_stats":null,"previous_names":["holiq/action-data"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/holiq/action-data","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holiq%2Faction-data","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holiq%2Faction-data/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holiq%2Faction-data/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holiq%2Faction-data/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/holiq","download_url":"https://codeload.github.com/holiq/action-data/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holiq%2Faction-data/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29252978,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-08T22:49:53.206Z","status":"ssl_error","status_checked_at":"2026-02-08T22:49:51.384Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["actions","data-transfer-object","dto","hacktoberfest","laravel","laravel-actions","laravel-dto"],"created_at":"2024-09-25T09:04:24.043Z","updated_at":"2026-02-09T01:31:41.404Z","avatar_url":"https://github.com/holiq.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Laravel Action Data\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/holiq/action-data.svg?style=flat-square)](https://packagist.org/packages/holiq/action-data)\n[![Total Downloads](https://img.shields.io/packagist/dt/holiq/action-data.svg?style=flat-square)](https://packagist.org/packages/holiq/action-data)\n[![License](https://img.shields.io/packagist/l/holiq/action-data.svg?style=flat-square)](https://packagist.org/packages/holiq/action-data)\n\nA Laravel package that provides an elegant way to generate and use Actions and Data Transfer Objects (DTOs) in your Laravel projects. This package promotes clean architecture by separating business logic into reusable Action classes and ensuring type-safe data handling with DTOs.\n\n## Table of Contents\n\n- [Features](#features)\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Usage](#usage)\n  - [Generating Actions](#generating-actions)\n  - [Generating DTOs](#generating-dtos)\n  - [Working with DTOs](#working-with-dtos)\n  - [Validation](#validation)\n  - [Nested DTOs](#nested-dtos)\n  - [Data Transformations](#data-transformations)\n- [Real-world Examples](#real-world-examples)\n- [API Reference](#api-reference)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Features\n\n- 🚀 **Simple Command Generation**: Generate Actions and DTOs with simple Artisan commands\n- 🔒 **Type Safety**: Built with PHP 8.2+ readonly classes for immutable data structures\n- 🏗️ **Clean Architecture**: Promotes separation of concerns and clean code practices\n- 🔄 **Automatic Data Mapping**: Seamless conversion between arrays, Form Requests, and Models\n- ✅ **Attribute-Based Validation**: Use PHP attributes for declarative validation rules\n- 🔧 **Custom Validation**: Support for custom validation callbacks and pipelines\n- 🌳 **Nested DTOs**: Automatic resolution of nested DTOs and arrays of DTOs\n- 🔄 **Data Transformations**: Built-in data transformation pipeline for clean data processing\n- 📁 **Customizable Paths**: Configure custom paths for Actions and DTOs\n- 🧪 **Well Tested**: Comprehensive test suite ensuring reliability\n- 📖 **Rich Documentation**: Extensive documentation and examples\n\n## Requirements\n\n- PHP 8.2 or higher\n- Laravel 11.0 or higher\n\n## Installation\n\nYou can install the package via Composer:\n\n```bash\ncomposer require holiq/action-data\n```\n\nThe package will automatically register its service provider.\n\nOptionally, you can publish the configuration file:\n\n```bash\nphp artisan vendor:publish --provider=\"Holiq\\ActionData\\ActionDataServiceProvider\" --tag=\"config\"\n```\n\nAfter publishing, you can customize the paths in `config/action-data.php`:\n\n```php\nreturn [\n    'action_path' =\u003e 'app/Actions',\n    'data_path' =\u003e 'app/DataTransferObjects',\n];\n```\n\n## Quick Start\n\n1. **Generate an Action with DTO:**\n\n   ```bash\n   php artisan make:action CreateUserAction --with-dto=CreateUserData\n   ```\n\n2. **Define your DTO with validation:**\n\n   ```php\n   readonly class CreateUserData extends DataTransferObject\n   {\n       public function __construct(\n           #[Required, Length(min: 2, max: 50)]\n           public string $name,\n\n           #[Required, Email]\n           public string $email,\n       ) {}\n   }\n   ```\n\n3. **Implement your Action:**\n\n   ```php\n   readonly class CreateUserAction extends Action\n   {\n       public function execute(CreateUserData $data): User\n       {\n           return User::create($data-\u003etoArray());\n       }\n   }\n   ```\n\n4. **Use in your controller:**\n\n   ```php\n   $userData = CreateUserData::resolve($request-\u003evalidated())\n       -\u003evalidateAttributes();\n\n   $user = CreateUserAction::resolve()-\u003eexecute($userData);\n   ```\n\n## Configuration\n\nAfter publishing the configuration file, you can customize the paths where Actions and DTOs are generated:\n\n```php\n// config/action-data.php\nreturn [\n    'action_path' =\u003e 'app/Actions',\n    'data_path' =\u003e 'app/DataTransferObjects',\n];\n```\n\n## Usage\n\n### Generating Actions\n\nGenerate Actions using the Artisan command with various options:\n\n```bash\n# Basic action\nphp artisan make:action StoreUserAction\n\n# Action in subdirectory\nphp artisan make:action User/StoreUserAction\n\n# Action with auto-generated DTO\nphp artisan make:action StoreUserAction --with-dto=StoreUserData\n\n# Force overwrite existing files\nphp artisan make:action StoreUserAction --force\n```\n\n**Basic Action structure:**\n\n```php\n\u003c?php\n\nnamespace App\\Actions;\n\nuse Holiq\\ActionData\\Foundation\\Action;\n\nreadonly class StoreUserAction extends Action\n{\n    public function execute(): mixed\n    {\n        // Your business logic here\n    }\n}\n```\n\n**Action with DTO parameter:**\n\n```php\n\u003c?php\n\nnamespace App\\Actions;\n\nuse App\\DataTransferObjects\\StoreUserData;\nuse Holiq\\ActionData\\Foundation\\Action;\n\nreadonly class StoreUserAction extends Action\n{\n    public function execute(StoreUserData $data): User\n    {\n        // Type-safe business logic with validated DTO\n        return User::create($data-\u003etoArray());\n    }\n}\n```\n\n### Generating DTOs\n\nGenerate DTOs using the Artisan command:\n\n```bash\n# Basic DTO\nphp artisan make:dto CreateUserData\n\n# DTO in subdirectory\nphp artisan make:dto User/CreateUserData\n\n# Force overwrite existing files\nphp artisan make:dto CreateUserData --force\n```\n\n**Generated DTO structure:**\n\n```php\n\u003c?php\n\nnamespace App\\DataTransferObjects;\n\nuse Holiq\\ActionData\\Foundation\\DataTransferObject;\n\nreadonly class CreateUserData extends DataTransferObject\n{\n    final public function __construct(\n        // Define your properties with validation attributes\n        // #[Required, Length(min: 1, max: 255)] public string $name,\n        // #[Required, Email] public string $email,\n    ) {}\n}\n```\n\n### Working with DTOs\n\n#### Creating and Resolving DTOs\n\nDTOs can be created from various data sources:\n\n```php\n// From array\n$userData = CreateUserData::resolve([\n    'first_name' =\u003e 'John',\n    'last_name' =\u003e 'Doe',\n    'email' =\u003e 'john@example.com'\n]);\n\n// From Form Request\n$userData = CreateUserData::resolveFrom($request);\n\n// From Eloquent Model\n$userData = CreateUserData::resolveFrom($user);\n```\n\n#### Array Conversion\n\nConvert DTOs to arrays with different formatting options:\n\n```php\nreadonly class CreateUserData extends DataTransferObject\n{\n    public function __construct(\n        public string $firstName,\n        public string $lastName,\n        public string $email,\n    ) {}\n}\n\n$data = new CreateUserData('John', 'Doe', 'john@example.com');\n\n// Convert to snake_case (default)\n$array = $data-\u003etoArray();\n// Result: ['first_name' =\u003e 'John', 'last_name' =\u003e 'Doe', 'email' =\u003e 'john@example.com']\n\n// Convert to camelCase\n$camelCase = $data-\u003etoCamelCase();\n// Result: ['firstName' =\u003e 'John', 'lastName' =\u003e 'Doe', 'email' =\u003e 'john@example.com']\n\n// Convert to JSON\n$json = $data-\u003etoJson();\n\n// Convert with context-specific exclusions\n$createArray = $data-\u003etoArrayForCreate();\n$updateArray = $data-\u003etoArrayForUpdate();\n```\n\n#### Property Exclusion\n\nControl which properties are included in specific contexts:\n\n```php\nreadonly class CreateUserData extends DataTransferObject\n{\n    public function __construct(\n        public string $firstName,\n        public string $lastName,\n        public string $email,\n        public ?string $password = null,\n    ) {}\n\n    protected function toExcludedPropertiesOnCreate(): array\n    {\n        return []; // Include all properties for create\n    }\n\n    protected function toExcludedPropertiesOnUpdate(): array\n    {\n        return ['password']; // Exclude password from updates\n    }\n}\n```\n\n### Validation\n\nLaravel Action Data provides powerful validation through PHP attributes and custom callbacks.\n\n#### Attribute-Based Validation\n\nUse PHP attributes for declarative validation rules:\n\n```php\nuse Holiq\\ActionData\\Attributes\\Validation\\{Required, Email, Length, Range, Pattern};\nuse Holiq\\ActionData\\Foundation\\DataTransferObject;\n\nreadonly class CreateUserData extends DataTransferObject\n{\n    public function __construct(\n        #[Required, Length(min: 2, max: 50)]\n        public string $name,\n\n        #[Required, Email]\n        public string $email,\n\n        #[Required, Range(min: 18, max: 120)]\n        public int $age,\n\n        #[Pattern(regex: '/^\\+?[1-9]\\d{1,14}$/')]\n        public ?string $phone = null,\n    ) {}\n}\n\n// Validate using attributes\ntry {\n    $user = CreateUserData::resolve($data);\n    $user-\u003evalidateAttributes();\n    // DTO is valid\n} catch (\\InvalidArgumentException $e) {\n    // Handle validation errors\n    echo $e-\u003egetMessage();\n}\n```\n\n**Available validation attributes:**\n\n- `#[Required]` - Field cannot be null, empty string, or empty array\n- `#[Email]` - Validates email format\n- `#[Length(min: int, max: int)]` - Validates string length\n- `#[Range(min: int|float, max: int|float)]` - Validates numeric ranges\n- `#[Pattern(regex: string)]` - Validates against regular expression\n\n#### Custom Validation Callbacks\n\nUse custom validation logic with chainable callbacks:\n\n```php\n$user = new CreateUserData('John Doe', 'john@example.com', 25);\n\n// Single validation\n$user-\u003evalidate(\n    fn (CreateUserData $data) =\u003e str_contains($data-\u003eemail, '@'),\n    'Email must contain @ symbol'\n);\n\n// Chain multiple validations\n$user\n    -\u003evalidate(fn ($data) =\u003e !empty($data-\u003ename), 'Name is required')\n    -\u003evalidate(fn ($data) =\u003e $data-\u003eage \u003e= 18, 'Must be adult')\n    -\u003evalidateAttributes(); // Combine with attribute validation\n```\n\n### Nested DTOs\n\nLaravel Action Data automatically resolves nested DTOs and arrays of DTOs:\n\n#### Simple Nested DTOs\n\n```php\nreadonly class AddressData extends DataTransferObject\n{\n    public function __construct(\n        public string $street,\n        public string $city,\n        public string $country,\n    ) {}\n}\n\nreadonly class UserData extends DataTransferObject\n{\n    public function __construct(\n        public string $name,\n        public string $email,\n        public AddressData $address, // Nested DTO\n    ) {}\n}\n\n// Automatically resolves nested structure\n$user = UserData::resolve([\n    'name' =\u003e 'John Doe',\n    'email' =\u003e 'john@example.com',\n    'address' =\u003e [\n        'street' =\u003e '123 Main St',\n        'city' =\u003e 'Anytown',\n        'country' =\u003e 'USA',\n    ],\n]);\n\n// Access nested data\necho $user-\u003eaddress-\u003estreet; // \"123 Main St\"\n```\n\n#### Arrays of DTOs\n\n```php\nreadonly class UserData extends DataTransferObject\n{\n    public function __construct(\n        public string $name,\n        public AddressData $currentAddress,\n        /** @var AddressData[] */\n        public array $previousAddresses = [], // Array of DTOs\n    ) {}\n}\n\n$user = UserData::resolve([\n    'name' =\u003e 'Jane Smith',\n    'currentAddress' =\u003e [\n        'street' =\u003e '456 Oak Ave',\n        'city' =\u003e 'Springfield',\n        'country' =\u003e 'USA',\n    ],\n    'previousAddresses' =\u003e [\n        [\n            'street' =\u003e '789 Pine St',\n            'city' =\u003e 'Oldtown',\n            'country' =\u003e 'USA',\n        ],\n        [\n            'street' =\u003e '321 Elm Dr',\n            'city' =\u003e 'Hometown',\n            'country' =\u003e 'USA',\n        ],\n    ],\n]);\n\n// Access array of DTOs\nforeach ($user-\u003epreviousAddresses as $address) {\n    echo $address-\u003estreet; // Each item is an AddressData instance\n}\n```\n\n### Data Transformations\n\nApply automatic data transformations during DTO resolution to clean and format your data:\n\n```php\nreadonly class UserProfileData extends DataTransferObject\n{\n    public function __construct(\n        public string $name,\n        public string $email,\n        public ?string $bio = null,\n        public int $age = 0,\n    ) {}\n\n    /**\n     * Define transformations applied during resolve()\n     */\n    protected static function transforms(): array\n    {\n        return [\n            'name' =\u003e fn ($value) =\u003e trim(strtoupper($value)),\n            'email' =\u003e fn ($value) =\u003e trim(strtolower($value)),\n            'bio' =\u003e fn ($value) =\u003e $value ? trim($value) : null,\n            'age' =\u003e fn ($value) =\u003e max(0, (int) $value), // Ensure non-negative\n        ];\n    }\n}\n\n$profile = UserProfileData::resolve([\n    'name' =\u003e '  john doe  ',           // Becomes \"JOHN DOE\"\n    'email' =\u003e '  JOHN@EXAMPLE.COM  ',  // Becomes \"john@example.com\"\n    'bio' =\u003e '  Software developer  ',   // Becomes \"Software developer\"\n    'age' =\u003e '-5',                       // Becomes 0\n]);\n```\n\n**Complex transformations example:**\n\n```php\nreadonly class ProductData extends DataTransferObject\n{\n    public function __construct(\n        public string $name,\n        public float $price,\n        /** @var string[] */\n        public array $tags,\n    ) {}\n\n    protected static function transforms(): array\n    {\n        return [\n            'name' =\u003e fn ($value) =\u003e ucwords(trim($value)),\n            'price' =\u003e fn ($value) =\u003e round((float) $value, 2),\n            'tags' =\u003e fn ($value) =\u003e is_array($value)\n                ? array_values(array_map('strtolower', array_filter($value)))\n                : [],\n        ];\n    }\n}\n\n$product = ProductData::resolve([\n    'name' =\u003e '  awesome widget  ',    // Becomes \"Awesome Widget\"\n    'price' =\u003e '19.999',               // Becomes 20.0\n    'tags' =\u003e ['Electronics', '', 'GADGET', null, 'Popular'], // Becomes [\"electronics\", \"gadget\", \"popular\"]\n]);\n```\n\n### Real-world Examples\n\n#### Complete User Management with Validation\n\n```php\n// Data Transfer Object with Validation\nnamespace App\\DataTransferObjects;\n\nuse Holiq\\ActionData\\Attributes\\Validation\\Email;\nuse Holiq\\ActionData\\Attributes\\Validation\\Length;\nuse Holiq\\ActionData\\Attributes\\Validation\\Pattern;\nuse Holiq\\ActionData\\Attributes\\Validation\\Required;\nuse Holiq\\ActionData\\Foundation\\DataTransferObject;\n\nreadonly class CreateUserData extends DataTransferObject\n{\n    public function __construct(\n        #[Required]\n        #[Length(min: 2, max: 50)]\n        public string $firstName,\n\n        #[Required]\n        #[Length(min: 2, max: 50)]\n        public string $lastName,\n\n        #[Required]\n        #[Email]\n        public string $email,\n\n        #[Required]\n        #[Length(min: 8)]\n        public string $password,\n\n        #[Pattern(regex: '/^\\+?[1-9]\\d{1,14}$/')]\n        public ?string $phone = null,\n    ) {}\n\n    /**\n     * Apply data transformations\n     *\n     * Note: Transform keys support both camelCase and snake_case.\n     * Use camelCase (firstName) or snake_case (first_name) - both work!\n     */\n    protected static function transforms(): array\n    {\n        return [\n            'firstName' =\u003e fn ($value) =\u003e ucfirst(trim($value)),\n            'lastName' =\u003e fn ($value) =\u003e ucfirst(trim($value)),\n            'email' =\u003e fn ($value) =\u003e strtolower(trim($value)),\n            'phone' =\u003e fn ($value) =\u003e $value ? preg_replace('/\\D/', '', $value) : null,\n        ];\n    }\n\n    protected function toExcludedPropertiesOnUpdate(): array\n    {\n        return ['password']; // Don't include password in updates\n    }\n}\n\n// Action Class\nnamespace App\\Actions\\User;\n\nuse App\\DataTransferObjects\\CreateUserData;\nuse App\\Models\\User;\nuse Holiq\\ActionData\\Foundation\\Action;\nuse Illuminate\\Support\\Facades\\Hash;\n\nreadonly class CreateUserAction extends Action\n{\n    public function execute(CreateUserData $data): User\n    {\n        // Data is already validated and transformed\n        return User::create([\n            'first_name' =\u003e $data-\u003efirstName,\n            'last_name' =\u003e $data-\u003elastName,\n            'email' =\u003e $data-\u003eemail,\n            'password' =\u003e Hash::make($data-\u003epassword),\n            'phone' =\u003e $data-\u003ephone,\n        ]);\n    }\n}\n\n// Form Request\nnamespace App\\Http\\Requests;\n\nuse Illuminate\\Foundation\\Http\\FormRequest;\n\nclass CreateUserRequest extends FormRequest\n{\n    public function rules(): array\n    {\n        return [\n            'first_name' =\u003e ['required', 'string', 'max:255'],\n            'last_name' =\u003e ['required', 'string', 'max:255'],\n            'email' =\u003e ['required', 'email', 'unique:users'],\n            'password' =\u003e ['required', 'min:8', 'confirmed'],\n            'phone' =\u003e ['nullable', 'string', 'max:20'],\n        ];\n    }\n}\n\n// Controller\nnamespace App\\Http\\Controllers;\n\nuse App\\Actions\\User\\CreateUserAction;\nuse App\\DataTransferObjects\\CreateUserData;\nuse App\\Http\\Requests\\CreateUserRequest;\nuse Illuminate\\Http\\JsonResponse;\n\nclass UserController extends Controller\n{\n    public function store(CreateUserRequest $request): JsonResponse\n    {\n        try {\n            // Resolve and validate DTO\n            $userData = CreateUserData::resolve($request-\u003evalidated())\n                -\u003evalidateAttributes();\n\n            // Execute action with validated DTO\n            $user = CreateUserAction::resolve()-\u003eexecute($userData);\n\n            return response()-\u003ejson([\n                'message' =\u003e 'User created successfully',\n                'data' =\u003e $user\n            ], 201);\n        } catch (\\InvalidArgumentException $e) {\n            return response()-\u003ejson([\n                'message' =\u003e 'Validation failed',\n                'errors' =\u003e $e-\u003egetMessage()\n            ], 422);\n        }\n    }\n}\n```\n\n#### Nested DTOs Example: Order Management\n\n```php\n// Address DTO\nreadonly class AddressData extends DataTransferObject\n{\n    public function __construct(\n        #[Required] public string $street,\n        #[Required] public string $city,\n        #[Required] public string $state,\n        #[Required] public string $zipCode,\n        #[Required] public string $country,\n    ) {}\n}\n\n// Order Item DTO\nreadonly class OrderItemData extends DataTransferObject\n{\n    public function __construct(\n        #[Required] public string $productId,\n        #[Required] public int $quantity,\n        #[Required] public float $price,\n    ) {}\n\n    protected static function transforms(): array\n    {\n        return [\n            'quantity' =\u003e fn ($value) =\u003e max(1, (int) $value),\n            'price' =\u003e fn ($value) =\u003e round((float) $value, 2),\n        ];\n    }\n}\n\n// Main Order DTO\nreadonly class CreateOrderData extends DataTransferObject\n{\n    public function __construct(\n        #[Required] public string $customerId,\n        #[Required] public AddressData $shippingAddress,\n        #[Required] public AddressData $billingAddress,\n        /** @var OrderItemData[] */\n        #[Required] public array $items,\n        public ?string $notes = null,\n    ) {}\n}\n\n// Usage\n$orderData = CreateOrderData::resolve([\n    'customer_id' =\u003e '12345',\n    'shipping_address' =\u003e [\n        'street' =\u003e '123 Main St',\n        'city' =\u003e 'Anytown',\n        'state' =\u003e 'CA',\n        'zip_code' =\u003e '12345',\n        'country' =\u003e 'USA',\n    ],\n    'billing_address' =\u003e [\n        'street' =\u003e '456 Oak Ave',\n        'city' =\u003e 'Somewhere',\n        'state' =\u003e 'NY',\n        'zip_code' =\u003e '67890',\n        'country' =\u003e 'USA',\n    ],\n    'items' =\u003e [\n        [\n            'product_id' =\u003e 'prod-1',\n            'quantity' =\u003e 2,\n            'price' =\u003e 29.99,\n        ],\n        [\n            'product_id' =\u003e 'prod-2',\n            'quantity' =\u003e 1,\n            'price' =\u003e 15.50,\n        ],\n    ],\n    'notes' =\u003e 'Please handle with care',\n]);\n```\n\n#### Advanced Example with Service Dependencies\n\n```php\n// Action with Dependencies\nnamespace App\\Actions\\User;\n\nuse App\\DataTransferObjects\\CreateUserData;\nuse App\\Models\\User;\nuse App\\Services\\EmailService;\nuse App\\Services\\UserService;\nuse Holiq\\ActionData\\Foundation\\Action;\n\nreadonly class CreateUserWithNotificationAction extends Action\n{\n    public function __construct(\n        private UserService $userService,\n        private EmailService $emailService,\n    ) {}\n\n    public function execute(CreateUserData $data): User\n    {\n        $user = $this-\u003euserService-\u003ecreate($data);\n\n        $this-\u003eemailService-\u003esendWelcomeEmail($user);\n\n        return $user;\n    }\n}\n\n// Usage in Controller\n$user = CreateUserWithNotificationAction::resolve()-\u003eexecute($userData);\n```\n\n## API Reference\n\n### Action Class\n\n#### `resolve(array $parameters = []): static`\n\nResolves an Action instance from Laravel's container with optional parameters.\n\n### DataTransferObject Class\n\n#### Core Methods\n\n**`resolve(array $data): static`**  \nCreates a DTO instance from an array with automatic key transformation and data transformations.\n\n**`resolveFrom(FormRequest|Model|array $abstract): static`**  \nCreates a DTO instance from various data sources.\n\n#### Array Conversion\n\n**`toArray(): array`** - Converts to snake_case array  \n**`toCamelCase(): array`** - Converts to camelCase array  \n**`toArrayForCreate(): array`** - Excludes properties from `toExcludedPropertiesOnCreate()`  \n**`toArrayForUpdate(): array`** - Excludes properties from `toExcludedPropertiesOnUpdate()`  \n**`toJson(int $options = 0): string`** - Converts to JSON string\n\n#### Validation\n\n**`validate(callable $validator, string $message): static`**  \nValidates using a custom callback.\n\n**`validateAttributes(): static`**  \nValidates using PHP attributes.\n\n#### Property Access\n\n**`has(string $property): bool`** - Checks if property exists  \n**`get(string $property, mixed $default = null): mixed`** - Gets property value\n\n#### Utility Methods\n\n**`clone(): static`** - Creates a clone  \n**`tap(callable $callback): static`** - Executes callback and returns instance  \n**`dump(): static`** - Dumps data for debugging  \n**`dd(): never`** - Dumps data and dies\n\n#### Protected Methods (Override in your DTOs)\n\n**`toExcludedPropertiesOnCreate(): array`** - Properties to exclude in create context  \n**`toExcludedPropertiesOnUpdate(): array`** - Properties to exclude in update context  \n**`transforms(): array`** - Data transformations for resolve()\n\n### Artisan Commands\n\n#### `make:action [name]`\n\nGenerates a new Action class.\n\n**Options:**\n\n- `--with-dto=DtoName` - Auto-generate corresponding DTO\n- `--force` - Overwrite existing files\n\n#### `make:dto [name]`\n\nGenerates a new Data Transfer Object class.\n\n**Options:**\n\n- `--force` - Overwrite existing files\n\n## Testing\n\nRun the test suite:\n\n```bash\ncomposer test\n```\n\nRun static analysis:\n\n```bash\ncomposer analyse\n```\n\nRun code formatting:\n\n```bash\ncomposer format\n```\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fholiq%2Faction-data","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fholiq%2Faction-data","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fholiq%2Faction-data/lists"}