laraditz/action
Define single-purpose Action classes for Laravel and Lumen to keep code DRY. Generate actions via artisan, pass data through constructor properties, and execute with handle() or a convenient static run() method. Includes a data() helper for all properties.
Single action class for Laravel to keep your application DRY. Each action encapsulates one business operation, receives its input through the constructor, and resolves services automatically via Laravel's container.
composer require laraditz/action
Use the Artisan command to generate an action class (placed in app/Actions/ by default):
php artisan make:action CreateNewPost
Fill in the generated file:
namespace App\Actions;
use App\Models\Post;
use Laraditz\Action\Action;
class CreateNewPost extends Action
{
public function __construct(
public string $title,
public string $body,
) {}
public function handle(): Post
{
return Post::create($this->data());
}
}
Instance style — construct first, then call run():
$post = (new CreateNewPost(title: 'Hello', body: 'World'))->run();
Static style — constructor arguments are passed directly to run():
$post = CreateNewPost::run(title: 'Hello', body: 'World');
Both styles are equivalent.
Type-hint services in handle() and Laravel's container injects them automatically:
namespace App\Actions;
use App\Mail\PostCreated;
use App\Models\Post;
use Illuminate\Contracts\Mail\Mailer;
use Laraditz\Action\Action;
class PublishPost extends Action
{
public function __construct(
public string $title,
public string $body,
public string $authorEmail,
) {}
public function handle(Mailer $mailer): Post
{
$post = Post::create($this->data());
$mailer->to($this->authorEmail)->send(new PostCreated($post));
return $post;
}
}
// $mailer is resolved from the container automatically
PublishPost::run(
title: 'My Post',
body: 'Content here',
authorEmail: '[email protected]',
);
Make an action queueable by implementing ShouldQueue and adding the standard Laravel queue traits. Do not add Dispatchable — the base Action class already provides dispatch().
namespace App\Actions;
use App\Mail\WelcomeEmail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Laraditz\Action\Action;
class SendWelcomeEmail extends Action implements ShouldQueue
{
use Queueable, InteractsWithQueue, SerializesModels;
public function __construct(
public string $email,
public string $name,
) {}
public function handle(Mailer $mailer): void
{
$mailer->to($this->email)->send(new WelcomeEmail($this->name));
}
}
Dispatching to the queue:
// Using the base class static dispatch()
SendWelcomeEmail::dispatch(email: '[email protected]', name: 'Alice');
// Using Laravel's global helper
dispatch(new SendWelcomeEmail(email: '[email protected]', name: 'Alice'));
When the queue worker processes the job, Laravel's CallQueuedHandler calls handle() through the container, so type-hinted dependencies are injected automatically — the same as when running synchronously.
Note: Do not add
use Illuminate\Foundation\Bus\Dispatchableto your action class. The baseActionclass already providesdispatch(), and adding the trait will cause a conflict.
data() Helperdata() returns all constructor-promoted properties as a key–value array, which is handy for mass-assignment:
public function handle(): Post
{
// Returns ['title' => '...', 'body' => '...']
return Post::create($this->data());
}
Actions with no constructor return an empty array from data().
Please see CHANGELOG for more information on what has changed recently.
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
MIT. Please see the license file for more information.
How can I help you explore Laravel packages today?