47 lines
3.1 KiB
PHP
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']);
|
|
});
|
|
}
|
|
}
|