refactor: fix all 105 PHPStan 2 strict type findings across core and modules

Resolve all non-false-positive PHPStan 2 findings, reducing the baseline
from 486 to 382 entries (only unused-public false positives remain).

Categories fixed:
- Remove 39 redundant type checks (is_string, is_array, is_object, method_exists)
- Remove 12 no-op array_values() on already-sequential lists
- Simplify 13 null-coalesce on guaranteed offsets
- Remove 8 always-true instanceof checks
- Replace 12 redundant test assertions (assertTrue(true) → addToAssertionCount)
- Simplify 6 unnecessary nullsafe operators (?-> → ->)
- Fix 6 always-true !== '' comparisons
- Fix remaining: unset.offset, return.unusedType, staticMethod narrowing

53 files changed across core/, modules/, pages/, and tests/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-14 12:54:20 +02:00
parent a736566071
commit 3f0db68b27
53 changed files with 90 additions and 640 deletions

View File

@@ -95,7 +95,7 @@ class AccessPolicyFactory
if ($this->moduleRegistry !== null) {
try {
foreach ($this->moduleRegistry->getAuthorizationPolicies() as $policyClass) {
if (!is_string($policyClass) || trim($policyClass) === '') {
if (trim($policyClass) === '') {
continue;
}
$policy = $this->instantiateModulePolicy($policyClass);

View File

@@ -15,9 +15,7 @@ class AuthorizationService
public function __construct(array $policies)
{
foreach ($policies as $policy) {
if ($policy instanceof AuthorizationPolicyInterface) {
$this->policies[] = $policy;
}
$this->policies[] = $policy;
}
}

View File

@@ -53,14 +53,10 @@ final class UiAccessService
continue;
}
if (!is_array($definition)) {
$resolved[$key] = false;
continue;
}
$ability = $definition['ability'];
$context = [];
if (array_key_exists('context', $definition) && is_array($definition['context'])) {
if (array_key_exists('context', $definition)) {
$context = $this->normalizeContext($definition['context']);
}
$resolved[$key] = $this->allow($actorUserId, $ability, [
@@ -113,7 +109,7 @@ final class UiAccessService
private function normalizeContext(array $context): array
{
$normalized = $this->normalizeValue($context);
return is_array($normalized) ? $normalized : [];
return $this->normalizeValue($context);
}
private function normalizeValue(mixed $value): mixed

View File

@@ -278,12 +278,10 @@ class TenantSsoService
if ($auth['client_secret_override_enc'] === '') {
return ['ok' => false, 'error' => 'client_secret_override_required'];
}
if ($auth['client_secret_override_enc'] !== '') {
try {
$clientSecret = $this->cryptoGateway->decryptString($auth['client_secret_override_enc']);
} catch (\Throwable $exception) {
return ['ok' => false, 'error' => 'secret_invalid'];
}
try {
$clientSecret = $this->cryptoGateway->decryptString($auth['client_secret_override_enc']);
} catch (\Throwable $exception) {
return ['ok' => false, 'error' => 'secret_invalid'];
}
if (trim($clientSecret) === '') {
return ['ok' => false, 'error' => 'client_secret_override_required'];

View File

@@ -138,6 +138,6 @@ class BrandingLogoService
usort($matches, static function ($a, $b) {
return filemtime($b) <=> filemtime($a);
});
return $matches[0] ?? null;
return $matches[0];
}
}

View File

@@ -136,9 +136,6 @@ class UserCustomFieldValueService
$tenantScopeId = (int) ($tenantScopeId ?? 0);
$orderedTenants = [];
foreach ($tenantSummaries as $tenantSummary) {
if (!is_array($tenantSummary)) {
continue;
}
$tenantId = (int) ($tenantSummary['id'] ?? 0);
if ($tenantId <= 0) {
continue;
@@ -579,7 +576,7 @@ class UserCustomFieldValueService
private static function mapPublicValueByType(string $type, ?array $valueData, array $optionsById)
{
$hasValue = is_array($valueData);
$hasValue = $valueData !== null;
if ($type === 'multiselect') {
if (!$hasValue) {
return [];

View File

@@ -112,7 +112,7 @@ trait ImageUploadTrait
usort($matches, static function ($a, $b) {
return filemtime($b) <=> filemtime($a);
});
return $matches[0] ?? null;
return $matches[0];
}
protected static function imageCreateResource(string $path, string $mime)

View File

@@ -126,9 +126,6 @@ class CsvReaderService
$lineNumber = 0;
while (($row = fgetcsv($handle, 0, $delimiter, '"', '\\')) !== false) {
$lineNumber++;
if (!is_array($row)) {
continue;
}
$row = $this->normalizeRowColumns($row, count($row));
if ($this->isEmptyRow($row)) {
continue;
@@ -207,9 +204,6 @@ class CsvReaderService
if ($lineNumber <= $headerLine) {
continue;
}
if (!is_array($row)) {
continue;
}
$row = $this->normalizeRowColumns($row, count($headers));
if ($this->isEmptyRow($row)) {
continue;

View File

@@ -161,7 +161,7 @@ class ScheduledJobRegistry
'default_schedule_time' => $jobDefinition['default_schedule_time'],
'default_schedule_weekdays_csv' => $jobDefinition['default_schedule_weekdays_csv'],
'default_catchup_once' => (int) $jobDefinition['default_catchup_once'],
'allowed_schedule_types' => array_values($jobDefinition['allowed_schedule_types']),
'allowed_schedule_types' => $jobDefinition['allowed_schedule_types'],
];
}
}

View File

@@ -196,7 +196,7 @@ class SchedulerRunService
$errorCode = 'job_not_registered';
} else {
$execution = $this->scheduledJobRegistry->execute((string) $job['job_key'], $actorUserId);
$status = ScheduledJobRunStatus::tryNormalize((string) $execution['status'])?->value
$status = ScheduledJobRunStatus::tryNormalize((string) $execution['status'])->value
?? ScheduledJobRunStatus::Failed->value;
$errorCode = $this->nullableString($execution['error_code']);
$errorMessage = $this->nullableString($execution['error_message']);

View File

@@ -156,7 +156,7 @@ class TenantAvatarService
usort($matches, static function ($a, $b) {
return filemtime($b) <=> filemtime($a);
});
return $matches[0] ?? null;
return $matches[0];
}
private function avatarDirs(string $uuid): array

View File

@@ -105,19 +105,9 @@ class UserAccessPdfService
private static function configurePdfOptions(Options $options): void
{
// Keep PDF rendering deterministic and avoid remote/network execution.
if (method_exists($options, 'setIsRemoteEnabled')) {
$options->setIsRemoteEnabled(false);
} else {
$options->set('isRemoteEnabled', false);
}
if (method_exists($options, 'setIsPhpEnabled')) {
$options->setIsPhpEnabled(false);
} else {
$options->set('isPhpEnabled', false);
}
if (method_exists($options, 'setDefaultFont')) {
$options->setDefaultFont('DejaVu Sans');
}
$options->setIsRemoteEnabled(false);
$options->setIsPhpEnabled(false);
$options->setDefaultFont('DejaVu Sans');
}
private static function renderTemplate(string $template, array $vars, string $locale): string

View File

@@ -217,6 +217,6 @@ class UserAvatarService
usort($matches, static function ($a, $b) {
return filemtime($b) <=> filemtime($a);
});
return $matches[0] ?? null;
return $matches[0];
}
}