diff --git a/src/Command/BpnXmlSyncCommand.php b/src/Command/BpnXmlSyncCommand.php index 52ce554..c59bee3 100644 --- a/src/Command/BpnXmlSyncCommand.php +++ b/src/Command/BpnXmlSyncCommand.php @@ -200,6 +200,7 @@ class BpnXmlSyncCommand extends Command } /** + * @return array * @throws FilesystemException */ private function syncFiles(SymfonyStyle $io): array diff --git a/src/Command/DraftInspectCommand.php b/src/Command/DraftInspectCommand.php index 8d11d17..9c63318 100644 --- a/src/Command/DraftInspectCommand.php +++ b/src/Command/DraftInspectCommand.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\Command; use App\Repository\BookingEditDraftRepository; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -20,6 +21,7 @@ class DraftInspectCommand extends Command { public function __construct( private readonly BookingEditDraftRepository $draftRepository, + private readonly EntityManagerInterface $entityManager, ) { parent::__construct(); } @@ -102,11 +104,10 @@ class DraftInspectCommand extends Command return Command::SUCCESS; } - $em = $this->draftRepository->getEntityManager(); foreach ($drafts as $draft) { - $em->remove($draft); + $this->entityManager->remove($draft); } - $em->flush(); + $this->entityManager->flush(); $io->success(sprintf('Deleted %d draft(s).', \count($drafts))); } diff --git a/src/Email/Mailer.php b/src/Email/Mailer.php index d530d94..1eb60b0 100644 --- a/src/Email/Mailer.php +++ b/src/Email/Mailer.php @@ -14,6 +14,9 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class Mailer { + /** + * @param array $defaults + */ public function __construct( private readonly MailerInterface $mailer, private readonly BodyRendererInterface $bodyRenderer, @@ -22,6 +25,10 @@ class Mailer ) { } + /** + * @param array $context + * @param array $options + */ public function createAndSendEmail(array $context, array $options): void { $config = $this->resolveConfig($options); @@ -35,6 +42,10 @@ class Mailer } } + /** + * @param array $context + * @param array $config + */ public function create(array $context, array $config): TemplatedEmail { $email = (new TemplatedEmail()) @@ -73,6 +84,10 @@ class Mailer } } + /** + * @param array $options + * @return array + */ private function resolveConfig(array $options): array { $resolver = new OptionsResolver(); diff --git a/src/Entity/BookingEditDraft.php b/src/Entity/BookingEditDraft.php index 2186659..3fbbd4a 100644 --- a/src/Entity/BookingEditDraft.php +++ b/src/Entity/BookingEditDraft.php @@ -49,8 +49,11 @@ class BookingEditDraft #[ORM\Column(type: 'integer', nullable: true)] private ?int $hotelId = null; + /** + * @var array + */ #[ORM\Column(type: 'json')] - private array $formData = []; + private array $formData; #[ORM\Column(type: 'datetime_immutable')] private \DateTimeImmutable $createdAt; @@ -58,6 +61,9 @@ class BookingEditDraft #[ORM\Column(type: 'datetime_immutable')] private \DateTimeImmutable $updatedAt; + /** + * @param array $formData + */ public function __construct(User $user, int $bookingId, \DateTimeImmutable $travelDate, array $formData) { $this->user = $user; @@ -139,11 +145,17 @@ class BookingEditDraft return null !== $this->dateId && null !== $this->hotelId; } + /** + * @return array + */ public function getFormData(): array { return $this->formData; } + /** + * @param array $formData + */ public function setFormData(array $formData): static { $this->formData = $formData; diff --git a/src/Entity/LogEntry.php b/src/Entity/LogEntry.php index 2af65a7..5da1010 100644 --- a/src/Entity/LogEntry.php +++ b/src/Entity/LogEntry.php @@ -22,9 +22,15 @@ class LogEntry #[ORM\Column(type: 'string', length: 255)] private ?string $message; + /** + * @var array|null + */ #[ORM\Column(type: 'json', nullable: true)] private ?array $context = []; + /** + * @var array|null + */ #[ORM\Column(type: 'json', nullable: true)] private ?array $extra = []; @@ -70,11 +76,17 @@ class LogEntry return $this; } + /** + * @return array|null + */ public function getContext(): ?array { return $this->context; } + /** + * @param array|null $context + */ public function setContext(?array $context): self { $this->context = $context; @@ -82,11 +94,17 @@ class LogEntry return $this; } + /** + * @return array|null + */ public function getExtra(): ?array { return $this->extra; } + /** + * @param array|null $extra + */ public function setExtra(?array $extra): self { $this->extra = $extra; diff --git a/src/Entity/User.php b/src/Entity/User.php index 9d830a9..42b58ef 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -26,9 +26,15 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface #[ORM\Column(type: 'integer', nullable: true)] private ?int $addressId = null; + /** + * @var array + */ #[ORM\Column(type: 'json')] private array $roles = []; + /** + * @var array + */ #[ORM\Column(type: 'json')] private array $hotelCodes = []; @@ -96,11 +102,17 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface return $this; } + /** + * @return array + */ public function getRoles(): array { return ['ROLE_USER', ...$this->roles]; } + /** + * @param array $roles + */ public function setRoles(array $roles): static { $this->roles = $roles; @@ -108,11 +120,17 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface return $this; } + /** + * @return array + */ public function getHotelCodes(): array { return $this->hotelCodes; } + /** + * @param array $hotelCodes + */ public function setHotelCodes(array $hotelCodes): static { $this->hotelCodes = $hotelCodes; diff --git a/src/EventListener/AccessDeniedListener.php b/src/EventListener/AccessDeniedListener.php index 26c18e8..968af31 100644 --- a/src/EventListener/AccessDeniedListener.php +++ b/src/EventListener/AccessDeniedListener.php @@ -7,6 +7,7 @@ namespace App\EventListener; use Psr\Log\LoggerInterface; use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Security\Core\Exception\AccessDeniedException; @@ -54,12 +55,15 @@ class AccessDeniedListener implements EventSubscriberInterface return; } + /** @var Session $session */ + $session = $request->getSession(); + if (null === $this->security->getUser()) { - $request->getSession()->getFlashBag()->add('info', 'Bitte melde dich an.'); + $session->getFlashBag()->add('info', 'Bitte melde dich an.'); } else { - $request->getSession()->getFlashBag()->add('error', 'Zugriff verweigert'); + $session->getFlashBag()->add('error', 'Zugriff verweigert'); // Unset potentially set target path to avoid access denied errors - $request->getSession()->remove('_security.main.target_path'); + $session->remove('_security.main.target_path'); } $this->authLogger->warning('Access denied', [ diff --git a/src/EventListener/AuthorizationCodeListener.php b/src/EventListener/AuthorizationCodeListener.php index 9271364..ef6b30d 100644 --- a/src/EventListener/AuthorizationCodeListener.php +++ b/src/EventListener/AuthorizationCodeListener.php @@ -43,7 +43,7 @@ class AuthorizationCodeListener { $request = $this->requestStack->getMainRequest(); - /** @var User $user */ + /** @var User|null $user */ $user = $this->security->getUser(); if (null === $user) { diff --git a/src/Logger/UserDataProcessor.php b/src/Logger/UserDataProcessor.php index 973f8dc..7fcf2b7 100644 --- a/src/Logger/UserDataProcessor.php +++ b/src/Logger/UserDataProcessor.php @@ -38,7 +38,7 @@ class UserDataProcessor return $record; } - /** @var User $user */ + /** @var User|null $user */ $user = $this->security->getUser(); if (null === $user) { diff --git a/src/Repository/LogEntryRepository.php b/src/Repository/LogEntryRepository.php index a459c3e..f15aa8b 100644 --- a/src/Repository/LogEntryRepository.php +++ b/src/Repository/LogEntryRepository.php @@ -28,6 +28,9 @@ class LogEntryRepository extends ServiceEntityRepository ->execute(); } + /** + * @return array + */ public function findWithErrorCodes(): array { return $this->createQueryBuilder('l') diff --git a/src/Security/Voter/BookingVoter.php b/src/Security/Voter/BookingVoter.php index 8072be2..2ef9dae 100644 --- a/src/Security/Voter/BookingVoter.php +++ b/src/Security/Voter/BookingVoter.php @@ -15,6 +15,8 @@ use Symfony\Component\Security\Core\Authorization\Voter\Voter; * Enforces ownership check via personId matching. VIEW access requires ownership, * EDIT access additionally requires the booking to be in an editable state * (determined by booking.isEditable()). + * + * @extends Voter */ class BookingVoter extends Voter { @@ -32,7 +34,7 @@ class BookingVoter extends Voter protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool { - /** @var User $user */ + /** @var User|null $user */ $user = $token->getUser(); if (null === $user) { diff --git a/src/Service/TravelSnapshotService.php b/src/Service/TravelSnapshotService.php index 61d76da..4f5ef51 100644 --- a/src/Service/TravelSnapshotService.php +++ b/src/Service/TravelSnapshotService.php @@ -76,17 +76,6 @@ class TravelSnapshotService return null; } - if (false === $travel instanceof Travel) { - $this->logger->warning('Snapshot payload deserialization returned unexpected type', [ - 'dateId' => $dateId, - 'hotelId' => $hotelId, - 'snapshotId' => $snapshot->getId(), - 'type' => get_debug_type($travel), - ]); - - return null; - } - return $travel; } @@ -173,11 +162,15 @@ class TravelSnapshotService /** * Refreshes snapshot payloads with extended availability data. - * + * @param array|null $xmlAvailableDateIds * @return array{processed:int,updated:int,failed:int} */ - public function refreshExtendedSnapshots(int $limit = 500, bool $force = false, int $refreshAfterMinutes = 360, ?array $xmlAvailableDateIds = null): array - { + public function refreshExtendedSnapshots( + int $limit = 500, + bool $force = false, + int $refreshAfterMinutes = 360, + ?array $xmlAvailableDateIds = null + ): array { $dateToThreshold = new \DateTimeImmutable('today'); $refreshBefore = new \DateTimeImmutable(sprintf('-%d minutes', $refreshAfterMinutes)); @@ -313,10 +306,6 @@ class TravelSnapshotService return null; } - if (false === $travel instanceof Travel) { - return null; - } - return $travel; } diff --git a/src/Twig/AppExtension.php b/src/Twig/AppExtension.php index 5fa3f75..aeaed62 100644 --- a/src/Twig/AppExtension.php +++ b/src/Twig/AppExtension.php @@ -21,7 +21,6 @@ class AppExtension extends AbstractExtension { return [ new TwigFilter('file_size', [AppRuntime::class, 'formatBytes']), - new TwigFilter('file_icon', [AppRuntime::class, 'fileIconFilter'], ['is_safe' => ['html']]), new TwigFilter('format_money', [AppRuntime::class, 'formatMoney']), new TwigFilter('format_service_price', [AppRuntime::class, 'formatServicePrice']), new TwigFilter('map_gender', [AppRuntime::class, 'mapGender']), diff --git a/src/Twig/AppRuntime.php b/src/Twig/AppRuntime.php index 73e4c40..21540e6 100644 --- a/src/Twig/AppRuntime.php +++ b/src/Twig/AppRuntime.php @@ -38,18 +38,6 @@ class AppRuntime implements RuntimeExtensionInterface ) { } - public function fileIconFilter(Environment $environment, string $mimeType, ?string $classes = 'w-4 h-4'): string - { - $icon = match ($mimeType) { - 'application/pdf' => 'pdf', - 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'excel', - 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'word', - default => 'download', - }; - - return $this->renderIcon($environment, $icon, $classes); - } - public function formatBytes(int $bytes, ?int $precision = 2): string { if (0 === $bytes) {