From 136d5fabffa97eac5448a42e68af9cf0b96357ae Mon Sep 17 00:00:00 2001 From: Richard Anderson Date: Sun, 25 May 2025 19:49:26 +0100 Subject: [PATCH 1/3] Readme update --- README.md | 542 +++++++++++++++++++++--------------------------------- 1 file changed, 208 insertions(+), 334 deletions(-) diff --git a/README.md b/README.md index 3f584e5..f457fbf 100644 --- a/README.md +++ b/README.md @@ -1,138 +1,172 @@ -# LumoSolutions - Actionable +# ⚡ Actionable -A Laravel package that provides a clean, elegant way to create dispatchable and runnable actions with built-in array conversion capabilities. Simplify your Laravel application's business logic with reusable, testable action classes. +> **Transform your Laravel code into clean, testable, and reusable actions.** Say goodbye to bloated controllers and hello to elegantly organized business logic! -## Features +
-- **Runnable Actions**: Execute actions synchronously with dependency injection support -- **Dispatchable Actions**: Queue actions for asynchronous execution -- **Array Conversion**: Convert objects to/from arrays with attribute-based customization -- **Artisan Commands**: Generate action and DTO stubs quickly -- **Flexible Attributes**: Control serialization behavior with custom attributes +[![CI Pipeline](https://github.com/LumoSolutions/actionable/actions/workflows/build.yml/badge.svg)](https://github.com/LumoSolutions/actionable/actions/workflows/build.yml) +[![codecov](https://codecov.io/gh/LumoSolutions/actionable/branch/main/graph/badge.svg)](https://codecov.io/gh/LumoSolutions/actionable) +[![Latest Stable Version](https://poser.pugx.org/lumosolutions/actionable/v/stable)](https://packagist.org/packages/lumosolutions/actionable) +[![Total Downloads](https://poser.pugx.org/lumosolutions/actionable/downloads)](https://packagist.org/packages/lumosolutions/actionable) +[![License](https://img.shields.io/github/license/LumoSolutions/actionable)](LICENSE) -## Installation +**[Installation](#-installation)** • **[Quick Start](#-quick-start)** • **[Features](#-key-features)** • **[Documentation](#-documentation)** • **[Examples](#-real-world-examples)** -Install the package via Composer: +
-```bash -composer require lumo-solutions/actionable +## 💡 Why Actionable? + +Ever found yourself writing the same business logic patterns over and over? Controllers getting too fat? Service classes becoming a mess? **Actionable is here to save the day!** + +```php +// ❌ The old way - Fat controllers, messy code +class UserController extends Controller +{ + public function register(Request $request) + { + // Validation logic... + // User creation logic... + // Email sending logic... + // Queue processing... + // 200 lines later... + } +} + +// ✅ The Actionable way - Clean, focused, reusable +RegisterUser::run($userData); ``` -## Quick Start +## 🎯 Key Features -### Creating a Basic Action +### 🏃‍♂️ **Runnable Actions** +Execute business logic with a single, expressive call. No more hunting through service classes! -```php -send(new WelcomeEmail($name)); } } ``` -### Running the Action - +**3️⃣ Use it anywhere:** ```php -// Execute the action synchronously SendWelcomeEmail::run('user@example.com', 'John Doe'); ``` -### Creating a Dispatchable Action +**That's it!** Clean, testable, reusable. 🎉 -```php -items->sum(fn($item) => $item->price * $item->quantity); } } + +// Usage +$total = CalculateOrderTotal::run($order); ``` -### Dispatching Actions to Queue +#### Queueable Actions + +Need background processing? Just add a trait! ```php -// Dispatch to default queue -ProcessLargeDataset::dispatch($largeDataArray); +class ProcessVideoUpload +{ + use IsRunnable, IsDispatchable; -// Dispatch to specific queue -ProcessLargeDataset::dispatchOn('heavy-processing', $largeDataArray); -``` + public function handle(Video $video): void + { + // Heavy processing logic here + } +} -## Creating DTOs with Array Conversion +// Run synchronously +ProcessVideoUpload::run($video); -### Basic DTO +// Or dispatch to queue +ProcessVideoUpload::dispatch($video); -```php -validated()); -```php -// Create from array -$userData = UserData::fromArray([ - 'name' => 'John Doe', - 'email' => 'john@example.com', - 'age' => 30 -]); - -// Convert to array -$array = $userData->toArray(); +// To API response +return response()->json($product->toArray()); ``` -## Attributes Reference - -The package provides several attributes to customize array conversion behavior. All attributes can be applied to constructor parameters or class properties. - -### #[FieldName] - Custom Field Mapping +### 🏷️ Powerful Attributes -Map property names to different array keys: +#### `#[FieldName]` - API-Friendly Naming ```php - 123, - 'full_name' => 'John Doe', - 'email_address' => 'john@example.com' -]); - -$array = $response->toArray(); -// Returns: ['user_id' => 123, 'full_name' => 'John Doe', 'email_address' => 'john@example.com'] ``` -### #[DateFormat] - Date Serialization Control - -Control how DateTime objects are formatted during array conversion: +#### `#[DateFormat]` - Date Formatting Made Easy ```php -toArray(); -// Returns formatted dates according to their attributes ``` -### #[ArrayOf] - Nested Object Arrays - -Handle arrays containing objects of a specific class: +#### `#[ArrayOf]` - Handle Nested Objects ```php - 'ORD-001', - 'items' => [ - ['name' => 'Laptop', 'quantity' => 1, 'price' => 999.99], - ['name' => 'Mouse', 'quantity' => 2, 'price' => 25.00] - ], - 'bundleItems' => [ - ['name' => 'Cable', 'quantity' => 1, 'price' => 15.00] - ] -]); - -// The arrays are automatically converted to OrderItem objects -echo $order->items[0]->name; // 'Laptop' ``` -### #[Ignore] - Exclude from Conversion - -Exclude sensitive or computed properties from array conversion: +#### `#[Ignore]` - Keep Secrets Secret ```php - $this->username, 'email' => $this->email]; - } } - -// Usage -$user = new UserAccount( - username: 'johndoe', - email: 'john@example.com', - password: 'secret123', - apiKey: 'api_key_here', - createdAt: new DateTime() -); - -$array = $user->toArray(); -// Returns: ['username' => 'johndoe', 'email' => 'john@example.com', 'createdAt' => '2024-01-01 12:00:00'] -// Password and apiKey are excluded ``` -### Combining Attributes +### 🛠️ Artisan Commands -You can combine multiple attributes on the same property: +Generate boilerplate with style: -```php -toArray(); // Clean, formatted output ready for API -``` - -## Artisan Commands - -The package provides convenient Artisan commands to generate boilerplate code: - -### Generate Action Classes - -```bash -# Generate basic runnable action -php artisan make:action SendNotification - -# Generate dispatchable action (can be queued) -php artisan make:action ProcessPayment --dispatchable - -# Generate invokable action -php artisan make:action CalculateTotal --invokable -``` - -The `make:action` command supports the following options: -- `--dispatchable` - Adds the `IsDispatchable` trait for queueing support -- `--invokable` - Creates an invokable action (uses `action.invokable.stub`) - -### Generate DTO Classes - -```bash -# Generate basic DTO with array conversion capabilities -php artisan make:dto UserRegistrationData -``` - -### Custom Stubs - -You can publish and customize the stubs used by the commands by creating them in your application's `stubs/lumosolutions/actionable/` directory. The package will automatically use your custom stubs if they exist: +// The Action +class ProcessOrder +{ + use IsRunnable, IsDispatchable; -- `action.stub` - Basic action template -- `action.dispatchable.stub` - Dispatchable action template -- `action.invokable.stub` - Invokable action template -- `dto.stub` - DTO template + public function handle(OrderData $orderData): Order + { + $order = DB::transaction(function () use ($orderData) { + $order = Order::create([...]); + + // Process items + foreach ($orderData->items as $item) { + $order->items()->create([...]); + } + + // Apply discount + if ($orderData->discountCode) { + ApplyDiscount::run($order, $orderData->discountCode); + } + + return $order; + }); + + // Queue follow-up actions + SendOrderConfirmation::dispatch($order); + UpdateInventory::dispatch($order); + + return $order; + } +} -Example custom stub location: +// Usage - It's this simple! +$orderData = OrderData::fromArray($request->validated()); +$order = ProcessOrder::run($orderData); ``` -stubs/ -└── lumosolutions/ - └── actionable/ - ├── action.stub - ├── action.dispatchable.stub - ├── action.invokable.stub - └── dto.stub -``` - -## Complete Example -Here's a complete example showing how to use actions and DTOs together: +### User Registration Flow ```php -referralSource); - #[Ignore] - public string $password - ) {} + return $user; + } } +``` -// Action to process user registration -class RegisterUser -{ - use IsRunnable, IsDispatchable; +## 🤝 Why We Think You Will Love Actionable - public function handle(UserRegistrationData $userData): User - { - // Validate and create user - $user = User::create([ - 'name' => $userData->fullName, - 'email' => $userData->email, - 'birth_date' => $userData->birthDate, - 'password' => Hash::make($userData->password) - ]); +### 🧪 **Testability First** +Each action is a single unit - mock dependencies, test in isolation, achieve 100% coverage with ease. - // Send welcome email asynchronously - SendWelcomeEmail::dispatch($user->email, $user->name); +### 📐 **Single Responsibility** +One action, one job. Your code stays focused and maintainable. - return $user; - } -} +### 🔁 **Reusability** +Use the same action in controllers, commands, jobs, or other actions. Write once, use everywhere. -// Usage -$registrationData = UserRegistrationData::fromArray($request->all()); -$user = RegisterUser::run($registrationData); -``` +### 📈 **Scalability** +Start simple with synchronous actions, scale to queues when needed. No refactoring required! + +## 🤲 Contributing + +We love contributions! Whether it's a bug fix, new feature, or improvement to our docs - we appreciate it all. Please feel free to submit a pull request or open an issue. + +## 📄 License -## Requirements +Actionable is open-sourced software licensed under the [MIT license](LICENSE). -- PHP 8.2 or higher -- Laravel 12.0 or higher +## 💬 Support & Community -## Contributing +- 🐛 **Found a bug?** [Open an issue](https://github.com/LumoSolutions/actionable/issues) +- 💡 **Have an idea?** [Start a discussion](https://github.com/LumoSolutions/actionable/discussions) +- 🔒 **Security concern?** Email me at richard@lumosolutions.org -Contributions are welcome! Please feel free to submit a Pull Request. +--- -## License +
-This package is open-sourced software licensed under the [MIT license](LICENSE). +**Built with ❤️ by [Lumo Solutions](https://lumosolutions.com)** -## Support +*Making Laravel development more enjoyable, one action at a time.* -If you discover any security vulnerabilities or bugs, please create an issue on GitHub. +
From d34baad0276faf436ab523d7da0995f552efba0a Mon Sep 17 00:00:00 2001 From: Richard Anderson Date: Sun, 25 May 2025 19:52:22 +0100 Subject: [PATCH 2/3] Minor Tweaks --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f457fbf..a121b6a 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ SendWelcomeEmail::run('user@example.com', 'John Doe'); ## 📚 Documentation -### 🎭 Actions +### ⚡ Actions Actions are the heart of your application's business logic. They're single-purpose classes that do one thing and do it well. @@ -358,8 +358,8 @@ Actionable is open-sourced software licensed under the [MIT license](LICENSE).
-**Built with ❤️ by [Lumo Solutions](https://lumosolutions.com)** +**Built with ❤️ by [Lumo Solutions](https://lumosolutions.org)** -*Making Laravel development more enjoyable, one action at a time.* +*Actionable: Making Laravel development more enjoyable, one action at a time.*
From 5b17463cf59fbc3759037d05975d39c7c0e1aea0 Mon Sep 17 00:00:00 2001 From: Richard Anderson Date: Sun, 25 May 2025 19:53:13 +0100 Subject: [PATCH 3/3] Removed why you will love section --- README.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/README.md b/README.md index a121b6a..386fdf3 100644 --- a/README.md +++ b/README.md @@ -326,20 +326,6 @@ class RegisterUser } ``` -## 🤝 Why We Think You Will Love Actionable - -### 🧪 **Testability First** -Each action is a single unit - mock dependencies, test in isolation, achieve 100% coverage with ease. - -### 📐 **Single Responsibility** -One action, one job. Your code stays focused and maintainable. - -### 🔁 **Reusability** -Use the same action in controllers, commands, jobs, or other actions. Write once, use everywhere. - -### 📈 **Scalability** -Start simple with synchronous actions, scale to queues when needed. No refactoring required! - ## 🤲 Contributing We love contributions! Whether it's a bug fix, new feature, or improvement to our docs - we appreciate it all. Please feel free to submit a pull request or open an issue.