getLocale(); } /** * Unique primary key. * * @return string */ public function getScoutKey(): mixed { return "{$this->type}_{$this->model_id}"; } /** * Indexed data. * * @return array */ public function toSearchableArray(): array { return [ 'id' => $this->getScoutKey(), 'type' => $this->type, 'model_id' => $this->model_id, 'id_key' => $this->id_key ?? null, 'slug' => $this->slug, 'title' => $this->title, 'content' => $this->content, ]; } /** * Highlights all search terms in a text. * * @param string $text * @param string $searchTerm * @return string */ public static function highlightTerms(string $text, string $searchTerm, int $contextLength = 150): string { if (trim($searchTerm) === '') { return $text; } // Clean terms list. $words = preg_split('/\s+/', $searchTerm, -1, PREG_SPLIT_NO_EMPTY); if (empty($words)) { return $text; } $fullText = strip_tags($text); $textLength = strlen($fullText); $ranges = []; // Collection of relevant ranges around each word. foreach ($words as $word) { $pattern = '/(? max(0, $matchPos - $contextLength), 'end' => min($textLength, $matchPos + $matchLen + $contextLength), ]; } } } // Return the entire text if there isn't matches. if (empty($ranges)) { return $text; } // Merging overlapping intervals. usort($ranges, fn($a, $b) => $a['start'] <=> $b['start']); $merged = []; foreach ($ranges as $r) { if (empty($merged) || $r['start'] > $merged[array_key_last($merged)]['end']) { $merged[] = $r; } else { $merged[array_key_last($merged)]['end'] = max( $merged[array_key_last($merged)]['end'], $r['end'] ); } } $snippets = []; foreach ($merged as $r) { $snippet = substr($fullText, $r['start'], $r['end'] - $r['start']); // Cut cleanly without breaking the words if ($r['start'] > 0) { $snippet = preg_replace('/^\S*\s/', '…', $snippet, 1); } if ($r['end'] < $textLength) { $snippet = preg_replace('/\s\S*$/', '…', $snippet, 1); } // Highlighting searched words foreach ($words as $word) { $pattern = '/(?$0', $snippet ); } $snippets[] = trim($snippet); if (count($snippets) >= 3) break; } $result = implode('… ', $snippets); $result = preg_replace('/\s*…\s*(?:…\s*)+/', ' … ', $result); return trim($result); } }