Skip to content

Configuration Guide

Jean-Marc Strauven edited this page Jul 31, 2025 · 1 revision

βš™οΈ Configuration Guide

Master advanced configuration options to customize Laravel Statecraft for your specific needs.

πŸ“– Overview

Laravel Statecraft offers extensive configuration options to adapt to different project structures, performance requirements, and business needs. This guide covers all configuration options from basic setup to advanced customization.

πŸ”§ Publishing Configuration

Basic Configuration

Publish the default configuration file:

php artisan vendor:publish --tag=statecraft-config

This creates config/statecraft.php with all available options:

<?php

return [
    /*
    |--------------------------------------------------------------------------
    | State Machines Path
    |--------------------------------------------------------------------------
    | Path where your YAML state machine definitions are stored
    */
    'state_machines_path' => base_path('state-machines'),
    
    /*
    |--------------------------------------------------------------------------
    | Default State Field
    |--------------------------------------------------------------------------
    | Default database field name to store current state
    */
    'default_state_field' => 'status',
    
    /*
    |--------------------------------------------------------------------------
    | History Tracking
    |--------------------------------------------------------------------------
    | Configuration for state transition history
    */
    'history' => [
        'enabled' => false,
        'table' => 'state_machine_histories',
        'model' => \Grazulex\LaravelStatecraft\Models\StateMachineHistory::class,
        'queue_recording' => false,
        'cleanup_enabled' => false,
        'retention_days' => 365,
    ],
    
    /*
    |--------------------------------------------------------------------------
    | Events Configuration
    |--------------------------------------------------------------------------
    | Configuration for state machine events
    */
    'events' => [
        'enabled' => true,
        'queue_listeners' => false,
        'queue_connection' => 'default',
    ],
    
    /*
    |--------------------------------------------------------------------------
    | Performance Settings
    |--------------------------------------------------------------------------
    | Caching and performance optimizations
    */
    'cache' => [
        'enabled' => true,
        'ttl' => 3600, // 1 hour
        'store' => 'default',
        'prefix' => 'statecraft',
    ],
    
    /*
    |--------------------------------------------------------------------------
    | Class Resolution
    |--------------------------------------------------------------------------
    | Default namespaces for guards and actions
    */
    'namespaces' => [
        'guards' => 'App\\Guards',
        'actions' => 'App\\Actions',
    ],
    
    /*
    |--------------------------------------------------------------------------
    | Validation
    |--------------------------------------------------------------------------
    | Validation settings for YAML files
    */
    'validation' => [
        'strict_mode' => false,
        'validate_on_load' => true,
        'validate_guards' => true,
        'validate_actions' => true,
    ],
];

πŸ“ File System Configuration

State Machines Path

Configure where YAML files are stored:

// Default: base_path('state-machines')
'state_machines_path' => base_path('state-machines'),

// Alternative locations
'state_machines_path' => resource_path('workflows'),
'state_machines_path' => storage_path('state-machines'),
'state_machines_path' => app_path('StateMachines/Definitions'),

Directory Structure Options

Flat structure (recommended for small projects):

state-machines/
β”œβ”€β”€ OrderStateMachine.yaml
β”œβ”€β”€ UserRegistrationStateMachine.yaml
└── ArticleWorkflow.yaml

Hierarchical structure (recommended for large projects):

state-machines/
β”œβ”€β”€ e-commerce/
β”‚   β”œβ”€β”€ OrderStateMachine.yaml
β”‚   β”œβ”€β”€ PaymentStateMachine.yaml
β”‚   └── RefundStateMachine.yaml
β”œβ”€β”€ content/
β”‚   β”œβ”€β”€ ArticleStateMachine.yaml
β”‚   └── CommentModerationStateMachine.yaml
└── user/
    β”œβ”€β”€ RegistrationStateMachine.yaml
    └── SubscriptionStateMachine.yaml

Custom File Loading

Create a custom file loader for special requirements:

