How to use Laravel's Conditionable Trait for dynamic actions

When working with multiple or complex conditional logic, if-else statements can quickly increase cognitive load and by extension, code maintainability.

However, Laravel provides a trait that we can leverage to create a fluent and dynamic API that provides a cleaner approach to conditional logic—the Conditionable trait. We will use Filament as a case study.

How Does Filament Use the Conditionable Trait?

In Filament, the Conditionable trait is particularly useful for creating actions that need to behave differently based on certain conditions. For instance, you might want an action to have a label only when another condition (e.g. $iconOnly) is false.

use Filament\Actions\Action;
use Filament\Forms;

Action::make('action')
    ->when($iconOnly, fn (Action $action) => $action->label('')->link())
    ->icon('...')
    ->action(function (array $data) {
        // do stuff
    });

In this example, the when() method checks if $iconOnly is true. If it is, the callback function modifies the action to remove the label and convert it into a link, such that the action is presented like a clickable icon.

Practical Example: A Flexible Action Builder

Let's look at how you might implement something similar in your own application using an action class.

  1. Create a Custom Action Class: Create a class that uses the Conditionable trait.

    <?php
    
    namespace App\Actions;
    
    use Illuminate\Support\Traits\Conditionable;
    
    class MyAction
    {
        use Conditionable;
    
        protected $label;
        protected $link = false;
        protected $formFields = [];
    
        public function label($label)
        {
            $this->label = $label;
            return $this;
        }
    
        public function link()
        {
            $this->link = true;
            return $this;
        }
    
        public function form(array $fields)
        {
            $this->formFields = $fields;
            return $this;
        }
    
        public function run(?callable $callback = null)
        {
            // Simulate a form submission
            if ($callback) {
                $data = ['dummy' => 'value']; // Mock form data
                call_user_func($callback, $data);
            }
        }
    }
    
    Databases in VS Code? Get DevDb
  2. Using the Action Builder: You can now use this class to build actions dynamically:

    use App\Actions\MyAction;
    
    MyAction::make('my_action')
        ->when(true, fn ($action) => $action->label('')->link())
        ->form([
            // Define your form fields here
        ])
        ->run(function (array $data) {
            dump($data);
        });
    

In this example, the when() method accepts a condition and a callback. If the condition is true, it runs the callback on the action instance.

Conclusion

With Laravel's Conditionable trait, you can build fluent and dynamic APIs in your applications, much like Filament does. This approach makes your code easier to understand and maintain by reducing the amount of conditional logic scattered throughout your application. However, while Conditionable makes your code more readable, don’t overuse it where simple structures like if/else would suffice.

Remember, writing cleaner and more dynamic code isn’t just about productivity; it’s also about making your codebase more welcoming for future contributors, even your future self!

Wanna chat about what you just read, or anything at all? Click here to tweet at me on 𝕏