Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
9.96% |
23 / 231 |
|
20.83% |
5 / 24 |
CRAP | |
0.00% |
0 / 1 |
Request | |
9.96% |
23 / 231 |
|
20.83% |
5 / 24 |
2960.58 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getManager | |
75.00% |
3 / 4 |
|
0.00% |
0 / 1 |
2.06 | |||
createQueryBuilder | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
insert | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
update | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
create | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
remove | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
findAll | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
findOneById | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
getModelClass | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
addArchivedClause | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
addCollectivityClause | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
addOrder | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
findAllByCollectivity | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
6 | |||
findBy | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
findAllArchived | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
findAllArchivedByCollectivity | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
countAllByCollectivity | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
findOneOrNullLastUpdateByCollectivity | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
count | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
30 | |||
findPaginated | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
30 | |||
addTableOrder | |
0.00% |
0 / 56 |
|
0.00% |
0 / 1 |
182 | |||
addTableWhere | |
0.00% |
0 / 49 |
|
0.00% |
0 / 1 |
210 | |||
findAllLate | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | /** |
4 | * This file is part of the MADIS - RGPD Management application. |
5 | * |
6 | * @copyright Copyright (c) 2018-2019 Soluris - Solutions Numériques Territoriales Innovantes |
7 | * |
8 | * This program is free software: you can redistribute it and/or modify |
9 | * it under the terms of the GNU Affero General Public License as published by |
10 | * the Free Software Foundation, either version 3 of the License, or |
11 | * (at your option) any later version. |
12 | * |
13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU Affero General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Affero General Public License |
19 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
20 | */ |
21 | |
22 | declare(strict_types=1); |
23 | |
24 | namespace App\Infrastructure\ORM\Registry\Repository; |
25 | |
26 | use App\Application\Traits\RepositoryUtils; |
27 | use App\Domain\Registry\Dictionary\RequestObjectDictionary; |
28 | use App\Domain\Registry\Dictionary\RequestStateDictionary; |
29 | use App\Domain\Registry\Model; |
30 | use App\Domain\Registry\Repository; |
31 | use App\Domain\User\Model\Collectivity; |
32 | use Doctrine\Common\Collections\Collection; |
33 | use Doctrine\ORM\EntityManagerInterface; |
34 | use Doctrine\ORM\QueryBuilder; |
35 | use Doctrine\ORM\Tools\Pagination\Paginator; |
36 | use Doctrine\Persistence\ManagerRegistry; |
37 | |
38 | class Request implements Repository\Request |
39 | { |
40 | use RepositoryUtils; |
41 | |
42 | private string $lateRequestDelayDays; |
43 | |
44 | /** |
45 | * @var ManagerRegistry |
46 | */ |
47 | protected $registry; |
48 | |
49 | /** |
50 | * Request constructor. |
51 | */ |
52 | public function __construct(ManagerRegistry $registry, string $lateRequestDelayDays) |
53 | { |
54 | $this->registry = $registry; |
55 | $this->lateRequestDelayDays = $lateRequestDelayDays; |
56 | } |
57 | |
58 | /** |
59 | * Get the registry manager |
60 | * Since we use Doctrine, we expect to get EntityManagerInterface. |
61 | * |
62 | * @throws \Exception |
63 | */ |
64 | protected function getManager(): EntityManagerInterface |
65 | { |
66 | $manager = $this->registry->getManager(); |
67 | |
68 | if (!$manager instanceof EntityManagerInterface) { |
69 | throw new \Exception('Registry Manager must be an instance of EntityManagerInterface #PHPStan'); |
70 | } |
71 | |
72 | return $manager; |
73 | } |
74 | |
75 | /** |
76 | * Create the base of QueryBuilder to use for repository calls. |
77 | * |
78 | * @throws \Exception |
79 | * |
80 | * @return QueryBuilder |
81 | */ |
82 | protected function createQueryBuilder() |
83 | { |
84 | return $this->getManager() |
85 | ->createQueryBuilder() |
86 | ->select('o') |
87 | ->from($this->getModelClass(), 'o') |
88 | ; |
89 | } |
90 | |
91 | /** |
92 | * Insert an object. |
93 | * |
94 | * @throws \Exception |
95 | */ |
96 | public function insert($object): void |
97 | { |
98 | $this->getManager()->persist($object); |
99 | $this->getManager()->flush(); |
100 | } |
101 | |
102 | /** |
103 | * Update an object. |
104 | * |
105 | * @throws \Exception |
106 | */ |
107 | public function update($object): void |
108 | { |
109 | $this->getManager()->flush(); |
110 | } |
111 | |
112 | /** |
113 | * Create an object. |
114 | */ |
115 | public function create() |
116 | { |
117 | $class = $this->getModelClass(); |
118 | |
119 | return new $class(); |
120 | } |
121 | |
122 | /** |
123 | * Remove an object. |
124 | * |
125 | * @throws \Exception |
126 | */ |
127 | public function remove($object): void |
128 | { |
129 | $this->getManager()->remove($object); |
130 | $this->getManager()->flush(); |
131 | } |
132 | |
133 | public function findAll(bool $deleted = false): array |
134 | { |
135 | $qb = $this->createQueryBuilder(); |
136 | |
137 | if ($deleted) { |
138 | $qb->andWhere('o.deletedAt is not null'); |
139 | } else { |
140 | $qb->andWhere('o.deletedAt is null'); |
141 | } |
142 | |
143 | return $qb |
144 | ->getQuery() |
145 | ->getResult() |
146 | ; |
147 | } |
148 | |
149 | public function findOneById(string $id) |
150 | { |
151 | return $this->registry |
152 | ->getManager() |
153 | ->getRepository($this->getModelClass()) |
154 | ->find($id) |
155 | ; |
156 | } |
157 | |
158 | protected function getModelClass(): string |
159 | { |
160 | return Model\Request::class; |
161 | } |
162 | |
163 | /** |
164 | * Add archived clause in query. |
165 | */ |
166 | protected function addArchivedClause(QueryBuilder $qb, bool $archived = false): QueryBuilder |
167 | { |
168 | // Get not archived |
169 | if (!$archived) { |
170 | return $qb->andWhere('o.deletedAt is null'); |
171 | } |
172 | |
173 | // Get archived |
174 | return $qb->andWhere('o.deletedAt is not null'); |
175 | } |
176 | |
177 | /** |
178 | * Add collectivity clause to query. |
179 | */ |
180 | protected function addCollectivityClause(QueryBuilder $qb, Collectivity $collectivity): QueryBuilder |
181 | { |
182 | return $qb |
183 | ->andWhere('o.collectivity = :collectivity') |
184 | ->setParameter('collectivity', $collectivity) |
185 | ; |
186 | } |
187 | |
188 | /** |
189 | * Add order to query. |
190 | */ |
191 | protected function addOrder(QueryBuilder $qb, array $order = []): QueryBuilder |
192 | { |
193 | foreach ($order as $key => $dir) { |
194 | $qb->addOrderBy("o.{$key}", $dir); |
195 | } |
196 | |
197 | return $qb; |
198 | } |
199 | |
200 | /** |
201 | * @throws \Exception |
202 | */ |
203 | public function findAllByCollectivity(Collectivity $collectivity, bool $deleted = false, array $order = []) |
204 | { |
205 | $qb = $this->createQueryBuilder(); |
206 | |
207 | $this->addCollectivityClause($qb, $collectivity); |
208 | |
209 | if ($deleted) { |
210 | $qb->andWhere('o.deletedAt is not null'); |
211 | } else { |
212 | $qb->andWhere('o.deletedAt is null'); |
213 | } |
214 | |
215 | $this->addOrder($qb, $order); |
216 | |
217 | return $qb |
218 | ->getQuery() |
219 | ->getResult() |
220 | ; |
221 | } |
222 | |
223 | /** |
224 | * @throws \Exception |
225 | */ |
226 | public function findBy(array $criteria = []) |
227 | { |
228 | $qb = $this->createQueryBuilder(); |
229 | |
230 | foreach ($criteria as $key => $value) { |
231 | $this->addWhereClause($qb, $key, $value); |
232 | } |
233 | |
234 | return $qb |
235 | ->getQuery() |
236 | ->getResult() |
237 | ; |
238 | } |
239 | |
240 | /** |
241 | * @throws \Exception |
242 | */ |
243 | public function findAllArchived(bool $archived = false, array $order = []) |
244 | { |
245 | $qb = $this->createQueryBuilder(); |
246 | |
247 | $this->addArchivedClause($qb, $archived); |
248 | $this->addOrder($qb, $order); |
249 | |
250 | return $qb |
251 | ->getQuery() |
252 | ->getResult() |
253 | ; |
254 | } |
255 | |
256 | /** |
257 | * @throws \Exception |
258 | */ |
259 | public function findAllArchivedByCollectivity(Collectivity $collectivity, bool $archived = false, array $order = []) |
260 | { |
261 | $qb = $this->createQueryBuilder(); |
262 | |
263 | $this->addCollectivityClause($qb, $collectivity); |
264 | $this->addArchivedClause($qb, $archived); |
265 | $this->addOrder($qb, $order); |
266 | |
267 | return $qb |
268 | ->getQuery() |
269 | ->getResult() |
270 | ; |
271 | } |
272 | |
273 | public function countAllByCollectivity(Collectivity $collectivity) |
274 | { |
275 | $qb = $this->createQueryBuilder(); |
276 | |
277 | $qb->select('COUNT(o.id)'); |
278 | $this->addCollectivityClause($qb, $collectivity); |
279 | |
280 | return $qb->getQuery()->getSingleScalarResult(); |
281 | } |
282 | |
283 | public function findOneOrNullLastUpdateByCollectivity(Collectivity $collectivity): ?Model\Request |
284 | { |
285 | $qb = $this->createQueryBuilder(); |
286 | |
287 | $this->addCollectivityClause($qb, $collectivity); |
288 | $qb->addOrderBy('o.updatedAt', 'DESC'); |
289 | $qb->setMaxResults(1); |
290 | |
291 | return $qb->getQuery()->getOneOrNullResult(); |
292 | } |
293 | |
294 | public function count(array $criteria = []) |
295 | { |
296 | $qb = $this |
297 | ->createQueryBuilder() |
298 | ->select('count(o.id)') |
299 | ; |
300 | if (\array_key_exists('archive', $criteria)) { |
301 | $this->addArchivedClause($qb, $criteria['archive']); |
302 | unset($criteria['archive']); |
303 | } |
304 | |
305 | if (isset($criteria['collectivity']) && $criteria['collectivity'] instanceof Collection) { |
306 | $qb->leftJoin('o.collectivity', 'collectivite'); |
307 | $this->addInClauseCollectivities($qb, $criteria['collectivity']->toArray()); |
308 | unset($criteria['collectivity']); |
309 | } |
310 | |
311 | foreach ($criteria as $key => $value) { |
312 | $this->addWhereClause($qb, $key, $value); |
313 | } |
314 | |
315 | return $qb |
316 | ->getQuery() |
317 | ->getSingleScalarResult() |
318 | ; |
319 | } |
320 | |
321 | public function findPaginated($firstResult, $maxResults, $orderColumn, $orderDir, $searches, $criteria = []) |
322 | { |
323 | $qb = $this->createQueryBuilder() |
324 | ->addSelect('collectivite') |
325 | ->leftJoin('o.collectivity', 'collectivite') |
326 | ->leftJoin('o.service', 'service') |
327 | ; |
328 | |
329 | if (\array_key_exists('archive', $criteria)) { |
330 | $this->addArchivedClause($qb, $criteria['archive']); |
331 | unset($criteria['archive']); |
332 | } |
333 | |
334 | if (isset($criteria['collectivity']) && $criteria['collectivity'] instanceof Collection) { |
335 | $this->addInClauseCollectivities($qb, $criteria['collectivity']->toArray()); |
336 | unset($criteria['collectivity']); |
337 | } |
338 | |
339 | $this->addTableOrder($qb, $orderColumn, $orderDir); |
340 | $this->addTableWhere($qb, $searches); |
341 | |
342 | foreach ($criteria as $key => $value) { |
343 | $this->addWhereClause($qb, $key, $value); |
344 | } |
345 | |
346 | $query = $qb->getQuery(); |
347 | $query->setFirstResult($firstResult); |
348 | $query->setMaxResults($maxResults); |
349 | |
350 | return new Paginator($query); |
351 | } |
352 | |
353 | private function addTableOrder(QueryBuilder $queryBuilder, $orderColumn, $orderDir) |
354 | { |
355 | switch ($orderColumn) { |
356 | case 'collectivite': |
357 | $queryBuilder->addOrderBy('collectivite.name', $orderDir); |
358 | break; |
359 | case 'service': |
360 | $queryBuilder->addOrderBy('service.name', $orderDir); |
361 | break; |
362 | case 'personne_concernee': |
363 | $queryBuilder->addSelect('IFELSE (o.applicant.concernedPeople = 1, |
364 | CONCAT(o.applicant.firstName, \' \', o.applicant.lastName), |
365 | CONCAT(o.concernedPeople.firstName, \' \', o.applicant.lastName)) |
366 | AS HIDDEN person_name') |
367 | ->addOrderBy('person_name', $orderDir); |
368 | break; |
369 | case 'date_demande': |
370 | $queryBuilder->addOrderBy('o.date', $orderDir); |
371 | break; |
372 | case 'date_traitement': |
373 | $queryBuilder->addOrderBy('o.answer.date', $orderDir); |
374 | break; |
375 | case 'objet_demande': |
376 | $queryBuilder->addSelect('(case |
377 | WHEN o.object = \'' . RequestObjectDictionary::OBJECT_ACCESS . '\' THEN 1 |
378 | WHEN o.object = \'' . RequestObjectDictionary::OBJECT_OTHER . '\' THEN 2 |
379 | WHEN o.object = \'' . RequestObjectDictionary::OBJECT_LIMIT_TREATMENT . '\' THEN 3 |
380 | WHEN o.object = \'' . RequestObjectDictionary::OBJECT_DATA_PORTABILITY . '\' THEN 4 |
381 | WHEN o.object = \'' . RequestObjectDictionary::OBJECT_CORRECT . '\' THEN 5 |
382 | WHEN o.object = \'' . RequestObjectDictionary::OBJECT_WITHDRAW_CONSENT . '\' THEN 6 |
383 | WHEN o.object = \'' . RequestObjectDictionary::OBJECT_DELETE . '\' THEN 7 |
384 | WHEN o.object = \'' . RequestObjectDictionary::OBJECT_OPPOSITE_TREATMENT . '\' THEN 8 |
385 | ELSE 9 END) AS HIDDEN hidden_object') |
386 | ->addOrderBy('hidden_object', $orderDir); |
387 | break; |
388 | case 'demande_complete': |
389 | $queryBuilder->addOrderBy('o.complete', $orderDir); |
390 | break; |
391 | case 'demandeur_legitime': |
392 | $queryBuilder->addOrderBy('o.legitimateApplicant', $orderDir); |
393 | break; |
394 | case 'demande_legitime': |
395 | $queryBuilder->addOrderBy('o.legitimateRequest', $orderDir); |
396 | break; |
397 | case 'etat_demande': |
398 | $queryBuilder->addSelect('(case |
399 | WHEN o.state = \'' . RequestStateDictionary::STATE_TO_TREAT . '\' THEN 1 |
400 | WHEN o.state = \'' . RequestStateDictionary::STATE_DENIED . '\' THEN 2 |
401 | WHEN o.state = \'' . RequestStateDictionary::STATE_COMPLETED_CLOSED . '\' THEN 3 |
402 | WHEN o.state = \'' . RequestStateDictionary::STATE_AWAITING_CONFIRMATION . '\' THEN 4 |
403 | WHEN o.state = \'' . RequestStateDictionary::STATE_ON_REQUEST . '\' THEN 5 |
404 | WHEN o.state = \'' . RequestStateDictionary::STATE_AWAITING_SERVICE . '\' THEN 6 |
405 | ELSE 7 END) AS HIDDEN hidden_state') |
406 | ->addOrderBy('hidden_state', $orderDir); |
407 | break; |
408 | case 'createdAt': |
409 | $queryBuilder->addOrderBy('o.createdAt', $orderDir); |
410 | break; |
411 | case 'updatedAt': |
412 | $queryBuilder->addOrderBy('o.updatedAt', $orderDir); |
413 | break; |
414 | } |
415 | } |
416 | |
417 | private function addTableWhere(QueryBuilder $queryBuilder, $searches) |
418 | { |
419 | foreach ($searches as $columnName => $search) { |
420 | switch ($columnName) { |
421 | case 'collectivite': |
422 | $queryBuilder->andWhere('collectivite.name LIKE :collectivite_nom') |
423 | ->setParameter('collectivite_nom', '%' . $search . '%'); |
424 | break; |
425 | case 'service': |
426 | $queryBuilder->andWhere('service.name LIKE :service_name') |
427 | ->setParameter('service_name', '%' . $search . '%'); |
428 | break; |
429 | case 'personne_concernee': |
430 | $queryBuilder->andWhere('IFELSE (o.applicant.concernedPeople = 1, |
431 | CONCAT(o.applicant.firstName, \' \', o.applicant.lastName), |
432 | CONCAT(o.concernedPeople.firstName, \' \', o.applicant.lastName)) |
433 | LIKE :person_name') |
434 | ->setParameter('person_name', '%' . $search . '%'); |
435 | break; |
436 | case 'date_demande': |
437 | $queryBuilder->andWhere('o.date BETWEEN :request_start_date AND :request_finish_date') |
438 | ->setParameter('request_start_date', date_create_from_format('d/m/y', substr($search, 0, 8))->format('Y-m-d 00:00:00')) |
439 | ->setParameter('request_finish_date', date_create_from_format('d/m/y', substr($search, 11, 8))->format('Y-m-d 23:59:59')); |
440 | break; |
441 | case 'objet_demande': |
442 | $this->addWhereClause($queryBuilder, 'object', $search); |
443 | break; |
444 | case 'demande_complete': |
445 | $this->addWhereClause($queryBuilder, 'complete', $search); |
446 | break; |
447 | case 'demandeur_legitime': |
448 | $this->addWhereClause($queryBuilder, 'legitimateApplicant', $search); |
449 | break; |
450 | case 'date_traitement': |
451 | $queryBuilder->andWhere('o.answer.date BETWEEN :treatment_start_date AND :treatment_finish_date') |
452 | ->setParameter('treatment_start_date', date_create_from_format('d/m/y', substr($search, 0, 8))->format('Y-m-d 00:00:00')) |
453 | ->setParameter('treatment_finish_date', date_create_from_format('d/m/y', substr($search, 11, 8))->format('Y-m-d 23:59:59')); |
454 | break; |
455 | case 'demande_legitime': |
456 | $this->addWhereClause($queryBuilder, 'legitimateRequest', $search); |
457 | break; |
458 | case 'etat_demande': |
459 | $this->addWhereClause($queryBuilder, 'state', $search); |
460 | break; |
461 | case 'createdAt': |
462 | $queryBuilder->andWhere('o.createdAt BETWEEN :created_start_date AND :created_finish_date') |
463 | ->setParameter('created_start_date', date_create_from_format('d/m/y', substr($search, 0, 8))->format('Y-m-d 00:00:00')) |
464 | ->setParameter('created_finish_date', date_create_from_format('d/m/y', substr($search, 11, 8))->format('Y-m-d 23:59:59')); |
465 | break; |
466 | case 'updatedAt': |
467 | $queryBuilder->andWhere('o.updatedAt BETWEEN :updated_start_date AND :updated_finish_date') |
468 | ->setParameter('updated_start_date', date_create_from_format('d/m/y', substr($search, 0, 8))->format('Y-m-d 00:00:00')) |
469 | ->setParameter('updated_finish_date', date_create_from_format('d/m/y', substr($search, 11, 8))->format('Y-m-d 23:59:59')); |
470 | break; |
471 | } |
472 | } |
473 | } |
474 | |
475 | public function findAllLate(): array |
476 | { |
477 | $now = new \DateTime(); |
478 | $lastMonth = $now->sub(\DateInterval::createFromDateString($this->lateRequestDelayDays . ' days')); |
479 | |
480 | return $this->createQueryBuilder() |
481 | ->andWhere('o.updatedAt < :lastmonth') |
482 | ->setParameter('lastmonth', $lastMonth->format('Y-m-d')) |
483 | ->getQuery() |
484 | ->getResult(); |
485 | } |
486 | } |