Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Action Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require laraditz/action
    

    Run the publish command (if needed for configuration):

    php artisan vendor:publish --provider="Laraditz\Action\ActionServiceProvider"
    
  2. Generate Your First Action:

    php artisan make:action CreateUser
    

    This creates a new class in app/Actions/CreateUser.php.

  3. Define Dependencies and Logic:

    namespace App\Actions;
    
    use Laraditz\Action\Action;
    use App\Models\User;
    
    class CreateUser extends Action
    {
        public function __construct(
            public string $name,
            public string $email
        ) {}
    
        public function handle(): void
        {
            User::create($this->data());
        }
    }
    
  4. First Usage:

    $action = new CreateUser(name: 'John Doe', email: 'john@example.com');
    $action->handle();
    

Where to Look First

  • Action Class: vendor/laraditz/action/src/Action.php – Core logic and helpers.
  • Artisan Command: vendor/laraditz/action/src/Console/MakeActionCommand.php – How actions are scaffolded.
  • Service Provider: vendor/laraditz/action/src/ActionServiceProvider.php – Registration and booting logic.

Implementation Patterns

Core Workflow

  1. Action Creation: Use make:action to scaffold a new action with constructor properties and a handle() method. This enforces dependency injection and type safety.

  2. Dependency Injection: Pass required dependencies via the constructor. The data() helper method aggregates all constructor properties into an array for easy access.

    $action = new ProcessOrder(
        orderId: $orderId,
        paymentMethod: $paymentMethod,
        userId: auth()->id()
    );
    $action->handle();
    
  3. Integration with Controllers: Use actions in controllers to encapsulate business logic, reducing controller bloat.

    public function store(Request $request)
    {
        $action = new CreateUser(
            name: $request->name,
            email: $request->email
        );
        $action->handle();
    
        return redirect()->route('users.index');
    }
    
  4. Reusable Actions: Create actions for common operations like validation, database operations, or API calls. For example:

    // app/Actions/ValidateUserInput.php
    class ValidateUserInput extends Action
    {
        public function __construct(
            public array $rules,
            public array $data
        ) {}
    
        public function handle(): void
        {
            validator($this->data, $this->rules)->validate();
        }
    }
    
  5. Chaining Actions: Combine multiple actions sequentially or conditionally.

    $validate = new ValidateUserInput($rules, $request->all());
    $validate->handle();
    
    $createUser = new CreateUser(
        name: $request->name,
        email: $request->email
    );
    $createUser->handle();
    
  6. Returning Data: Use the handle() method to return data instead of void for actions that need to provide output.

    public function handle(): array
    {
        return $this->data();
    }
    

    Then use it like this:

    $result = (new GetUserProfile($userId))->handle();
    
  7. Middleware Integration: Use actions in middleware to centralize logic like authentication or authorization checks.

    public function handle($request, Closure $next)
    {
        $checkPermission = new CheckUserPermission(
            userId: auth()->id(),
            requiredPermission: 'edit_post'
        );
        $checkPermission->handle();
    
        return $next($request);
    }
    

Gotchas and Tips

Pitfalls

  1. Constructor Properties vs. Public Properties: Avoid mixing constructor properties with additional public properties. The data() helper only aggregates constructor properties. If you need extra properties, use a method like getExtraData() or initialize them in the constructor.

    // Bad: $this->extraData is not included in $this->data()
    public $extraData;
    
    // Good: Initialize in constructor
    public function __construct(
        public string $name,
        public string $email,
        public array $metadata = []
    ) {}
    
  2. Type Safety: The package doesn’t enforce return types for the handle() method. Explicitly declare return types (e.g., void, array, Model) to ensure consistency and IDE support.

    public function handle(): User
    {
        return User::create($this->data());
    }
    
  3. Overriding data(): If you override the data() method, ensure it still returns an array of constructor properties for backward compatibility.

    public function data(): array
    {
        return array_merge(parent::data(), ['custom_key' => 'value']);
    }
    
  4. Circular Dependencies: Avoid circular dependencies between actions. If Action A calls Action B, which in turn calls Action A, it will lead to infinite recursion or errors.

  5. Lumen Compatibility: While the package supports Lumen, ensure you’re using the correct service provider registration. Lumen may require manual binding if not auto-discovered.


Debugging Tips

  1. Check Constructor Properties: Use var_dump($this->data()) inside handle() to verify the data being passed to the action.

  2. Logging: Add logging in the handle() method to trace execution flow.

    \Log::info('Action executed with data:', $this->data());
    
  3. Exception Handling: Wrap action calls in try-catch blocks to handle exceptions gracefully.

    try {
        $action->handle();
    } catch (\Exception $e) {
        \Log::error('Action failed:', ['error' => $e->getMessage()]);
        abort(500, 'An error occurred.');
    }
    
  4. Artisan Command Issues: If make:action isn’t working, ensure the service provider is registered in config/app.php under the providers array.


Extension Points

  1. Custom Action Traits: Create reusable traits for common action behaviors, such as logging, validation, or transaction handling.

    trait HandlesTransactions
    {
        public function handle(): void
        {
            \DB::beginTransaction();
            try {
                // Business logic
                \DB::commit();
            } catch (\Exception $e) {
                \DB::rollBack();
                throw $e;
            }
        }
    }
    
  2. Action Events: Dispatch events within actions to decouple logic and enable observability.

    public function handle(): void
    {
        event(new UserCreated($this->data()));
        User::create($this->data());
    }
    
  3. Dynamic Actions: Use reflection or dynamic class generation to create actions on the fly for highly dynamic workflows. However, this should be used sparingly due to complexity.

  4. Testing Actions: Write unit tests for actions by mocking dependencies. Example:

    public function test_create_user_action()
    {
        $action = new CreateUser(name: 'Test', email: 'test@example.com');
        $this->assertNull($action->handle()); // Or assert the created user
    }
    
  5. Action Caching: Cache action instances if they’re stateless and called frequently (e.g., in middleware or filters).

    $action = app()->makeWith(CreateUser::class, [
        'name' => 'Cached User',
        'email' => 'cached@example.com'
    ]);
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope