Completed
Push — master ( 845964...864a7b )
by Louis
16s
created

PaginateHelper   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 149
Duplicated Lines 4.03 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 22
lcom 1
cbo 4
dl 6
loc 149
rs 10
c 1
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A setRequest() 0 4 1
F paginateData() 0 80 16
B paginateView() 6 38 4

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace KI\CoreBundle\Helper;
4
5
use Doctrine\ORM\EntityManager;
6
use Doctrine\ORM\EntityRepository;
7
use Symfony\Component\HttpFoundation\JsonResponse;
8
use Symfony\Component\HttpFoundation\RequestStack;
9
use Symfony\Component\HttpFoundation\Response;
10
11
class PaginateHelper
12
{
13
    protected $manager;
14
    protected $request;
15
16
    public function __construct(EntityManager $manager)
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $manager. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

The EntityManager might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
17
    {
18
        $this->manager = $manager;
19
    }
20
21
    public function setRequest(RequestStack $requestStack)
22
    {
23
        $this->request = $requestStack->getCurrentRequest();
24
    }
25
26
    /**
27
     * En fonction de la requête, récupère les données utiles à la pagination
28
     * @param  EntityRepository $repository Le repository sur lequel effectuer les comptes
29
     * @return array                        Les données de pagination (nombre de pages, etc.)
30
     */
31
    public function paginateData(EntityRepository $repository, array $findBy = [])
32
    {
33
        $queryBuilder = $repository->createQueryBuilder('o');
34
        $request = $this->request->query;
35
36
        // On s'assure de bien recevoir des arrays
37
        foreach ($findBy as $key => $value) {
38
            $findBy[$key] = array($value);
39
        }
40
41
        // On récupère les paramètres de la requête
42
        $page  = $request->has('page') ? $request->get('page') : 1;
43
        $limit = $request->has('limit') ? $request->get('limit') : 100;
44
        $sort  = $request->has('sort') ? $request->get('sort') : null;
45
46
        if ($sort === null) {
47
            $sortBy = ['id' => 'DESC'];
48
        } else {
49
            $sortBy = [];
50
51
            foreach (explode(',', $sort) as $value) {
52
                $order = preg_match('/^\-.*/isU', $value) ? 'DESC' : 'ASC';
53
                $field = preg_replace('/^\-/isU', '', $value);
54
                $sortBy[$field] = $order;
55
            }
56
        }
57
58
        foreach ($request->all() as $key => $values) {
59
            if ($key != 'page' && $key != 'limit' && $key != 'sort') {
60
                $findBy[$key] = explode(',', $values);
61
            }
62
        }
63
64
        // On compte le nombre total d'entrées dans la BDD
65
        $queryBuilder->select('count(o.id)');
66
        foreach ($findBy as $key => $values){
67
            $andCount = 0;
68
            $and = '';
69
            foreach($values as $value){
70
                if($andCount > 0){
71
                    $and .= ' OR ';
72
                }
73
                $and .= 'o.' . $key . ' = :' . $key . $andCount;
74
                $queryBuilder->setParameter($key . $andCount, $value);
75
76
                $andCount++;
77
            }
78
            $queryBuilder->andWhere($and);
79
        }
80
81
        foreach($sortBy as $field => $order){
82
            $queryBuilder->addOrderBy('o.' . $field, $order);
83
        }
84
85
        $count = $queryBuilder->getQuery()->getSingleScalarResult();
86
87
        // On vérifie que l'utilisateur ne fasse pas de connerie avec les variables
88
        $totalPages = ceil($count/$limit);
89
        $limit = min($limit, 10000);
90
        $limit = max($limit, 1);
91
        $page  = min($page, $totalPages);
92
        $page  = max($page, 1);
93
94
        $results = $queryBuilder->select('o')
95
                    ->setMaxResults($limit)
96
                    ->setFirstResult(($page - 1)*$limit)
97
                    ->getQuery()
98
                    ->getResult();
99
100
        return [
101
            'findBy'     => $findBy,
102
            'sortBy'     => $sortBy,
103
            'limit'      => $limit,
104
            'offset'     => ($page - 1)*$limit,
105
            'page'       => $page,
106
            'totalPages' => $totalPages,
107
            'count'      => $count,
108
            'results'    => $results,
109
        ];
110
    }
111
112
    /**
113
     * Génère les headers de pagination et renvoie la réponse
114
     * @param  array   $results    Les résultats à paginer
115
     * @param  integer $limit      Le nombre d'objets par page
116
     * @param  integer $page       Le numéro de la page en cours
117
     * @param  integer $totalPages Le nombre total de pages
118
     * @param  integer $count      Le nombre total d'objets
119
     * @return Response
120
     */
121
    public function paginateView($results, $limit, $page, $totalPages, $count)
122
    {
123
        // On prend l'url de la requête
124
        $baseUrl = '<'.str_replace($this->request->getBaseUrl(), '', $this->request->getRequestUri());
125
126
        // On enlève tous les paramètres GET de type "page" et "limit" précédents s'il y en avait
127
        $baseUrl = preg_replace('/[\?&](page|limit)=\d+/', '', $baseUrl);
128
        $baseUrl .= !preg_match('/\?/', $baseUrl) ? '?' : '&';
129
130
        // On va générer les notres pour les links
131
        $baseUrl .= 'page=';
132
        $links = [];
133
134
        // First
135
        $links[] = $baseUrl.'1'.'&limit='.$limit.'>;rel=first';
136
137
        // Previous
138 View Code Duplication
        if ($page > 1) {
139
            $links[] = $baseUrl.($page - 1).'&limit='.$limit.'>;rel=previous';
140
        }
141
142
        // Self
143
        $links[] = $baseUrl.$page.'&limit='.$limit.'>;rel=self';
144
145
        // Next
146 View Code Duplication
        if ($page < $totalPages) {
147
            $links[] = $baseUrl.($page + 1).'&limit='.$limit.'>;rel=next';
148
        }
149
150
        // Last
151
        $links[] = $baseUrl.$totalPages.'&limit='.$limit.'>;rel=last';
152
153
        return [
154
            $results,
155
            $links,
156
            $count
157
        ];
158
    }
159
}
160