$diagnoses * @return Collection */ public function match(iterable $diagnoses): Collection { $dxList = collect($diagnoses)->map(function ($d) { if ($d instanceof Diagnosis) { return [ 'code' => $d->code, 'description' => $d->description, ]; } return [ 'code' => $d['code'] ?? null, 'description' => $d['description'] ?? null, ]; })->filter(fn ($d) => filled($d['code']) || filled($d['description'])); if ($dxList->isEmpty()) { return collect(); } $pathways = ClinicalPathway::query() ->active() ->orderBy('sort_order') ->get(); $matches = []; foreach ($pathways as $pathway) { $rules = $pathway->match_rules ?? []; $bestRank = null; $bestReason = null; foreach ($dxList as $dx) { $result = $this->matchDiagnosis($dx, $rules); if ($result === null) { continue; } if ($bestRank === null || $result['rank'] > $bestRank) { $bestRank = $result['rank']; $bestReason = $result['reason']; } } if ($bestRank !== null) { $matches[] = [ 'pathway' => $pathway, 'pathway_code' => $pathway->code, 'pathway_name' => $pathway->name, 'rank' => $bestRank, 'match_reason' => $bestReason, ]; } } return collect($matches) ->sort(function ($a, $b) { if ($a['rank'] !== $b['rank']) { return $b['rank'] <=> $a['rank']; } return $a['pathway']->sort_order <=> $b['pathway']->sort_order; }) ->values(); } /** * @param array{code?: ?string, description?: ?string} $dx * @param array $rules * @return array{rank: int, reason: string}|null */ protected function matchDiagnosis(array $dx, array $rules): ?array { $desc = $this->normalize((string) ($dx['description'] ?? '')); $codeStripped = $this->stripCode((string) ($dx['code'] ?? '')); foreach ($rules['exclude_keywords'] ?? [] as $exclude) { $ex = $this->normalize((string) $exclude); if ($ex !== '' && $desc !== '' && str_contains($desc, $ex)) { return null; } } foreach ($rules['icd_prefixes'] ?? [] as $prefix) { $p = $this->stripCode((string) $prefix); if ($p !== '' && $codeStripped !== '' && str_starts_with($codeStripped, $p)) { return ['rank' => 100, 'reason' => 'icd_prefix:'.$prefix]; } } foreach ($rules['keywords'] ?? [] as $keyword) { $kw = $this->normalize((string) $keyword); if ($kw !== '' && $desc !== '' && str_contains($desc, $kw)) { return ['rank' => 50, 'reason' => 'keyword:'.$keyword]; } } return null; } protected function normalize(string $s): string { $s = mb_strtolower(trim($s)); $s = preg_replace('/\s+/u', ' ', $s) ?? $s; return $s; } protected function stripCode(string $code): string { return strtoupper(preg_replace('/[^A-Za-z0-9]/', '', $code) ?? ''); } }