PHP code example of solution-forest / workflow-state-machine

1. Go to this page and download the library: Download solution-forest/workflow-state-machine 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/ */

    

solution-forest / workflow-state-machine example snippets


use WorkflowStateMachine\Traits\HasWorkflowStates;

class Task extends Model
{
    use HasWorkflowStates;
    
    // Your model content...
    
    // The workflow relationship is automatically handled via 'workflowable' polymorphic relation
    // You can assign a workflow to this model instance:
    // $task->workflow()->associate($workflow);
}

use WorkflowStateMachine\Traits\CanManageWorkflowStates;

class User extends Authenticatable
{
    use CanManageWorkflowStates;
    
    // Optional: Override permission logic
    public function canChangeWorkflowState($model, string $toStatus): bool
    {
        // Custom permission logic
        return $this->hasRole('admin') || $this->id === $model->user_id;
    }
}

return [
    'status' => [
        'draft' => 'Draft',
        'pending' => 'Pending',
        'in_progress' => 'In Progress',
        'review' => 'Under Review',
        'approved' => 'Approved',
        'rejected' => 'Rejected',
        'completed' => 'Completed',
        'cancelled' => 'Cancelled',
    ],
    
    // Other configurations...
];

use WorkflowStateMachine\Traits\HasWorkflowStates;

class Order extends Model
{
    use HasWorkflowStates;
    
    protected $fillable = ['customer_name', 'order_state'];
    
    // Customize the status column name for this model
    protected $status_column = 'order_state';
}

return [
    // Default status column name for all models
    'status_column' => 'state', // default: 'status'
    
    // Other configurations...
];

class Order extends Model
{
    use HasWorkflowStates;
    
    protected $status_column = 'order_state'; // Custom column name
}

// You can always access status via the 'status' attribute
$order = Order::find(1);
echo $order->status; // Returns value from 'order_state' column

// Setting status also works dynamically
$order->status = 'approved'; // Sets the 'order_state' column
$order->save();

// Or use the explicit methods
echo $order->getCurrentStatus(); // Same as $order->status
$order->setStatus('completed');  // Same as $order->status = 'completed'

use WorkflowStateMachine\Traits\HasWorkflowStates;

class Order extends Model
{
    use HasWorkflowStates;
    
    protected $fillable = ['customer_name', 'order_status'];
    protected $status_column = 'order_status';
    
    // Custom status array for this model
    protected $status_array = [
        'pending' => 'Pending Payment',
        'paid' => 'Payment Received', 
        'processing' => 'Processing Order',
        'shipped' => 'Shipped',
        'delivered' => 'Delivered',
        'cancelled' => 'Cancelled',
    ];
}

// This model will use the global config status array
class Task extends Model 
{
    use HasWorkflowStates;
    
    protected $fillable = ['title', 'status'];
    // No custom $status_array, uses config
}

use WorkflowStateMachine\Models\Workflow;
use WorkflowStateMachine\Models\WorkflowProcess;
use WorkflowStateMachine\Models\WorkflowRule;

// Create a workflow
$workflow = Workflow::create([
    'name' => 'task_approval_workflow',
    'description' => 'Task approval workflow',
    'starting_status' => 'draft',
    'ending_status' => 'completed',
]);

// If 'auto_create_processes' is enabled in config, processes will be automatically 
// created based on the status array (excluding 'rejected' and 'cancelled')
// Otherwise, manually create workflow processes:

$process1 = WorkflowProcess::create([
    'workflow_id' => $workflow->id,
    'name' => 'submit_for_review',
    'from_status' => 'draft',
    'to_status' => 'pending',
    'order' => 1,
    'auto_transition' => true,
    'completed' => false,
]);

$process2 = WorkflowProcess::create([
    'workflow_id' => $workflow->id,
    'name' => 'approve_task',
    'from_status' => 'pending',
    'to_status' => 'approved',
    'order' => 2,
    'auto_transition' => false,
    'completed' => false,
]);

// Assign workflow to a model instance via polymorphic relationship
$task = Task::create(['title' => 'New Task']);
$task->workflow()->associate($workflow);
$task->save();

// Enable auto-creation in config/workflow-state-machine.php
'auto_create_processes' => true,

// With this enabled, creating a workflow will automatically generate processes:
$workflow = Workflow::create([
    'name' => 'task_approval_workflow',
    'description' => 'Task approval workflow',
    'starting_status' => 'draft',
    'ending_status' => 'completed',
]);

// Automatically creates processes for status transitions:
// draft → pending → in_progress → review → approved → completed
// (excluding 'rejected' and 'cancelled' from the flow)