// In a service provider
$this->app->singleton(StateDefinitionLoader::class, function ($app) {
    return new CustomStateDefinitionLoader([
        'primary_path' => config('statecraft.state_machines_path'),
        'fallback_paths' => [
            resource_path('legacy-workflows'),
            storage_path('external-workflows'),
        ],
        'file_extensions' => ['yaml', 'yml', 'json'],
    ]);
});

πŸ“Š History Configuration

Basic History Settings

'history' => [
    'enabled' => true,
    'table' => 'state_machine_histories',
    'model' => \App\Models\CustomStateMachineHistory::class,
]

Advanced History Configuration

'history' => [
    'enabled' => true,
    'table' => 'state_machine_histories',
    'model' => \App\Models\StateMachineHistory::class,
    
    // Performance options
    'queue_recording' => true,
    'queue_connection' => 'database',
    'queue' => 'state-transitions',
    'batch_size' => 100,
    
    // Cleanup configuration
    'cleanup_enabled' => true,
    'retention_days' => 365,
    'cleanup_schedule' => '0 2 * * *', // Daily at 2 AM
    
    // Storage optimization
    'compress_metadata' => true,
    'partition_by_month' => true,
    
    // Per-model settings
    'model_settings' => [
        'App\Models\Order' => [
            'retention_days' => 2555, // 7 years for orders
            'detailed_logging' => true,
        ],
        'App\Models\TempWorkflow' => [
            'retention_days' => 30,
            'detailed_logging' => false,
        ],
    ],
]

Custom History Model

Create a custom history model for specific requirements:

<?php

namespace App\Models;

use Grazulex\LaravelStatecraft\Models\StateMachineHistory as BaseHistory;

class CustomStateMachineHistory extends BaseHistory
{
    protected $table = 'custom_state_histories';
    
    protected $fillable = [
        'model_type',
        'model_id',
        'state_machine',
        'transition',
        'from_state',
        'to_state',
        'context',
        'user_id',
        'ip_address',
        'user_agent',
        'session_id',
    ];
    
    protected $casts = [
        'context' => 'encrypted:array', // Encrypt sensitive data
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
    ];
    
    // Custom relationships
    public function user()
    {
        return $this->belongsTo(User::class);
    }
    
    // Custom scopes
    public function scopeByUser($query, $userId)
    {
        return $query->where('user_id', $userId);
    }
    
    public function scopeRecent($query, $days = 30)
    {
        return $query->where('created_at', '>=', now()->subDays($days));
    }
}

🎯 Events Configuration

Basic Events Setup

'events' => [
    'enabled' => true,
    'queue_listeners' => false,
]

Advanced Events Configuration

'events' => [
    'enabled' => true,
    
    // Performance settings
    'queue_listeners' => true,
    'queue_connection' => 'redis',
    'queue' => 'state-events',
    
    // Event filtering
    'dispatch_events' => [
        'state_transitioning' => true,
        'state_transitioned' => true,
        'transition_failed' => true,
        'guard_failed' => false, // Disable noisy events
    ],
    
    // Custom event classes
    'event_classes' => [
        'state_transitioning' => \App\Events\CustomStateTransitioning::class,
        'state_transitioned' => \App\Events\CustomStateTransitioned::class,
    ],
    
    // Model-specific settings
    'model_settings' => [
        'App\Models\Order' => [
            'enable_broadcasting' => true,
            'broadcast_channel' => 'orders.{id}',
        ],
        'App\Models\InternalWorkflow' => [
            'enabled' => false, // Disable events for internal workflows
        ],
    ],
]

Custom Event Classes

Create custom event classes for specific business logic:

<?php

namespace App\Events;

use Grazulex\LaravelStatecraft\Events\StateTransitioned as BaseEvent;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class OrderStateTransitioned extends BaseEvent implements ShouldBroadcast
{
    use InteractsWithSockets;
    
    public function broadcastOn()
    {
        return [
            new Channel('orders'),
            new PrivateChannel('user.' . $this->model->customer_id),
        ];
    }
    
    public function broadcastWith()
    {
        return [
            'order_id' => $this->model->id,
            'previous_state' => $this->from,
            'new_state' => $this->to,
            'transition' => $this->transition,
            'timestamp' => now()->toISOString(),
        ];
    }
}

