diff --git a/src/Auth/AclAdapter/DbAclAdapter.php b/src/Auth/AclAdapter/DbAclAdapter.php index 9d813a1..92a3290 100644 --- a/src/Auth/AclAdapter/DbAclAdapter.php +++ b/src/Auth/AclAdapter/DbAclAdapter.php @@ -83,9 +83,8 @@ protected function buildKey(?string $plugin, ?string $prefix, string $controller if ($prefix) { $key .= $prefix . '/'; } - $key .= $controller; - return $key; + return $key . $controller; } } diff --git a/src/Auth/AllowAdapter/DbAllowAdapter.php b/src/Auth/AllowAdapter/DbAllowAdapter.php index ff4f470..5bae49c 100644 --- a/src/Auth/AllowAdapter/DbAllowAdapter.php +++ b/src/Auth/AllowAdapter/DbAllowAdapter.php @@ -61,9 +61,8 @@ protected function buildKey(?string $plugin, ?string $prefix, string $controller if ($prefix) { $key .= $prefix . '/'; } - $key .= $controller; - return $key; + return $key . $controller; } } diff --git a/src/Controller/Admin/AclController.php b/src/Controller/Admin/AclController.php index 280b85b..188c49f 100644 --- a/src/Controller/Admin/AclController.php +++ b/src/Controller/Admin/AclController.php @@ -59,43 +59,39 @@ public function toggle(): ?Response { if (!in_array($type, ['none', 'allow', 'deny'], true)) { throw new BadRequestException('Invalid permission type'); } - if (!in_array($roleId, array_values((new RoleSourceService())->getRoles()), true)) { + if (!in_array($roleId, (new RoleSourceService())->getRoles(), true)) { throw new BadRequestException('Invalid role'); } $permissionsTable = $this->fetchTable('TinyAuthBackend.AclPermissions'); + /** @var \TinyAuthBackend\Model\Entity\AclPermission|null $existing */ $existing = $permissionsTable->find() ->where(['action_id' => $actionId, 'role_id' => $roleId]) ->first(); if ($type === 'none') { - if ($existing) { - if (!$permissionsTable->delete($existing)) { - $this->response = $this->response->withStatus(500); - $this->set('error', 'Failed to delete permission'); - } + if ($existing && !$permissionsTable->delete($existing)) { + $this->response = $this->response->withStatus(500); + $this->set('error', 'Failed to delete permission'); + } + } elseif ($existing) { + $existing->type = $type; + $existing->description = $description; + if (!$permissionsTable->save($existing)) { + $this->response = $this->response->withStatus(500); + $this->set('error', 'Failed to update permission'); } } else { - /** @var \TinyAuthBackend\Model\Entity\AclPermission|null $existing */ - if ($existing) { - $existing->type = $type; - $existing->description = $description; - if (!$permissionsTable->save($existing)) { - $this->response = $this->response->withStatus(500); - $this->set('error', 'Failed to update permission'); - } - } else { - $permission = $permissionsTable->newEntity([ - 'action_id' => $actionId, - 'role_id' => $roleId, - 'type' => $type, - 'description' => $description, - ]); - if (!$permissionsTable->save($permission)) { - $this->response = $this->response->withStatus(500); - $this->set('error', 'Failed to save permission'); - } + $permission = $permissionsTable->newEntity([ + 'action_id' => $actionId, + 'role_id' => $roleId, + 'type' => $type, + 'description' => $description, + ]); + if (!$permissionsTable->save($permission)) { + $this->response = $this->response->withStatus(500); + $this->set('error', 'Failed to save permission'); } } @@ -117,7 +113,7 @@ public function search(): void { $this->viewBuilder()->disableAutoLayout(); $q = $this->request->getQuery('q', ''); - $q = substr($q, 0, 100); // Limit search query length + $q = substr((string)$q, 0, 100); // Limit search query length $results = ['controllers' => [], 'actions' => [], 'roles' => []]; if (strlen($q) >= 2) { @@ -244,7 +240,7 @@ protected function buildInheritedPermissions(array $roles, array $actionIds, arr $effectiveAcl = (new HierarchyService())->applyInheritance($acl, $availableRoles); $inheritedPermissions = []; foreach ($actionIds as $actionId) { - foreach (($effectiveAcl['selected']['allow'][(string)$actionId] ?? []) as $alias => $roleId) { + foreach (($effectiveAcl['selected']['allow'][(string)$actionId] ?? []) as $roleId) { if (($directPermissions[$actionId][$roleId] ?? null) === 'allow') { continue; } diff --git a/src/Controller/Admin/AppController.php b/src/Controller/Admin/AppController.php index 731d466..96ecdb2 100644 --- a/src/Controller/Admin/AppController.php +++ b/src/Controller/Admin/AppController.php @@ -110,7 +110,6 @@ private function runGate(Closure $gate): void { try { $allowed = $gate() === true; } catch (ForbiddenException $e) { - // Caller explicitly chose the 403 path — respect it. throw $e; } catch (Throwable $e) { // Convert any other failure (broken callable, transient DB diff --git a/src/Controller/Admin/ResourcesController.php b/src/Controller/Admin/ResourcesController.php index bc3e653..215e4e5 100644 --- a/src/Controller/Admin/ResourcesController.php +++ b/src/Controller/Admin/ResourcesController.php @@ -89,7 +89,7 @@ public function toggle(): ?Response { if (!in_array($type, ['none', 'allow', 'deny'], true)) { throw new BadRequestException('Invalid permission type'); } - if (!in_array($roleId, array_values((new RoleSourceService())->getRoles()), true)) { + if (!in_array($roleId, (new RoleSourceService())->getRoles(), true)) { throw new BadRequestException('Invalid role'); } @@ -103,37 +103,33 @@ public function toggle(): ?Response { $resourceAclTable = $this->fetchTable('TinyAuthBackend.ResourceAcl'); + /** @var \TinyAuthBackend\Model\Entity\ResourceAcl|null $existing */ $existing = $resourceAclTable->find() ->where(['resource_ability_id' => $abilityId, 'role_id' => $roleId]) ->first(); if ($type === 'none') { - if ($existing) { - if (!$resourceAclTable->delete($existing)) { - $this->response = $this->response->withStatus(500); - $this->set('error', 'Failed to remove permission'); - } + if ($existing && !$resourceAclTable->delete($existing)) { + $this->response = $this->response->withStatus(500); + $this->set('error', 'Failed to remove permission'); + } + } elseif ($existing) { + $existing->type = $type; + $existing->scope_id = $scopeId; + if (!$resourceAclTable->save($existing)) { + $this->response = $this->response->withStatus(500); + $this->set('error', 'Failed to update permission'); } } else { - /** @var \TinyAuthBackend\Model\Entity\ResourceAcl|null $existing */ - if ($existing) { - $existing->type = $type; - $existing->scope_id = $scopeId; - if (!$resourceAclTable->save($existing)) { - $this->response = $this->response->withStatus(500); - $this->set('error', 'Failed to update permission'); - } - } else { - $permission = $resourceAclTable->newEntity([ - 'resource_ability_id' => $abilityId, - 'role_id' => $roleId, - 'type' => $type, - 'scope_id' => $scopeId, - ]); - if (!$resourceAclTable->save($permission)) { - $this->response = $this->response->withStatus(500); - $this->set('error', 'Failed to create permission'); - } + $permission = $resourceAclTable->newEntity([ + 'resource_ability_id' => $abilityId, + 'role_id' => $roleId, + 'type' => $type, + 'scope_id' => $scopeId, + ]); + if (!$resourceAclTable->save($permission)) { + $this->response = $this->response->withStatus(500); + $this->set('error', 'Failed to create permission'); } } diff --git a/src/Identity/EntityIdentity.php b/src/Identity/EntityIdentity.php index a3b87a7..764d0ad 100644 --- a/src/Identity/EntityIdentity.php +++ b/src/Identity/EntityIdentity.php @@ -79,7 +79,7 @@ public function can(string $action, mixed $resource): bool { * @inheritDoc */ public function canResult(string $action, mixed $resource): ResultInterface { - if ($this->service === null) { + if (!$this->service instanceof AuthorizationServiceInterface) { throw new BadMethodCallException( 'EntityIdentity::canResult() requires an AuthorizationService. ' . 'Construct EntityIdentity with a service, or call can() instead.', @@ -93,7 +93,7 @@ public function canResult(string $action, mixed $resource): ResultInterface { * @inheritDoc */ public function applyScope(string $action, mixed $resource, mixed ...$optionalArgs): mixed { - if ($this->service === null) { + if (!$this->service instanceof AuthorizationServiceInterface) { return $resource; } diff --git a/src/Model/Table/RolesTable.php b/src/Model/Table/RolesTable.php index 9113728..418771f 100644 --- a/src/Model/Table/RolesTable.php +++ b/src/Model/Table/RolesTable.php @@ -120,12 +120,9 @@ public function validationDefault(Validator $validator): Validator { if (!$value) { return true; } - // Can't be your own parent - if (isset($context['data']['id']) && (int)$value === (int)$context['data']['id']) { - return false; - } - return true; + // Can't be your own parent + return !(isset($context['data']['id']) && (int)$value === (int)$context['data']['id']); }, 'message' => __d('tinyauth_backend', 'A role cannot be its own parent.'), ]) @@ -155,6 +152,7 @@ public function validationDefault(Validator $validator): Validator { return false; // Circular reference detected } $visited[] = $parentId; + /** @var \TinyAuthBackend\Model\Entity\Role|null $parent */ $parent = $this->find()->select(['parent_id'])->where(['id' => $parentId])->first(); $parentId = $parent ? (int)$parent->parent_id : null; $maxDepth--; diff --git a/src/Model/Table/ScopesTable.php b/src/Model/Table/ScopesTable.php index e7ed499..8b5d86d 100644 --- a/src/Model/Table/ScopesTable.php +++ b/src/Model/Table/ScopesTable.php @@ -58,7 +58,7 @@ public function validationDefault(Validator $validator): Validator { ->requirePresence('entity_field', 'create') ->notEmptyString('entity_field') ->add('entity_field', 'validFieldName', [ - 'rule' => ['custom', '/^[a-zA-Z_][a-zA-Z0-9_]*$/'], + 'rule' => ['custom', '/^[a-zA-Z_]\w*$/'], 'message' => __d('tinyauth_backend', 'Invalid field name. Use only letters, numbers, and underscores.'), ]); @@ -68,7 +68,7 @@ public function validationDefault(Validator $validator): Validator { ->requirePresence('user_field', 'create') ->notEmptyString('user_field') ->add('user_field', 'validFieldName', [ - 'rule' => ['custom', '/^[a-zA-Z_][a-zA-Z0-9_]*$/'], + 'rule' => ['custom', '/^[a-zA-Z_]\w*$/'], 'message' => __d('tinyauth_backend', 'Invalid field name. Use only letters, numbers, and underscores.'), ]); diff --git a/src/Policy/TinyAuthPolicy.php b/src/Policy/TinyAuthPolicy.php index b157586..94412f6 100644 --- a/src/Policy/TinyAuthPolicy.php +++ b/src/Policy/TinyAuthPolicy.php @@ -77,7 +77,7 @@ public function __construct(?TinyAuthService $tinyAuth = null) { */ public function before(?IdentityInterface $identity, mixed $resource, string $action): ?bool { $user = $this->resolveUser($identity); - if ($user === null) { + if (!$user instanceof EntityInterface) { return false; } @@ -101,7 +101,7 @@ public function before(?IdentityInterface $identity, mixed $resource, string $ac */ public function can(?IdentityInterface $identity, string $ability, EntityInterface $entity): bool { $user = $this->resolveUser($identity); - if ($user === null) { + if (!$user instanceof EntityInterface) { return false; } @@ -235,7 +235,7 @@ public function scopeView(?IdentityInterface $identity, SelectQuery $query): Sel */ protected function applyScopeConditions(?IdentityInterface $identity, SelectQuery $query, string $ability): SelectQuery { $user = $this->resolveUser($identity); - if ($user === null) { + if (!$user instanceof EntityInterface) { return $query->where(['1 = 0']); } @@ -266,7 +266,7 @@ protected function applyScopeConditions(?IdentityInterface $identity, SelectQuer * @return \Cake\Datasource\EntityInterface|null */ protected function resolveUser(?IdentityInterface $identity): ?EntityInterface { - if ($identity === null) { + if (!$identity instanceof IdentityInterface) { return null; } $data = $identity->getOriginalData(); diff --git a/src/Policy/TinyAuthResolver.php b/src/Policy/TinyAuthResolver.php index 2b62259..f642f47 100644 --- a/src/Policy/TinyAuthResolver.php +++ b/src/Policy/TinyAuthResolver.php @@ -100,7 +100,7 @@ public function __construct(array $allowedClasses = [], ?TinyAuthPolicy $policy public function getPolicy(mixed $resource): object { $classes = $this->resolveCandidateClasses($resource); if ($classes === []) { - throw new MissingPolicyException([is_object($resource) ? $resource::class : gettype($resource)]); + throw new MissingPolicyException([get_debug_type($resource)]); } if (!$this->isAllowed($classes)) { diff --git a/src/Service/FeatureService.php b/src/Service/FeatureService.php index 30af370..63cc32e 100644 --- a/src/Service/FeatureService.php +++ b/src/Service/FeatureService.php @@ -84,15 +84,13 @@ public function getEnabledFeatures(): array { } elseif ($configValue === false) { // Force disabled $result[$feature] = false; - } else { + } elseif ($feature === 'roles') { // Auto-detect - if ($feature === 'roles') { - // Special handling: roles available from external source OR table - $hasExternalSource = Configure::read('TinyAuthBackend.roleSource') !== null; - $result[$feature] = $hasExternalSource || $this->tableExists($table); - } else { - $result[$feature] = $this->tableExists($table); - } + // Special handling: roles available from external source OR table + $hasExternalSource = Configure::read('TinyAuthBackend.roleSource') !== null; + $result[$feature] = $hasExternalSource || $this->tableExists($table); + } else { + $result[$feature] = $this->tableExists($table); } } @@ -184,7 +182,7 @@ protected function tableExists(string $tableName): bool { $tables = $connection->getSchemaCollection()->listTables(); return in_array($tableName, $tables, true); - } catch (Exception $e) { + } catch (Exception) { // Treat connection errors as "table missing" - conservative approach // Logging could be added here if debugging is needed return false; diff --git a/src/Service/ImportExportService.php b/src/Service/ImportExportService.php index 73989d6..9af7344 100644 --- a/src/Service/ImportExportService.php +++ b/src/Service/ImportExportService.php @@ -185,16 +185,17 @@ public function importIni(string $content, string $mode = 'merge'): array { $prefix = null; $name = $controllerPath; - if (str_contains($name, '.')) { - [$plugin, $name] = explode('.', $name, 2); + if (str_contains((string)$name, '.')) { + [$plugin, $name] = explode('.', (string)$name, 2); } - if (str_contains($name, '/')) { - $parts = explode('/', $name); + if (str_contains((string)$name, '/')) { + $parts = explode('/', (string)$name); $name = array_pop($parts); $prefix = implode('/', $parts); } // Find or create controller + /** @var \TinyAuthBackend\Model\Entity\TinyauthController|null $controller */ $controller = $controllersTable->find() ->where([ 'plugin IS' => $plugin, @@ -217,16 +218,19 @@ public function importIni(string $content, string $mode = 'merge'): array { continue; } } + /** @var \TinyAuthBackend\Model\Entity\TinyauthController $typedController */ + $typedController = $controller; // Process actions foreach ($actions as $actionName => $rolesList) { + /** @var \TinyAuthBackend\Model\Entity\Action|null $action */ $action = $actionsTable->find() - ->where(['controller_id' => $controller->id, 'name' => $actionName]) + ->where(['controller_id' => $typedController->id, 'name' => $actionName]) ->first(); if (!$action) { $action = $actionsTable->newEntity([ - 'controller_id' => $controller->id, + 'controller_id' => $typedController->id, 'name' => $actionName, 'is_public' => false, ]); @@ -238,9 +242,11 @@ public function importIni(string $content, string $mode = 'merge'): array { continue; } } + /** @var \TinyAuthBackend\Model\Entity\Action $typedAction */ + $typedAction = $action; // Parse roles - $roleAliases = array_map('trim', explode(',', $rolesList)); + $roleAliases = array_map('trim', explode(',', (string)$rolesList)); foreach ($roleAliases as $alias) { if (!isset($roleLookup[$alias])) { $result['errors'][] = "Unknown role: {$alias}"; @@ -250,13 +256,14 @@ public function importIni(string $content, string $mode = 'merge'): array { $roleId = $roleLookup[$alias]; + /** @var \TinyAuthBackend\Model\Entity\AclPermission|null $existing */ $existing = $permissionsTable->find() - ->where(['action_id' => $action->id, 'role_id' => $roleId]) + ->where(['action_id' => $typedAction->id, 'role_id' => $roleId]) ->first(); if (!$existing) { $permission = $permissionsTable->newEntity([ - 'action_id' => $action->id, + 'action_id' => $typedAction->id, 'role_id' => $roleId, 'type' => 'allow', ]); diff --git a/src/Service/ResourceSyncService.php b/src/Service/ResourceSyncService.php index 863a583..308678c 100644 --- a/src/Service/ResourceSyncService.php +++ b/src/Service/ResourceSyncService.php @@ -112,6 +112,7 @@ public function sync(array $options = []): array { $result = ['added' => 0, 'abilities_added' => 0]; foreach ($scanned as $item) { + /** @var \TinyAuthBackend\Model\Entity\Resource|null $existing */ $existing = $resourcesTable->find() ->where(['entity_class' => $item['entity_class']]) ->first(); @@ -129,17 +130,20 @@ public function sync(array $options = []): array { } if ($existing && $addDefaultAbilities) { + /** @var \TinyAuthBackend\Model\Entity\Resource $typedExisting */ + $typedExisting = $existing; foreach ($this->defaultAbilities as $abilityName) { + /** @var \TinyAuthBackend\Model\Entity\ResourceAbility|null $existingAbility */ $existingAbility = $abilitiesTable->find() ->where([ - 'resource_id' => $existing->id, + 'resource_id' => $typedExisting->id, 'name' => $abilityName, ]) ->first(); if (!$existingAbility) { $ability = $abilitiesTable->newEntity([ - 'resource_id' => $existing->id, + 'resource_id' => $typedExisting->id, 'name' => $abilityName, ]); if ($abilitiesTable->save($ability)) { diff --git a/src/Service/RoleSourceService.php b/src/Service/RoleSourceService.php index 2ef8ce9..749881c 100644 --- a/src/Service/RoleSourceService.php +++ b/src/Service/RoleSourceService.php @@ -157,7 +157,7 @@ protected function getRolesFromTable(): array { ->toArray(); return $roles; - } catch (Exception $e) { + } catch (Exception) { return []; } } @@ -217,7 +217,7 @@ protected function syncExternalRoles(array $roles): void { try { /** @var \TinyAuthBackend\Model\Table\RolesTable $rolesTable */ $rolesTable = TableRegistry::getTableLocator()->get('TinyAuthBackend.Roles'); - } catch (Exception $e) { + } catch (Exception) { return; } @@ -225,20 +225,24 @@ protected function syncExternalRoles(array $roles): void { foreach ($roles as $alias => $id) { $sortOrder++; + /** @var \TinyAuthBackend\Model\Entity\Role|null $role */ $role = $rolesTable->find()->where(['id' => $id])->first(); if (!$role) { $role = $rolesTable->find()->where(['alias' => $alias])->first(); } if ($role) { - $role = $rolesTable->patchEntity($role, [ + /** @var \TinyAuthBackend\Model\Entity\Role $typedRole */ + $typedRole = $role; + /** @var \TinyAuthBackend\Model\Entity\Role $updatedRole */ + $updatedRole = $rolesTable->patchEntity($typedRole, [ 'id' => $id, 'alias' => $alias, - 'name' => $role->name ?: ucfirst($alias), + 'name' => $typedRole->name ?: ucfirst($alias), 'parent_id' => null, - 'sort_order' => $role->sort_order ?: $sortOrder, + 'sort_order' => $typedRole->sort_order ?: $sortOrder, ]); - $rolesTable->save($role); + $rolesTable->save($updatedRole); continue; } diff --git a/src/Service/TinyAuthService.php b/src/Service/TinyAuthService.php index 300fd75..54f0afa 100644 --- a/src/Service/TinyAuthService.php +++ b/src/Service/TinyAuthService.php @@ -271,6 +271,7 @@ public function getUserRoles(EntityInterface $user): array { if (!$multiRole) { $roleColumn = Configure::read('TinyAuthBackend.roleColumn') ?: 'role_id'; $rolesTable = TableRegistry::getTableLocator()->get('TinyAuthBackend.Roles'); + /** @var \TinyAuthBackend\Model\Entity\Role|null $role */ $role = $rolesTable->find()->where(['id' => $user->get($roleColumn)])->first(); return $role ? [$role->alias] : []; diff --git a/src/Utility/Importer.php b/src/Utility/Importer.php index cad3904..7a04084 100644 --- a/src/Utility/Importer.php +++ b/src/Utility/Importer.php @@ -128,6 +128,7 @@ protected function ensureAction(array $row, string $actionName): array { /** @var \TinyAuthBackend\Model\Table\ActionsTable $actionsTable */ $actionsTable = $this->fetchModel('TinyAuthBackend.Actions'); + /** @var \TinyAuthBackend\Model\Entity\TinyauthController|null $controller */ $controller = $controllersTable->find() ->where([ 'plugin IS' => $row['plugin'], @@ -145,6 +146,7 @@ protected function ensureAction(array $row, string $actionName): array { $controllersTable->saveOrFail($controller); } + /** @var \TinyAuthBackend\Model\Entity\Action|null $action */ $action = $actionsTable->find() ->where([ 'controller_id' => $controller->id, @@ -191,6 +193,7 @@ protected function upsertAclPermission(int $actionId, string $roleAlias, string /** @var \TinyAuthBackend\Model\Table\AclPermissionsTable $permissionsTable */ $permissionsTable = $this->fetchModel('TinyAuthBackend.AclPermissions'); + /** @var \TinyAuthBackend\Model\Entity\AclPermission|null $permission */ $permission = $permissionsTable->find() ->where(['action_id' => $actionId, 'role_id' => $roleId]) ->first(); diff --git a/tests/schema.php b/tests/schema.php index 2b6fd5e..d246930 100644 --- a/tests/schema.php +++ b/tests/schema.php @@ -21,7 +21,7 @@ $tableObject = (new ReflectionClass($class))->getProperty('table'); $tableName = $tableObject->getDefaultValue(); - } catch (ReflectionException $e) { + } catch (ReflectionException) { continue; }