PHP code example of fazzinipierluigi / laravel-rails

1. Go to this page and download the library: Download fazzinipierluigi/laravel-rails library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

fazzinipierluigi / laravel-rails example snippets


return [
    /*
    |--------------------------------------------------------------------------
    | Permission Resolver
    |--------------------------------------------------------------------------
    | Custom PermissionResolverInterface implementation.
    | If null, auto-detected: just-a-gate → spatie/laravel-permission → Laravel Gate.
    */
    'permission_resolver' => null,
];

use Fazzinipierluigi\LaravelRails\Models\Workflow;
use Fazzinipierluigi\LaravelRails\Models\State;
use Fazzinipierluigi\LaravelRails\Models\Transition;

$workflow = Workflow::create(['name' => 'Order Approval', 'slug' => 'order-approval']);

$start    = State::create(['workflow_id' => $workflow->id, 'name' => 'Pending',  'slug' => 'pending',  'is_start' => true]);
$review   = State::create(['workflow_id' => $workflow->id, 'name' => 'Review',   'slug' => 'review']);
$approved = State::create(['workflow_id' => $workflow->id, 'name' => 'Approved', 'slug' => 'approved', 'is_end' => true]);
$rejected = State::create(['workflow_id' => $workflow->id, 'name' => 'Rejected', 'slug' => 'rejected', 'is_end' => true]);

Transition::create(['from' => $start->id,  'to' => $review->id,   'sort' => 0]);
Transition::create(['from' => $review->id, 'to' => $approved->id, 'sort' => 0]);
Transition::create(['from' => $review->id, 'to' => $rejected->id, 'sort' => 1]);

$state->codeGT('step_01');  // current code > step_01
$state->codeGTE('step_01'); // >=
$state->codeLT('step_05');  // <
$state->codeEQ('step_03');  // ==

$state->canView($user);   // Returns bool. Null $user → false if permissions set.

$transition->can($instance);         // State match + advance permission + execute_condition
$transition->can_show($instance);    // State match + view permission + show_condition
$transition->can_exit($instance);    // exit_condition only
$transition->canAdvance($user);      // Advance permission only (no instance needed)

use Fazzinipierluigi\LaravelRails\Interfaces\ActionInterface;

class MyAction implements ActionInterface
{
    public static string $display_name = 'My Action';

