Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.95% covered (danger)
0.95%
2 / 210
8.70% covered (danger)
8.70%
2 / 23
CRAP
0.00% covered (danger)
0.00%
0 / 1
Violation
0.95% covered (danger)
0.95%
2 / 210
8.70% covered (danger)
8.70%
2 / 23
3441.49
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getManager
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 createQueryBuilder
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 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
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getModelClass
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addWhereClause
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 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
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 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 / 18
0.00% covered (danger)
0.00%
0 / 1
30
 addTableOrder
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 1
132
 addTableWhere
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
182
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\ViolationCauseDictionary;
28use App\Domain\Registry\Dictionary\ViolationGravityDictionary;
29use App\Domain\Registry\Dictionary\ViolationNatureDictionary;
30use App\Domain\Registry\Dictionary\ViolationNotificationDictionary;
31use App\Domain\Registry\Model;
32use App\Domain\Registry\Repository;
33use App\Domain\User\Model\Collectivity;
34use Doctrine\Common\Collections\Collection;
35use Doctrine\ORM\EntityManagerInterface;
36use Doctrine\ORM\QueryBuilder;
37use Doctrine\ORM\Tools\Pagination\Paginator;
38use Doctrine\Persistence\ManagerRegistry;
39
40class Violation implements Repository\Violation
41{
42    use RepositoryUtils;
43    /**
44     * @var ManagerRegistry
45     */
46    protected $registry;
47
48    /**
49     * Violation constructor.
50     */
51    public function __construct(ManagerRegistry $registry)
52    {
53        $this->registry = $registry;
54    }
55
56    /**
57     * Get the registry manager
58     * Since we use Doctrine, we expect to get EntityManagerInterface.
59     *
60     * @throws \Exception
61     */
62    protected function getManager(): EntityManagerInterface
63    {
64        $manager = $this->registry->getManager();
65
66        if (!$manager instanceof EntityManagerInterface) {
67            throw new \Exception('Registry Manager must be an instance of EntityManagerInterface #PHPStan');
68        }
69
70        return $manager;
71    }
72
73    /**
74     * Create the base of QueryBuilder to use for repository calls.
75     *
76     * @throws \Exception
77     */
78    protected function createQueryBuilder(): QueryBuilder
79    {
80        return $this->getManager()
81            ->createQueryBuilder()
82            ->select('o')
83            ->from($this->getModelClass(), 'o')
84        ;
85    }
86
87    /**
88     * Insert an object.
89     *
90     * @throws \Exception
91     */
92    public function insert($object): void
93    {
94        $this->getManager()->persist($object);
95        $this->getManager()->flush();
96    }
97
98    /**
99     * Update an object.
100     *
101     * @throws \Exception
102     */
103    public function update($object): void
104    {
105        $this->getManager()->flush();
106    }
107
108    /**
109     * Create an object.
110     */
111    public function create()
112    {
113        $class = $this->getModelClass();
114
115        return new $class();
116    }
117
118    /**
119     * Remove an object.
120     *
121     * @throws \Exception
122     */
123    public function remove($object): void
124    {
125        $this->getManager()->remove($object);
126        $this->getManager()->flush();
127    }
128
129    /**
130     * @throws \Exception
131     */
132    public function findAll(bool $deleted = false): array
133    {
134        $qb = $this->createQueryBuilder();
135
136        if ($deleted) {
137            $qb->andWhere('o.deletedAt is not null');
138        } else {
139            $qb->andWhere('o.deletedAt is null');
140        }
141
142        return $qb
143            ->getQuery()
144            ->getResult()
145        ;
146    }
147
148    /**
149     * Get an object by ID.
150     *
151     * @param string $id The ID to find
152     *
153     * @return object|null
154     */
155    public function findOneById(string $id)
156    {
157        return $this->registry
158            ->getManager()
159            ->getRepository($this->getModelClass())
160            ->find($id)
161        ;
162    }
163
164    protected function getModelClass(): string
165    {
166        return Model\Violation::class;
167    }
168
169    /**
170     * Add a where clause.
171     */
172    protected function addWhereClause(QueryBuilder $qb, string $key, $value): QueryBuilder
173    {
174        return $qb
175            ->andWhere("o.{$key} = :{$key}_value")
176            ->setParameter("{$key}_value", $value)
177        ;
178    }
179
180    /**
181     * Add archive clause to query.
182     */
183    protected function addArchivedClause(QueryBuilder $qb, bool $archived = false): QueryBuilder
184    {
185        // Get not archived
186        if (!$archived) {
187            return $qb->andWhere('o.deletedAt is null');
188        }
189
190        // Get archived
191        return $qb->andWhere('o.deletedAt is not null');
192    }
193
194    /**
195     * Add collectivity clause to query.
196     */
197    protected function addCollectivityClause(QueryBuilder $qb, Collectivity $collectivity): QueryBuilder
198    {
199        return $qb
200            ->andWhere('o.collectivity = :collectivity')
201            ->setParameter('collectivity', $collectivity)
202        ;
203    }
204
205    /**
206     * Add order to query.
207     */
208    protected function addOrder(QueryBuilder $qb, array $order = []): QueryBuilder
209    {
210        foreach ($order as $key => $dir) {
211            $qb->addOrderBy("o.{$key}", $dir);
212        }
213
214        return $qb;
215    }
216
217    /**
218     * @throws \Exception
219     */
220    public function findAllByCollectivity(Collectivity $collectivity, bool $deleted = false, array $order = [])
221    {
222        $qb = $this->createQueryBuilder();
223
224        $this->addCollectivityClause($qb, $collectivity);
225
226        if ($deleted) {
227            $qb->andWhere('o.deletedAt is not null');
228        } else {
229            $qb->andWhere('o.deletedAt is null');
230        }
231
232        $this->addOrder($qb, $order);
233
234        return $qb
235            ->getQuery()
236            ->getResult()
237        ;
238    }
239
240    /**
241     * @throws \Exception
242     */
243    public function findBy(array $criteria = [])
244    {
245        $qb = $this->createQueryBuilder();
246
247        foreach ($criteria as $key => $value) {
248            $this->addWhereClause($qb, $key, $value);
249        }
250
251        return $qb
252            ->getQuery()
253            ->getResult()
254        ;
255    }
256
257    /**
258     * @throws \Exception
259     */
260    public function findAllArchivedByCollectivity(Collectivity $collectivity, bool $archived = false, array $order = [])
261    {
262        $qb = $this->createQueryBuilder();
263
264        $this->addCollectivityClause($qb, $collectivity);
265        $this->addArchivedClause($qb, $archived);
266        $this->addOrder($qb, $order);
267
268        return $qb
269            ->getQuery()
270            ->getResult()
271        ;
272    }
273
274    public function countAllByCollectivity(Collectivity $collectivity)
275    {
276        $qb = $this->createQueryBuilder();
277
278        $qb->select('COUNT(o.id)');
279        $this->addCollectivityClause($qb, $collectivity);
280
281        return $qb->getQuery()->getSingleScalarResult();
282    }
283
284    public function findOneOrNullLastUpdateByCollectivity(Collectivity $collectivity): ?Model\Violation
285    {
286        $qb = $this->createQueryBuilder();
287
288        $this->addCollectivityClause($qb, $collectivity);
289        $qb->addOrderBy('o.updatedAt', 'DESC');
290        $qb->setMaxResults(1);
291
292        return $qb->getQuery()->getOneOrNullResult();
293    }
294
295    public function count(array $criteria = [])
296    {
297        $qb = $this
298                ->createQueryBuilder()
299                ->select('count(o.id)')
300        ;
301
302        if (\array_key_exists('archive', $criteria)) {
303            $this->addArchivedClause($qb, $criteria['archive']);
304            unset($criteria['archive']);
305        }
306
307        if (isset($criteria['collectivity']) && $criteria['collectivity'] instanceof Collection) {
308            $qb->leftJoin('o.collectivity', 'collectivite');
309            $this->addInClauseCollectivities($qb, $criteria['collectivity']->toArray());
310            unset($criteria['collectivity']);
311        }
312
313        foreach ($criteria as $key => $value) {
314            $this->addWhereClause($qb, $key, $value);
315        }
316
317        return $qb
318                ->getQuery()
319                ->getSingleScalarResult()
320        ;
321    }
322
323    public function findPaginated($firstResult, $maxResults, $orderColumn, $orderDir, $searches, $criteria = [])
324    {
325        $qb = $this->createQueryBuilder();
326
327        if (\array_key_exists('archive', $criteria)) {
328            $this->addArchivedClause($qb, $criteria['archive']);
329            unset($criteria['archive']);
330        }
331
332        $qb->leftJoin('o.collectivity', 'collectivite')
333            ->leftJoin('o.service', 'service')
334            ->addSelect('collectivite');
335
336        if (isset($criteria['collectivity']) && $criteria['collectivity'] instanceof Collection) {
337            $this->addInClauseCollectivities($qb, $criteria['collectivity']->toArray());
338            unset($criteria['collectivity']);
339        }
340
341        foreach ($criteria as $key => $value) {
342            $this->addWhereClause($qb, $key, $value);
343        }
344
345        $this->addTableOrder($qb, $orderColumn, $orderDir);
346        $this->addTableWhere($qb, $searches);
347
348        $query = $qb->getQuery();
349        $query->setFirstResult($firstResult);
350        $query->setMaxResults($maxResults);
351
352        return new Paginator($query);
353    }
354
355    private function addTableOrder(QueryBuilder $queryBuilder, $orderColumn, $orderDir)
356    {
357        switch ($orderColumn) {
358            case 'collectivite':
359                $queryBuilder->addOrderBy('collectivite.name', $orderDir);
360                break;
361            case 'service':
362                $queryBuilder->addOrderBy('service.name', $orderDir);
363                break;
364            case 'date':
365
366                $queryBuilder->addOrderBy('o.date', $orderDir);
367                break;
368            case 'nature':
369                $queryBuilder->addSelect('(case
370                WHEN o.violationNatures LIKE \'%' . ViolationNatureDictionary::NATURE_INTEGRITY . '%\' THEN 1
371                WHEN o.violationNatures LIKE \'%' . ViolationNatureDictionary::NATURE_CONFIDENTIALITY . '%\' THEN 2
372                WHEN o.violationNatures LIKE \'%' . ViolationNatureDictionary::NATURE_AVAILABILITY . '%\' THEN 3
373
374                ELSE 4 END) AS HIDDEN hidden_violation_nature')
375                    ->addOrderBy('hidden_violation_nature', $orderDir);
376                break;
377            case 'cause':
378                $queryBuilder->addSelect('(case
379                WHEN o.cause = \'' . ViolationCauseDictionary::CAUSE_EXTERNAL_ACCIDENTAL . '\' THEN 1
380                WHEN o.cause = \'' . ViolationCauseDictionary::CAUSE_EXTERNAL_MALICIOUS . '\' THEN 2
381                WHEN o.cause = \'' . ViolationCauseDictionary::CAUSE_INTERNAL_ACCIDENTAL . '\' THEN 3
382                WHEN o.cause = \'' . ViolationCauseDictionary::CAUSE_INTERNAL_MALICIOUS . '\' THEN 4
383                WHEN o.cause = \'' . ViolationCauseDictionary::CAUSE_UNKNOWN . '\' THEN 5
384                ELSE 6 END) AS HIDDEN hidden_cause')
385                    ->addOrderBy('hidden_cause', $orderDir);
386                break;
387            case 'gravity':
388                $queryBuilder->addSelect('(case
389                WHEN o.gravity = \'' . ViolationGravityDictionary::GRAVITY_IMPORTANT . '\' THEN 1
390                WHEN o.gravity = \'' . ViolationGravityDictionary::GRAVITY_LIMITED . '\' THEN 2
391                WHEN o.gravity = \'' . ViolationGravityDictionary::GRAVITY_MAXIMUM . '\' THEN 3
392                WHEN o.gravity = \'' . ViolationGravityDictionary::GRAVITY_NEGLIGIBLE . '\' THEN 4
393                ELSE 5 END) AS HIDDEN hidden_gravity')
394                    ->addOrderBy('hidden_gravity', $orderDir);
395                break;
396            case 'notification':
397                $queryBuilder->addSelect('(case
398                WHEN o.notification = \'' . ViolationNotificationDictionary::NOTIFICATION_NOTHING . '\' THEN 1
399                WHEN o.notification = \'' . ViolationNotificationDictionary::NOTIFICATION_CNIL . '\' THEN 2
400                WHEN o.notification = \'' . ViolationNotificationDictionary::NOTIFICATION_CROSS_BORDER . '\' THEN 3
401                WHEN o.notification = \'' . ViolationNotificationDictionary::NOTIFICATION_OTHER . '\' THEN 4
402                ELSE 5 END) AS HIDDEN hidden_notif')
403                    ->addOrderBy('hidden_notif', $orderDir);
404                break;
405            case 'createdAt':
406                $queryBuilder->addOrderBy('o.createdAt', $orderDir);
407                break;
408            case 'inProgress':
409                $queryBuilder->addOrderBy('o.inProgress', $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 :nom')
423                        ->setParameter('nom', '%' . $search . '%');
424                    break;
425                case 'service':
426                    $queryBuilder->andWhere('service.name LIKE :sernom')
427                        ->setParameter('sernom', '%' . $search . '%');
428                    break;
429                case 'date':
430                    $queryBuilder->andWhere('o.date BETWEEN :date_start_date AND :date_finish_date')
431                        ->setParameter('date_start_date', date_create_from_format('d/m/y', substr($search, 0, 8))->format('Y-m-d 00:00:00'))
432                        ->setParameter('date_finish_date', date_create_from_format('d/m/y', substr($search, 11, 8))->format('Y-m-d 23:59:59'));
433                    break;
434                case 'nature':
435                    $queryBuilder->andWhere('o.violationNatures LIKE :nature')
436                        ->setParameter('nature', '%' . $search . '%');
437                    break;
438                case 'inProgress':
439                    $this->addWhereClause($queryBuilder, 'inProgress', $search);
440                    break;
441                case 'cause':
442                    $this->addWhereClause($queryBuilder, 'cause', $search);
443                    break;
444                case 'gravity':
445                    $this->addWhereClause($queryBuilder, 'gravity', $search);
446                    break;
447                case 'notification':
448                    if ('none' == $search) {
449                        $queryBuilder->andWhere('o.notification IS NULL');
450                    } else {
451                        $this->addWhereClause($queryBuilder, 'notification', $search);
452                    }
453
454                    break;
455                case 'createdAt':
456                    $queryBuilder->andWhere('o.createdAt BETWEEN :created_start_date AND :created_finish_date')
457                        ->setParameter('created_start_date', date_create_from_format('d/m/y', substr($search, 0, 8))->format('Y-m-d 00:00:00'))
458                        ->setParameter('created_finish_date', date_create_from_format('d/m/y', substr($search, 11, 8))->format('Y-m-d 23:59:59'));
459                    break;
460                case 'updatedAt':
461                    $queryBuilder->andWhere('o.updatedAt BETWEEN :updated_start_date AND :updated_finish_date')
462                        ->setParameter('updated_start_date', date_create_from_format('d/m/y', substr($search, 0, 8))->format('Y-m-d 00:00:00'))
463                        ->setParameter('updated_finish_date', date_create_from_format('d/m/y', substr($search, 11, 8))->format('Y-m-d 23:59:59'));
464                    break;
465            }
466        }
467    }
468}