Files
breadcrumb-the-shire/core/Service/Access/AccessPolicyFactory.php
fs 3f0db68b27 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>
2026-04-14 12:54:20 +02:00

124 lines
4.8 KiB
PHP

<?php
namespace MintyPHP\Service\Access;
use MintyPHP\App\Module\ModuleRegistry;
use MintyPHP\Service\Tenant\TenantScopeService;
class AccessPolicyFactory
{
private ?UserAuthorizationPolicy $userAuthorizationPolicy = null;
private ?RoleAuthorizationPolicy $roleAuthorizationPolicy = null;
private ?PermissionAuthorizationPolicy $permissionAuthorizationPolicy = null;
private ?OperationsAuthorizationPolicy $operationsAuthorizationPolicy = null;
private ?SettingsAuthorizationPolicy $settingsAuthorizationPolicy = null;
private ?TenantAuthorizationPolicy $tenantAuthorizationPolicy = null;
private ?DepartmentAuthorizationPolicy $departmentAuthorizationPolicy = null;
private ?AuthorizationService $authorizationService = null;
private \Closure $moduleClassResolver;
public function __construct(
private readonly PermissionService $permissionService,
private readonly TenantScopeService $tenantScopeService,
private readonly ?ModuleRegistry $moduleRegistry = null,
?callable $moduleClassResolver = null
) {
$this->moduleClassResolver = $moduleClassResolver !== null
? \Closure::fromCallable($moduleClassResolver)
: static fn (string $class): ?object => null;
}
public function createUserAuthorizationPolicy(): UserAuthorizationPolicy
{
return $this->userAuthorizationPolicy ??= new UserAuthorizationPolicy(
$this->permissionService,
$this->tenantScopeService
);
}
public function createRoleAuthorizationPolicy(): RoleAuthorizationPolicy
{
return $this->roleAuthorizationPolicy ??= new RoleAuthorizationPolicy($this->permissionService);
}
public function createPermissionAuthorizationPolicy(): PermissionAuthorizationPolicy
{
return $this->permissionAuthorizationPolicy ??= new PermissionAuthorizationPolicy($this->permissionService);
}
public function createOperationsAuthorizationPolicy(): OperationsAuthorizationPolicy
{
return $this->operationsAuthorizationPolicy ??= new OperationsAuthorizationPolicy($this->permissionService);
}
public function createSettingsAuthorizationPolicy(): SettingsAuthorizationPolicy
{
return $this->settingsAuthorizationPolicy ??= new SettingsAuthorizationPolicy($this->permissionService);
}
public function createTenantAuthorizationPolicy(): TenantAuthorizationPolicy
{
return $this->tenantAuthorizationPolicy ??= new TenantAuthorizationPolicy(
$this->permissionService,
$this->tenantScopeService
);
}
public function createDepartmentAuthorizationPolicy(): DepartmentAuthorizationPolicy
{
return $this->departmentAuthorizationPolicy ??= new DepartmentAuthorizationPolicy(
$this->permissionService,
$this->tenantScopeService
);
}
// Assembles all policies into a single AuthorizationService.
// Core policies are registered first; module-contributed policies are appended.
// Each ability maps to exactly one policy via supports() — first match wins.
public function createAuthorizationService(): AuthorizationService
{
if ($this->authorizationService !== null) {
return $this->authorizationService;
}
$policies = [
$this->createUserAuthorizationPolicy(),
$this->createRoleAuthorizationPolicy(),
$this->createPermissionAuthorizationPolicy(),
$this->createOperationsAuthorizationPolicy(),
$this->createSettingsAuthorizationPolicy(),
$this->createTenantAuthorizationPolicy(),
$this->createDepartmentAuthorizationPolicy(),
];
// Append module-contributed authorization policies.
if ($this->moduleRegistry !== null) {
try {
foreach ($this->moduleRegistry->getAuthorizationPolicies() as $policyClass) {
if (trim($policyClass) === '') {
continue;
}
$policy = $this->instantiateModulePolicy($policyClass);
if ($policy instanceof AuthorizationPolicyInterface) {
$policies[] = $policy;
}
}
} catch (\Throwable) {
// fail-open: no module registry available in this context
}
}
return $this->authorizationService = new AuthorizationService($policies);
}
private function instantiateModulePolicy(string $policyClass): ?AuthorizationPolicyInterface
{
try {
$instance = ($this->moduleClassResolver)($policyClass);
return $instance instanceof AuthorizationPolicyInterface ? $instance : null;
} catch (\Throwable) {
return null;
}
}
}