    public static array $configuration_schema = [
        ['name' => 'message', 'type' => 'text', 'label' => 'Message', '

$workflow = Workflow::getBySlug('order-approval');
$instance = $workflow->instantiate($order, 'user:' . auth()->id());

$redirectUrl = $instance->progress();         // system-triggered
$redirectUrl = $instance->progress('user:42'); // user-triggered

$instance->state;        // Current State model
$instance->state_id;     // Current State UUID
$instance->workflow;     // Workflow model
$instance->entity;       // The entity (Order, User, etc.)
$instance->variables;    // Array of workflow variables

use Fazzinipierluigi\LaravelRails\Classes\VariableResolver;

$resolved = VariableResolver::resolve('Hello {{variables.name}}, total: {{variables.total}}', $instance, $entity);

$instance->getVariable('price');           // dot-notation get, returns null if missing
$instance->getVariable('price', 0);        // with default
$instance->setVariable('status', 'active'); // dot-notation set + save
$instance->mergeVariables(['a' => 1, 'b' => 2]); // merge + save
$instance->hasVariable('price');           // bool

$context = VariableResolver::buildContext($instance, $entity);
// Returns:
// [
//   'variables' => ['price' => 99, ...],
//   'entity'    => ['id' => '...', 'status' => 'pending', ...],
//   'request'   => [...],  // current request data
//   'instance'  => ['id' => '...', 'workflow_id' => '...', 'state_id' => '...'],
// ]

$parser = new \Fazzinipierluigi\LaravelRails\Classes\Expression\Parser();
$parser->onVariable = fn($name, &$val) => $val = $instance->getVariable($name) ?? 0;
$result = $parser->execute('quantity * unit_price * (1 + tax_rate)');

ExecutionLog {
    id:           UUID
    instance_id:  UUID (FK)
    event:        string
    subject_type: 'state' | 'transition' | 'action' | null
    subject_id:   UUID | null
    data:         array  // full event details
    triggered_by: string // 'user:42', 'system', 'auto', 'trigger:uuid'
    occurred_at:  datetime
}

ExecutionLog::forInstance($instanceId)->get();
ExecutionLog::forInstance($instanceId)->ofEvent('state.entered')->get();
ExecutionLog::forInstance($instanceId)->forState($stateId)->get();
ExecutionLog::forInstance($instanceId)->forTransition($transitionId)->get();

$logger = $instance->logger();          // 'system' triggered_by
$logger = $instance->logger('user:42'); // first call locks triggered_by

interface PermissionResolverInterface
{
    public function check(mixed $user, array $permissions, string $operator = 'OR'): bool;
    public function getDriverName(): string;
}

// config/laravel-rails.php
'permission_resolver' => App\Permissions\MyResolver::class,

class MyResolver implements PermissionResolverInterface
{
    public function check(mixed $user, array $permissions, string $operator = 'OR'): bool
    {
        // Your logic here
    }
    public function getDriverName(): string { return 'my-driver'; }
}

$state->canView($user);    // Uses view_permissions + view_operator

$transition->can_show($instance); // view_permissions + view_operator + show_condition

$transition->can($instance);       // advance_permissions + advance_operator + execute_condition
$transition->canAdvance($user);    // advance_permissions only (no instance)

WorkflowTrigger {
    id:            UUID
    workflow_id:   UUID (FK)
    name:          string
    type:          'scheduled' | 'manual' | 'entity_event'
    configuration: JSON
    is_active:     bool
    last_run_at:   timestamp?
}

Schedule::command('rail:trigger:scheduled')->everyMinute();

$order->fireManualTrigger('trigger-name-or-uuid');

$transitions = $instance->availableTransitions();
// Returns Collection<Transition>, ordered by sort, filtered by can_show()

use Fazzinipierluigi\LaravelRails\Traits\IsWorkflowEntity;

class Order extends Model
{
    use IsWorkflowEntity;
}

// Start the workflow for this entity
$order->startWorkflow('order-approval'); // workflow slug

// Get the current workflow instance
$instance = $order->getWorkflowInstance('order-approval');

// Advance the workflow
$redirectUrl = $order->progressWorkflow('order-approval');

// Fire a manual trigger
$order->fireManualTrigger('trigger-name-or-uuid');

class TestCase extends OrchestraTestCase
{
    protected function getPackageProviders($app): array
    {
        return [LaravelRailsServiceProvider::class];
    }

    protected function getEnvironmentSetUp($app): void
    {
        $app['config']->set('database.default', 'testing');
        $app['config']->set('database.connections.testing', [
            'driver' => 'sqlite', 'database' => ':memory:',
        ]);
        $app['config']->set('session.driver', 'array');
        $app['config']->set('queue.default', 'sync');
    }

    protected function setUp(): void
    {
        parent::setUp();
        Model::unguard();       // Allow ::create() calls
        $this->artisan('migrate'); // Run all package migrations
        // Create test entity tables (orders, users)
    }
}

WorkflowFactory::twoState($slug)        // Start → End
WorkflowFactory::threeState($slug)      // Start → Middle → End
WorkflowFactory::withForm($slug)        // Start -[form]-> Review → End
WorkflowFactory::withConditional($slug) // Start → Conditional → Branch A/B → End
WorkflowFactory::createOrder($attrs)    // Create test Order entity
WorkflowFactory::addAction($model, $phase, $actionClass, $config)

$this->app->instance(PermissionResolverInterface::class, new VanillaGateResolver());
Gate::define('my-ability', fn($user) => true);
$this->actingAs($user);

Queue::fake();
$workflow->instantiate($order);
Queue::assertDispatched(AutoAdvanceWorkflow::class);

Queue::fake();
$instance = $workflow->instantiate($order);
$job = new AutoAdvanceWorkflow($instance->id);
$job->handle();
$instance->refresh();
$this->assertEquals($end->id, $instance->state_id);
bash
php artisan automata:install
bash
php artisan migrate
bash
php artisan vendor:publish --tag=laravel-rails.config
bash
php artisan automata:action:register "App\Rails\Actions\MyAction"
bash
php artisan rail:make-action SendApprovalEmail
# Creates app/Rails/Actions/SendApprovalEmail.php
blade
@laravel_rail_form($transition->id, $instance->id)
{{-- Or with options: --}}
@laravel_rail_form($transition->id, $instance->id, ['submit_label' => 'Submit', 'form_class' => 'my-form'])
bash
php artisan queue:work
bash
php artisan rail:trigger:scheduled [--dry-run]
blade
@laravel_rail_form($transitionId, $instanceId, ['submit_label' => 'Approve', 'form_class' => 'custom-form'])