⚑ Performance Configuration

Caching Settings

'cache' => [
    'enabled' => true,
    'ttl' => 3600, // Cache for 1 hour
    'store' => 'redis', // Use Redis for better performance
    'prefix' => 'statecraft',
    
    // What to cache
    'cache_definitions' => true,
    'cache_resolved_guards' => true,
    'cache_resolved_actions' => true,
    'cache_available_transitions' => true,
    
    // Cache invalidation
    'auto_invalidate' => true,
    'invalidate_on_file_change' => true,
]

Database Optimization

'database' => [
    // Use database connections optimized for reads
    'read_connection' => 'mysql_read',
    'write_connection' => 'mysql_write',
    
    // Query optimization
    'eager_load_relationships' => true,
    'use_query_cache' => true,
    
    // Bulk operations
    'batch_size' => 1000,
    'chunk_size' => 500,
]

Memory Management

'memory' => [
    'max_definitions_in_memory' => 100,
    'clear_resolved_instances' => true,
    'use_weak_references' => true,
]

πŸ›‘οΈ Security Configuration

Access Control

'security' => [
    // Restrict who can execute transitions
    'require_authentication' => true,
    'check_permissions' => true,
    
    // Audit settings
    'log_all_transitions' => true,
    'log_failed_attempts' => true,
    'log_guard_failures' => false,
    
    // Validation
    'validate_guard_classes' => true,
    'validate_action_classes' => true,
    'allow_dynamic_loading' => false, // Prevent code injection
]

Encryption

'encryption' => [
    'encrypt_context' => true,
    'encrypt_metadata' => true,
    'encryption_key' => env('STATECRAFT_ENCRYPTION_KEY'),
]

πŸ—οΈ Class Resolution Configuration

Namespace Configuration

'namespaces' => [
    'guards' => 'App\\Guards',
    'actions' => 'App\\Actions',
    
    // Model-specific namespaces
    'model_namespaces' => [
        'App\\Models\\Order' => [
            'guards' => 'App\\OrderWorkflow\\Guards',
            'actions' => 'App\\OrderWorkflow\\Actions',
        ],
        'App\\Models\\Article' => [
            'guards' => 'App\\Content\\Guards',
            'actions' => 'App\\Content\\Actions',
        ],
    ],
]

Custom Resolver

Implement a custom class resolver:

<?php

namespace App\Services;

use Grazulex\LaravelStatecraft\Contracts\ClassResolver;

class CustomClassResolver implements ClassResolver
{
    public function resolveGuard(string $className, string $modelClass = null): string
    {
        // Custom logic for resolving guard classes
        if (str_starts_with($className, 'Legacy.')) {
            return $this->resolveLegacyClass($className);
        }
        
        return $this->resolveModernClass($className, 'Guards');
    }
    
    public function resolveAction(string $className, string $modelClass = null): string
    {
        // Custom logic for resolving action classes
        return $this->resolveModernClass($className, 'Actions');
    }
    
    private function resolveModernClass(string $className, string $type): string
    {
        // Implementation details...
    }
}

Register the custom resolver:

// In a service provider
$this->app->singleton(ClassResolver::class, CustomClassResolver::class);

πŸ” Validation Configuration

Validation Settings

'validation' => [
    'strict_mode' => false,
    'validate_on_load' => true,
    'validate_guards' => true,
    'validate_actions' => true,
    
    // YAML validation
    'yaml_schema_validation' => true,
    'custom_schema_path' => resource_path('schemas/statecraft.json'),
    
    // Runtime validation
    'validate_state_existence' => true,
    'validate_transition_paths' => true,
    'check_circular_dependencies' => true,
    
    // Error handling
    'fail_on_validation_errors' => false,
    'log_validation_warnings' => true,
]

