fix: type mismatches and handle nullable values

This commit is contained in:
2026-08-27 10:16:03 +02:00
parent c33c1b6bf0
commit e7f3233dbc
9 changed files with 67 additions and 47 deletions
+12 -4
View File
@@ -31,12 +31,15 @@ class ResponseParser
public function parseXmlString(string $type, string $content): mixed public function parseXmlString(string $type, string $content): mixed
{ {
$xml = simplexml_load_string($content); $xml = simplexml_load_string($content);
if (false === $xml) {
throw new ResponseParserException('Unable to parse XML response');
}
// Override type when present in XML to catch error responses // Override type when present in XML to catch error responses
$responseType = $type; $responseType = $type;
$responseTypeXml = $xml->xpath('satz/@typ'); $responseTypeXml = $xml->xpath('satz/@typ') ?: [];
if (0 < count($responseTypeXml)) { if (0 < count($responseTypeXml)) {
$responseType = (string) $xml->xpath('satz/@typ')[0]; $responseType = (string) $responseTypeXml[0];
} }
switch ($responseType) { switch ($responseType) {
@@ -91,7 +94,12 @@ class ResponseParser
$gender = 'W' === strtoupper($gender) ? 'F' : strtoupper($gender); $gender = 'W' === strtoupper($gender) ? 'F' : strtoupper($gender);
$dateString = (string) $addressXml->geburtsdatum; $dateString = (string) $addressXml->geburtsdatum;
$dateOfBirth = empty($dateString) ? null : \DateTimeImmutable::createFromFormat('d.m.Y', $dateString); $dateOfBirth = null;
if ('' !== $dateString) {
$parsedDate = \DateTimeImmutable::createFromFormat('d.m.Y', $dateString);
$dateOfBirth = false === $parsedDate ? null : $parsedDate;
}
$response = new ProfileResponse(); $response = new ProfileResponse();
$response $response
@@ -146,7 +154,7 @@ class ResponseParser
$personId = (int) $xml->idperson; $personId = (int) $xml->idperson;
$updated = false; $updated = false;
$updatedXml = $xml->xpath('änderung|aenderung'); $updatedXml = $xml->xpath('änderung|aenderung') ?: [];
if (0 < count($updatedXml)) { if (0 < count($updatedXml)) {
$updated = 'true' === strtolower((string) $updatedXml[0]); $updated = 'true' === strtolower((string) $updatedXml[0]);
} }
@@ -32,18 +32,15 @@ class EditController extends AbstractController
public function index(EmailTextKey $key, Request $request): Response public function index(EmailTextKey $key, Request $request): Response
{ {
$definition = $this->catalog->get($key); $definition = $this->catalog->get($key);
$emailText = $this->emailTextRepository->findByKey($key); $existing = $this->emailTextRepository->findByKey($key);
$isNew = null === $emailText;
// Editing a mail for the first time starts from the delivered wording rather than // Editing a mail for the first time starts from the delivered wording rather than
// from an empty form, so an admin adjusts a sentence instead of rewriting the mail. // from an empty form, so an admin adjusts a sentence instead of rewriting the mail.
if (true === $isNew) { $emailText = $existing ?? (new EmailText($key))
$emailText = (new EmailText($key))
->setSubject($definition->defaultSubject) ->setSubject($definition->defaultSubject)
->setHeadline($definition->defaultHeadline) ->setHeadline($definition->defaultHeadline)
->setBody($definition->defaultBody) ->setBody($definition->defaultBody)
; ;
}
$form = $this->createForm(EmailTextType::class, $emailText, [ $form = $this->createForm(EmailTextType::class, $emailText, [
'definition' => $definition, 'definition' => $definition,
@@ -51,10 +48,7 @@ class EditController extends AbstractController
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
if (true === $isNew) {
$this->entityManager->persist($emailText); $this->entityManager->persist($emailText);
}
$this->entityManager->flush(); $this->entityManager->flush();
$this->addFlash('success', 'Der E-Mail-Text wurde aktualisiert'); $this->addFlash('success', 'Der E-Mail-Text wurde aktualisiert');
@@ -2,6 +2,7 @@
namespace App\Controller\Admin\Teamer; namespace App\Controller\Admin\Teamer;
use App\Controller\Traits\AuthenticatedUserTrait;
use App\Controller\Traits\ReturnUrlTrait; use App\Controller\Traits\ReturnUrlTrait;
use App\Email\MailBodyRenderer; use App\Email\MailBodyRenderer;
use App\Form\TeamerMailingType; use App\Form\TeamerMailingType;
@@ -21,6 +22,7 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
class MailingController extends AbstractController class MailingController extends AbstractController
{ {
use AuthenticatedUserTrait;
use ReturnUrlTrait; use ReturnUrlTrait;
public function __construct( public function __construct(
@@ -47,7 +49,7 @@ class MailingController extends AbstractController
} }
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$this->mailingService->sendPreview($form->getData(), $this->getUser()); $this->mailingService->sendPreview($form->getData(), $this->getAuthenticatedUser());
$this->addFlash('success', sprintf( $this->addFlash('success', sprintf(
'Die Vorschau wurde an %s gesendet', 'Die Vorschau wurde an %s gesendet',
@@ -164,7 +166,7 @@ class MailingController extends AbstractController
*/ */
private function renderPreview(TeamerMailingDto $mailingDto): array private function renderPreview(TeamerMailingDto $mailingDto): array
{ {
$values = $this->mailingService->placeholderValuesForUser($this->getUser()); $values = $this->mailingService->placeholderValuesForUser($this->getAuthenticatedUser());
return [ return [
'subject' => $this->mailingService->render($mailingDto->getSubject(), $values), 'subject' => $this->mailingService->render($mailingDto->getSubject(), $values),
@@ -0,0 +1,20 @@
<?php
namespace App\Controller\Traits;
use App\Entity\User;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
trait AuthenticatedUserTrait
{
public function getAuthenticatedUser(): User
{
$user = $this->getUser();
if (null === $user) {
throw new AuthenticationException();
}
return $user;
}
}
+2 -2
View File
@@ -172,7 +172,7 @@ class User implements UserInterface, TimestampableEntityInterface, SoftDeletable
public function getInitials(): string public function getInitials(): string
{ {
$token = substr($this->getFirstName(), 0, 1).substr($this->getLastName(), 0, 2); $token = substr($this->getFirstName() ?? '', 0, 1).substr($this->getLastName() ?? '', 0, 2);
return strtoupper($token); return strtoupper($token);
} }
@@ -328,7 +328,7 @@ class User implements UserInterface, TimestampableEntityInterface, SoftDeletable
public function getUserIdentifier(): string public function getUserIdentifier(): string
{ {
return $this->email; return $this->email ?? '';
} }
public function getTeamer(): ?Teamer public function getTeamer(): ?Teamer
+7 -2
View File
@@ -41,9 +41,14 @@ class DeletedUserSubscriber implements EventSubscriberInterface
return; return;
} }
$user = $this->security->getUser(); $currentUser = $this->security->getUser();
if (false === $user instanceof User || false === $user->isDeleted()) { if (false === $currentUser instanceof User) {
return;
}
/** @var User $currentUser */
if (false === $currentUser->isDeleted()) {
return; return;
} }
+1 -1
View File
@@ -158,7 +158,7 @@ class AssignmentRepository extends ServiceEntityRepository
; ;
} }
if (0 < count($filterDto->getHotels())) { if (0 < count((array)$filterDto->getHotels())) {
$constraints = []; $constraints = [];
foreach ($filterDto->getHotels() as $index => $hotel) { foreach ($filterDto->getHotels() as $index => $hotel) {
$constraints[] = $qb->expr()->like('destination.hotel', ':hotel'.$index); $constraints[] = $qb->expr()->like('destination.hotel', ':hotel'.$index);
@@ -56,17 +56,11 @@
<td class="px-4 py-3 text-right">{{ stat.providedFeedbacks }}</td> <td class="px-4 py-3 text-right">{{ stat.providedFeedbacks }}</td>
<td class="px-4 py-3 text-right">{{ stat.missingFeedbacks }}</td> <td class="px-4 py-3 text-right">{{ stat.missingFeedbacks }}</td>
<td class="px-4 py-3 text-right"> <td class="px-4 py-3 text-right">
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium <span class="{{ html_classes('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', {
{% if stat.percentageProvided >= 80 %} 'bg-green-100 text-green-800': totalPercentage >= 80,
bg-green-100 text-green-800 'bg-yellow-100 text-yellow-800': totalPercentage >= 50,
{% elseif stat.percentageProvided >= 50 %} 'bg-red-100 text-red-800': totalPercentage >= 0
bg-yellow-100 text-yellow-800 }) }}">{{ stat.percentageProvided|number_format(1, ',', '.') }}%</span>
{% else %}
bg-red-100 text-red-800
{% endif %}
">
{{ stat.percentageProvided|number_format(1, ',', '.') }}%
</span>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
@@ -87,17 +81,11 @@
<td class="px-4 py-3 text-right">{{ totalProvided }}</td> <td class="px-4 py-3 text-right">{{ totalProvided }}</td>
<td class="px-4 py-3 text-right">{{ totalMissing }}</td> <td class="px-4 py-3 text-right">{{ totalMissing }}</td>
<td class="px-4 py-3 text-right"> <td class="px-4 py-3 text-right">
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium <span class="{{ html_classes('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', {
{% if totalPercentage >= 80 %} 'bg-green-100 text-green-800': totalPercentage >= 80,
bg-green-100 text-green-800 'bg-yellow-100 text-yellow-800': totalPercentage >= 50,
{% elseif totalPercentage >= 50 %} 'bg-red-100 text-red-800': totalPercentage >= 0
bg-yellow-100 text-yellow-800 }) }}">{{ totalPercentage|number_format(1, ',', '.') }}%</span>
{% else %}
bg-red-100 text-red-800
{% endif %}
">
{{ totalPercentage|number_format(1, ',', '.') }}%
</span>
</td> </td>
</tr> </tr>
</tfoot> </tfoot>
+4 -1
View File
@@ -93,6 +93,9 @@ class EmailTextCatalogTest extends KernelTestCase
{ {
self::bootKernel(); self::bootKernel();
return self::getContainer()->get(EmailTextCatalog::class); /** @var EmailTextCatalog $catalog */
$catalog = self::getContainer()->get(EmailTextCatalog::class);
return $catalog;
} }
} }