lumosolutions / actionable
Provides a clean, elegant way to create dispatchable and runnable actions in Laravel with built-in array conversion capabilities
Requires
- php: >=8.3
Requires (Dev)
- larastan/larastan: ^2.9||^3.0
- laravel/pint: ^1.22
- orchestra/testbench: ^10.0.0||^9.0.0||^8.22.0
- pestphp/pest: ^3.0
README
Installation • Quick Start • Features • Documentation • Examples
Transform your Laravel code into clean, testable, and reusable actions. Say goodbye to bloated controllers and hello to elegantly organized business logic!
💡 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!
// ❌ 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);
🎯 Key Features
🏃♂️ Runnable Actions
Execute business logic with a single, expressive call. No more hunting through service classes!
📬 Dispatchable Actions
Seamlessly queue your actions for background processing. It's as easy as changing run()
to dispatch()
!
💡 Smart Code Completion
Full IntelliSense support with auto-completion for runnable and dispatchable actions across all major IDEs.
🔄 Smart Array Conversion
Convert between arrays and objects effortlessly with our powerful attribute system. Perfect for APIs!
🛠️ Artisan Generators
Scaffold Actions and DTOs in seconds with our intuitive Artisan commands.
🎨 Flexible Attributes
Fine-tune serialization behavior with elegant attributes like #[FieldName]
, #[DateFormat]
, and more!
📦 Installation
composer require lumosolutions/actionable
That's it! No configuration needed. Start writing better code immediately.
🚀 Quick Start
Your First Action in 30 Seconds
1️⃣ Generate an action:
php artisan make:action SendWelcomeEmail
2️⃣ Define your logic:
class SendWelcomeEmail { use IsRunnable; public function handle(string $email, string $name): void { Mail::to($email)->send(new WelcomeEmail($name)); } }
3️⃣ Use it anywhere:
SendWelcomeEmail::run('user@example.com', 'John Doe');
That's it! Clean, testable, reusable. 🎉
📚 Documentation
⚡ Actions
Actions are the heart of your application's business logic. They're single-purpose classes that do one thing and do it well.
Basic Actions
class CalculateOrderTotal { use IsRunnable; public function handle(Order $order): float { return $order->items->sum(fn($item) => $item->price * $item->quantity); } } // Usage $total = CalculateOrderTotal::run($order);
Queueable Actions
Need background processing? Just add a trait!
class ProcessVideoUpload { use IsRunnable, IsDispatchable; public function handle(Video $video): void { // Heavy processing logic here } } // Run synchronously ProcessVideoUpload::run($video); // Or dispatch to queue ProcessVideoUpload::dispatch($video); // Use a specific queue ProcessVideoUpload::dispatchOn('video-processing', $video);
🗄️ Data Transfer Objects (DTOs)
DTOs with superpowers! Convert between arrays and objects seamlessly.
class ProductData { use ArrayConvertible; public function __construct( public string $name, public float $price, public int $stock ) {} } // From request data $product = ProductData::fromArray($request->validated()); // To API response return response()->json($product->toArray());
🏷️ Powerful Attributes
#[FieldName]
- API-Friendly Naming
class UserResponse { use ArrayConvertible; public function __construct( #[FieldName('user_id')] public int $userId, #[FieldName('full_name')] public string $fullName ) {} }
#[DateFormat]
- Date Formatting Made Easy
class EventData { use ArrayConvertible; public function __construct( #[DateFormat('Y-m-d')] public DateTime $date, #[DateFormat('H:i')] public DateTime $startTime ) {} }
#[ArrayOf]
- Handle Nested Objects
class ShoppingCart { use ArrayConvertible; public function __construct( #[ArrayOf(CartItem::class)] public array $items ) {} }
#[Ignore]
- Keep Secrets Secret
class UserAccount { use ArrayConvertible; public function __construct( public string $email, #[Ignore] public string $password, #[Ignore] public string $apiSecret ) {} }
🛠️ Artisan Commands
Generate boilerplate with style:
# Basic action php artisan make:action ProcessOrder # Queueable action php artisan make:action SendNewsletter --dispatchable # Invokable action php artisan make:action CalculateShipping --invokable # DTO with array conversion php artisan make:dto OrderData # Enable Smart Code Completion php artisan ide-helper:actions
🌟 Real-World Examples
E-commerce Order Processing
// The DTO class OrderData { use ArrayConvertible; public function __construct( #[FieldName('customer_email')] public string $customerEmail, #[ArrayOf(OrderItemData::class)] public array $items, #[FieldName('discount_code')] public ?string $discountCode = null ) {} } // The Action class ProcessOrder { use IsRunnable, IsDispatchable; 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; } } // Usage - It's this simple! $orderData = OrderData::fromArray($request->validated()); $order = ProcessOrder::run($orderData);
User Registration Flow
class RegisterUser { use IsRunnable; public function handle(RegistrationData $data): User { $user = CreateUser::run($data); SendWelcomeEmail::dispatch($user); NotifyAdmins::dispatch($user); TrackRegistration::dispatch($user, $data->referralSource); return $user; } }
🤲 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
Actionable is open-sourced software licensed under the MIT license.
💬 Support & Community
- 🐛 Found a bug? Open an issue
- 💡 Have an idea? Start a discussion
- 🔒 Security concern? Email me at richard@lumosolutions.org
Built with ❤️ by Lumo Solutions
Actionable: Making Laravel development more enjoyable, one action at a time.