<?php
 namespace App\Services\Product; use App\Models\Product; use App\Models\ProductConfigOptionDependency; use Illuminate\Support\Collection; class ConfigOptionDependencyEvaluator { public function rulesForProduct(Product $product): array { $groupIds = $product->configOptions() ->pluck('product_config_options.group_id') ->filter() ->unique() ->values(); if ($groupIds->isEmpty()) { return []; } return ProductConfigOptionDependency::whereIn('group_id', $groupIds) ->orderBy('order') ->get() ->map(fn (ProductConfigOptionDependency $d) => [ 'source_option_id' => (int) $d->source_option_id, 'operator' => $d->operator, 'value_ids' => $d->matchValueIds(), 'target_option_id' => (int) $d->target_option_id, 'action' => $d->action, ]) ->all(); } public function evaluate(array $rules, array $selected, array $baseRequired = []): array { $result = []; $byTarget = []; foreach ($rules as $rule) { $byTarget[(int) $rule['target_option_id']][] = $rule; } foreach ($byTarget as $targetId => $targetRules) { $base = $baseRequired[$targetId] ?? false; $showRules = array_filter($targetRules, fn ($r) => $r['action'] === 'show'); $hideRules = array_filter($targetRules, fn ($r) => $r['action'] === 'hide'); $visible = true; if (! empty($showRules)) { $visible = false; foreach ($showRules as $r) { if ($this->conditionMet($r, $selected)) { $visible = true; break; } } } if ($visible && ! empty($hideRules)) { foreach ($hideRules as $r) { if ($this->conditionMet($r, $selected)) { $visible = false; break; } } } $required = $base; if ($visible) { foreach ($targetRules as $r) { if ($r['action'] === 'require' && $this->conditionMet($r, $selected)) { $required = true; } elseif ($r['action'] === 'optional' && $this->conditionMet($r, $selected)) { $required = false; } } } else { $required = false; } $result[(int) $targetId] = [ 'visible' => $visible, 'required' => $required, ]; } return $result; } public function conditionMet(array $rule, array $selected): bool { $sourceId = (int) $rule['source_option_id']; $raw = $selected[$sourceId] ?? ($selected[(string) $sourceId] ?? null); $selectedIds = $this->normalizeSelected($raw); $hasSelection = ! empty($selectedIds); $valueIds = array_map('intval', $rule['value_ids'] ?? []); switch ($rule['operator']) { case 'any': return $hasSelection; case 'equals': if (empty($valueIds)) { return false; } return in_array($valueIds[0], $selectedIds, true); case 'not_equals': if (empty($valueIds)) { return false; } return $hasSelection && ! in_array($valueIds[0], $selectedIds, true); case 'in': if (empty($valueIds)) { return false; } return count(array_intersect($valueIds, $selectedIds)) > 0; default: return false; } } private function normalizeSelected(mixed $raw): array { if ($raw === null || $raw === '' || $raw === []) { return []; } if ($raw instanceof Collection) { $raw = $raw->all(); } if (is_array($raw)) { return array_values(array_filter(array_map('intval', $raw))); } $int = (int) $raw; return $int > 0 ? [$int] : []; } } 