Passed
Push — master ( 5fc2ed...cfc9ff )
by Marcel
05:20
created

SettingsController::substitutions()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 93
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 67
c 0
b 0
f 0
nc 3
nop 3
dl 0
loc 93
ccs 0
cts 51
cp 0
crap 20
rs 8.72

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace App\Controller;
4
5
use Symfony\Component\HttpFoundation\Response;
6
use App\Converter\EnumStringConverter;
7
use App\Entity\AppointmentCategory;
8
use App\Entity\Grade;
9
use App\Entity\Section;
10
use App\Entity\UserType;
11
use App\Form\ColorType;
12
use App\Form\ExamStudentRuleType;
13
use App\Form\MarkdownType;
14
use App\Menu\Builder;
15
use App\Repository\AppointmentCategoryRepositoryInterface;
16
use App\Repository\GradeRepositoryInterface;
17
use App\Repository\SectionRepositoryInterface;
18
use App\Settings\AppointmentsSettings;
19
use App\Settings\BookSettings;
20
use App\Settings\DashboardSettings;
21
use App\Settings\ExamSettings;
22
use App\Settings\GeneralSettings;
23
use App\Settings\ImportSettings;
24
use App\Settings\NotificationSettings;
25
use App\Settings\StudentAbsenceSettings;
26
use App\Settings\SubstitutionSettings;
27
use App\Settings\TimetableSettings;
28
use App\Sorting\GradeNameStrategy;
29
use App\Sorting\Sorter;
30
use App\Utils\ArrayUtils;
31
use DateTime;
32
use SchulIT\CommonBundle\Helper\DateHelper;
33
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
34
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, App\Controller\AbstractController. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
35
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
36
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
37
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
38
use Symfony\Component\Form\Extension\Core\Type\DateType;
39
use Symfony\Component\Form\Extension\Core\Type\EmailType;
40
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
41
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
42
use Symfony\Component\Form\Extension\Core\Type\TextType;
43
use Symfony\Component\Form\Extension\Core\Type\TimeType;
44
use Symfony\Component\HttpFoundation\Request;
45
use Symfony\Component\Routing\Annotation\Route;
46
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
47
use Symfony\Component\Validator\Constraints\NotBlank;
48
use Symfony\Component\Validator\Constraints\Type;
49
use Symfony\Contracts\Translation\TranslatorInterface;
50
51
#[Route(path: '/admin/settings')]
52
#[Security("is_granted('ROLE_ADMIN')")]
53
class SettingsController extends AbstractController {
54
55
    #[Route(path: '', name: 'admin_settings')]
56
    public function index(): Response {
57
        return $this->redirectToRoute('admin_settings_general');
58
    }
59
60
    #[Route(path: '/general', name: 'admin_settings_general')]
61
    public function general(Request $request, GeneralSettings $settings, DateHelper $dateHelper, SectionRepositoryInterface $sectionRepository): Response {
62
        $currentYear = (int)$dateHelper->getToday()->format('Y');
63
        $choices = [ ];
64
        for($year = $currentYear - 1; $year <= $currentYear + 1; $year++) {
65
            $choices[sprintf('%d/%d', $year, $year+1)] = $year;
66
        }
67
68
        $builder = $this->createFormBuilder();
69
        $builder
70
            ->add('current_section', ChoiceType::class,  [
71
                'choices' => ArrayUtils::createArrayWithKeysAndValues(
72
                    $sectionRepository->findAll(),
73
                    fn(Section $section) => $section->getDisplayName(),
74
                    fn(Section $section) => $section->getId()
75
                ),
76
                'data' => $settings->getCurrentSectionId(),
77
                'label' => 'admin.settings.general.current_section.label',
78
                'help' => 'admin.settings.general.current_section.help'
79
            ]);
80
        $form = $builder->getForm();
81
        $form->handleRequest($request);
82
83
        if($form->isSubmitted() && $form->isValid()) {
84
            $map = [
85
                'current_section' => function($sectionId) use ($settings) {
86
                    $settings->setCurrentSectionId($sectionId);
87
                }
88
            ];
89
90
            foreach($map as $formKey => $callable) {
91
                $value = $form->get($formKey)->getData();
92
                $callable($value);
93
            }
94
95
            $this->addFlash('success', 'admin.settings.success');
96
97
            return $this->redirectToRoute('admin_settings_general');
98
        }
99
100
        return $this->render('admin/settings/general.html.twig', [
101
            'form' => $form->createView()
102
        ]);
103
    }
104
105
    #[Route(path: '/dashboard', name: 'admin_settings_dashboard')]
106
    public function dashboard(Request $request, DashboardSettings $dashboardSettings): Response {
107
        $builder = $this->createFormBuilder();
108
        $builder
109
            ->add('removable_types', TextType::class, [
110
                'label' => 'admin.settings.dashboard.removable_substitutions.label',
111
                'help' => 'admin.settings.dashboard.removable_substitutions.help',
112
                'data' => implode(',', $dashboardSettings->getRemovableSubstitutionTypes()),
113
                'required' => false
114
            ])
115
            ->add('additional_types', TextType::class, [
116
                'label' => 'admin.settings.dashboard.additional_substitutions.label',
117
                'help' => 'admin.settings.dashboard.additional_substitutions.help',
118
                'data' => implode(',', $dashboardSettings->getAdditionalSubstitutionTypes()),
119
                'required' => false
120
            ])
121
            ->add('free_lesson_types', TextType::class, [
122
                'label' => 'admin.settings.dashboard.free_lesson_types.label',
123
                'help' => 'admin.settings.dashboard.free_lesson_types.help',
124
                'data' => implode(',', $dashboardSettings->getFreeLessonSubstitutionTypes()),
125
                'required' => false
126
            ])
127
            ->add('next_day_threshold', TimeType::class, [
128
                'label' => 'admin.settings.dashboard.next_day_threshold.label',
129
                'help' => 'admin.settings.dashboard.next_day_threshold.help',
130
                'data' => $dashboardSettings->getNextDayThresholdTime(),
131
                'required' => false,
132
                'input' => 'string',
133
                'input_format' => 'H:i',
134
                'widget' => 'single_text'
135
            ])
136
            ->add('skip_weekends', CheckboxType::class, [
137
                'label' => 'admin.settings.dashboard.skip_weekends.label',
138
                'help' => 'admin.settings.dashboard.skip_weekends.help',
139
                'required' => false,
140
                'data' => $dashboardSettings->skipWeekends(),
141
                'label_attr' => [
142
                    'class' => 'checkbox-custom'
143
                ]
144
            ])
145
            ->add('past_days', IntegerType::class, [
146
                'label' => 'admin.settings.dashboard.past_days.label',
147
                'help' => 'admin.settings.dashboard.past_days.label',
148
                'required' => true,
149
                'data' => $dashboardSettings->getNumberPastDays(),
150
                'constraints' => [
151
                    new GreaterThanOrEqual(0)
152
                ]
153
            ])
154
            ->add('future_days', IntegerType::class, [
155
                'label' => 'admin.settings.dashboard.future_days.label',
156
                'help' => 'admin.settings.dashboard.future_days.label',
157
                'required' => true,
158
                'data' => $dashboardSettings->getNumberFutureDays(),
159
                'constraints' => [
160
                    new GreaterThanOrEqual(0)
161
                ]
162
            ]);
163
164
        $form = $builder->getForm();
165
        $form->handleRequest($request);
166
167
        if($form->isSubmitted() && $form->isValid()) {
168
            $map = [
169
                'removable_types' => function($types) use ($dashboardSettings) {
170
                    $dashboardSettings->setRemovableSubstitutionTypes(explode(',', $types));
171
                },
172
                'additional_types' => function($types) use ($dashboardSettings) {
173
                    $dashboardSettings->setAdditionalSubstitutionTypes(explode(',', $types));
174
                },
175
                'free_lesson_types' => function($types) use ($dashboardSettings) {
176
                    $dashboardSettings->setFreeLessonSubstitutionTypes(explode(',', $types));
177
                },
178
                'next_day_threshold' => function($threshold) use ($dashboardSettings) {
179
                    $dashboardSettings->setNextDayThresholdTime($threshold);
180
                },
181
                'skip_weekends' => function($skipWeekends) use ($dashboardSettings) {
182
                    $dashboardSettings->setSkipWeekends($skipWeekends);
183
                },
184
                'past_days' => function($days) use ($dashboardSettings) {
185
                    $dashboardSettings->setNumberPastDays($days);
186
                },
187
                'future_days' => function($days) use ($dashboardSettings) {
188
                    $dashboardSettings->setNumberFutureDays($days);
189
                }
190
            ];
191
192
            foreach($map as $formKey => $callable) {
193
                $value = $form->get($formKey)->getData();
194
                $callable($value);
195
            }
196
197
            $this->addFlash('success', 'admin.settings.success');
198
199
            return $this->redirectToRoute('admin_settings_dashboard');
200
        }
201
202
        return $this->render('admin/settings/dashboard.html.twig', [
203
            'form' => $form->createView()
204
        ]);
205
    }
206
207
    #[Route(path: '/notifications', name: 'admin_settings_notifications')]
208
    public function notifications(Request $request, NotificationSettings $notificationSettings, EnumStringConverter $enumStringConverter): Response {
209
        $builder = $this->createFormBuilder();
210
        $builder
211
            ->add('email_enabled', ChoiceType::class, [
212
                'choices' => ArrayUtils::createArray(array_map(fn(UserType $case) => $case->name, UserType::cases()), UserType::cases()),
0 ignored issues
show
Bug introduced by
The property name does not seem to exist on App\Entity\UserType.
Loading history...
213
                'choice_label' => fn(UserType $userType) => $enumStringConverter->convert($userType),
214
                'choice_value' => fn(UserType $userType) => $userType->value,
215
                'expanded' => true,
216
                'multiple' => true,
217
                'label' => 'admin.settings.notifications.email.label',
218
                'help' => 'admin.settings.notifications.email.help',
219
                'data' => $notificationSettings->getEmailEnabledUserTypes(),
220
                'label_attr' => [
221
                    'class' => 'checkbox-custom'
222
                ]
223
            ]);
224
225
        $form = $builder->getForm();
226
        $form->handleRequest($request);
227
228
        if($form->isSubmitted() && $form->isValid()) {
229
            $map = [
230
                'email_enabled' => function($types) use ($notificationSettings) {
231
                    $notificationSettings->setEmailEnabledUserTypes($types);
232
                }
233
            ];
234
235
            foreach($map as $formKey => $callable) {
236
                $value = $form->get($formKey)->getData();
237
                $callable($value);
238
            }
239
240
            $this->addFlash('success', 'admin.settings.success');
241
242
            return $this->redirectToRoute('admin_settings_notifications');
243
        }
244
245
        return $this->render('admin/settings/notifications.html.twig', [
246
            'form' => $form->createView()
247
        ]);
248
    }
249
250
    #[Route(path: '/absences', name: 'admin_settings_absences')]
251
    public function absences(Request $request, StudentAbsenceSettings $settings): Response {
252
        $builder = $this->createFormBuilder();
253
        $builder
254
            ->add('enabled', CheckboxType::class, [
255
                'required' => false,
256
                'data' => $settings->isEnabled(),
257
                'label' => 'admin.settings.student_absences.enabled',
258
                'label_attr' => [
259
                    'class' => 'checkbox-custom'
260
                ]
261
            ])
262
            ->add('recipient', EmailType::class, [
263
                'required' => false,
264
                'data' => $settings->getRecipient(),
265
                'label' => 'admin.settings.student_absences.recipient.label',
266
                'help' => 'admin.settings.student_absences.recipient.help'
267
            ])
268
            ->add('introduction_text', MarkdownType::class, [
269
                'required' => false,
270
                'data' => $settings->getIntroductionText(),
271
                'label' => 'admin.settings.student_absences.introduction_text.label',
272
                'help' => 'admin.settings.student_absences.introduction_text.help'
273
            ])
274
            ->add('privacy_url', TextType::class, [
275
                'required' => true,
276
                'data' => $settings->getPrivacyUrl(),
277
                'label' => 'admin.settings.student_absences.privacy_url.label',
278
                'help' => 'admin.settings.student_absences.privacy_url.help'
279
            ])
280
            ->add('retention_days', IntegerType::class, [
281
                'required' => true,
282
                'data' => $settings->getRetentionDays(),
283
                'label' => 'admin.settings.student_absences.retention_days.label',
284
                'help' => 'admin.settings.student_absences.retention_days.help',
285
                'constraints' => [
286
                    new GreaterThanOrEqual(0)
287
                ]
288
            ])
289
            ->add('next_day_threshold', TimeType::class, [
290
                'label' => 'admin.settings.dashboard.next_day_threshold.label',
291
                'help' => 'admin.settings.dashboard.next_day_threshold.help',
292
                'data' => $settings->getNextDayThresholdTime(),
293
                'required' => false,
294
                'input' => 'string',
295
                'input_format' => 'H:i',
296
                'widget' => 'single_text'
297
            ]);
298
299
        $form = $builder->getForm();
300
        $form->handleRequest($request);
301
302
        if($form->isSubmitted() && $form->isValid()) {
303
            $map = [
304
                'enabled' => function($enabled) use ($settings) {
305
                    $settings->setEnabled($enabled);
306
                },
307
                'recipient' => function($recipient) use ($settings) {
308
                    $settings->setRecipient($recipient);
309
                },
310
                'privacy_url' => function($url) use ($settings) {
311
                    $settings->setPrivacyUrl($url);
312
                },
313
                'retention_days' => function($days) use ($settings) {
314
                    $settings->setRetentionDays($days);
315
                },
316
                'introduction_text' => function($text) use ($settings) {
317
                    $settings->setIntroductionText($text);
318
                },
319
                'next_day_threshold' => function($threshold) use ($settings) {
320
                    $settings->setNextDayThresholdTime($threshold);
321
                },
322
            ];
323
324
            foreach($map as $formKey => $callable) {
325
                $value = $form->get($formKey)->getData();
326
                $callable($value);
327
            }
328
329
            $this->addFlash('success', 'admin.settings.success');
330
331
            return $this->redirectToRoute('admin_settings_absences');
332
        }
333
334
        return $this->render('admin/settings/absences.html.twig', [
335
            'form' => $form->createView()
336
        ]);
337
    }
338
339
    #[Route(path: '/exams', name: 'admin_settings_exams')]
340
    public function exams(Request $request, ExamSettings $examSettings, EnumStringConverter $enumStringConverter,
341
                          GradeRepositoryInterface $gradeRepository, Sorter $sorter): Response {
342
        $builder = $this->createFormBuilder();
343
        $builder
344
            ->add('visibility', ChoiceType::class, [
345
                'choices' => ArrayUtils::createArray(array_map(fn(UserType $case) => $case->name, UserType::cases()), UserType::cases()),
0 ignored issues
show
Bug introduced by
The property name does not seem to exist on App\Entity\UserType.
Loading history...
346
                'choice_label' => fn(UserType $userType) => $enumStringConverter->convert($userType),
347
                'choice_value' => fn(UserType $userType) => $userType->value,
348
                'expanded' => true,
349
                'multiple' => true,
350
                'label' => 'label.visibility',
351
                'data' => $examSettings->getVisibility(),
352
                'label_attr' => [
353
                    'class' => 'checkbox-custom'
354
                ]
355
            ])
356
            ->add('window', IntegerType::class, [
357
                'label' => 'admin.settings.exams.window.label',
358
                'help' => 'admin.settings.exams.window.help',
359
                'constraints' => [
360
                    new Type(['type' => 'integer']),
361
                    new GreaterThanOrEqual(['value' => 0])
362
                ],
363
                'data' => $examSettings->getTimeWindowForStudents()
364
            ])
365
            ->add('window_supervisions', IntegerType::class, [
366
                'label' => 'admin.settings.exams.window.supervisions.label',
367
                'help' => 'admin.settings.exams.window.supervisions.help',
368
                'constraints' => [
369
                    new Type(['type' => 'integer']),
370
                    new GreaterThanOrEqual(['value' => 0])
371
                ],
372
                'data' => $examSettings->getTimeWindowForStudentsToSeeSupervisions()
373
            ])
374
            ->add('notifications_enabled', CheckboxType::class, [
375
                'label' => 'admin.settings.exams.notifications.enabled.label',
376
                'help' => 'admin.settings.exams.notifications.enabled.help',
377
                'required' => false,
378
                'data' => $examSettings->isNotificationsEnabled(),
379
                'label_attr' => [
380
                    'class' => 'checkbox-custom'
381
                ]
382
            ])
383
            ->add('notifications_sender', TextType::class, [
384
                'label' => 'admin.settings.exams.notifications.sender.label',
385
                'help' => 'admin.settings.exams.notifications.sender.help',
386
                'required' => false,
387
                'data' => $examSettings->getNotificationSender()
388
            ])
389
            ->add('notifications_replyaddress', EmailType::class, [
390
                'label' => 'admin.settings.exams.notifications.reply_address.label',
391
                'help' => 'admin.settings.exams.notifications.reply_address.help',
392
                'required' => false,
393
                'data' => $examSettings->getNotificationReplyToAddress()
394
            ])
395
            ->add('number_of_exams_day', IntegerType::class, [
396
                'label' => 'admin.settings.exams.planning.number_of_exams_day.label',
397
                'help' => 'admin.settings.exams.planning.number_of_exams_day.help',
398
                'required' => true,
399
                'data' => $examSettings->getMaximumNumberOfExamsPerDay()
400
            ])
401
            ->add('visible_grades', ChoiceType::class, [
402
                'label' => 'admin.settings.exams.visible_grades.label',
403
                'help' => 'admin.settings.exams.visible_grades.help',
404
                'choices' => ArrayUtils::createArrayWithKeysAndValues($gradeRepository->findAll(), fn(Grade $grade) => $grade->getName(), fn(Grade $grade) => $grade->getId()),
405
                'multiple' => true,
406
                'expanded' => false,
407
                'attr' => [
408
                    'size' => 10
409
                ],
410
                'data' => $examSettings->getVisibleGradeIds()
411
            ]);
412
413
        $grades = $gradeRepository->findAll();
414
        $sorter->sort($grades, GradeNameStrategy::class);
415
416
        foreach($grades as $grade) {
417
            $builder->add(sprintf('number_of_exams_week_%d', $grade->getId()), IntegerType::class, [
418
                'label' => 'admin.settings.exams.planning.number_of_exams_week.label',
419
                'label_translation_parameters' => [
420
                    '%grade%' => $grade->getName()
421
                ],
422
                'help' => 'admin.settings.exams.planning.number_of_exams_week.help',
423
                'required' => true,
424
                'data' => $examSettings->getMaximumNumberOfExamsPerWeek($grade)
425
            ]);
426
        }
427
428
        $form = $builder->getForm();
429
        $form->handleRequest($request);
430
431
        if($form->isSubmitted() && $form->isValid()) {
432
            $map = [
433
                'visibility' => function(array $visibility) use ($examSettings) {
434
                    $examSettings->setVisibility($visibility);
435
                },
436
                'window' => function(int $window) use ($examSettings) {
437
                    $examSettings->setTimeWindowForStudents($window);
438
                },
439
                'window_supervisions' => function(int $window) use ($examSettings) {
440
                    $examSettings->setTimeWindowForStudentsToSeeSupervisions($window);
441
                },
442
                'notifications_enabled' => function(bool $enabled) use ($examSettings) {
443
                    $examSettings->setNotificationsEnabled($enabled);
444
                },
445
                'notifications_sender' => function(?string $sender) use ($examSettings) {
446
                    $examSettings->setNotificationSender($sender);
447
                },
448
                'notifications_replyaddress' => function(?string $address) use($examSettings) {
449
                    $examSettings->setNotificationReplyToAddress($address);
450
                },
451
                'number_of_exams_day' => function(int $number) use ($examSettings) {
452
                    $examSettings->setMaximumNumberOfExamsPerDay($number);
453
                },
454
                'visible_grades' => function(?array $visibleGrades) use($examSettings) {
455
                    $examSettings->setVisibleGradeIds($visibleGrades ?? [ ]);
456
                }
457
            ];
458
459
            foreach($grades as $grade) {
460
                $map[sprintf('number_of_exams_week_%d', $grade->getId())] = function(int $number) use($grade, $examSettings) {
461
                    $examSettings->setMaximumNumberOfExamsPerWeek($grade, $number);
462
                };
463
            }
464
465
            foreach($map as $formKey => $callable) {
466
                $value = $form->get($formKey)->getData();
467
                $callable($value);
468
            }
469
470
            $this->addFlash('success', 'admin.settings.success');
471
472
            return $this->redirectToRoute('admin_settings_exams');
473
        }
474
475
        return $this->render('admin/settings/exams.html.twig', [
476
            'form' => $form->createView(),
477
            'grades' => $grades
478
        ]);
479
    }
480
481
    #[Route(path: '/timetable', name: 'admin_settings_timetable')]
482
    public function timetable(Request $request, TimetableSettings $timetableSettings, GradeRepositoryInterface $gradeRepository,
483
                              AppointmentCategoryRepositoryInterface $appointmentCategoryRepository, EnumStringConverter $enumStringConverter, TranslatorInterface $translator): Response {
484
        $builder = $this->createFormBuilder();
485
        $builder
486
            ->add('days', ChoiceType::class, [
487
                'label' => 'admin.settings.timetable.days.label',
488
                'help' => 'admin.settings.timetable.days.help',
489
                'data' => $timetableSettings->getDays(),
490
                'choices' => [
491
                    'date.days.0' => 0,
492
                    'date.days.1' => 1,
493
                    'date.days.2' => 2,
494
                    'date.days.3' => 3,
495
                    'date.days.4' => 4,
496
                    'date.days.5' => 5,
497
                    'date.days.6' => 6
498
                ],
499
                'expanded' => true,
500
                'multiple' => true,
501
                'label_attr' => [
502
                    'class' => 'checkbox-custom'
503
                ]
504
            ])
505
            ->add('lessons', IntegerType::class, [
506
                'label' => 'admin.settings.timetable.max_lessons.label',
507
                'help' => 'admin.settings.timetable.max_lessons.help',
508
                'constraints' => [
509
                    new Type(['type' => 'integer']),
510
                    new GreaterThanOrEqual(['value' => 0])
511
                ],
512
                'data' => $timetableSettings->getMaxLessons()
513
            ])
514
            ->add('categories', ChoiceType::class, [
515
                'label' => 'admin.settings.timetable.no_school_category.label',
516
                'help' => 'admin.settings.timetable.no_school_category.help',
517
                'choices' => ArrayUtils::createArrayWithKeysAndValues($appointmentCategoryRepository->findAll(), fn(AppointmentCategory $category) => $category->getName(), fn(AppointmentCategory $category) => $category->getId()),
518
                'placeholder' => 'admin.settings.timetable.no_school_category.none',
519
                'required' => false,
520
                'multiple' => true,
521
                'data' => $timetableSettings->getCategoryIds(),
522
                'label_attr' => [
523
                    'class' => 'checkbox-custom'
524
                ]
525
            ])
526
            ->add('grades_course_names', ChoiceType::class, [
527
                'label' => 'admin.settings.timetable.grades_course_names.label',
528
                'help' => 'admin.settings.timetable.grades_course_names.help',
529
                'choices' => ArrayUtils::createArrayWithKeysAndValues($gradeRepository->findAll(), fn(Grade $grade) => $grade->getName(), fn(Grade $grade) => $grade->getId()),
530
                'multiple' => true,
531
                'expanded' => false,
532
                'attr' => [
533
                    'size' => 10
534
                ],
535
                'data' => $timetableSettings->getGradeIdsWithCourseNames()
536
            ])
537
            ->add('grades_membership_types', ChoiceType::class, [
538
                'label' => 'admin.settings.timetable.grades_membership_types.label',
539
                'help' => 'admin.settings.timetable.grades_membership_types.help',
540
                'choices' => ArrayUtils::createArrayWithKeysAndValues($gradeRepository->findAll(), fn(Grade $grade) => $grade->getName(), fn(Grade $grade) => $grade->getId()),
541
                'multiple' => true,
542
                'expanded' => false,
543
                'attr' => [
544
                    'size' => 10
545
                ],
546
                'data' => $timetableSettings->getGradeIdsWithMembershipTypes()
547
            ]);
548
549
        $userTypes = UserType::cases();
550
551
        foreach($userTypes as $name => $userType) {
552
            $builder
553
                ->add(sprintf('start_%s', $name), DateType::class, [
554
                    'label' => 'admin.settings.appointments.start.label',
555
                    'label_translation_parameters' => [
556
                        '%type%' => $enumStringConverter->convert($userType)
557
                    ],
558
                    'help' => 'admin.settings.appointments.start.help',
559
                    'data' => $timetableSettings->getStartDate($userType),
560
                    'widget' => 'single_text',
561
                    'required' => false
562
                ])
563
                ->add(sprintf('end_%s', $name), DateType::class, [
564
                    'label' => 'admin.settings.appointments.end.label',
565
                    'label_translation_parameters' => [
566
                        '%type%' => $enumStringConverter->convert($userType)
567
                    ],
568
                    'help' => 'admin.settings.appointments.end.help',
569
                    'data' => $timetableSettings->getEndDate($userType),
570
                    'widget' => 'single_text',
571
                    'required' => false
572
                ]);
573
        }
574
575
        for($lesson = 1; $lesson <= $timetableSettings->getMaxLessons(); $lesson++) {
576
            $builder
577
                ->add(sprintf('lesson_%d_start', $lesson), TimeType::class, [
578
                    'label' => $translator->trans('admin.settings.timetable.lesson.start', [ '%lesson%' => $lesson ]),
579
                    'data' => $timetableSettings->getStart($lesson),
580
                    'widget' => 'single_text',
581
                    'required' => false,
582
                    'input' => 'string',
583
                    'input_format' => 'H:i'
584
                ])
585
                ->add(sprintf('lesson_%d_end', $lesson), TimeType::class, [
586
                    'label' => $translator->trans('admin.settings.timetable.lesson.end', [ '%lesson%' => $lesson ]),
587
                    'data' => $timetableSettings->getEnd($lesson),
588
                    'widget' => 'single_text',
589
                    'required' => false,
590
                    'input' => 'string',
591
                    'input_format' => 'H:i'
592
                ]);
593
594
            if($lesson > 1) {
595
                $builder
596
                    ->add(sprintf('lesson_%d_collapsible', $lesson), CheckboxType::class, [
597
                        'label' => $translator->trans('admin.settings.timetable.lesson.collapsible', ['%lesson%' => $lesson]),
598
                        'data' => $timetableSettings->isCollapsible($lesson),
599
                        'required' => false,
600
                        'label_attr' => [
601
                            'class' => 'checkbox-custom'
602
                        ]
603
                    ]);
604
            }
605
        }
606
607
        $builder
608
            ->add('supervision_label', TextType::class, [
609
                'label' => 'admin.settings.timetable.supervision.label',
610
                'required' => true,
611
                'data' => $timetableSettings->getSupervisionLabel(),
612
            ])
613
            ->add('supervision_begin', TimeType::class, [
614
                'label' => 'admin.settings.timetable.supervision.start',
615
                'data' => $timetableSettings->getStart(0),
616
                'widget' => 'single_text',
617
                'input' => 'string'
618
            ])
619
            ->add('supervision_color', ColorType::class, [
620
                'label' => 'admin.settings.timetable.supervision.color',
621
                'data' => $timetableSettings->getSupervisionColor(),
622
                'required' => false
623
            ]);
624
625
        for($lesson = 1; $lesson <= $timetableSettings->getMaxLessons(); $lesson++) {
626
            $builder
627
                ->add(sprintf('supervision_label_before_%d', $lesson), TextType::class, [
628
                    'label' => $translator->trans('admin.settings.timetable.supervision.label_before.label', [ '%lesson%' => $lesson ]),
629
                    'help' => $translator->trans('admin.settings.timetable.supervision.label_before.help', [ '%lesson%' => $lesson ]),
630
                    'data' => $timetableSettings->getDescriptionBeforeLesson($lesson),
631
                    'required' => false
632
                ]);
633
        }
634
635
        $form = $builder->getForm();
636
        $form->handleRequest($request);
637
638
        if($form->isSubmitted() && $form->isValid()) {
639
            $timetableSettings->setMaxLessons($form->get('lessons')->getData());
640
            $timetableSettings->setCategoryIds($form->get('categories')->getData());
641
            $timetableSettings->setSupervisionLabel($form->get('supervision_label')->getData());
642
            $timetableSettings->setSupervisionColor($form->get('supervision_color')->getData());
643
            $timetableSettings->setStart(0, $form->get('supervision_begin')->getData());
644
            $timetableSettings->setGradeIdsWithCourseNames($form->get('grades_course_names')->getData());
645
            $timetableSettings->setGradeIdsWithMembershipTypes($form->get('grades_membership_types')->getData());
646
647
            foreach($userTypes as $name => $userType) {
648
                $timetableSettings->setStartDate($userType, $form->get(sprintf('start_%s', $name))->getData());
649
                $timetableSettings->setEndDate($userType, $form->get(sprintf('end_%s', $name))->getData());
650
            }
651
652
            for($lesson = 1; $lesson <= $timetableSettings->getMaxLessons(); $lesson++) {
653
                $startKey = sprintf('lesson_%d_start', $lesson);
654
                $endKey = sprintf('lesson_%d_end', $lesson);
655
                $collapsibleKey = sprintf('lesson_%d_collapsible', $lesson);
656
                $supervisionKey = sprintf('supervision_label_before_%d', $lesson);
657
658
                if($form->has($startKey)) {
659
                    $timetableSettings->setStart($lesson, $form->get($startKey)->getData());
660
                }
661
662
                if($form->has($endKey)) {
663
                    $timetableSettings->setEnd($lesson, $form->get($endKey)->getData());
664
                }
665
666
                if($form->has($collapsibleKey)) {
667
                    $timetableSettings->setCollapsible($lesson, $form->get($collapsibleKey)->getData());
668
                }
669
670
                if($form->has($supervisionKey)) {
671
                    $timetableSettings->setDescriptionBeforeLesson($lesson, $form->get($supervisionKey)->getData());
672
                }
673
            }
674
675
            $this->addFlash('success', 'admin.settings.success');
676
            return $this->redirectToRoute('admin_settings_timetable');
677
        }
678
679
        return $this->render('admin/settings/timetable.html.twig', [
680
            'form' => $form->createView(),
681
            'maxLessons' => $timetableSettings->getMaxLessons(),
682
            'userTypes' => $userTypes
683
        ]);
684
    }
685
686
    #[Route(path: '/substitutions', name: 'admin_settings_substitutions')]
687
    public function substitutions(Request $request, SubstitutionSettings $substitutionSettings, EnumStringConverter $enumStringConverter): Response {
688
        $builder = $this->createFormBuilder();
689
        $builder
690
            ->add('ahead_days', IntegerType::class, [
691
                'label' => 'admin.settings.substitutions.number_of_ahead_substitutions.label',
692
                'help' => 'admin.settings.substitutions.number_of_ahead_substitutions.help',
693
                'constraints' => [
694
                    new Type(['type' => 'integer']),
695
                    new GreaterThanOrEqual(['value' => 0])
696
                ],
697
                'data' => $substitutionSettings->getNumberOfAheadDaysForSubstitutions()
698
            ])
699
            ->add('skip_weekends', CheckboxType::class, [
700
                'label' => 'admin.settings.substitutions.skip_weekends.label',
701
                'help' => 'admin.settings.substitutions.skip_weekends.help',
702
                'required' => false,
703
                'data' => $substitutionSettings->skipWeekends(),
704
                'label_attr' => [
705
                    'class' => 'checkbox-custom'
706
                ]
707
            ])
708
            ->add('absence_visibility', ChoiceType::class, [
709
                'choices' => ArrayUtils::createArray(array_map(fn(UserType $case) => $case->name, UserType::cases()), UserType::cases()),
0 ignored issues
show
Bug introduced by
The property name does not seem to exist on App\Entity\UserType.
Loading history...
710
                'choice_label' => fn(UserType $userType) => $enumStringConverter->convert($userType),
711
                'choice_value' => fn(UserType $userType) => $userType->value,
712
                'expanded' => true,
713
                'multiple' => true,
714
                'label' => 'label.absence_visibility',
715
                'data' => $substitutionSettings->getAbsenceVisibility(),
716
                'label_attr' => [
717
                    'class' => 'checkbox-custom'
718
                ]
719
            ])
720
            ->add('notifications_enabled', CheckboxType::class, [
721
                'label' => 'admin.settings.substitutions.notifications.enabled.label',
722
                'help' => 'admin.settings.substitutions.notifications.enabled.help',
723
                'required' => false,
724
                'data' => $substitutionSettings->isNotificationsEnabled(),
725
                'label_attr' => [
726
                    'class' => 'checkbox-custom'
727
                ]
728
            ])
729
            ->add('notifications_sender', TextType::class, [
730
                'label' => 'admin.settings.substitutions.notifications.sender.label',
731
                'help' => 'admin.settings.substitutions.notifications.sender.help',
732
                'required' => false,
733
                'data' => $substitutionSettings->getNotificationSender()
734
            ])
735
            ->add('notifications_replyaddress', EmailType::class, [
736
                'label' => 'admin.settings.substitutions.notifications.reply_address.label',
737
                'help' => 'admin.settings.substitutions.notifications.reply_address.help',
738
                'required' => false,
739
                'data' => $substitutionSettings->getNotificationReplyToAddress()
740
            ]);
741
742
        $form = $builder->getForm();
743
        $form->handleRequest($request);
744
745
        if($form->isSubmitted() && $form->isValid()) {
746
            $map = [
747
                'ahead_days' => function(int $days) use ($substitutionSettings) {
748
                    $substitutionSettings->setNumberOfAheadDaysForSubstitutions($days);
749
                },
750
                'skip_weekends' => function(bool $skipWeekends) use ($substitutionSettings) {
751
                    $substitutionSettings->setSkipWeekends($skipWeekends);
752
                },
753
                'absence_visibility' => function(array $visibility) use ($substitutionSettings) {
754
                    $substitutionSettings->setAbsenceVisibility($visibility);
755
                },
756
                'notifications_enabled' => function(bool $enabled) use ($substitutionSettings) {
757
                    $substitutionSettings->setNotificationsEnabled($enabled);
758
                },
759
                'notifications_sender' => function(?string $sender) use($substitutionSettings) {
760
                    $substitutionSettings->setNotificationSender($sender);
761
                },
762
                'notifications_replyaddress' => function(?string $address) use($substitutionSettings) {
763
                    $substitutionSettings->setNotificationReplyToAddress($address);
764
                }
765
            ];
766
767
            foreach($map as $formKey => $callable) {
768
                $value = $form->get($formKey)->getData();
769
                $callable($value);
770
            }
771
772
            $this->addFlash('success', 'admin.settings.success');
773
774
            return $this->redirectToRoute('admin_settings_substitutions');
775
        }
776
777
        return $this->render('admin/settings/substitutions.html.twig', [
778
            'form' => $form->createView()
779
        ]);
780
    }
781
782
    #[Route(path: '/appointments', name: 'admin_settings_appointments')]
783
    public function appointments(Request $request, AppointmentsSettings $appointmentsSettings, EnumStringConverter $enumStringConverter): Response {
784
        $builder = $this->createFormBuilder();
785
        $userTypes = UserType::cases();
786
787
        foreach($userTypes as $name => $userType) {
788
            $builder
789
                ->add(sprintf('start_%s', $name), DateType::class, [
790
                    'label' => 'admin.settings.appointments.start.label',
791
                    'label_translation_parameters' => [
792
                        '%type%' => $enumStringConverter->convert($userType)
793
                    ],
794
                    'help' => 'admin.settings.appointments.start.help',
795
                    'data' => $appointmentsSettings->getStart($userType),
796
                    'widget' => 'single_text',
797
                    'required' => false
798
                ])
799
                ->add(sprintf('end_%s', $name), DateType::class, [
800
                    'label' => 'admin.settings.appointments.end.label',
801
                    'label_translation_parameters' => [
802
                        '%type%' => $enumStringConverter->convert($userType)
803
                    ],
804
                    'help' => 'admin.settings.appointments.end.help',
805
                    'data' => $appointmentsSettings->getEnd($userType),
806
                    'widget' => 'single_text',
807
                    'required' => false
808
                ]);
809
        }
810
811
        $builder->add('exam_color', ColorType::class, [
812
            'label' => 'admin.settings.appointments.exam_color.label',
813
            'help' => 'admin.settings.appointments.exam_color.help',
814
            'data' => $appointmentsSettings->getExamColor(),
815
            'required' => false
816
        ]);
817
        $form = $builder->getForm();
818
        $form->handleRequest($request);
819
820
        if($form->isSubmitted() && $form->isValid()) {
821
            $map = [
822
                'exam_color' => function(?string $color) use($appointmentsSettings) {
823
                    $appointmentsSettings->setExamColor($color);
824
                }
825
            ];
826
827
            foreach($userTypes as $name => $userType) {
828
                $map['start_' . $name] = function(?DateTime $dateTime) use ($appointmentsSettings, $userType) {
829
                    $appointmentsSettings->setStart($userType, $dateTime);
830
                };
831
832
                $map['end_' . $name] = function(?DateTime $dateTime) use ($appointmentsSettings, $userType) {
833
                    $appointmentsSettings->setEnd($userType, $dateTime);
834
                };
835
            }
836
837
            foreach($map as $formKey => $callable) {
838
                $value = $form->get($formKey)->getData();
839
                $callable($value);
840
            }
841
842
            $this->addFlash('success', 'admin.settings.success');
843
844
            return $this->redirectToRoute('admin_settings_appointments');
845
846
        }
847
848
        return $this->render('admin/settings/appointments.html.twig', [
849
            'form' => $form->createView(),
850
            'userTypes' => $userTypes
851
        ]);
852
    }
853
854
    #[Route(path: '/import', name: 'admin_settings_import')]
855
    public function import(Request $request, ImportSettings $settings, SectionRepositoryInterface $sectionRepository): Response {
856
        $builder = $this->createFormBuilder();
857
        $builder
858
            ->add('rules', CollectionType::class, [
859
                'entry_type' => ExamStudentRuleType::class,
860
                'allow_add' => true,
861
                'allow_delete' => true,
862
                'by_reference' => false,
863
                'help' => 'label.comma_separated',
864
                'data' => $settings->getExamRules()
865
            ])
866
            ->add('fallback_section', ChoiceType::class, [
867
                'label' => 'label.section',
868
                'placeholder' => 'label.choose',
869
                'choices' => ArrayUtils::createArrayWithKeysAndValues(
870
                    $sectionRepository->findAll(),
871
                    fn(Section $section) => $section->getDisplayName(),
872
                    fn(Section $section) => $section->getId()
873
                ),
874
                'data' => $settings->getFallbackSection()
875
            ]);
876
        $form = $builder->getForm();
877
        $form->handleRequest($request);
878
879
        if($form->isSubmitted() && $form->isValid()) {
880
            $map = [
881
                'rules' => function(array $rules) use($settings) {
882
                    $settings->setExamRules($rules);
883
                },
884
                'fallback_section' => function(?int $sectionId) use($settings) {
885
                    $settings->setFallbackSection($sectionId);
886
                }
887
            ];
888
889
            foreach($map as $formKey => $callable) {
890
                $value = $form->get($formKey)->getData();
891
                $callable($value);
892
            }
893
894
            $this->addFlash('success', 'admin.settings.success');
895
896
            return $this->redirectToRoute('admin_settings_import');
897
        }
898
899
        return $this->render('admin/settings/import.html.twig', [
900
            'form' => $form->createView()
901
        ]);
902
    }
903
904
    #[Route(path: '/book', name: 'admin_settings_book')]
905
    public function book(Request $request, BookSettings $settings, GradeRepositoryInterface $gradeRepository): Response {
906
        $builder = $this->createFormBuilder();
907
        $builder->add('grades_grade_teacher_excuses', ChoiceType::class, [
908
                'label' => 'admin.settings.book.excuses.grades_grade_teacher_excuses.label',
909
                'help' => 'admin.settings.book.excuses.grades_grade_teacher_excuses.help',
910
                'choices' => ArrayUtils::createArrayWithKeysAndValues($gradeRepository->findAll(), fn(Grade $grade) => $grade->getName(), fn(Grade $grade) => $grade->getId()),
911
                'multiple' => true,
912
                'expanded' => false,
913
                'attr' => [
914
                    'size' => 10
915
                ],
916
                'data' => $settings->getGradesGradeTeacherExcuses()
917
            ])
918
            ->add('grades_tuition_teacher_excuses', ChoiceType::class, [
919
                'label' => 'admin.settings.book.excuses.grades_tuition_teacher_excuses.label',
920
                'help' => 'admin.settings.book.excuses.grades_tuition_teacher_excuses.help',
921
                'choices' => ArrayUtils::createArrayWithKeysAndValues($gradeRepository->findAll(), fn(Grade $grade) => $grade->getName(), fn(Grade $grade) => $grade->getId()),
922
                'multiple' => true,
923
                'expanded' => false,
924
                'attr' => [
925
                    'size' => 10
926
                ],
927
                'data' => $settings->getGradesTuitionTeacherExcuses()
928
            ])
929
            ->add('exclude_student_status', TextType::class, [
930
                'label' => 'admin.settings.book.exclude_student_status.label',
931
                'help' => 'admin.settings.book.exclude_student_status.help',
932
                'required' => false,
933
                'data' => implode(',', $settings->getExcludeStudentsStatus())
934
            ]);
935
        $form = $builder->getForm();
936
        $form->handleRequest($request);
937
938
        if($form->isSubmitted() && $form->isValid()) {
939
            $map = [
940
                'grades_grade_teacher_excuses' => function(array $ids) use($settings) {
941
                    $settings->setGradesGradeTeacherExcuses($ids);
942
                },
943
                'grades_tuition_teacher_excuses' => function(array $ids) use($settings) {
944
                    $settings->setGradesTuitionTeacherExcuses($ids);
945
                },
946
                'exclude_student_status' => function(?string $status) use($settings) {
947
                    if(empty($status)) {
948
                        $settings->setExcludeStudentsStatus([]);
949
                    } else {
950
                        $settings->setExcludeStudentsStatus(
951
                            array_map(fn($status) => trim($status), explode(',', $status))
952
                        );
953
                    }
954
                }
955
            ];
956
957
            foreach($map as $formKey => $callable) {
958
                $value = $form->get($formKey)->getData();
959
                $callable($value);
960
            }
961
962
            $this->addFlash('success', 'admin.settings.success');
963
964
            return $this->redirectToRoute('admin_settings_book');
965
        }
966
967
        return $this->render('admin/settings/book.html.twig', [
968
            'form' => $form->createView()
969
        ]);
970
    }
971
972
}