Files
ABSDEV/Modules/Workflow/Services/WorkflowManager.php
T
2026-07-24 14:59:44 +01:00

47 lines
3.1 KiB
PHP

<?php
namespace Modules\Workflow\Services;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
use Modules\Workflow\Models\WorkflowDefinition;
use Modules\Workflow\Models\WorkflowHistory;
use Modules\Workflow\Models\WorkflowInstance;
use Modules\Workflow\Models\WorkflowStage;
use Modules\Workflow\Models\WorkflowTransition;
final class WorkflowManager
{
public function start(Model $subject, WorkflowDefinition $definition, ?Authenticatable $user = null): WorkflowInstance
{
return DB::transaction(function () use ($subject, $definition, $user) {
$stage = $definition->stages()->where('is_initial', true)->first() ?? $definition->stages()->firstOrFail();
$instance = WorkflowInstance::updateOrCreate(['subject_type' => $subject->getMorphClass(), 'subject_id' => $subject->getKey()], ['workflow_definition_id' => $definition->getKey(), 'workflow_stage_id' => $stage->getKey(), 'status' => $stage->is_terminal ? 'completed' : 'active', 'started_by' => $user?->getAuthIdentifier(), 'due_at' => $stage->due_days ? now()->addDays($stage->due_days) : null, 'completed_at' => $stage->is_terminal ? now() : null]);
WorkflowHistory::create(['workflow_instance_id' => $instance->id, 'to_stage_id' => $stage->id, 'user_id' => $user?->getAuthIdentifier(), 'action' => 'started']);
return $instance->fresh(['definition', 'stage']);
});
}
public function transition(WorkflowInstance $instance, string $action, ?Authenticatable $user = null, ?string $comment = null): WorkflowInstance
{
return DB::transaction(function () use ($instance, $action, $user, $comment) {
$transition = WorkflowTransition::where('workflow_definition_id', $instance->workflow_definition_id)->where('from_stage_id', $instance->workflow_stage_id)->where('action', $action)->first();
if (! $transition) {
throw ValidationException::withMessages(['action' => 'This transition is not available.']);
} if ($transition->requires_comment && blank($comment)) {
throw ValidationException::withMessages(['comment' => 'A comment is required.']);
} if ($transition->required_permission && (! $user || ! method_exists($user, 'can') || ! $user->can($transition->required_permission))) {
abort(403);
} $target = WorkflowStage::findOrFail($transition->to_stage_id);
$from = $instance->workflow_stage_id;
$instance->update(['workflow_stage_id' => $target->id, 'status' => $target->is_terminal ? 'completed' : 'active', 'due_at' => $target->due_days ? now()->addDays($target->due_days) : null, 'completed_at' => $target->is_terminal ? now() : null]);
WorkflowHistory::create(['workflow_instance_id' => $instance->id, 'from_stage_id' => $from, 'to_stage_id' => $target->id, 'user_id' => $user?->getAuthIdentifier(), 'action' => $action, 'comment' => $comment]);
return $instance->fresh(['definition', 'stage', 'subject']);
});
}
}