Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
6.88% |
15 / 218 |
|
35.29% |
6 / 17 |
CRAP | |
0.00% |
0 / 1 |
ReferentielController | |
6.88% |
15 / 218 |
|
35.29% |
6 / 17 |
1680.10 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
getDomain | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getModel | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getModelClass | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getFormType | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
createAction | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
12 | |||
editAction | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
duplicateAction | |
0.00% |
0 / 39 |
|
0.00% |
0 / 1 |
42 | |||
formPrePersistData | |
0.00% |
0 / 40 |
|
0.00% |
0 / 1 |
110 | |||
listAction | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
listDataTables | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
6 | |||
generateActionCellContent | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
6 | |||
getLabelAndKeysArray | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
rightsAction | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
20 | |||
exportAction | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
6 | |||
importAction | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
20 | |||
formatToFileCompliant | |
0.00% |
0 / 8 |
|
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\Domain\Maturity\Controller; |
25 | |
26 | use App\Application\Controller\CRUDController; |
27 | use App\Application\Symfony\Security\UserProvider; |
28 | use App\Application\Traits\ServersideDatatablesTrait; |
29 | use App\Domain\Maturity\Form\Type\ImportModeleType; |
30 | use App\Domain\Maturity\Form\Type\ModeleReferentielRightsType; |
31 | use App\Domain\Maturity\Form\Type\ReferentielType; |
32 | use App\Domain\Maturity\Model; |
33 | use App\Domain\Maturity\Repository; |
34 | use Doctrine\ORM\EntityManagerInterface; |
35 | use JMS\Serializer\SerializerBuilder; |
36 | use Knp\Snappy\Pdf; |
37 | use Symfony\Component\HttpFoundation\JsonResponse; |
38 | use Symfony\Component\HttpFoundation\Request; |
39 | use Symfony\Component\HttpFoundation\Response; |
40 | use Symfony\Component\HttpFoundation\ResponseHeaderBag; |
41 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
42 | use Symfony\Component\Routing\RouterInterface; |
43 | use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; |
44 | use Symfony\Contracts\Translation\TranslatorInterface; |
45 | |
46 | /** |
47 | * @property Repository\Referentiel $repository |
48 | */ |
49 | class ReferentielController extends CRUDController |
50 | { |
51 | use ServersideDatatablesTrait; |
52 | |
53 | /** |
54 | * @var AuthorizationCheckerInterface |
55 | */ |
56 | protected $authorizationChecker; |
57 | |
58 | /** |
59 | * @var UserProvider |
60 | */ |
61 | protected $userProvider; |
62 | |
63 | protected RouterInterface $router; |
64 | |
65 | public function __construct( |
66 | EntityManagerInterface $entityManager, |
67 | TranslatorInterface $translator, |
68 | Repository\Referentiel $repository, |
69 | AuthorizationCheckerInterface $authorizationChecker, |
70 | UserProvider $userProvider, |
71 | RouterInterface $router, |
72 | Pdf $pdf, |
73 | ) { |
74 | parent::__construct($entityManager, $translator, $repository, $pdf, $userProvider, $authorizationChecker); |
75 | $this->authorizationChecker = $authorizationChecker; |
76 | $this->userProvider = $userProvider; |
77 | $this->router = $router; |
78 | } |
79 | |
80 | protected function getDomain(): string |
81 | { |
82 | return 'maturity'; |
83 | } |
84 | |
85 | protected function getModel(): string |
86 | { |
87 | return 'referentiel'; |
88 | } |
89 | |
90 | protected function getModelClass(): string |
91 | { |
92 | return Model\Referentiel::class; |
93 | } |
94 | |
95 | protected function getFormType(): string |
96 | { |
97 | return ReferentielType::class; |
98 | } |
99 | |
100 | /** |
101 | * {@inheritdoc} |
102 | * Override method in order to hydrate survey answers. |
103 | */ |
104 | public function createAction(Request $request): Response |
105 | { |
106 | /** |
107 | * @var Model\Referentiel |
108 | */ |
109 | $modelClass = $this->getModelClass(); |
110 | $object = new $modelClass(); |
111 | |
112 | $form = $this->createForm($this->getFormType(), $object); |
113 | |
114 | $form->handleRequest($request); |
115 | if ($form->isSubmitted() && $form->isValid()) { |
116 | $this->formPrePersistData($object); |
117 | $this->entityManager->persist($object); |
118 | $this->entityManager->flush(); |
119 | |
120 | $this->addFlash('success', $this->getFlashbagMessage('success', 'create', $object->getName())); |
121 | |
122 | return $this->redirectToRoute($this->getRouteName('list')); |
123 | } |
124 | |
125 | return $this->render($this->getTemplatingBasePath('create'), [ |
126 | 'form' => $form->createView(), |
127 | ]); |
128 | } |
129 | |
130 | public function editAction(Request $request, string $id): Response |
131 | { |
132 | /** @var Model\Referentiel $object */ |
133 | $object = $this->repository->findOneById($id); |
134 | if (!$object) { |
135 | throw new NotFoundHttpException("No object found with ID '{$id}'"); |
136 | } |
137 | |
138 | $sections = $this->entityManager->getRepository(Model\Domain::class)->findBy(['referentiel' => $object]); |
139 | |
140 | $form = $this->createForm($this->getFormType(), $object, ['validation_groups' => ['default', $this->getModel(), 'edit']]); |
141 | |
142 | $form->handleRequest($request); |
143 | if ($form->isSubmitted() && $form->isValid()) { |
144 | $this->formPrePersistData($object); |
145 | $this->entityManager->persist($object); |
146 | $this->entityManager->flush(); |
147 | |
148 | $this->addFlash('success', $this->getFlashbagMessage('success', 'edit', $object)); |
149 | |
150 | return $this->redirectToRoute($this->getRouteName('list')); |
151 | } |
152 | |
153 | return $this->render($this->getTemplatingBasePath('edit'), [ |
154 | 'form' => $form->createView(), |
155 | ]); |
156 | } |
157 | |
158 | public function duplicateAction(Request $request, string $id): Response |
159 | { |
160 | /** @var Model\Referentiel $object */ |
161 | $object = $this->repository->findOneById($id); |
162 | if (!$object) { |
163 | throw new NotFoundHttpException("No object found with ID '{$id}'"); |
164 | } |
165 | |
166 | $newRef = new Model\Referentiel(); |
167 | |
168 | $newRef->setName($object->getName()); |
169 | $newRef->setDescription($object->getDescription()); |
170 | |
171 | $newRef->setAuthorizedCollectivities($object->getAuthorizedCollectivities()); |
172 | |
173 | $newRef->setAuthorizedCollectivityTypes($object->getAuthorizedCollectivityTypes()); |
174 | $newRef->setOptionRightSelection($newRef->getOptionRightSelection()); |
175 | |
176 | /** @var Model\Domain $domain */ |
177 | foreach ($object->getDomains() as $domain) { |
178 | $d = new Model\Domain(); |
179 | $d->setName($domain->getName()); |
180 | $d->setDescription($domain->getDescription()); |
181 | $d->setReferentiel($newRef); |
182 | $d->setColor($domain->getColor()); |
183 | $d->setPosition($domain->getPosition()); |
184 | |
185 | $this->entityManager->persist($d); |
186 | /** @var Model\Question $q */ |
187 | foreach ($domain->getQuestions() as $q) { |
188 | $newQ = new Model\Question(); |
189 | $newQ->setPosition($q->getPosition()); |
190 | $newQ->setName($q->getName()); |
191 | $newQ->setOptional($q->getOptional()); |
192 | if ($q->getOptional()) { |
193 | $newQ->setOptionReason($q->getOptionReason()); |
194 | } |
195 | $newQ->setWeight($q->getWeight()); |
196 | $newQ->setDomain($d); |
197 | $this->entityManager->persist($newQ); |
198 | /** @var Model\Answer $a */ |
199 | foreach ($q->getAnswers() as $a) { |
200 | $newA = new Model\Answer(); |
201 | $newA->setName($a->getName()); |
202 | $newA->setPosition($a->getPosition()); |
203 | $newA->setRecommendation($a->getRecommendation()); |
204 | $newA->setResponse($a->getResponse()); |
205 | $newA->setQuestion($newQ); |
206 | $this->entityManager->persist($newA); |
207 | } |
208 | } |
209 | } |
210 | |
211 | $this->entityManager->persist($newRef); |
212 | $this->entityManager->flush(); |
213 | |
214 | $this->addFlash('success', $this->getFlashbagMessage('success', 'duplicate', $object)); |
215 | |
216 | return $this->redirectToRoute($this->getRouteName('edit'), ['id' => $newRef->getId()->toString()]); |
217 | } |
218 | |
219 | public function formPrePersistData($object, $form = null) |
220 | { |
221 | $domains = []; |
222 | |
223 | $colors = [ |
224 | 'info', |
225 | 'success', |
226 | 'primary', |
227 | 'warning', |
228 | ]; |
229 | |
230 | // get all existing domains |
231 | $toRemove = $this->entityManager->getRepository(Model\Domain::class)->findBy(['referentiel' => $object]); |
232 | |
233 | foreach ($object->getDomains() as $k => $domain) { |
234 | $key = array_search($domain, $toRemove); |
235 | if (false !== $key) { |
236 | unset($toRemove[$key]); |
237 | } |
238 | /* @var Model\Domain $domain */ |
239 | // $domain->setPosition($k); |
240 | $domain->setColor($colors[$k % 4]); |
241 | |
242 | // get all existing questions |
243 | $toRemoveQuestions = $this->entityManager->getRepository(Model\Question::class)->findBy(['domain' => $domain]); |
244 | |
245 | $questions = []; |
246 | foreach ($domain->getQuestions() as $n => $question) { |
247 | /** @var Model\Question $question */ |
248 | $key = array_search($question, $toRemoveQuestions); |
249 | if (false !== $key) { |
250 | unset($toRemoveQuestions[$key]); |
251 | } |
252 | |
253 | // $question->setPosition($n); |
254 | $question->setDomain($domain); |
255 | // get all existing Answers |
256 | $toRemoveAnswers = $this->entityManager->getRepository(Model\Answer::class)->findBy(['question' => $question]); |
257 | $answers = []; |
258 | foreach ($question->getAnswers() as $l => $answer) { |
259 | /** @var Model\Answer $answer */ |
260 | $key = array_search($answer, $toRemoveAnswers); |
261 | if (false !== $key) { |
262 | unset($toRemoveAnswers[$key]); |
263 | } |
264 | // $answer->setPosition($l); |
265 | $answer->setQuestion($question); |
266 | $answers[] = $answer; |
267 | } |
268 | |
269 | foreach ($toRemoveAnswers as $removing) { |
270 | $this->entityManager->remove($removing); |
271 | } |
272 | |
273 | $question->setAnswers($answers); |
274 | |
275 | $questions[] = $question; |
276 | } |
277 | foreach ($toRemoveQuestions as $removing) { |
278 | $this->entityManager->remove($removing); |
279 | } |
280 | $domain->setQuestions($questions); |
281 | $domain->setReferentiel($object); |
282 | |
283 | $domains[] = $domain; |
284 | } |
285 | // Remove deleted domains |
286 | foreach ($toRemove as $removing) { |
287 | $this->entityManager->remove($removing); |
288 | } |
289 | |
290 | $object->setDomains($domains); |
291 | } |
292 | |
293 | /** |
294 | * The list action view |
295 | * Get data & display them. |
296 | */ |
297 | public function listAction(): Response |
298 | { |
299 | return $this->render('Maturity/Referentiel/list.html.twig', [ |
300 | 'totalItem' => $this->repository->count(), |
301 | 'route' => $this->router->generate('maturity_referentiel_list_datatables'), |
302 | ]); |
303 | } |
304 | |
305 | public function listDataTables(Request $request): JsonResponse |
306 | { |
307 | $referentiels = $this->getResults($request); |
308 | $reponse = $this->getBaseDataTablesResponse($request, $referentiels); |
309 | |
310 | foreach ($referentiels as $referentiel) { |
311 | $reponse['data'][] = [ |
312 | 'name' => $referentiel->getName(), |
313 | 'description' => $referentiel->getDescription(), |
314 | 'createdAt' => date_format($referentiel->getCreatedAt(), 'd-m-Y H:i'), |
315 | 'updatedAt' => date_format($referentiel->getUpdatedAt(), 'd-m-Y H:i'), |
316 | 'actions' => $this->generateActionCellContent($referentiel), |
317 | ]; |
318 | } |
319 | |
320 | $reponse['recordsTotal'] = count($reponse['data']); |
321 | $reponse['recordsFiltered'] = count($reponse['data']); |
322 | |
323 | return new JsonResponse($reponse); |
324 | } |
325 | |
326 | private function generateActionCellContent(Model\Referentiel $referentiel) |
327 | { |
328 | $id = $referentiel->getId(); |
329 | $htmltoReturnIfAdmin = ''; |
330 | |
331 | if ($this->authorizationChecker->isGranted('ROLE_ADMIN')) { |
332 | $htmltoReturnIfAdmin = '<a href="' . $this->router->generate('maturity_referentiel_rights', ['id' => $id]) . '"> |
333 | <i aria-hidden="true" class="fa fa-user-shield"></i> ' |
334 | . $this->translator->trans('global.action.rights') . |
335 | '</a>'; |
336 | } |
337 | |
338 | return |
339 | '<a href="' . $this->router->generate('maturity_referentiel_edit', ['id' => $id]) . '"> |
340 | <i aria-hidden="true" class="fa fa-pencil"></i> ' |
341 | . $this->translator->trans('global.action.edit') . |
342 | '</a>' |
343 | . $htmltoReturnIfAdmin . |
344 | '<a href="' . $this->router->generate('maturity_referentiel_duplicate', ['id' => $id]) . '"> |
345 | <i aria-hidden="true" class="fa fa-clone"></i> ' . |
346 | $this->translator->trans('global.action.duplicate') . |
347 | '</a>' . |
348 | '<a href="' . $this->router->generate('maturity_referentiel_export', ['id' => $id]) . '"> |
349 | <i aria-hidden="true" class="fa fa-file-code"></i> ' . |
350 | $this->translator->trans('global.action.export') . |
351 | '</a>' . |
352 | '<a href="' . $this->router->generate('maturity_referentiel_delete', ['id' => $id]) . '"> |
353 | <i aria-hidden="true" class="fa fa-trash"></i> ' . |
354 | $this->translator->trans('global.action.delete') . |
355 | '</a>'; |
356 | } |
357 | |
358 | protected function getLabelAndKeysArray(): array |
359 | { |
360 | return [ |
361 | '0' => 'name', |
362 | '1' => 'description', |
363 | '2' => 'createdAt', |
364 | '3' => 'updatedAt', |
365 | '4' => 'actions', |
366 | ]; |
367 | } |
368 | |
369 | public function rightsAction(Request $request, string $id): Response |
370 | { |
371 | $object = $this->repository->findOneById($id); |
372 | if (!$object) { |
373 | throw new NotFoundHttpException("No object found with ID '{$id}'"); |
374 | } |
375 | $form = $this->createForm(ModeleReferentielRightsType::class, $object); |
376 | |
377 | $form->handleRequest($request); |
378 | |
379 | if ($form->isSubmitted() && $form->isValid()) { |
380 | $this->formPrePersistData($object); |
381 | $this->entityManager->persist($object); |
382 | $this->entityManager->flush(); |
383 | |
384 | $this->addFlash('success', $this->getFlashbagMessage('success', 'rights', $object)); |
385 | |
386 | return $this->redirectToRoute($this->getRouteName('list')); |
387 | } |
388 | |
389 | return $this->render('Maturity/Referentiel/rights.html.twig', [ |
390 | 'form' => $form->createView(), |
391 | ]); |
392 | } |
393 | |
394 | public function exportAction(string $id) |
395 | { |
396 | $object = $this->repository->findOneById($id); |
397 | if (!$object) { |
398 | throw new NotFoundHttpException("No object found with ID '{$id}'"); |
399 | } |
400 | /** @var Model\Referentiel $toExport */ |
401 | $toExport = clone $object; |
402 | |
403 | $serializer = SerializerBuilder::create()->build(); |
404 | $xml = $serializer->serialize($toExport, 'xml'); |
405 | |
406 | $response = new Response($xml); |
407 | $disposition = $response->headers->makeDisposition( |
408 | ResponseHeaderBag::DISPOSITION_ATTACHMENT, |
409 | self::formatToFileCompliant($object->getName()) . '.xml' |
410 | ); |
411 | |
412 | $response->headers->set('Content-Disposition', $disposition); |
413 | |
414 | return $response; |
415 | } |
416 | |
417 | public function importAction(Request $request) |
418 | { |
419 | $form = $this->createForm(ImportModeleType::class); |
420 | $form->handleRequest($request); |
421 | if ($form->isSubmitted() && $form->isValid()) { |
422 | $content = file_get_contents($form->getData()['file']->getPathname()); |
423 | $serializer = SerializerBuilder::create()->build(); |
424 | /* @var Model\Referentiel $object */ |
425 | |
426 | try { |
427 | $object = $serializer->deserialize($content, Model\Referentiel::class, 'xml'); |
428 | $object->deserialize(); |
429 | } catch (\Exception $e) { |
430 | $this->addFlash('danger', "Impossible d'importer ce fichier"); |
431 | |
432 | return $this->redirectToRoute($this->getRouteName('list')); |
433 | } |
434 | // $object->setDomains($domain); |
435 | |
436 | $object->setCreatedAt(new \DateTimeImmutable()); |
437 | $object->setName('(import) ' . $object->getName()); |
438 | $this->entityManager->persist($object); |
439 | $this->entityManager->flush(); |
440 | $this->addFlash('success', $this->getFlashbagMessage('success', 'import', $object)); |
441 | |
442 | return $this->redirectToRoute($this->getRouteName('list')); |
443 | } |
444 | |
445 | return $this->render($this->getTemplatingBasePath('import'), [ |
446 | 'form' => $form->createView(), |
447 | ]); |
448 | } |
449 | |
450 | private static function formatToFileCompliant(string $string) |
451 | { |
452 | $unwanted_array = [ |
453 | 'Š' => 'S', 'š' => 's', 'Ž' => 'Z', 'ž' => 'z', 'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A', 'Å' => 'A', 'Æ' => 'A', 'Ç' => 'C', 'È' => 'E', 'É' => 'E', |
454 | 'Ê' => 'E', 'Ë' => 'E', 'Ì' => 'I', 'Í' => 'I', 'Î' => 'I', 'Ï' => 'I', 'Ñ' => 'N', 'Ò' => 'O', 'Ó' => 'O', 'Ô' => 'O', 'Õ' => 'O', 'Ö' => 'O', 'Ø' => 'O', 'Ù' => 'U', |
455 | 'Ú' => 'U', 'Û' => 'U', 'Ü' => 'U', 'Ý' => 'Y', 'Þ' => 'B', 'ß' => 'Ss', 'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a', 'ä' => 'a', 'å' => 'a', 'æ' => 'a', 'ç' => 'c', |
456 | 'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e', 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ð' => 'o', 'ñ' => 'n', 'ò' => 'o', 'ó' => 'o', 'ô' => 'o', 'õ' => 'o', |
457 | 'ö' => 'o', 'ø' => 'o', 'ù' => 'u', 'ú' => 'u', 'û' => 'u', 'ý' => 'y', 'þ' => 'b', 'ÿ' => 'y', |
458 | ]; |
459 | |
460 | return strtr($string, $unwanted_array); |
461 | } |
462 | } |