Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
76.60% |
144 / 188 |
|
66.67% |
2 / 3 |
CRAP | |
0.00% |
0 / 1 |
UserType | |
76.60% |
144 / 188 |
|
66.67% |
2 / 3 |
15.17 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
buildForm | |
75.00% |
132 / 176 |
|
0.00% |
0 / 1 |
12.89 | |||
configureOptions | |
100.00% |
8 / 8 |
|
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 | |
22 | declare(strict_types=1); |
23 | |
24 | namespace App\Domain\User\Form\Type; |
25 | |
26 | use App\Domain\User\Form\DataTransformer\MoreInfoTransformer; |
27 | use App\Domain\User\Form\DataTransformer\RoleTransformer; |
28 | use App\Domain\User\Model\Collectivity; |
29 | use App\Domain\User\Model\Service; |
30 | use App\Domain\User\Model\User; |
31 | use Doctrine\ORM\EntityRepository; |
32 | use Knp\DictionaryBundle\Form\Type\DictionaryType; |
33 | use Symfony\Bridge\Doctrine\Form\Type\EntityType; |
34 | use Symfony\Component\Form\AbstractType; |
35 | use Symfony\Component\Form\Extension\Core\Type\CheckboxType; |
36 | use Symfony\Component\Form\Extension\Core\Type\EmailType; |
37 | use Symfony\Component\Form\Extension\Core\Type\PasswordType; |
38 | use Symfony\Component\Form\Extension\Core\Type\RepeatedType; |
39 | use Symfony\Component\Form\Extension\Core\Type\TextType; |
40 | use Symfony\Component\Form\FormBuilderInterface; |
41 | use Symfony\Component\Form\FormEvent; |
42 | use Symfony\Component\Form\FormEvents; |
43 | use Symfony\Component\Form\FormInterface; |
44 | use Symfony\Component\OptionsResolver\OptionsResolver; |
45 | use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; |
46 | use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; |
47 | use Symfony\Component\Security\Core\Security; |
48 | |
49 | class UserType extends AbstractType |
50 | { |
51 | /** |
52 | * @var AuthorizationCheckerInterface |
53 | */ |
54 | private $authorizationChecker; |
55 | |
56 | /** |
57 | * @var EncoderFactoryInterface |
58 | */ |
59 | private $encoderFactory; |
60 | |
61 | /** |
62 | * @var Security |
63 | */ |
64 | private $security; |
65 | |
66 | private bool $activeNotifications; |
67 | |
68 | /** |
69 | * UserType constructor. |
70 | */ |
71 | public function __construct( |
72 | AuthorizationCheckerInterface $authorizationChecker, |
73 | EncoderFactoryInterface $encoderFactory, |
74 | Security $security, |
75 | bool $activeNotifications, |
76 | ) { |
77 | $this->authorizationChecker = $authorizationChecker; |
78 | $this->encoderFactory = $encoderFactory; |
79 | $this->security = $security; |
80 | $this->activeNotifications = $activeNotifications; |
81 | } |
82 | |
83 | /** |
84 | * Build type form. |
85 | */ |
86 | public function buildForm(FormBuilderInterface $builder, array $options) |
87 | { |
88 | if (array_key_exists('data', $options)) { |
89 | // Role est mono-valué dans le form, j'enleve ROLE_API |
90 | $options['data']->setRoles(array_diff($options['data']->getRoles(), ['ROLE_API'])); |
91 | } |
92 | |
93 | $collectivity = $options['data']->getCollectivity(); |
94 | $serviceDisabled = !$collectivity->getIsServicesEnabled(); |
95 | /** @var User $authenticatedUser */ |
96 | $authenticatedUser = $this->security->getUser(); |
97 | |
98 | $encoderFactory = $this->encoderFactory; |
99 | |
100 | // Add collectivity general information only for admins |
101 | if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) { |
102 | $builder |
103 | ->add('collectivity', EntityType::class, [ |
104 | 'class' => Collectivity::class, |
105 | 'label' => 'global.label.organization', |
106 | 'query_builder' => function (EntityRepository $er) { |
107 | return $er->createQueryBuilder('c') |
108 | ->orderBy('c.name', 'ASC'); |
109 | }, |
110 | 'required' => true, |
111 | 'attr' => [ |
112 | 'autocomplete' => 'organization', |
113 | ], |
114 | ]) |
115 | ->add('roles', DictionaryType::class, [ |
116 | 'label' => 'user.user.label.roles', |
117 | 'required' => true, |
118 | 'name' => 'user_user_role', |
119 | 'multiple' => false, |
120 | 'expanded' => true, |
121 | ]) |
122 | ->add('apiAuthorized', CheckboxType::class, [ |
123 | 'label' => 'user.user.label.apiAuthorized', |
124 | 'required' => false, |
125 | ]) |
126 | |
127 | ->add('enabled', CheckboxType::class, [ |
128 | 'label' => 'user.user.label.enabled', |
129 | 'required' => false, |
130 | ]) |
131 | ->add('collectivitesReferees', EntityType::class, [ |
132 | 'class' => Collectivity::class, |
133 | 'label' => 'user.user.label.collectivitesReferees', |
134 | 'query_builder' => function (EntityRepository $er) { |
135 | return $er->createQueryBuilder('c') |
136 | ->orderBy('c.name', 'ASC'); |
137 | }, |
138 | 'required' => false, |
139 | 'multiple' => true, |
140 | 'expanded' => false, |
141 | 'attr' => [ |
142 | 'class' => 'selectpicker', |
143 | 'title' => 'global.placeholder.multiple_select', |
144 | 'data-live-search' => true, |
145 | 'aria-label' => 'Structures rattachées', |
146 | 'autocomplete' => 'organization', |
147 | ], |
148 | ]) |
149 | ->add('ssoKey', TextType::class, [ |
150 | 'label' => 'user.user.label.sso_key', |
151 | 'required' => false, |
152 | 'attr' => [ |
153 | 'maxlength' => 255, |
154 | ], |
155 | 'purify_html' => true, |
156 | ]); |
157 | |
158 | $builder |
159 | ->get('roles') |
160 | ->addModelTransformer(new RoleTransformer()); |
161 | } |
162 | |
163 | $formModifier = function (FormInterface $form, Collectivity $collectivity) use ($serviceDisabled, $authenticatedUser) { |
164 | $queryBuilder = function (EntityRepository $er) use ($serviceDisabled, $authenticatedUser, $collectivity) { |
165 | if ($serviceDisabled) { |
166 | return $er->createQueryBuilder('s') |
167 | ->where(':user MEMBER OF s.users') |
168 | ->setParameter(':user', $authenticatedUser) |
169 | ->orderBy('s.name', 'ASC'); |
170 | } |
171 | |
172 | return $er->createQueryBuilder('s') |
173 | ->where('s.collectivity = :collectivity') |
174 | ->setParameter(':collectivity', $collectivity) |
175 | ->orderBy('s.name', 'ASC'); |
176 | }; |
177 | |
178 | if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) { |
179 | $form->add('services', EntityType::class, [ |
180 | 'class' => Service::class, |
181 | 'label' => 'user.user.label.services', |
182 | 'disabled' => $serviceDisabled, |
183 | 'required' => false, |
184 | 'multiple' => true, |
185 | 'expanded' => false, |
186 | 'query_builder' => $queryBuilder, |
187 | ]); |
188 | } else { |
189 | $form->add('services', EntityType::class, [ |
190 | 'class' => Service::class, |
191 | 'label' => 'user.user.label.services', |
192 | 'disabled' => true, |
193 | 'required' => false, |
194 | 'multiple' => true, |
195 | 'expanded' => false, |
196 | 'query_builder' => $queryBuilder, |
197 | 'attr' => [ |
198 | 'readonly' => true, ], |
199 | ]); |
200 | } |
201 | }; |
202 | |
203 | if ($this->authorizationChecker->isGranted('ROLE_PREVIEW') && !$serviceDisabled) { |
204 | $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formModifier) { |
205 | $formModifier($event->getForm(), $event->getData()->getCollectivity()); |
206 | }); |
207 | $builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) use ($formModifier) { |
208 | $formModifier($event->getForm(), $event->getData()->getCollectivity()); |
209 | }); |
210 | } |
211 | |
212 | // Now add standard information |
213 | $builder |
214 | ->add('firstName', TextType::class, [ |
215 | 'label' => 'global.label.contact.first_name', |
216 | 'required' => true, |
217 | 'attr' => [ |
218 | 'maxlength' => 255, |
219 | 'autocomplete' => 'given-name', |
220 | ], |
221 | 'purify_html' => true, |
222 | ]) |
223 | ->add('lastName', TextType::class, [ |
224 | 'label' => 'global.label.contact.last_name', |
225 | 'required' => true, |
226 | 'attr' => [ |
227 | 'maxlength' => 255, |
228 | 'autocomplete' => 'family-name', |
229 | ], |
230 | 'purify_html' => true, |
231 | ]) |
232 | ->add('email', EmailType::class, [ |
233 | 'label' => 'global.label.contact.email', |
234 | 'required' => true, |
235 | 'attr' => [ |
236 | 'maxlength' => 255, |
237 | 'autocomplete' => 'email', |
238 | ], |
239 | ]) |
240 | ->add('moreInfos', DictionaryType::class, [ |
241 | 'label' => 'user.user.label.moreInfos', |
242 | 'required' => false, |
243 | 'name' => 'user_user_moreInfo', |
244 | 'multiple' => false, |
245 | 'expanded' => true, |
246 | 'placeholder' => 'Aucune information', |
247 | ]) |
248 | ->add('plainPassword', RepeatedType::class, [ |
249 | 'type' => PasswordType::class, |
250 | 'first_options' => [ |
251 | 'label' => 'user.security.label.password', |
252 | 'attr' => [ |
253 | 'maxlength' => 255, |
254 | ], |
255 | ], |
256 | 'second_options' => [ |
257 | 'label' => 'user.security.label.password_repeat', |
258 | 'attr' => [ |
259 | 'maxlength' => 255, |
260 | ], |
261 | ], |
262 | 'required' => false, |
263 | ]) |
264 | ; |
265 | |
266 | if ($this->activeNotifications) { |
267 | $builder->add('emailNotificationPreference', EmailNotificationPreferenceType::class); |
268 | if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) { |
269 | $builder->add('notGeneratesNotifications', CheckboxType::class, [ |
270 | 'label' => 'notifications.label.not_generates_notifications', |
271 | 'required' => false, |
272 | ]); |
273 | } |
274 | } |
275 | |
276 | $builder |
277 | ->get('moreInfos') |
278 | ->addModelTransformer(new MoreInfoTransformer()) |
279 | ; |
280 | |
281 | $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use ($encoderFactory) { |
282 | $user = $event->getData(); |
283 | if (null === $user->getPlainPassword() || !$event->getForm()->isValid()) { |
284 | return; |
285 | } |
286 | |
287 | $encoder = $encoderFactory->getEncoder($user); |
288 | $user->setPassword($encoder->encodePassword($user->getPlainPassword(), '')); // No salt with bcrypt |
289 | |
290 | $user->eraseCredentials(); |
291 | }); |
292 | } |
293 | |
294 | /** |
295 | * Provide type options. |
296 | */ |
297 | public function configureOptions(OptionsResolver $resolver) |
298 | { |
299 | $resolver |
300 | ->setDefaults([ |
301 | 'data_class' => User::class, |
302 | 'validation_groups' => [ |
303 | 'default', |
304 | 'user', |
305 | ], |
306 | ]); |
307 | } |
308 | } |