FlowTaskRegistry
The FlowTaskRegistry is a central registry for all flow task drivers. It provides a predictable lookup mechanism, prevents duplicate registrations, and enables efficient retrieval of tasks per subject and per type.
Namespace
JobMetric\Flow\Support\FlowTaskRegistry
Overview
The registry indexes tasks by:
- Subject: The model class name (FQCN) that the task operates on
- Type: The task type (action, validation, restriction)
- Class: The concrete task driver class name
This three-level indexing structure (subject -> type -> class) allows for efficient lookups and prevents duplicate registrations.
Registration
Register a Task
Register a new flow task driver instance:
use JobMetric\Flow\Support\FlowTaskRegistry;
use App\Flows\Order\SendEmailActionTask;
$registry = app('FlowTaskRegistry');
$registry->register(new SendEmailActionTask);
Requirements:
- Task must implement
AbstractTaskDriver - Task must have a non-empty subject (returned by
subject()method) - Task type is automatically determined from the task class
Throws InvalidArgumentException if:
- Task subject is empty
- Same task class is already registered for the same subject and type
Registration in Service Provider
Typically, tasks are registered in a service provider:
use App\Flows\Order\SendEmailActionTask;
use App\Flows\Order\ValidatePaymentValidationTask;
use App\Flows\Order\RestrictCancellationRestrictionTask;
use JobMetric\Flow\Support\FlowTaskRegistry;
public function boot(): void
{
$registry = app('FlowTaskRegistry');
$registry->register(new SendEmailActionTask)
->register(new ValidatePaymentValidationTask)
->register(new RestrictCancellationRestrictionTask);
}
Or using the FlowTask facade:
use JobMetric\Flow\Facades\FlowTask;
public function boot(): void
{
FlowTask::register(new SendEmailActionTask);
FlowTask::register(new ValidatePaymentValidationTask);
FlowTask::register(new RestrictCancellationRestrictionTask);
}
Querying Tasks
Get All Tasks
Get all registered tasks grouped by subject, type, and class name:
$registry = app('FlowTaskRegistry');
$allTasks = $registry->all();
Returns:
[
'App\Models\Order' => [
'action' => [
'App\Flows\Order\SendEmailActionTask' => $taskInstance,
'App\Flows\Order\UpdateStatusActionTask' => $taskInstance,
],
'validation' => [
'App\Flows\Order\ValidatePaymentValidationTask' => $taskInstance,
],
'restriction' => [
'App\Flows\Order\RestrictCancellationRestrictionTask' => $taskInstance,
],
],
'App\Models\Invoice' => [
// ...
],
]
Get Tasks for Subject
Get all registered tasks for a specific subject (model class):
$registry = app('FlowTaskRegistry');
$orderTasks = $registry->forSubject('App\Models\Order');
Returns:
[
'action' => [
'App\Flows\Order\SendEmailActionTask' => $taskInstance,
],
'validation' => [
'App\Flows\Order\ValidatePaymentValidationTask' => $taskInstance,
],
'restriction' => [
'App\Flows\Order\RestrictCancellationRestrictionTask' => $taskInstance,
],
]
Get Tasks for Subject and Type
Get all registered tasks for a specific subject and type:
$registry = app('FlowTaskRegistry');
$actionTasks = $registry->forSubjectAndType('App\Models\Order', 'action');
Returns:
[
'App\Flows\Order\SendEmailActionTask' => $taskInstance,
'App\Flows\Order\UpdateStatusActionTask' => $taskInstance,
]
Throws exception if: Invalid task type is provided (must be 'action', 'validation', or 'restriction')
Check Task Existence
Check if a task is registered for a specific subject, type, and class:
$registry = app('FlowTaskRegistry');
$exists = $registry->has(
'App\Models\Order',
'action',
'App\Flows\Order\SendEmailActionTask'
);
Returns: bool
Check Class Existence
Check if a task class is registered (regardless of subject/type):
$registry = app('FlowTaskRegistry');
$exists = $registry->hasClass('App\Flows\Order\SendEmailActionTask');
Returns: bool
Note: Class name is normalized (forward slashes converted to backslashes, trimmed)
Get Task by Class
Get a registered task driver instance by class name:
$registry = app('FlowTaskRegistry');
$task = $registry->get('App\Flows\Order\SendEmailActionTask');
Returns: AbstractTaskDriver|null
Note: Returns the first matching task instance found (since class names are unique per subject/type)
Internal Structure
The registry maintains tasks in a three-level array structure:
protected array $tasks = [
'subject_class' => [
'task_type' => [
'task_class' => $taskInstance,
],
],
];
Example:
[
'App\Models\Order' => [
'action' => [
'App\Flows\Order\SendEmailActionTask' => $sendEmailTask,
'App\Flows\Order\UpdateStatusActionTask' => $updateStatusTask,
],
'validation' => [
'App\Flows\Order\ValidatePaymentValidationTask' => $validatePaymentTask,
],
],
]
Task Type Detection
Task types are automatically determined using FlowTask::determineTaskType():
- Tasks extending
AbstractActionTask→'action' - Tasks extending
AbstractValidationTask→'validation' - Tasks extending
AbstractRestrictionTask→'restriction'
Complete Examples
Example 1: Registering Multiple Tasks
use App\Flows\Order\SendEmailActionTask;
use App\Flows\Order\ValidatePaymentValidationTask;
use App\Flows\Order\RestrictCancellationRestrictionTask;
use JobMetric\Flow\Support\FlowTaskRegistry;
public function boot(): void
{
$registry = app('FlowTaskRegistry');
// Register all tasks for Order model
$registry->register(new SendEmailActionTask)
->register(new ValidatePaymentValidationTask)
->register(new RestrictCancellationRestrictionTask);
}
Example 2: Conditional Registration
use App\Flows\Order\SendEmailActionTask;
use JobMetric\Flow\Support\FlowTaskRegistry;
public function boot(): void
{
$registry = app('FlowTaskRegistry');
// Only register if not already registered
if (!$registry->hasClass(SendEmailActionTask::class)) {
$registry->register(new SendEmailActionTask);
}
}
Example 3: Getting Tasks for a Model
use JobMetric\Flow\Support\FlowTaskRegistry;
$registry = app('FlowTaskRegistry');
// Get all tasks for Order model
$orderTasks = $registry->forSubject('App\Models\Order');
// Get only action tasks
$actionTasks = $registry->forSubjectAndType('App\Models\Order', 'action');
// Use tasks
foreach ($actionTasks as $taskClass => $taskInstance) {
echo "Task: {$taskClass}\n";
}
Example 4: Checking Task Availability
use JobMetric\Flow\Support\FlowTaskRegistry;
$registry = app('FlowTaskRegistry');
// Check if specific task exists
if ($registry->has('App\Models\Order', 'action', 'App\Flows\Order\SendEmailActionTask')) {
$task = $registry->get('App\Flows\Order\SendEmailActionTask');
// Use task
}
// Check if any task of this class exists
if ($registry->hasClass('App\Flows\Order\SendEmailActionTask')) {
// Task is registered somewhere
}
Error Handling
Duplicate Registration
If you try to register the same task twice:
$registry = app('FlowTaskRegistry');
$task = new SendEmailActionTask;
$registry->register($task); // ✅ Success
$registry->register($task); // ❌ InvalidArgumentException
Error Message:
Task 'App\Flows\Order\SendEmailActionTask' is already registered for subject 'App\Models\Order' and type 'action'.
Empty Subject
If a task has an empty subject:
// Task with empty subject() method
$task = new InvalidTask;
$registry->register($task); // ❌ InvalidArgumentException
Error Message:
Task subject must not be an empty string.
Invalid Task Type
If you query with an invalid task type:
$registry->forSubjectAndType('App\Models\Order', 'invalid'); // ❌ Exception
Best Practices
-
Register in Service Providers: Always register tasks in service provider
boot()method -
Check Before Registering: Check if task is already registered to avoid errors:
if (!$registry->hasClass(SendEmailActionTask::class)) {
$registry->register(new SendEmailActionTask);
} -
Use Facade: Use
FlowTaskfacade for cleaner code:FlowTask::register(new SendEmailActionTask); -
Group by Model: Organize task registration by model for better maintainability
-
Document Task Classes: Document which tasks are registered for each model
Integration with FlowTransition
The registry is used by FlowTransition service to:
- Validate task drivers when creating/updating transitions
- Resolve task instances during transition execution
- Ensure tasks are properly registered before use
Related Documentation
- FlowTask Service - Task management
- MakeTask Command - Generating task drivers
- FlowTaskContext - Task execution context
- FlowTransition Service - Transition execution
- StoreFlowTaskRequest - Task validation