// The auto-created processes will have:
// - Sequential ordering (1, 2, 3, ...)
// - Generated names based on status transitions
// - auto_transition set to false by default
// - completed set to false by default

// config/workflow-state-machine.php
return [
    // ... other config options ...
    
    // Auto-create workflow for models when they are created
    'auto_create_workflow' => true, // default: false
    'auto_workflow_name' => 'Default Workflow', // default workflow name
    
    // Auto-create processes based on status array when workflow is created
    'auto_create_processes' => true, // default: false
];

use WorkflowStateMachine\Traits\HasWorkflowStates;

class Task extends Model
{
    use HasWorkflowStates;
    
    protected $fillable = ['title', 'description', 'status'];
}

// Enable auto-creation in config
config(['workflow-state-machine.auto_create_workflow' => true]);

// Create a new task - workflow will be auto-created
$task = Task::create([
    'title' => 'Complete project',
    'description' => 'Finish the project by Friday'
]);

// The task now has a workflow automatically assigned
echo $task->workflow->name; // "Default Workflow"
echo $task->status; // "draft" (first status from config)

// config/workflow-state-machine.php
'status' => [
    'draft' => 'Draft',
    'pending' => 'Pending',
    'in_progress' => 'In Progress',
    'review' => 'Under Review',
    'approved' => 'Approved',
    'completed' => 'Completed',
],

use WorkflowStateMachine\Services\AutoWorkflowService;

$workflow = AutoWorkflowService::createWorkflowForModel($model);



namespace App\Rules;

use WorkflowStateMachine\Contracts\WorkflowRuleContract;
use WorkflowStateMachine\Models\WorkflowProcess;

class CustomRule implements WorkflowRuleContract
{
    public function handle($model, WorkflowProcess $process, $user): bool
    {
        // Your business logic here
        return true;
    }

    public function getMessage(): string
    {
        return 'Transition is not allowed by CustomRule.';
    }
}

// app/WorkflowRules/UserPermissionRule.php
namespace App\WorkflowRules;

use WorkflowStateMachine\Contracts\WorkflowRuleContract;
use WorkflowStateMachine\Models\WorkflowProcess;

class UserPermissionRule implements WorkflowRuleContract
{
    public function handle($model, WorkflowProcess $process, $user): bool
    {
        // Check if user has permission to transition this model
        if (!$user) {
            return false;
        }
        
        // Custom business logic
        if ($process->to_status === 'approved') {
            return $user->hasRole('manager') || $user->hasRole('admin');
        }
        
        if ($process->to_status === 'completed') {
            return $model->assignee_id === $user->id || $user->hasRole('admin');
        }
        
        return true;
    }
    
    public function getMessage(): string
    {
        return 'User does not have permission to perform this transition.';
    }
}

public function handle($model, WorkflowProcess $process, $user): bool
{
    if (!$user) {
        return false;
    }

    // Only managers can approve
    if ($process->to_status === 'approved') {
        return $user->hasRole('manager');
    }

    return true;
}

public function handle($model, WorkflowProcess $process, $user): bool
{
    // Check if model is ready for transition
    if ($process->to_status === 'published' && !$model->is_complete) {
        return false;
    }

    return true;
}

public function handle($model, WorkflowProcess $process, $user): bool
{
    // Only allow transitions during business hours
    if ($process->to_status === 'live') {
        $hour = now()->hour;
        return $hour >= 9 && $hour <= 17;
    }

    return true;
}

#### Attaching Rules to Processes

Create and assign rules to processes:


// When a task is updated, auto-transition rules are checked
$task = Task::find(1);
$task->update(['assignee_id' => 5]);
// Event triggered: WorkflowAutoTransitionEvent

// When related models are updated
$task->comments()->create(['content' => 'Review completed']);
// If configured, this can also trigger auto-transition checks

$task = Task::find(1);
$workflow = $task->workflow;

// Get status roadmap
$roadmap = $workflow->getStatusRoadmap();
// Returns: ['draft', 'pending', 'approved', 'completed']

// Get current position in workflow
$currentStep = $task->getCurrentWorkflowStep();

// Get previous status in the workflow
$previousStatus = $task->getPreviousStatus();
// Returns: 'draft' if current status is 'pending', null if at the beginning

// Get next status in the workflow
$nextStatus = $task->getNextStatus();
// Returns: 'approved' if current status is 'pending', null if at the end

// Check if task can proceed to next step
$canProceed = $task->canProceedToNextStep($user);

$task = Task::find(1);
$user = auth()->user();

// Check if transition is possible
if ($task->canTransitionTo('completed', $user)) {
    $task->transitionTo('completed', $user);
}

