chore: cleanup, add PHPStan type annotations

This commit is contained in:
Björn Fromme
2026-04-03 13:45:41 +02:00
parent a264526127
commit fce6d1615a
14 changed files with 91 additions and 41 deletions
+1
View File
@@ -200,6 +200,7 @@ class BpnXmlSyncCommand extends Command
} }
/** /**
* @return array<string, int>
* @throws FilesystemException * @throws FilesystemException
*/ */
private function syncFiles(SymfonyStyle $io): array private function syncFiles(SymfonyStyle $io): array
+4 -3
View File
@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Command; namespace App\Command;
use App\Repository\BookingEditDraftRepository; use App\Repository\BookingEditDraftRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
@@ -20,6 +21,7 @@ class DraftInspectCommand extends Command
{ {
public function __construct( public function __construct(
private readonly BookingEditDraftRepository $draftRepository, private readonly BookingEditDraftRepository $draftRepository,
private readonly EntityManagerInterface $entityManager,
) { ) {
parent::__construct(); parent::__construct();
} }
@@ -102,11 +104,10 @@ class DraftInspectCommand extends Command
return Command::SUCCESS; return Command::SUCCESS;
} }
$em = $this->draftRepository->getEntityManager();
foreach ($drafts as $draft) { 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))); $io->success(sprintf('Deleted %d draft(s).', \count($drafts)));
} }
+15
View File
@@ -14,6 +14,9 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
class Mailer class Mailer
{ {
/**
* @param array<string, mixed> $defaults
*/
public function __construct( public function __construct(
private readonly MailerInterface $mailer, private readonly MailerInterface $mailer,
private readonly BodyRendererInterface $bodyRenderer, private readonly BodyRendererInterface $bodyRenderer,
@@ -22,6 +25,10 @@ class Mailer
) { ) {
} }
/**
* @param array<string, mixed> $context
* @param array<string, mixed> $options
*/
public function createAndSendEmail(array $context, array $options): void public function createAndSendEmail(array $context, array $options): void
{ {
$config = $this->resolveConfig($options); $config = $this->resolveConfig($options);
@@ -35,6 +42,10 @@ class Mailer
} }
} }
/**
* @param array<string, mixed> $context
* @param array<string, mixed> $config
*/
public function create(array $context, array $config): TemplatedEmail public function create(array $context, array $config): TemplatedEmail
{ {
$email = (new TemplatedEmail()) $email = (new TemplatedEmail())
@@ -73,6 +84,10 @@ class Mailer
} }
} }
/**
* @param array<string, mixed> $options
* @return array<string, mixed>
*/
private function resolveConfig(array $options): array private function resolveConfig(array $options): array
{ {
$resolver = new OptionsResolver(); $resolver = new OptionsResolver();
+13 -1
View File
@@ -49,8 +49,11 @@ class BookingEditDraft
#[ORM\Column(type: 'integer', nullable: true)] #[ORM\Column(type: 'integer', nullable: true)]
private ?int $hotelId = null; private ?int $hotelId = null;
/**
* @var array<string, mixed>
*/
#[ORM\Column(type: 'json')] #[ORM\Column(type: 'json')]
private array $formData = []; private array $formData;
#[ORM\Column(type: 'datetime_immutable')] #[ORM\Column(type: 'datetime_immutable')]
private \DateTimeImmutable $createdAt; private \DateTimeImmutable $createdAt;
@@ -58,6 +61,9 @@ class BookingEditDraft
#[ORM\Column(type: 'datetime_immutable')] #[ORM\Column(type: 'datetime_immutable')]
private \DateTimeImmutable $updatedAt; private \DateTimeImmutable $updatedAt;
/**
* @param array<string, mixed> $formData
*/
public function __construct(User $user, int $bookingId, \DateTimeImmutable $travelDate, array $formData) public function __construct(User $user, int $bookingId, \DateTimeImmutable $travelDate, array $formData)
{ {
$this->user = $user; $this->user = $user;
@@ -139,11 +145,17 @@ class BookingEditDraft
return null !== $this->dateId && null !== $this->hotelId; return null !== $this->dateId && null !== $this->hotelId;
} }
/**
* @return array<string, mixed>
*/
public function getFormData(): array public function getFormData(): array
{ {
return $this->formData; return $this->formData;
} }
/**
* @param array<string, mixed> $formData
*/
public function setFormData(array $formData): static public function setFormData(array $formData): static
{ {
$this->formData = $formData; $this->formData = $formData;
+18
View File
@@ -22,9 +22,15 @@ class LogEntry
#[ORM\Column(type: 'string', length: 255)] #[ORM\Column(type: 'string', length: 255)]
private ?string $message; private ?string $message;
/**
* @var array<string, mixed>|null
*/
#[ORM\Column(type: 'json', nullable: true)] #[ORM\Column(type: 'json', nullable: true)]
private ?array $context = []; private ?array $context = [];
/**
* @var array<string, mixed>|null
*/
#[ORM\Column(type: 'json', nullable: true)] #[ORM\Column(type: 'json', nullable: true)]
private ?array $extra = []; private ?array $extra = [];
@@ -70,11 +76,17 @@ class LogEntry
return $this; return $this;
} }
/**
* @return array<string, mixed>|null
*/
public function getContext(): ?array public function getContext(): ?array
{ {
return $this->context; return $this->context;
} }
/**
* @param array<string, mixed>|null $context
*/
public function setContext(?array $context): self public function setContext(?array $context): self
{ {
$this->context = $context; $this->context = $context;
@@ -82,11 +94,17 @@ class LogEntry
return $this; return $this;
} }
/**
* @return array<string, mixed>|null
*/
public function getExtra(): ?array public function getExtra(): ?array
{ {
return $this->extra; return $this->extra;
} }
/**
* @param array<string, mixed>|null $extra
*/
public function setExtra(?array $extra): self public function setExtra(?array $extra): self
{ {
$this->extra = $extra; $this->extra = $extra;
+18
View File
@@ -26,9 +26,15 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\Column(type: 'integer', nullable: true)] #[ORM\Column(type: 'integer', nullable: true)]
private ?int $addressId = null; private ?int $addressId = null;
/**
* @var array<string>
*/
#[ORM\Column(type: 'json')] #[ORM\Column(type: 'json')]
private array $roles = []; private array $roles = [];
/**
* @var array<string>
*/
#[ORM\Column(type: 'json')] #[ORM\Column(type: 'json')]
private array $hotelCodes = []; private array $hotelCodes = [];
@@ -96,11 +102,17 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this; return $this;
} }
/**
* @return array<string>
*/
public function getRoles(): array public function getRoles(): array
{ {
return ['ROLE_USER', ...$this->roles]; return ['ROLE_USER', ...$this->roles];
} }
/**
* @param array<string> $roles
*/
public function setRoles(array $roles): static public function setRoles(array $roles): static
{ {
$this->roles = $roles; $this->roles = $roles;
@@ -108,11 +120,17 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this; return $this;
} }
/**
* @return array<string>
*/
public function getHotelCodes(): array public function getHotelCodes(): array
{ {
return $this->hotelCodes; return $this->hotelCodes;
} }
/**
* @param array<string> $hotelCodes
*/
public function setHotelCodes(array $hotelCodes): static public function setHotelCodes(array $hotelCodes): static
{ {
$this->hotelCodes = $hotelCodes; $this->hotelCodes = $hotelCodes;
+7 -3
View File
@@ -7,6 +7,7 @@ namespace App\EventListener;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Bundle\SecurityBundle\Security; use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Exception\AccessDeniedException;
@@ -54,12 +55,15 @@ class AccessDeniedListener implements EventSubscriberInterface
return; return;
} }
/** @var Session $session */
$session = $request->getSession();
if (null === $this->security->getUser()) { if (null === $this->security->getUser()) {
$request->getSession()->getFlashBag()->add('info', 'Bitte melde dich an.'); $session->getFlashBag()->add('info', 'Bitte melde dich an.');
} else { } else {
$request->getSession()->getFlashBag()->add('error', 'Zugriff verweigert'); $session->getFlashBag()->add('error', 'Zugriff verweigert');
// Unset potentially set target path to avoid access denied errors // 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', [ $this->authLogger->warning('Access denied', [
@@ -43,7 +43,7 @@ class AuthorizationCodeListener
{ {
$request = $this->requestStack->getMainRequest(); $request = $this->requestStack->getMainRequest();
/** @var User $user */ /** @var User|null $user */
$user = $this->security->getUser(); $user = $this->security->getUser();
if (null === $user) { if (null === $user) {
+1 -1
View File
@@ -38,7 +38,7 @@ class UserDataProcessor
return $record; return $record;
} }
/** @var User $user */ /** @var User|null $user */
$user = $this->security->getUser(); $user = $this->security->getUser();
if (null === $user) { if (null === $user) {
+3
View File
@@ -28,6 +28,9 @@ class LogEntryRepository extends ServiceEntityRepository
->execute(); ->execute();
} }
/**
* @return array<int, LogEntry>
*/
public function findWithErrorCodes(): array public function findWithErrorCodes(): array
{ {
return $this->createQueryBuilder('l') return $this->createQueryBuilder('l')
+3 -1
View File
@@ -15,6 +15,8 @@ use Symfony\Component\Security\Core\Authorization\Voter\Voter;
* Enforces ownership check via personId matching. VIEW access requires ownership, * Enforces ownership check via personId matching. VIEW access requires ownership,
* EDIT access additionally requires the booking to be in an editable state * EDIT access additionally requires the booking to be in an editable state
* (determined by booking.isEditable()). * (determined by booking.isEditable()).
*
* @extends Voter<string, mixed>
*/ */
class BookingVoter extends Voter class BookingVoter extends Voter
{ {
@@ -32,7 +34,7 @@ class BookingVoter extends Voter
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{ {
/** @var User $user */ /** @var User|null $user */
$user = $token->getUser(); $user = $token->getUser();
if (null === $user) { if (null === $user) {
+7 -18
View File
@@ -76,17 +76,6 @@ class TravelSnapshotService
return null; 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; return $travel;
} }
@@ -173,11 +162,15 @@ class TravelSnapshotService
/** /**
* Refreshes snapshot payloads with extended availability data. * Refreshes snapshot payloads with extended availability data.
* * @param array<int>|null $xmlAvailableDateIds
* @return array{processed:int,updated:int,failed:int} * @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'); $dateToThreshold = new \DateTimeImmutable('today');
$refreshBefore = new \DateTimeImmutable(sprintf('-%d minutes', $refreshAfterMinutes)); $refreshBefore = new \DateTimeImmutable(sprintf('-%d minutes', $refreshAfterMinutes));
@@ -313,10 +306,6 @@ class TravelSnapshotService
return null; return null;
} }
if (false === $travel instanceof Travel) {
return null;
}
return $travel; return $travel;
} }
-1
View File
@@ -21,7 +21,6 @@ class AppExtension extends AbstractExtension
{ {
return [ return [
new TwigFilter('file_size', [AppRuntime::class, 'formatBytes']), 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_money', [AppRuntime::class, 'formatMoney']),
new TwigFilter('format_service_price', [AppRuntime::class, 'formatServicePrice']), new TwigFilter('format_service_price', [AppRuntime::class, 'formatServicePrice']),
new TwigFilter('map_gender', [AppRuntime::class, 'mapGender']), new TwigFilter('map_gender', [AppRuntime::class, 'mapGender']),
-12
View File
@@ -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 public function formatBytes(int $bytes, ?int $precision = 2): string
{ {
if (0 === $bytes) { if (0 === $bytes) {