Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.98% covered (success)
90.98%
363 / 399
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
TreatmentType
90.98% covered (success)
90.98%
363 / 399
66.67% covered (warning)
66.67%
2 / 3
15.17
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 buildForm
90.72% covered (success)
90.72%
352 / 388
0.00% covered (danger)
0.00%
0 / 1
13.13
 configureOptions
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
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\Domain\Registry\Form\Type;
25
26use App\Application\Form\Type\LinkableType;
27use App\Domain\Registry\Form\Type\Embeddable\ComplexChoiceAreaType;
28use App\Domain\Registry\Form\Type\Embeddable\ComplexChoiceType;
29use App\Domain\Registry\Model\Contractor;
30use App\Domain\Registry\Model\Mesurement;
31use App\Domain\Registry\Model\Proof;
32use App\Domain\Registry\Model\Request;
33use App\Domain\Registry\Model\Tool;
34use App\Domain\Registry\Model\Treatment;
35use App\Domain\Registry\Model\TreatmentDataCategory;
36use App\Domain\Registry\Model\Violation;
37use App\Domain\User\Model\Service;
38use App\Domain\User\Model\User;
39use Doctrine\Common\Collections\Criteria;
40use Doctrine\ORM\EntityRepository;
41use Knp\DictionaryBundle\Form\Type\DictionaryType;
42use Symfony\Bridge\Doctrine\Form\Type\EntityType;
43use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
44use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
45use Symfony\Component\Form\Extension\Core\Type\CollectionType;
46use Symfony\Component\Form\Extension\Core\Type\HiddenType;
47use Symfony\Component\Form\Extension\Core\Type\IntegerType;
48use Symfony\Component\Form\Extension\Core\Type\TextareaType;
49use Symfony\Component\Form\Extension\Core\Type\TextType;
50use Symfony\Component\Form\FormBuilderInterface;
51use Symfony\Component\OptionsResolver\OptionsResolver;
52use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
53use Symfony\Component\Security\Core\Security;
54
55class TreatmentType extends LinkableType
56{
57    /**
58     * @var Security
59     */
60    private $security;
61    private AuthorizationCheckerInterface $authorizationChecker;
62
63    public function __construct(Security $security, AuthorizationCheckerInterface $authorizationChecker)
64    {
65        $this->security             = $security;
66        $this->authorizationChecker = $authorizationChecker;
67        parent::__construct($security);
68    }
69
70    /**
71     * Build type form.
72     */
73    public function buildForm(FormBuilderInterface $builder, array $options)
74    {
75        /** @var Treatment $treatment */
76        $treatment = $options['data'];
77        /** @var User $user */
78        $user         = $this->security->getUser();
79        $collectivity = null;
80        if ($treatment) {
81            $collectivity = $treatment->getCollectivity();
82        }
83
84        if (!$collectivity) {
85            $collectivity = $user->getCollectivity();
86        }
87        $builder
88            ->add('public', CheckboxType::class, [
89                'label'    => 'registry.treatment.label.public_registry',
90                'required' => false,
91            ])
92            ->add('name', TextType::class, [
93                'label'    => 'registry.treatment.label.name',
94                'required' => true,
95                'attr'     => [
96                    'maxlength' => 255,
97                ],
98                'purify_html' => true,
99            ])
100            ->add('exempt_AIPD', CheckboxType::class, [
101                'label'    => 'registry.treatment.label.exempt_AIPD',
102                'required' => false,
103            ])
104
105            ->add('goal', TextareaType::class, [
106                'label'    => 'registry.treatment.label.goal',
107                'required' => false,
108                'attr'     => [
109                    'rows' => 4,
110                ],
111                'purify_html' => true,
112            ])
113            ->add('manager', TextType::class, [
114                'label'    => 'registry.treatment.label.manager',
115                'required' => false,
116                'attr'     => [
117                    'maxlength' => 255,
118                ],
119                'purify_html' => true,
120            ])
121
122            ->add('paperProcessing', CheckboxType::class, [
123                'label'    => 'registry.treatment.label.paper_processing',
124                'required' => false,
125            ])
126            ->add('legalBasis', DictionaryType::class, [
127                'label'    => 'registry.treatment.label.legal_basis',
128                'name'     => 'registry_treatment_legal_basis',
129                'required' => true,
130            ])
131            ->add('legalBasisJustification', TextareaType::class, [
132                'label'       => 'registry.treatment.label.legal_basis_justification',
133                'required'    => false,
134                'purify_html' => true,
135            ])
136            ->add('observation', TextareaType::class, [
137                'label'    => 'registry.treatment.label.observation',
138                'required' => false,
139                'attr'     => [
140                    'rows' => 2,
141                ],
142                'purify_html' => true,
143            ])
144            ->add('concernedPeopleParticular', ComplexChoiceType::class, [
145                'label'    => 'registry.treatment.label.concerned_people_particular',
146                'required' => false,
147            ])
148            ->add('concernedPeopleUser', ComplexChoiceType::class, [
149                'label'    => 'registry.treatment.label.concerned_people_user',
150                'required' => false,
151            ])
152            ->add('concernedPeopleAgent', ComplexChoiceType::class, [
153                'label'    => 'registry.treatment.label.concerned_people_agent',
154                'required' => false,
155            ])
156            ->add('concernedPeopleElected', ComplexChoiceType::class, [
157                'label'    => 'registry.treatment.label.concerned_people_elected',
158                'required' => false,
159            ])
160            ->add('concernedPeopleCompany', ComplexChoiceType::class, [
161                'label'    => 'registry.treatment.label.concerned_people_company',
162                'required' => false,
163            ])
164            ->add('concernedPeoplePartner', ComplexChoiceType::class, [
165                'label'    => 'registry.treatment.label.concerned_people_partner',
166                'required' => false,
167            ])
168            ->add('concernedPeopleUsager', ComplexChoiceType::class, [
169                'label'    => 'registry.treatment.label.concerned_people_usager',
170                'required' => false,
171            ])
172            ->add('concernedPeopleOther', ComplexChoiceType::class, [
173                'label'    => 'registry.treatment.label.concerned_people_other',
174                'required' => false,
175            ])
176            ->add('dataCategories', EntityType::class, [
177                'label'         => 'registry.treatment.label.data_category',
178                'class'         => TreatmentDataCategory::class,
179                'required'      => false,
180                'expanded'      => false,
181                'multiple'      => true,
182                'query_builder' => function (EntityRepository $er) {
183                    return $er->createQueryBuilder('dc')
184                        ->orderBy('dc.position', Criteria::ASC);
185                },
186                'choice_attr' => function (TreatmentDataCategory $model) {
187                    if ($model->isSensible()) {
188                        return [
189                            'style' => 'font-weight: bold;',
190                        ];
191                    }
192
193                    return [];
194                },
195                'attr' => [
196                    'class'            => 'selectpicker',
197                    'data-live-search' => 'true',
198                    'title'            => 'global.placeholder.multiple_select',
199                    'aria-label'       => 'Catégorie de données',
200                ],
201            ])
202            ->add('dataCategoryOther', TextareaType::class, [
203                'label'    => 'registry.treatment.label.data_category_other',
204                'required' => false,
205                'attr'     => [
206                    'rows' => 3,
207                ],
208                'purify_html' => true,
209            ])
210            ->add('dataOrigin', TextType::class, [
211                'label'    => 'registry.treatment.label.data_origin',
212                'required' => false,
213                'attr'     => [
214                    'maxlength' => 255,
215                ],
216                'purify_html' => true,
217            ])
218            ->add('recipientCategory', TextareaType::class, [
219                'label'    => 'registry.treatment.label.recipient_category',
220                'required' => false,
221                'attr'     => [
222                    'rows' => 2,
223                ],
224                'purify_html' => true,
225            ])
226            ->add('securityAccessControl', ComplexChoiceAreaType::class, [
227                'label'    => 'registry.treatment.label.security_access_control',
228                'required' => false,
229            ])
230            ->add('securityUpdate', ComplexChoiceAreaType::class, [
231                'label'    => 'registry.treatment.label.security_update',
232                'required' => false,
233            ])
234            ->add('securitySaving', ComplexChoiceAreaType::class, [
235                'label'    => 'registry.treatment.label.security_saving',
236                'required' => false,
237            ])
238            ->add('securityTracability', ComplexChoiceAreaType::class, [
239                'label'    => 'registry.treatment.label.security_tracability',
240                'required' => false,
241            ])
242            ->add('securityOther', ComplexChoiceAreaType::class, [
243                'label'    => 'registry.treatment.label.security_other',
244                'required' => false,
245            ])
246            ->add('systematicMonitoring', CheckboxType::class, [
247                'label'    => 'registry.treatment.label.systematic_monitoring',
248                'required' => false,
249            ])
250            ->add('largeScaleCollection', CheckboxType::class, [
251                'label'    => 'registry.treatment.label.large_scale_collection',
252                'required' => false,
253            ])
254            ->add('vulnerablePeople', CheckboxType::class, [
255                'label'    => 'registry.treatment.label.vulnerable_people',
256                'required' => false,
257            ])
258            ->add('dataCrossing', CheckboxType::class, [
259                'label'    => 'registry.treatment.label.data_crossing',
260                'required' => false,
261            ])
262            ->add('evaluationOrRating', CheckboxType::class, [
263                'label'    => 'registry.treatment.label.evaluation_or_rating',
264                'required' => false,
265            ])
266            ->add('automatedDecisionsWithLegalEffect', CheckboxType::class, [
267                'label'    => 'registry.treatment.label.automated_decisions_with_legal_effect',
268                'required' => false,
269            ])
270            ->add('automaticExclusionService', CheckboxType::class, [
271                'label'    => 'registry.treatment.label.automatic_exclusion_service',
272                'required' => false,
273            ])
274            ->add('innovativeUse', CheckboxType::class, [
275                'label'    => 'registry.treatment.label.innovative_use',
276                'required' => false,
277            ])
278            ->add('active', ChoiceType::class, [
279                'label'    => 'registry.treatment.label.active',
280                'required' => true,
281                'choices'  => [
282                    'global.label.active'   => true,
283                    'global.label.inactive' => false,
284                ],
285                'multiple' => false,
286                'expanded' => true,
287            ])
288            ->add('author', DictionaryType::class, [
289                'label'    => 'registry.treatment.label.author',
290                'name'     => 'registry_treatment_author',
291                'required' => true,
292            ])
293            ->add('coordonneesResponsableTraitement', TextareaType::class, [
294                'label'    => 'registry.treatment.label.coordonnees_responsable_traitement',
295                'required' => false,
296                'attr'     => [
297                    'rows' => 3,
298                ],
299                'purify_html' => true,
300            ])
301            ->add('collectingMethod', DictionaryType::class, [
302                'label'       => 'registry.treatment.label.collecting_method',
303                'name'        => 'registry_treatment_collecting_method',
304                'required'    => false,
305                'expanded'    => false,
306                'multiple'    => true,
307                'placeholder' => 'global.placeholder.precision',
308                'attr'        => [
309                    'class'            => 'selectpicker',
310                    'data-live-search' => 'true',
311                    'title'            => 'global.placeholder.multiple_select',
312                    'aria-label'       => 'Moyens de la collecte',
313                ],
314            ])
315            ->add('estimatedConcernedPeople', IntegerType::class, [
316                'label'    => 'registry.treatment.label.estimated_concerned_people',
317                'required' => false,
318                'attr'     => [
319                    'min' => 0,
320                ],
321            ])
322            ->add('securityEntitledPersons', CheckboxType::class, [
323                'label'    => 'registry.treatment.label.security_entitled_persons',
324                'required' => false,
325            ])
326            ->add('securityOpenAccounts', CheckboxType::class, [
327                'label'    => 'registry.treatment.label.security_open_accounts',
328                'required' => false,
329            ])
330            ->add('securitySpecificitiesDelivered', CheckboxType::class, [
331                'label'    => 'registry.treatment.label.security_specificities_delivered',
332                'required' => false,
333            ])
334            ->add('shelfLifes', CollectionType::class, [
335                'entry_type'   => ShelfLifeType::class,
336                'allow_add'    => true,
337                'allow_delete' => true,
338                'by_reference' => false,
339            ])
340            ->add('otherCollectingMethod', TextType::class, [
341                'label'       => 'registry.treatment.label.otherCollectingMethod',
342                'required'    => false,
343                'purify_html' => true,
344            ])
345            ->add('updatedBy', HiddenType::class, [
346                'required' => false,
347                'data'     => $user ? $user->getFirstName() . ' ' . strtoupper($user->getLastName()) : '',
348            ])
349            ->add('legalMentions', CheckboxType::class, [
350                'label'    => 'registry.treatment.label.legal_mentions',
351                'required' => false,
352            ])
353            ->add('consentRequest', CheckboxType::class, [
354                'label'    => 'registry.treatment.label.consent_request',
355                'required' => false,
356            ])
357            ->add('consentRequestFormat', TextType::class, [
358                'label'       => 'registry.treatment.label.consent_request_format',
359                'required'    => false,
360                'purify_html' => true,
361            ])
362
363        ;
364
365        if ($this->authorizationChecker->isGranted('ROLE_ADMIN') || $this->authorizationChecker->isGranted('ROLE_REFERENT')) {
366            $builder
367                ->add('dpoMessage', TextareaType::class, [
368                    'label'       => 'registry.treatment.label.dpoMessage',
369                    'required'    => false,
370                    'purify_html' => true,
371                ])
372                ->add('statut', DictionaryType::class, [
373                    'label'    => 'registry.treatment.label.statut',
374                    'name'     => 'treatment_statut',
375                    'required' => true,
376                ]);
377        } else {
378            $builder
379                ->add('statut', HiddenType::class, [
380                    'data' => 'finished',
381                ]);
382        }
383
384        $builder->add('mesurements',
385            EntityType::class,
386            $this->getLinkedFormField(
387                'global.label.linked_mesurement',
388                Mesurement::class,
389                $treatment,
390                'Actions de protection',
391                ['status' => 'asc', 'name' => 'asc'],
392            ),
393        )
394            ->add('treatments', EntityType::class, $this->getLinkedFormField(
395                'global.label.linked_treatment',
396                Treatment::class,
397                $treatment,
398                'Traitements',
399                ['active' => 'desc', 'name' => 'asc'],
400            ),
401            )
402            ->add('violations', EntityType::class, $this->getLinkedFormField(
403                'global.label.linked_violation',
404                Violation::class,
405                $treatment,
406                'Violations',
407                ['deletedAt' => 'asc', 'date' => 'asc'],
408            ),
409            )
410            ->add('proofs', EntityType::class, $this->getLinkedFormField(
411                'global.label.linked_proof',
412                Proof::class,
413                $treatment,
414                'Preuves',
415                ['deletedAt' => 'asc', 'name' => 'asc'],
416            ),
417            )
418            ->add('requests', EntityType::class, $this->getLinkedFormField(
419                'global.label.linked_request',
420                Request::class,
421                $treatment,
422                'Demandes',
423                ['deletedAt' => 'asc', 'date' => 'asc'],
424            ),
425            )
426            ->add('contractors', EntityType::class, $this->getLinkedFormField(
427                'global.label.linked_contractor',
428                Contractor::class,
429                $treatment,
430                'Sous-traitants',
431                ['name' => 'asc'],
432            ),
433            )
434        ;
435
436        if ($collectivity && $collectivity->isHasModuleTools()) {
437            $builder->add('tools', EntityType::class, $this->getLinkedFormField(
438                'global.label.linked_tool',
439                Tool::class,
440                $treatment,
441                'Logiciels et supports',
442                'name',
443            ),
444            );
445        } else {
446            $builder->add('software', TextType::class, [
447                'label'    => 'registry.treatment.label.tools_if_inactif',
448                'required' => false,
449                'attr'     => [
450                    'maxlength' => 255,
451                ],
452                'purify_html' => true,
453            ]);
454        }
455
456        // Check if services are enabled for the collectivity's treatment
457        if ($options['data']->getCollectivity()->getIsServicesEnabled()) {
458            $builder->add('service', EntityType::class, [
459                'class'         => Service::class,
460                'label'         => 'registry.label.service',
461                'query_builder' => function (EntityRepository $er) use ($treatment) {
462                    if ($treatment->getCollectivity()) {
463                        /** @var User $authenticatedUser */
464                        $authenticatedUser = $this->security->getUser();
465                        $collectivity      = $treatment->getCollectivity();
466
467                        $qb = $er->createQueryBuilder('s')
468                        ->where('s.collectivity = :collectivity')
469                        ->setParameter(':collectivity', $collectivity)
470                        ;
471
472                        if (!$this->authorizationChecker->isGranted('ROLE_ADMIN') && $authenticatedUser->getServices()->getValues()) {
473                            $qb->leftJoin('s.users', 'users')
474                                ->andWhere('users.id = :id')
475                                ->setParameter('id', $authenticatedUser->getId())
476                            ;
477                        }
478
479                        $qb
480                        ->orderBy('s.name', 'ASC');
481
482                        return $qb;
483                    }
484
485                    return $er->createQueryBuilder('s')
486                        ->orderBy('s.name', 'ASC');
487                },
488                'required' => false,
489            ]);
490        }
491    }
492
493    /**
494     * Provide type options.
495     */
496    public function configureOptions(OptionsResolver $resolver)
497    {
498        $resolver
499            ->setDefaults([
500                'data_class'        => Treatment::class,
501                'validation_groups' => [
502                    'default',
503                    'treatment',
504                ],
505            ]);
506    }
507}