Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
9.96% covered (danger)
9.96%
23 / 231
20.83% covered (danger)
20.83%
5 / 24
CRAP
0.00% covered (danger)
0.00%
0 / 1
Request
9.96% covered (danger)
9.96%
23 / 231
20.83% covered (danger)
20.83%
5 / 24
2960.58
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getManager
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 createQueryBuilder
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 insert
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 update
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 create
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 remove
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 findAll
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 findOneById
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getModelClass
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addArchivedClause
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 addCollectivityClause
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 addOrder
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 findAllByCollectivity
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 findBy
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 findAllArchived
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 findAllArchivedByCollectivity
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 countAllByCollectivity
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 findOneOrNullLastUpdateByCollectivity
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 count
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
30
 findPaginated
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
30
 addTableOrder
0.00% covered (danger)
0.00%
0 / 56
0.00% covered (danger)
0.00%
0 / 1
182
 addTableWhere
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 1
210
 findAllLate
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
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
22declare(strict_types=1);
23
24namespace App\Infrastructure\ORM\Registry\Repository;
25
26use App\Application\Traits\RepositoryUtils;
27use App\Domain\Registry\Dictionary\RequestObjectDictionary;
28use App\Domain\Registry\Dictionary\RequestStateDictionary;
29use App\Domain\Registry\Model;
30use App\Domain\Registry\Repository;
31use App\Domain\User\Model\Collectivity;
32use Doctrine\Common\Collections\Collection;
33use Doctrine\ORM\EntityManagerInterface;
34use Doctrine\ORM\QueryBuilder;
35use Doctrine\ORM\Tools\Pagination\Paginator;
36use Doctrine\Persistence\ManagerRegistry;
37
38class 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}