From cc1ab396affe67b68c0e978baa00bccb8fac7e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Wed, 4 Oct 2023 15:10:16 +0200 Subject: [PATCH] WIP Impelement more stuff --- assets/images/icons.svg | 3 + config/services.yaml | 3 + migrations/Version20231004073716.php | 31 +++ migrations/Version20231004074116.php | 31 +++ migrations/Version20231004074136.php | 31 +++ src/BusProNet/DataProvider/Countries.php | 4 +- src/BusProNet/ResponseParser.php | 6 +- .../Admin/Teamer/AvailabilityController.php | 21 ++ .../Admin/Teamer/CrmSelectionsController.php | 21 ++ .../Admin/Teamer/ProfileController.php | 21 ++ .../Teamer/RecentAssignmentsController.php | 21 ++ .../Admin/Teamer/SkillsController.php | 28 +++ .../TrainingAttendance/CreateController.php | 79 ++++++ .../TrainingAttendance/DeleteController.php | 37 +++ src/Controller/Teamer/IndexController.php | 16 +- .../Teamer/Profile/SkillsController.php | 4 +- src/Entity/Period.php | 56 ----- src/Entity/Teamer.php | 30 ++- src/Form/TeamerJobProfileType.php | 2 +- src/Menu/AdminMenuBuilder.php | 56 ++++- src/Repository/PeriodRepository.php | 66 ----- src/Twig/AppExtension.php | 4 + src/Twig/AppRuntime.php | 42 ++++ templates/_partials/_menu.html.twig | 14 +- templates/admin/teamer/availability.html.twig | 16 ++ .../admin/teamer/crm_selections.html.twig | 16 ++ templates/admin/teamer/index.html.twig | 5 +- templates/admin/teamer/profile.html.twig | 230 ++++++++++++++++++ .../admin/teamer/recent_assignments.html.twig | 16 ++ templates/admin/teamer/skills.html.twig | 118 +++++++++ .../training_attendance/create.html.twig | 9 + templates/base.html.twig | 2 +- templates/teamer/index.html.twig | 11 + templates/teamer/profile/index.html.twig | 41 ++-- templates/teamer/profile/skills.html.twig | 14 +- 35 files changed, 928 insertions(+), 177 deletions(-) create mode 100644 migrations/Version20231004073716.php create mode 100644 migrations/Version20231004074116.php create mode 100644 migrations/Version20231004074136.php create mode 100644 src/Controller/Admin/Teamer/AvailabilityController.php create mode 100644 src/Controller/Admin/Teamer/CrmSelectionsController.php create mode 100644 src/Controller/Admin/Teamer/ProfileController.php create mode 100644 src/Controller/Admin/Teamer/RecentAssignmentsController.php create mode 100644 src/Controller/Admin/Teamer/SkillsController.php create mode 100644 src/Controller/Admin/Teamer/TrainingAttendance/CreateController.php create mode 100644 src/Controller/Admin/Teamer/TrainingAttendance/DeleteController.php delete mode 100644 src/Entity/Period.php delete mode 100644 src/Repository/PeriodRepository.php create mode 100644 templates/admin/teamer/availability.html.twig create mode 100644 templates/admin/teamer/crm_selections.html.twig create mode 100644 templates/admin/teamer/profile.html.twig create mode 100644 templates/admin/teamer/recent_assignments.html.twig create mode 100644 templates/admin/teamer/skills.html.twig create mode 100644 templates/admin/teamer/training_attendance/create.html.twig diff --git a/assets/images/icons.svg b/assets/images/icons.svg index 39dadb2..90e412e 100644 --- a/assets/images/icons.svg +++ b/assets/images/icons.svg @@ -26,6 +26,9 @@ + + + diff --git a/config/services.yaml b/config/services.yaml index e96e9a9..d17f25f 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -63,6 +63,9 @@ services: - name: knp_menu.menu_builder method: createMainMenu alias: admin_main + - name: knp_menu.menu_builder + method: createTeamerMenu + alias: admin_teamer App\Menu\ManagerMenuBuilder: arguments: diff --git a/migrations/Version20231004073716.php b/migrations/Version20231004073716.php new file mode 100644 index 0000000..aee4477 --- /dev/null +++ b/migrations/Version20231004073716.php @@ -0,0 +1,31 @@ +addSql('DROP TABLE period'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE TABLE period (id INT AUTO_INCREMENT NOT NULL, date_from DATE NOT NULL COMMENT \'(DC2Type:date_immutable)\', date_to DATE NOT NULL COMMENT \'(DC2Type:date_immutable)\', created_by VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, updated_by VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'\' '); + } +} diff --git a/migrations/Version20231004074116.php b/migrations/Version20231004074116.php new file mode 100644 index 0000000..2437c9b --- /dev/null +++ b/migrations/Version20231004074116.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE teamer CHANGE language language VARCHAR(255) DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE teamer CHANGE language language VARCHAR(255) NOT NULL'); + } +} diff --git a/migrations/Version20231004074136.php b/migrations/Version20231004074136.php new file mode 100644 index 0000000..27862df --- /dev/null +++ b/migrations/Version20231004074136.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE teamer CHANGE size size VARCHAR(2) DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE teamer CHANGE size size VARCHAR(2) NOT NULL'); + } +} diff --git a/src/BusProNet/DataProvider/Countries.php b/src/BusProNet/DataProvider/Countries.php index 7ef775c..cc56e80 100644 --- a/src/BusProNet/DataProvider/Countries.php +++ b/src/BusProNet/DataProvider/Countries.php @@ -32,8 +32,8 @@ class Countries return $countries; } - public function get(int $id): ?Country + public function get(string $token): ?Country { - return $this->getAll()[$id] ?? null; + return $this->getAll()[$token] ?? null; } } \ No newline at end of file diff --git a/src/BusProNet/ResponseParser.php b/src/BusProNet/ResponseParser.php index 3a70948..62a41ab 100644 --- a/src/BusProNet/ResponseParser.php +++ b/src/BusProNet/ResponseParser.php @@ -176,15 +176,15 @@ class ResponseParser $countries = []; foreach ($xml->xpath('laender/land') as $item) { - $id = (int) $item->attributes()['id']; + $token = (string) $item->attributes()['kuerzel']; $country = new Country(); $country - ->setId($id) + ->setId((int) $item->attributes()['id']) ->setName((string) $item->attributes()['bezeichnung']) ->setToken((string) $item->attributes()['kuerzel']) ->setNationality((string) $item->attributes()['nationalitaet']) ; - $countries[$id] = $country; + $countries[$token] = $country; } $response = new BaseDataResponse(); diff --git a/src/Controller/Admin/Teamer/AvailabilityController.php b/src/Controller/Admin/Teamer/AvailabilityController.php new file mode 100644 index 0000000..90378d3 --- /dev/null +++ b/src/Controller/Admin/Teamer/AvailabilityController.php @@ -0,0 +1,21 @@ +render('admin/teamer/availability.html.twig', [ + 'teamer' => $teamer, + ]); + } +} \ No newline at end of file diff --git a/src/Controller/Admin/Teamer/CrmSelectionsController.php b/src/Controller/Admin/Teamer/CrmSelectionsController.php new file mode 100644 index 0000000..998f9d0 --- /dev/null +++ b/src/Controller/Admin/Teamer/CrmSelectionsController.php @@ -0,0 +1,21 @@ +render('admin/teamer/crm_selections.html.twig', [ + 'teamer' => $teamer, + ]); + } +} \ No newline at end of file diff --git a/src/Controller/Admin/Teamer/ProfileController.php b/src/Controller/Admin/Teamer/ProfileController.php new file mode 100644 index 0000000..72bff60 --- /dev/null +++ b/src/Controller/Admin/Teamer/ProfileController.php @@ -0,0 +1,21 @@ +render('admin/teamer/profile.html.twig', [ + 'teamer' => $teamer, + ]); + } +} \ No newline at end of file diff --git a/src/Controller/Admin/Teamer/RecentAssignmentsController.php b/src/Controller/Admin/Teamer/RecentAssignmentsController.php new file mode 100644 index 0000000..9bce49d --- /dev/null +++ b/src/Controller/Admin/Teamer/RecentAssignmentsController.php @@ -0,0 +1,21 @@ +render('admin/teamer/recent_assignments.html.twig', [ + 'teamer' => $teamer, + ]); + } +} \ No newline at end of file diff --git a/src/Controller/Admin/Teamer/SkillsController.php b/src/Controller/Admin/Teamer/SkillsController.php new file mode 100644 index 0000000..7f44ea9 --- /dev/null +++ b/src/Controller/Admin/Teamer/SkillsController.php @@ -0,0 +1,28 @@ +trainingRepository->getList(); + + return $this->render('admin/teamer/skills.html.twig', [ + 'teamer' => $teamer, + 'trainings' => $trainings, + ]); + } +} \ No newline at end of file diff --git a/src/Controller/Admin/Teamer/TrainingAttendance/CreateController.php b/src/Controller/Admin/Teamer/TrainingAttendance/CreateController.php new file mode 100644 index 0000000..a6d2604 --- /dev/null +++ b/src/Controller/Admin/Teamer/TrainingAttendance/CreateController.php @@ -0,0 +1,79 @@ + 'id'])] + Training $training, + #[MapEntity(mapping: ['teamer_id' => 'id'])] + Teamer $teamer, + Request $request + ): JsonResponse { + $response = new AjaxModalResponseDto(); + $action = $this->generateUrl('app_admin_teamer_skills_training_attendance_create', [ + 'training_id' => $training->getId(), + 'teamer_id' => $teamer->getId(), + ]); + + $attendance = new TrainingAttendance(); + $attendance + ->setTeamer($teamer) + ->setTraining($training) + ; + + $form = $this + ->createFormBuilder($attendance, ['action' => $action, 'ajax_submit' => true]) + ->add('date', AbbreviatedDateType::class, [ + 'label' => 'Datum', + ]) + ->getForm() + ; + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->entityManager->persist($attendance); + $this->entityManager->flush(); + + $this->addFlash('success', 'Die Teilnahme wurde hinzugefügt'); + $this->logger->info('Create training attendance', [ + 'teamer' => $teamer->getUuid(), + 'training' => $training->getName(), + ]); + + $redirectUrl = $this->generateUrl('app_admin_teamer_skills', ['uuid' => $teamer->getUuid()]); + $response->setCloseAndRedirect($redirectUrl); + } else { + $content = $this->renderView('admin/teamer/training_attendance/create.html.twig', [ + 'form' => $form + ]); + $response->setContent($content); + } + + return $this->json($response); + } +} \ No newline at end of file diff --git a/src/Controller/Admin/Teamer/TrainingAttendance/DeleteController.php b/src/Controller/Admin/Teamer/TrainingAttendance/DeleteController.php new file mode 100644 index 0000000..754f2bf --- /dev/null +++ b/src/Controller/Admin/Teamer/TrainingAttendance/DeleteController.php @@ -0,0 +1,37 @@ +getTeamer(); + + $this->entityManager->remove($attendance); + $this->entityManager->flush(); + + $this->addFlash('success', 'Die Teilnahme an der Fortbilundg wurde gelöscht'); + $this->logger->info('Delete training attendance', [ + 'teamer' => $teamer->getUuid(), + ]); + + return $this->redirectToRoute('app_admin_teamer_skills', ['uuid' => $teamer->getUuid()]); + } +} \ No newline at end of file diff --git a/src/Controller/Teamer/IndexController.php b/src/Controller/Teamer/IndexController.php index 9956818..1964ce9 100644 --- a/src/Controller/Teamer/IndexController.php +++ b/src/Controller/Teamer/IndexController.php @@ -2,17 +2,31 @@ namespace App\Controller\Teamer; +use App\Entity\User; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Http\Attribute\IsGranted; +use Symfony\Component\Validator\Validator\ValidatorInterface; class IndexController extends AbstractController { + public function __construct(private readonly ValidatorInterface $validator) + {} + #[Route('/teamer', name: 'app_teamer_index')] #[IsGranted('ROLE_TEAMER')] public function index(): Response { - return $this->render('teamer/index.html.twig'); + /** @var User $user */ + $user = $this->getUser(); + $teamer = $user->getTeamer(); + + // Validate teamer data to show missing data right away + $errors = $this->validator->validate($teamer, null, ['profile_preflight']); + + return $this->render('teamer/index.html.twig', [ + 'errors' => $errors, + ]); } } \ No newline at end of file diff --git a/src/Controller/Teamer/Profile/SkillsController.php b/src/Controller/Teamer/Profile/SkillsController.php index b6bab23..d3f1154 100644 --- a/src/Controller/Teamer/Profile/SkillsController.php +++ b/src/Controller/Teamer/Profile/SkillsController.php @@ -35,11 +35,11 @@ class SkillsController extends AbstractController foreach ($jobProfiles as $profile) { $selectableJobProfiles[$profile->getId()] = true; - if (null !== $profile->getRequiredTraining() && false === $teamer->hasTraining($profile->getRequiredTraining())) { + if (null !== $profile->getRequiredTraining() && null === $teamer->getTrainingAttendance($profile->getRequiredTraining())) { $selectableJobProfiles[$profile->getId()] = false; } foreach ($profile->getRequiredLicenses() as $license) { - if (false === $teamer->hasLicenseOfType($license)) { + if (null === $teamer->getLicenseOfType($license)) { $selectableJobProfiles[$profile->getId()] = false; } } diff --git a/src/Entity/Period.php b/src/Entity/Period.php deleted file mode 100644 index 9fbe3af..0000000 --- a/src/Entity/Period.php +++ /dev/null @@ -1,56 +0,0 @@ -id; - } - - public function getDateFrom(): ?\DateTimeImmutable - { - return $this->dateFrom; - } - - public function setDateFrom(\DateTimeImmutable $dateFrom): static - { - $this->dateFrom = $dateFrom; - - return $this; - } - - public function getDateTo(): ?\DateTimeImmutable - { - return $this->dateTo; - } - - public function setDateTo(\DateTimeImmutable $dateTo): static - { - $this->dateTo = $dateTo; - - return $this; - } -} diff --git a/src/Entity/Teamer.php b/src/Entity/Teamer.php index 8441ae6..c6d6bd4 100644 --- a/src/Entity/Teamer.php +++ b/src/Entity/Teamer.php @@ -121,11 +121,11 @@ class Teamer implements TimestampableEntityInterface #[ORM\Column] private array $pickups = []; - #[ORM\Column(length: 255)] + #[ORM\Column(length: 255, nullable: true)] #[Assert\NotBlank(message: 'Bitte gib deine Sprache(n) an', groups: ['profile', 'profile_preflight'])] private ?string $language = null; - #[ORM\Column(length: 2)] + #[ORM\Column(length: 2, nullable: true)] private ?string $size = null; public function __construct() @@ -143,6 +143,11 @@ class Teamer implements TimestampableEntityInterface $this->customAvailabilities = new ArrayCollection(); } + public function __toString() + { + return $this->getFullName(); + } + public function toPayload(): array { // Transform gender value @@ -224,6 +229,15 @@ class Teamer implements TimestampableEntityInterface return $this; } + public function getFullName(bool $formal = false): string + { + if (true === $formal) { + return sprintf('%s, %s', $this->getLastName(), $this->getFirstName()); + } + + return sprintf('%s %s', $this->getFirstName(), $this->getLastName()); + } + public function getGender(): ?string { return $this->gender; @@ -494,15 +508,15 @@ class Teamer implements TimestampableEntityInterface return $this; } - public function hasTraining(Training $training): bool + public function getTrainingAttendance(Training $training): ?TrainingAttendance { foreach ($this->getTrainingAttendances() as $attendance) { if ($attendance->getTraining() === $training) { - return true; + return $attendance; } } - return false; + return null; } /** @@ -535,15 +549,15 @@ class Teamer implements TimestampableEntityInterface return $this; } - public function hasLicenseOfType(string $type): bool + public function getLicenseOfType(string $type): ?License { foreach ($this->getLicenses() as $license) { if ($type === $license->getType()) { - return true; + return $license; } } - return false; + return null; } /** diff --git a/src/Form/TeamerJobProfileType.php b/src/Form/TeamerJobProfileType.php index da353aa..96dde73 100644 --- a/src/Form/TeamerJobProfileType.php +++ b/src/Form/TeamerJobProfileType.php @@ -29,7 +29,7 @@ class TeamerJobProfileType extends AbstractType $requirements[].= $training->getName(); } foreach ($choice->getRequiredLicenses() as $license) { - $requirements[] = sprintf('Offizielle %slehrer*innenlizenz', ucfirst($license)); + $requirements[] = sprintf('Offizielle %slehrer*innenlizenz', ucfirst(strtolower($license))); } if ($requirements) { diff --git a/src/Menu/AdminMenuBuilder.php b/src/Menu/AdminMenuBuilder.php index 44adc90..023493f 100644 --- a/src/Menu/AdminMenuBuilder.php +++ b/src/Menu/AdminMenuBuilder.php @@ -6,9 +6,9 @@ use Knp\Menu\ItemInterface; class AdminMenuBuilder extends AbstractMenuBuilder { - public function createMainMenu(array $options): ItemInterface + private function getMainMenuItems(): array { - $menuItems = [ + return [ [ 'route' => 'app_admin_index', 'title' => 'Dashboard', @@ -34,7 +34,7 @@ class AdminMenuBuilder extends AbstractMenuBuilder 'title' => 'Teamerübersicht', 'icon' => 'users', 'hideChildren' => true, - 'children' => [], + 'children' => $this->getTeamerMenuItems(), ], [ 'route' => false, @@ -86,8 +86,42 @@ class AdminMenuBuilder extends AbstractMenuBuilder ], ], ]; + } - $menu = $this->createMenu($menuItems); + private function getTeamerMenuItems(): array + { + return [ + [ + 'route' => 'app_admin_teamer_profile', + 'title' => 'Stammdaten & Foto', + 'routeParameters' => $this->getDefaultRouteParameters('uuid'), + ], + [ + 'route' => 'app_admin_teamer_skills', + 'title' => 'Jobprofile & Skills', + 'routeParameters' => $this->getDefaultRouteParameters('uuid'), + ], + [ + 'route' => 'app_admin_teamer_availability', + 'title' => 'Verfügbarkeit', + 'routeParameters' => $this->getDefaultRouteParameters('uuid'), + ], + [ + 'route' => 'app_admin_teamer_crm_selections', + 'title' => 'Selektionsmerkmale', + 'routeParameters' => $this->getDefaultRouteParameters('uuid'), + ], + [ + 'route' => 'app_admin_teamer_recent_assignments', + 'title' => 'Vergangene Einsätze', + 'routeParameters' => $this->getDefaultRouteParameters('uuid'), + ], + ]; + } + + public function createMainMenu(array $options): ItemInterface + { + $menu = $this->createMenu($this->getMainMenuItems()); $this->addDivider($menu); @@ -100,4 +134,18 @@ class AdminMenuBuilder extends AbstractMenuBuilder return $menu; } + + public function createTeamerMenu(array $options): ItemInterface + { + $menu = $this->createMenu($this->getTeamerMenuItems()); + + $this->addDivider($menu); + + $menu->addChild('zurück zur Übersicht', [ + 'route' => 'app_admin_teamer_index', + 'icon' => 'back', + ]); + + return $menu; + } } \ No newline at end of file diff --git a/src/Repository/PeriodRepository.php b/src/Repository/PeriodRepository.php deleted file mode 100644 index 114767d..0000000 --- a/src/Repository/PeriodRepository.php +++ /dev/null @@ -1,66 +0,0 @@ - - * - * @method Period|null find($id, $lockMode = null, $lockVersion = null) - * @method Period|null findOneBy(array $criteria, array $orderBy = null) - * @method Period[] findAll() - * @method Period[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) - */ -class PeriodRepository extends ServiceEntityRepository -{ - public function __construct(ManagerRegistry $registry) - { - parent::__construct($registry, Period::class); - } - - public function save(Period $entity, bool $flush = false): void - { - $this->getEntityManager()->persist($entity); - - if ($flush) { - $this->getEntityManager()->flush(); - } - } - - public function remove(Period $entity, bool $flush = false): void - { - $this->getEntityManager()->remove($entity); - - if ($flush) { - $this->getEntityManager()->flush(); - } - } - -// /** -// * @return Period[] Returns an array of Period objects -// */ -// public function findByExampleField($value): array -// { -// return $this->createQueryBuilder('p') -// ->andWhere('p.exampleField = :val') -// ->setParameter('val', $value) -// ->orderBy('p.id', 'ASC') -// ->setMaxResults(10) -// ->getQuery() -// ->getResult() -// ; -// } - -// public function findOneBySomeField($value): ?Period -// { -// return $this->createQueryBuilder('p') -// ->andWhere('p.exampleField = :val') -// ->setParameter('val', $value) -// ->getQuery() -// ->getOneOrNullResult() -// ; -// } -} diff --git a/src/Twig/AppExtension.php b/src/Twig/AppExtension.php index f3f38f5..5dfed09 100644 --- a/src/Twig/AppExtension.php +++ b/src/Twig/AppExtension.php @@ -15,6 +15,10 @@ class AppExtension extends AbstractExtension new TwigFilter('file_icon', [AppRuntime::class, 'fileIconFilter'], ['is_safe' => ['html']]), new TwigFilter('date_diff', [AppRuntime::class, 'dateDiffForHumans']), new TwigFilter('format_money', [AppRuntime::class, 'formatMoney']), + new TwigFilter('license_label', [AppRuntime::class, 'licenseLabel']), + new TwigFilter('teamer_status_label', [AppRuntime::class, 'teamerStatusLabel']), + new TwigFilter('bpn_country_label', [AppRuntime::class, 'bpnCountryLabel']), + new TwigFilter('bpn_pickup_label', [AppRuntime::class, 'bpnPickupLabel']), ]; } diff --git a/src/Twig/AppRuntime.php b/src/Twig/AppRuntime.php index b9bb483..35830b1 100644 --- a/src/Twig/AppRuntime.php +++ b/src/Twig/AppRuntime.php @@ -2,6 +2,10 @@ namespace App\Twig; +use App\BusProNet\DataProvider\Countries; +use App\BusProNet\DataProvider\Pickups; +use App\BusProNet\Model\Country; +use App\Entity\Teamer; use Carbon\Carbon; use Symfony\Component\HttpFoundation\RequestStack; use Twig\Environment; @@ -13,10 +17,48 @@ class AppRuntime implements RuntimeExtensionInterface public function __construct( private readonly RequestStack $requestStack, private readonly IntlExtension $intlExtension, + private readonly Countries $countries, + private readonly Pickups $pickups, private readonly string $environment ) { } + public function teamerStatusLabel(string $status): string + { + if (Teamer::STATUS_NEW === $status) { + return 'Neuteamer'; + } + + return 'Bestandsteamer'; + } + + public function licenseLabel(string $type): string + { + return sprintf('Offizielle %slehrer*innenlizenz', ucfirst(strtolower($type))); + } + + public function bpnCountryLabel(string $token, string $property = 'name'): string + { + $country = $this->countries->get($token); + + if (null === $country) { + return 'unbekannt'; + } + + return 'nationality' === $property ? $country->getNationality() : $country->getName(); + } + + public function bpnPickupLabel(int $id): string + { + $pickup = $this->pickups->get($id); + + if (null === $pickup) { + return 'unbekannt'; + } + + return $pickup->getCity(); + } + public function fileIconFilter(Environment $environment, string $mimeType, ?string $classes = 'w-4 h-4'): string { $icon = match ($mimeType) { diff --git a/templates/_partials/_menu.html.twig b/templates/_partials/_menu.html.twig index 42dbe9b..2c2256d 100644 --- a/templates/_partials/_menu.html.twig +++ b/templates/_partials/_menu.html.twig @@ -3,13 +3,13 @@ {% block list %} {% if item.hasChildren and options.depth is not same as(0) and item.displayChildren %} {% if item.level == 0 %} -
- -
+
+ +
{% else %}