59 خطوط
2.2 KiB
PHP
59 خطوط
2.2 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\AutomationRule;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
|
|
class AutomationDispatcher
|
|
{
|
|
public function __construct(private AutomationEngine $engine) {}
|
|
|
|
public function dispatch(string $trigger, Model $subject, string $eventKey, array $context = []): void
|
|
{
|
|
$teamId = $subject->getAttribute('team_id');
|
|
$rules = AutomationRule::where('trigger', $trigger)->where('is_active', true)
|
|
->where(fn ($query) => $query->whereNull('team_id')->when($teamId, fn ($team) => $team->orWhere('team_id', $teamId)))
|
|
->get();
|
|
foreach ($rules as $rule) {
|
|
if (! $this->matches($rule->conditions ?? [], $subject, $context)) {
|
|
continue;
|
|
}
|
|
$runs = $rule->runs()->where('subject_type', $subject::class)->where('subject_id', $subject->getKey())->count();
|
|
if ($runs >= $rule->max_runs_per_record) {
|
|
continue;
|
|
}
|
|
try {
|
|
$this->engine->run($rule, $subject, "automation:{$rule->id}:{$eventKey}", $context);
|
|
} catch (\Throwable) {
|
|
// The run log contains the failure; business lifecycle must remain available.
|
|
}
|
|
}
|
|
}
|
|
|
|
private function matches(array $conditions, Model $subject, array $context): bool
|
|
{
|
|
foreach ($conditions as $condition) {
|
|
$field = $condition['field'] ?? null;
|
|
$operator = $condition['operator'] ?? 'equals';
|
|
$expected = $condition['value'] ?? null;
|
|
if (! $field) {
|
|
return false;
|
|
}
|
|
$actual = $context[$field] ?? $subject->getAttribute($field);
|
|
$matches = match ($operator) {
|
|
'not_equals' => $actual != $expected,
|
|
'greater_than' => is_numeric($actual) && $actual > $expected,
|
|
'less_than' => is_numeric($actual) && $actual < $expected,
|
|
'contains' => is_string($actual) && str_contains($actual, (string) $expected),
|
|
default => $actual == $expected,
|
|
};
|
|
if (! $matches) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|