// Auto transition (if rules allow)
$task->checkAutoTransition($user);

// Get available transitions
$availableTransitions = $task->getAvailableTransitions($user);

// Get all status change records for a model
$auditLogs = $task->workflowAuditLogs;

// Get recent records
$recentLogs = $task->workflowAuditLogs()
    ->where('created_at', '>=', now()->subDays(7))
    ->get();

// Get workflow progress
$progress = $task->getWorkflowProgress();

// Rollback to previous state
$task->rollbackToPreviousState($user);

// Rollback to specific state
$task->rollbackToState('pending', $user);

// Get rollback history
$rollbackHistory = $task->getRollbackHistory();

return [
    'status' => [
        'draft' => 'Draft',
        'pending' => 'Pending',
        'in_progress' => 'In Progress',
        'review' => 'Under Review',
        'approved' => 'Approved',
        'rejected' => 'Rejected',
        'completed' => 'Completed',
        'cancelled' => 'Cancelled',
    ],
    
    'table_names' => [
        'workflows' => 'workflows',
        'workflow_rules' => 'workflow_rules',
        'workflow_processes' => 'workflow_processes',
        'workflow_process_rules' => 'workflow_process_rules',
        'workflow_audit_logs' => 'workflow_audit_logs',
    ],
    
    'morph_name' => 'workflowable',
    
    'enable_audit_log' => true,
    'enable_rollback' => true,
    'enable_auto_transition' => true,
    
    'auto_transition_delay' => 0, // seconds
    
    // Auto-create processes based on status array when workflow is created
    'auto_create_processes' => false, // default: false
    
    'events' => [
        'auto_check_on_model_update' => true,
        'auto_check_on_relation_update' => false,
    ],
];

use WorkflowStateMachine\Traits\HasWorkflowStates;

class CriticalTask extends Model
{
    use HasWorkflowStates;
    
    // Enable auto-transition for this model specifically
    protected $enable_auto_transition = true;
}

class ManualReviewTask extends Model
{
    use HasWorkflowStates;
    
    // Disable auto-transition for this model (

// Global config setting
'enable_auto_transition' => false,

// This model will auto-transition despite global setting being disabled
class AutomatedProcess extends Model
{
    use HasWorkflowStates;
    
    protected $enable_auto_transition = true; // Overrides global config
}

// This model uses the global config setting (false in this case)
class StandardTask extends Model
{
    use HasWorkflowStates;
    // No $enable_auto_transition property, so uses global config
}

// Model with auto-transition enabled
class AutomatedTask extends Model
{
    use HasWorkflowStates;
    protected $enable_auto_transition = true;
}

// When workflows are auto-generated for this model,
// all WorkflowProcess records will have auto_transition = true

// app/WorkflowRules/MinimumTimeRule.php
namespace App\WorkflowRules;

use WorkflowStateMachine\Contracts\WorkflowRuleContract;
use WorkflowStateMachine\Models\WorkflowProcess;

class MinimumTimeRule implements WorkflowRuleContract
{
    public function handle($model, WorkflowProcess $process, $user): bool
    {
        // Ensure model has been in current status for at least 24 hours
        if (!$model->status_changed_at) {
            return false;
        }
        
        return $model->status_changed_at->diffInHours(now()) >= 24;
    }
    
    public function getMessage(): string
    {
        return 'Model must remain in current status for at least 24 hours.';
    }
}

// app/WorkflowRules/RequiredFieldsRule.php
namespace App\WorkflowRules;

use WorkflowStateMachine\Contracts\WorkflowRuleContract;
use WorkflowStateMachine\Models\WorkflowProcess;

class RequiredFieldsRule implements WorkflowRuleContract
{
    public function handle($model, WorkflowProcess $process, $user): bool
    {
        // Check if public function getMessage(): string
    {
        return 'Required fields must be completed before status transition.';
    }
}

// Events are automatically dispatched when:
// 1. Model is updated
// 2. Related models are updated (if configured)

// You can also manually trigger auto-transition checks
use WorkflowStateMachine\Events\WorkflowAutoTransitionEvent;

// Dispatch the event manually
event(new WorkflowAutoTransitionEvent($task, $user));

// Listen to workflow events in your EventServiceProvider
protected $listen = [
    'WorkflowStateMachine\Events\StatusChanged' => [
        'App\Listeners\NotifyStatusChange',
    ],
    'WorkflowStateMachine\Events\WorkflowCompleted' => [
        'App\Listeners\HandleWorkflowCompletion',
    ],
];
bash
php artisan migrate