Custom Validation Rules

'custom_validators' => [
    'guards' => \App\Validators\GuardValidator::class,
    'actions' => \App\Validators\ActionValidator::class,
    'yaml' => \App\Validators\YamlValidator::class,
]

🌍 Environment-Specific Configuration

Development Environment

// config/statecraft.php for development
'debug' => [
    'enabled' => env('APP_DEBUG', false),
    'log_all_operations' => true,
    'validate_strictly' => true,
    'show_debug_info' => true,
],

'cache' => [
    'enabled' => false, // Disable caching in development
],

'validation' => [
    'strict_mode' => true,
    'fail_on_validation_errors' => true,
],

Production Environment

// config/statecraft.php for production
'cache' => [
    'enabled' => true,
    'ttl' => 86400, // Cache for 24 hours
    'store' => 'redis',
],

'history' => [
    'enabled' => true,
    'queue_recording' => true,
    'cleanup_enabled' => true,
],

'events' => [
    'queue_listeners' => true,
    'queue_connection' => 'redis',
],

'validation' => [
    'strict_mode' => false,
    'validate_on_load' => false, // Skip validation in production
],

Testing Environment

// config/statecraft.php for testing
'history' => [
    'enabled' => false, // Disable history in tests
],

'events' => [
    'enabled' => false, // Disable events in tests unless specifically testing them
],

'cache' => [
    'enabled' => false,
],

πŸ”§ Advanced Customization

Custom State Machine Manager

Create a custom state machine manager:

<?php

namespace App\Services;

use Grazulex\LaravelStatecraft\StateMachineManager as BaseManager;

class CustomStateMachineManager extends BaseManager
{
    protected function beforeTransition($model, $from, $to, $transition, $context)
    {
        // Custom logic before any transition
        $this->auditService->logTransitionAttempt($model, $from, $to);
        
        return parent::beforeTransition($model, $from, $to, $transition, $context);
    }
    
    protected function afterTransition($model, $from, $to, $transition, $context)
    {
        // Custom logic after any transition
        parent::afterTransition($model, $from, $to, $transition, $context);
        
        $this->notificationService->handleStateChange($model, $from, $to);
    }
}

Register the custom manager:

// In a service provider
$this->app->singleton('statecraft.manager', CustomStateMachineManager::class);

πŸ“‹ Configuration Validation

Validate Configuration

Create a command to validate your configuration:

php artisan statecraft:validate-config

Configuration Health Check

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class StatecraftHealthCheck extends Command
{
    protected $signature = 'statecraft:health-check';
    
    public function handle()
    {
        $this->info('Checking Laravel Statecraft configuration...');
        
        // Check file paths
        $this->checkPaths();
        
        // Check database configuration
        $this->checkDatabase();
        
        // Check cache configuration
        $this->checkCache();
        
        // Check class resolution
        $this->checkClassResolution();
        
        $this->info('Health check completed!');
    }
    
    private function checkPaths()
    {
        $path = config('statecraft.state_machines_path');
        
        if (!is_dir($path)) {
            $this->error("State machines path does not exist: {$path}");
        } else {
            $this->info("βœ“ State machines path exists: {$path}");
        }
    }
    
    // Additional check methods...
}

πŸš€ Best Practices

Configuration Organization

  1. Environment-specific configs - Use different settings per environment
  2. Namespace organization - Group related guards and actions
  3. Performance tuning - Enable caching and queuing in production
  4. Security hardening - Enable validation and auditing
  5. Monitoring setup - Configure logging and health checks

Deployment Considerations

// Optimize for production deployment
'deployment' => [
    'precompile_definitions' => true,
    'validate_on_deploy' => true,
    'warm_cache' => true,
    'check_dependencies' => true,
]

πŸš€ Next Steps

Now that you understand configuration, explore:

Core Features

Advanced Topics

Optimization

Ready to test your configuration? Check out πŸ§ͺ Testing Guide!

Clone this wiki locally