diff --git a/src/Repository/Blog/PostRepositoryQuery.php b/src/Repository/Blog/PostRepositoryQuery.php index 0def03f..8396d25 100644 --- a/src/Repository/Blog/PostRepositoryQuery.php +++ b/src/Repository/Blog/PostRepositoryQuery.php @@ -63,6 +63,12 @@ class PostRepositoryQuery extends RepositoryQuery public function search(?string $keywords, ?string $tag) { + $keywords = explode(' ', $keywords); + + $filter = fn($keyword) => trim($keyword) !== '' && preg_match('/[a-zA-Z]+/', $keyword) && mb_strlen($keyword) > 3; + + $keywords = array_filter($keywords, $filter); + if ($keywords) { $conn = $this->repository->getEm()->getConnection(); @@ -70,43 +76,91 @@ class PostRepositoryQuery extends RepositoryQuery 'SELECT post.id, post.title, - MATCH(post.title) AGAINST(:search) AS MATCH_TITLE, - MATCH(post.content) AGAINST(:search) AS MATCH_CONTENT + post.content, + post.published_at FROM post WHERE post.status = 1 AND post.published_at < :date - ORDER BY - MATCH_TITLE DESC, - MATCH_CONTENT DESC '); $statement = $query->execute([ - ':search' => $keywords, ':date' => (new \DateTime())->format('Y-m-d H:i:s'), ]); $results = $statement->fetchAll(); $ids = []; + $matches = []; foreach ($results as $k => $v) { - $rate = ($v['MATCH_TITLE'] * 2) + $v['MATCH_CONTENT']; + $added = false; + $initWords = explode(' ', $v['title']); + $words = []; - if ($rate >= 7) { - $ids[] = $v['id']; + foreach ($initWords as $initWord) { + $words = array_merge($words, preg_split('/[:_-]+/', $initWord)); } - } - if (0 == count($ids)) { - foreach ($results as $k => $v) { - $rate = ($v['MATCH_TITLE'] * 2) + $v['MATCH_CONTENT']; + $words = array_filter($words, $filter); - if ($rate >= 6) { - $ids[] = $v['id']; + foreach ($keywords as $keyword) { + if ($added) { + continue; + } + + foreach ($words as $word) { + if ($added) { + continue; + } + + if (str_contains(mb_strtolower($word), mb_strtolower($keyword))) { + $matches[] = [ + 'id' => $v['id'], + 'published_at' => $v['published_at'], + 'similarity' => 100, + ]; + + $added = true; + } elseif(str_contains($v['content'], $keyword)) { + $matches[] = [ + 'id' => $v['id'], + 'published_at' => $v['published_at'], + 'similarity' => 99, + ]; + + $added = true; + } else { + $lev = levenshtein($word, $keyword); + $similarity = 100 - ($lev * 100 / mb_strlen($word)); + + if ($similarity > 70) { + $matches[] = [ + 'id' => $v['id'], + 'published_at' => $v['published_at'], + 'similarity' => $similarity, + ]; + + $added = true; + } + } } } } + usort($matches, function($a, $b) { + if ($a['similarity'] > $b['similarity']) { + return -1; + } + + if ($b['similarity'] > $a['similarity']) { + return 1; + } + + return ($a['published_at'] <> $b['published_at']) * -1; + }); + + $ids = array_column($matches, 'id'); + if (!$ids) { $ids = [-1]; }