add search engine
This commit is contained in:
parent
c3c49d89cd
commit
120dcdaa44
|
@ -7,6 +7,7 @@
|
|||
"php": ">=7.2.5",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"beberlei/doctrineextensions": "^1.3",
|
||||
"bjeavons/zxcvbn-php": "^1.2",
|
||||
"cocur/slugify": "^4.0",
|
||||
"composer/package-versions-deprecated": "1.11.99.1",
|
||||
|
|
|
@ -9,6 +9,9 @@ doctrine:
|
|||
auto_generate_proxy_classes: true
|
||||
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
|
||||
auto_mapping: true
|
||||
dql:
|
||||
string_functions:
|
||||
FIELD: DoctrineExtensions\Query\Mysql\Field
|
||||
mappings:
|
||||
App\Core\Entity:
|
||||
is_bundle: false
|
||||
|
|
|
@ -28,28 +28,8 @@ abstract class RepositoryQuery
|
|||
|
||||
public function __call(string $name, $params): self
|
||||
{
|
||||
$fn = function (&$data) {
|
||||
if (is_string($data)) {
|
||||
$words = explode(' ', $data);
|
||||
|
||||
foreach ($words as $k => $v) {
|
||||
if (isset($v[0]) && '.' === $v[0]) {
|
||||
$words[$k] = $this->id.$v;
|
||||
}
|
||||
}
|
||||
|
||||
$data = implode(' ', $words);
|
||||
} elseif (is_array($data)) {
|
||||
foreach ($data as $k => $v) {
|
||||
$fn($data[$k]);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
};
|
||||
|
||||
foreach ($params as $key => $value) {
|
||||
$fn($params[$key]);
|
||||
$this->populateDqlId($params[$key]);
|
||||
}
|
||||
|
||||
call_user_func_array([$this->query, $name], $params);
|
||||
|
@ -93,4 +73,25 @@ abstract class RepositoryQuery
|
|||
{
|
||||
return $this->repository;
|
||||
}
|
||||
|
||||
protected function populateDqlId(&$data)
|
||||
{
|
||||
if (is_string($data)) {
|
||||
$words = explode(' ', $data);
|
||||
|
||||
foreach ($words as $k => $v) {
|
||||
if (isset($v[0]) && '.' === $v[0]) {
|
||||
$words[$k] = $this->id.$v;
|
||||
}
|
||||
}
|
||||
|
||||
$data = implode(' ', $words);
|
||||
} elseif (is_array($data)) {
|
||||
foreach ($data as $k => $v) {
|
||||
$this->populateDqlId($data[$k]);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ use App\Repository\Blog\PostRepositoryQuery;
|
|||
use App\UrlGenerator\PostGenerator;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use App\Core\Site\SiteStore;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class PostController extends PageController
|
||||
{
|
||||
|
@ -58,6 +59,23 @@ class PostController extends PageController
|
|||
]);
|
||||
}
|
||||
|
||||
public function search(Request $request, int $page = 1): Response
|
||||
{
|
||||
$query = $request->query->get('query');
|
||||
|
||||
if ($query) {
|
||||
$entities = $this->createQuery()
|
||||
->search($query)
|
||||
->paginate($page, 5)
|
||||
;
|
||||
}
|
||||
|
||||
return $this->defaultRender('blog/post/search.html.twig', [
|
||||
'pager' => $entities ?? null,
|
||||
'query' => $query,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @UrlGenerator(service=PostGenerator::class, method="category")
|
||||
*/
|
||||
|
|
|
@ -13,6 +13,10 @@ use Symfony\Component\HttpFoundation\File\File;
|
|||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=PostRepository::class)
|
||||
* @ORM\Table(indexes={
|
||||
* @ORM\Index(name="post_title", columns={"title"}, flags={"fulltext"}),
|
||||
* @ORM\Index(name="post_content", columns={"content"}, flags={"fulltext"})
|
||||
* })
|
||||
* @ORM\HasLifecycleCallbacks
|
||||
*/
|
||||
class Post implements EntityInterface
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Repository\Blog;
|
|||
use App\Entity\Blog\Post;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use App\Core\Manager\EntityManager;
|
||||
|
||||
class PostRepository extends ServiceEntityRepository
|
||||
{
|
||||
|
@ -12,4 +13,9 @@ class PostRepository extends ServiceEntityRepository
|
|||
{
|
||||
parent::__construct($registry, Post::class);
|
||||
}
|
||||
|
||||
public function getEm()
|
||||
{
|
||||
return $this->getEntityManager();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ namespace App\Repository\Blog;
|
|||
|
||||
use App\Core\Repository\RepositoryQuery;
|
||||
use App\Entity\Blog\Category;
|
||||
use App\Entity\User;
|
||||
use Knp\Component\Pager\PaginatorInterface;
|
||||
|
||||
/**
|
||||
|
@ -37,13 +36,14 @@ class PostRepositoryQuery extends RepositoryQuery
|
|||
return $this
|
||||
->andWhere('.status = 1')
|
||||
->andWhere('.publishedAt <= :now')
|
||||
->setParameter(':now', (new \DateTime('now'))->format('Y-m-d H:i:s'));
|
||||
->setParameter(':now', (new \DateTime('now'))->format('Y-m-d H:i:s'))
|
||||
;
|
||||
}
|
||||
|
||||
public function useFilters(array $filters)
|
||||
{
|
||||
foreach ($filters as $name => $value) {
|
||||
if ($value === null) {
|
||||
if (null === $value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ class PostRepositoryQuery extends RepositoryQuery
|
|||
$this->andWhere('.'.$name.' LIKE :'.$name);
|
||||
$this->setParameter(':'.$name, '%'.$value.'%');
|
||||
} else {
|
||||
if ($name === 'category') {
|
||||
if ('category' === $name) {
|
||||
$this->inCategory($value);
|
||||
}
|
||||
}
|
||||
|
@ -62,4 +62,60 @@ class PostRepositoryQuery extends RepositoryQuery
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function search(string $keywords)
|
||||
{
|
||||
$conn = $this->repository->getEm()->getConnection();
|
||||
|
||||
$statement = $conn->prepare(
|
||||
'SELECT
|
||||
post.id,
|
||||
post.title,
|
||||
MATCH(post.title) AGAINST(:search) AS MATCH_TITLE,
|
||||
MATCH(post.content) AGAINST(:search) AS MATCH_CONTENT
|
||||
FROM post
|
||||
WHERE
|
||||
post.status = 1 AND
|
||||
post.published_at < :date
|
||||
ORDER BY
|
||||
MATCH_TITLE DESC,
|
||||
MATCH_CONTENT DESC
|
||||
');
|
||||
|
||||
$statement->execute([
|
||||
':search' => $keywords,
|
||||
':date' => (new \DateTime())->format('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
$results = $statement->fetchAll();
|
||||
$ids = [];
|
||||
|
||||
foreach ($results as $k => $v) {
|
||||
$rate = ($v['MATCH_TITLE'] * 2) + $v['MATCH_CONTENT'];
|
||||
|
||||
if ($rate >= 7) {
|
||||
$ids[] = $v['id'];
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == count($ids)) {
|
||||
foreach ($results as $k => $v) {
|
||||
$rate = ($v['MATCH_TITLE'] * 2) + $v['MATCH_CONTENT'];
|
||||
|
||||
if ($rate >= 6) {
|
||||
$ids[] = $v['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$ids) {
|
||||
$ids = [-1];
|
||||
}
|
||||
|
||||
return $this
|
||||
->orderBy('FIELD(p.id, :ids)')
|
||||
->andWhere('.id IN(:ids)')
|
||||
->setParameter(':ids', $ids)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
"beberlei/assert": {
|
||||
"version": "v3.3.0"
|
||||
},
|
||||
"beberlei/doctrineextensions": {
|
||||
"version": "v1.3.0"
|
||||
},
|
||||
"behat/transliterator": {
|
||||
"version": "v1.3.0"
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue