Passed
Push — fix_coverage_in_scrutinizer ( cd0379...a04ba4 )
by Herberto
13:22
created

PostRepository::findLatest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 1
crap 1
1
<?php
2
3
/*
4
 * This file is part of the Symfony package.
5
 *
6
 * (c) Fabien Potencier <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace App\Repository;
13
14
use App\Entity\Post;
15
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
16
use Doctrine\Common\Persistence\ManagerRegistry;
17
use Doctrine\ORM\Query;
18
use Pagerfanta\Adapter\DoctrineORMAdapter;
19
use Pagerfanta\Pagerfanta;
20
21
/**
22
 * This custom Doctrine repository contains some methods which are useful when
23
 * querying for blog post information.
24
 *
25
 * See https://symfony.com/doc/current/book/doctrine.html#custom-repository-classes
26
 *
27
 * @author Ryan Weaver <[email protected]>
28
 * @author Javier Eguiluz <[email protected]>
29
 * @author Yonel Ceruto <[email protected]>
30
 */
31
class PostRepository extends ServiceEntityRepository
32
{
33 10
    public function __construct(ManagerRegistry $registry)
34
    {
35 10
        parent::__construct($registry, Post::class);
36 10
    }
37
38 4
    public function findLatest(int $page = 1): Pagerfanta
39
    {
40 4
        $query = $this->getEntityManager()
41 4
            ->createQuery('
42
                SELECT p, a, t
43
                FROM App:Post p
44
                JOIN p.author a
45
                LEFT JOIN p.tags t
46
                WHERE p.publishedAt <= :now
47
                ORDER BY p.publishedAt DESC
48
            ')
49 4
            ->setParameter('now', new \DateTime())
50
        ;
51
52 4
        return $this->createPaginator($query, $page);
53
    }
54
55 4
    private function createPaginator(Query $query, int $page): Pagerfanta
56
    {
57 4
        $paginator = new Pagerfanta(new DoctrineORMAdapter($query));
58 4
        $paginator->setMaxPerPage(Post::NUM_ITEMS);
59 4
        $paginator->setCurrentPage($page);
60
61 4
        return $paginator;
62
    }
63
64
    /**
65
     * @return Post[]
66
     */
67
    public function findBySearchQuery(string $rawQuery, int $limit = Post::NUM_ITEMS): array
68
    {
69
        $query = $this->sanitizeSearchQuery($rawQuery);
70
        $searchTerms = $this->extractSearchTerms($query);
71
72
        if (0 === count($searchTerms)) {
73
            return [];
74
        }
75
76
        $queryBuilder = $this->createQueryBuilder('p');
77
78
        foreach ($searchTerms as $key => $term) {
79
            $queryBuilder
80
                ->orWhere('p.title LIKE :t_'.$key)
81
                ->setParameter('t_'.$key, '%'.$term.'%')
82
            ;
83
        }
84
85
        return $queryBuilder
86
            ->orderBy('p.publishedAt', 'DESC')
87
            ->setMaxResults($limit)
88
            ->getQuery()
89
            ->getResult();
90
    }
91
92
    /**
93
     * Removes all non-alphanumeric characters except whitespaces.
94
     */
95
    private function sanitizeSearchQuery(string $query): string
96
    {
97
        return preg_replace('/[^[:alnum:] ]/', '', trim(preg_replace('/[[:space:]]+/', ' ', $query)));
98
    }
99
100
    /**
101
     * Splits the search query into terms and removes the ones which are irrelevant.
102
     */
103
    private function extractSearchTerms(string $searchQuery): array
104
    {
105
        $terms = array_unique(explode(' ', mb_strtolower($searchQuery)));
106
107
        return array_filter($terms, function ($term) {
108
            return 2 <= mb_strlen($term);
109
        });
110
    }
111
}
112