fix: resolve all quality gate failures — i18n key, typography tokens, PHPStan errors, style

- Add missing i18n key "LDAP attribute map could not be encoded" (de+en)
- Replace raw font-weight/line-height with design tokens in app-topbar.css
- Fix import ordering in SchedulerRunService.php (php-cs-fixer)
- Fix PHPStan mock chain errors in DebitorDetailServiceTest and TenantSsoServiceTest (PHPUnit 12 API)
- Simplify redundant comparison in NotificationService dedupe window
- Add PHPStan type hint for mock callback array in SchedulerJobFailedNotificationListenerTest
- Fix undefined variable and add flow-analysis suppression in login().php
- Increase dev PHP memory_limit to 1G for PHPStan (prod stays 256M)

All 6 quality gates now pass: QG-001 (1618 tests), QG-002 (0 errors),
QG-003 (6630 assertions), QG-006 (0 fixable), QG-008, QG-009.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-13 19:06:12 +02:00
parent 3827b09205
commit 4967095bb8
10 changed files with 13 additions and 10 deletions

View File

@@ -5,7 +5,7 @@ error_reporting=E_ALL & ~E_DEPRECATED
log_errors=1
; --- Resource limits ---
memory_limit=256M
memory_limit=1G
upload_max_filesize=10M
post_max_size=12M

View File

@@ -1434,6 +1434,7 @@
"Write-only. Leave empty to keep current value.": "Nur Schreibzugriff. Leer lassen, um den aktuellen Wert beizubehalten.",
"Your account is deactivated.": "Ihr Konto ist deaktiviert.",
"LDAP": "LDAP",
"LDAP attribute map could not be encoded": "LDAP-Attributzuordnung konnte nicht kodiert werden",
"Drop file here or click to select": "Datei hierher ziehen oder klicken",
"Remove selected file": "Ausgewaehlte Datei entfernen",
"Replace": "Ersetzen",

View File

@@ -1434,6 +1434,7 @@
"Write-only. Leave empty to keep current value.": "Write-only. Leave empty to keep current value.",
"Your account is deactivated.": "Your account is deactivated.",
"LDAP": "LDAP",
"LDAP attribute map could not be encoded": "LDAP attribute map could not be encoded",
"Drop file here or click to select": "Drop file here or click to select",
"Remove selected file": "Remove selected file",
"Replace": "Replace",

View File

@@ -2,13 +2,13 @@
namespace MintyPHP\Service\Scheduler;
use MintyPHP\App\Module\ModuleEventDispatcher;
use MintyPHP\Domain\Taxonomy\ScheduledJobRunStatus;
use MintyPHP\Domain\Taxonomy\ScheduledJobTriggerType;
use MintyPHP\Domain\Taxonomy\SchedulerRuntimeResult;
use MintyPHP\Repository\Scheduler\ScheduledJobRepositoryInterface;
use MintyPHP\Repository\Scheduler\ScheduledJobRunRepositoryInterface;
use MintyPHP\Repository\Scheduler\SchedulerRuntimeRepositoryInterface;
use MintyPHP\App\Module\ModuleEventDispatcher;
use MintyPHP\Repository\Support\DatabaseSessionRepository;
use MintyPHP\Repository\Support\RepoQuery;
use MintyPHP\Service\Audit\AuditRecorderInterface;

View File

@@ -1350,7 +1350,7 @@ class DebitorDetailServiceTest extends TestCase
{
$futureDate = date('Y-m-d', strtotime('+7 days'));
$gateway = $this->createMock(BcODataGateway::class);
$gateway->method('getMeetingsForCustomer')->with('10254')->willReturn([
$gateway->expects($this->any())->method('getMeetingsForCustomer')->with('10254')->willReturn([
['Entry_No' => 1, 'Appointment_Date' => $futureDate, 'Customer_No' => '10254', 'Customer_Name' => 'Test GmbH', 'Salesperson_Code' => 'MER', 'Comment' => 'Workshop', 'Released_by' => '', 'Release_Date' => '0001-01-01'],
]);

View File

@@ -236,7 +236,7 @@ class NotificationService
}
$windowMinutes = self::DEDUPE_TYPES[$type];
$windowMinutes = is_int($windowMinutes) && $windowMinutes > 0 ? $windowMinutes : self::DEDUPE_WINDOW_MINUTES;
$windowMinutes = is_int($windowMinutes) ? $windowMinutes : self::DEDUPE_WINDOW_MINUTES;
$tenantScope = $tenantId !== null && $tenantId > 0 ? $tenantId : 0;
$raw = implode('|', [

View File

@@ -39,6 +39,7 @@ class SchedulerJobFailedNotificationListenerTest extends TestCase
[30, [2, 3]],
]);
/** @var list<array{user: int, tenant: int|null}> $calls */
$calls = [];
$this->notifService->expects($this->exactly(4))
->method('createFromMessage')

View File

@@ -88,14 +88,14 @@ $resolveLoginCandidates = static function (string $inputEmail) use ($userReadRep
$isKnownActiveUser = $user && (int) ($user['active'] ?? 0) === 1 && (int) ($user['id'] ?? 0) > 0;
$tenants = [];
$discovery = false;
if ($isKnownActiveUser) {
$userId = (int) $user['id'];
$tenants = $userTenantContextService->getAssignedActiveTenants($userId);
}
// Fallback: domain-based SSO discovery for users not yet provisioned locally
$discovery = false;
$discoveryMethodsByTenantId = [];
if (!$tenants) {
$discoveryResults = $tenantSsoService->discoverTenantsByEmailDomain($emailValue);
if (!$discoveryResults) {
@@ -103,7 +103,6 @@ $resolveLoginCandidates = static function (string $inputEmail) use ($userReadRep
}
$discovery = true;
$tenants = array_map(static fn (array $r): array => $r['tenant'], $discoveryResults);
$discoveryMethodsByTenantId = [];
foreach ($discoveryResults as $r) {
$discoveryMethodsByTenantId[(int) $r['id']] = $r['methods'];
}
@@ -120,6 +119,7 @@ $resolveLoginCandidates = static function (string $inputEmail) use ($userReadRep
if ($tenantSlug === '') {
continue;
}
/** @phpstan-ignore ternary.alwaysFalse ($discovery is set to true inside the !$tenants branch that also reassigns $tenants) */
$methods = $discovery
? ($discoveryMethodsByTenantId[$tenantId] ?? ['local' => false, 'microsoft' => false, 'microsoft_reason' => '', 'ldap' => false, 'ldap_reason' => ''])
: $tenantSsoService->resolveTenantLoginMethods($tenantId);

View File

@@ -467,7 +467,7 @@ class TenantSsoServiceTest extends TestCase
$tenantGateway->method('findById')->willReturn(['id' => 5, 'status' => 'active', 'uuid' => 'abc', 'description' => 'Acme']);
$microsoftRepo = $this->createMock(TenantMicrosoftAuthRepositoryInterface::class);
$microsoftRepo->method('findEnabledWithExplicitDomain')->with('acme.com')->willReturn([
$microsoftRepo->expects($this->any())->method('findEnabledWithExplicitDomain')->with('acme.com')->willReturn([
['tenant_id' => 5, 'allowed_domains' => 'acme.com'],
]);
$microsoftRepo->method('findByTenantId')->willReturn([

View File

@@ -174,8 +174,8 @@
box-shadow: none;
color: var(--app-topbar-muted);
font-size: inherit;
font-weight: normal;
line-height: 1;
font-weight: var(--font-regular);
line-height: var(--leading-none);
cursor: pointer;
transition:
background-color var(--app-transition),