| Total Complexity | 151 |
| Total Lines | 787 |
| Duplicated Lines | 0 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 0 |
Complex classes like TPermissionsManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use TPermissionsManager, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 161 | class TPermissionsManager extends \Prado\TModule implements IPermissions |
||
| 162 | { |
||
| 163 | public const PERMISSIONS_BEHAVIOR = 'permissions'; |
||
| 164 | |||
| 165 | public const USER_PERMISSIONS_BEHAVIOR = 'usercan'; |
||
| 166 | |||
| 167 | public const PERMISSIONS_CONFIG_BEHAVIOR = 'permissionsConfig'; |
||
| 168 | |||
| 169 | public const PERM_PERMISSIONS_SHELL = 'permissions_shell'; |
||
| 170 | |||
| 171 | public const PERM_PERMISSIONS_MANAGE_ROLES = 'permissions_manage_roles'; |
||
| 172 | |||
| 173 | public const PERM_PERMISSIONS_MANAGE_RULES = 'permissions_manage_rules'; |
||
| 174 | |||
| 175 | /** @var string[] roles that get all permissions, default [] */ |
||
| 176 | private $_superRoles; |
||
| 177 | |||
| 178 | /** @var string[] Default roles to give all users, default [] */ |
||
| 179 | private $_defaultRoles; |
||
| 180 | |||
| 181 | /** @var array<string, \Prado\Security\TAuthorizationRuleCollection> contains the rules for each permission */ |
||
| 182 | private $_permissionRules = []; |
||
| 183 | |||
| 184 | /** @var array<string, string> contains the short descriptions for each permission */ |
||
| 185 | private $_descriptions = []; |
||
| 186 | |||
| 187 | /** @var array<string, \Prado\Security\TAuthorizationRule[]> the rules to apply to newly registered Permissions */ |
||
| 188 | private $_autoRules = []; |
||
| 189 | |||
| 190 | /** @var array<string, string[]> contains the hierarchy of roles and children roles/permissions */ |
||
| 191 | private $_hierarchy = []; |
||
| 192 | |||
| 193 | /** @var bool is the module initialized */ |
||
| 194 | private $_initialized = false; |
||
| 195 | |||
| 196 | /** @var string role hierarchy and permission rules information file */ |
||
| 197 | private $_permissionFile; |
||
| 198 | |||
| 199 | /** @var numeric the priority of the Allow With Permission Rule, default 5 */ |
||
|
|
|||
| 200 | private $_autoRulePriority = 5; |
||
| 201 | |||
| 202 | /** @var bool add allow users with permission-role, default true */ |
||
| 203 | private $_autoAllowWithPermission = true; |
||
| 204 | |||
| 205 | /** @var bool add module rules, allows User's data, default true */ |
||
| 206 | private $_autoRulePresetRules = true; |
||
| 207 | |||
| 208 | /** @var bool add Deny All rule to every permissions as the last rule, default true */ |
||
| 209 | private $_autoDenyAll = true; |
||
| 210 | |||
| 211 | /** @var numeric the priority of the module Rule, usually these are Allow User As Owner, default 1000000 */ |
||
| 212 | private $_autoDenyAllPriority = 1000000; |
||
| 213 | |||
| 214 | /** @var \Prado\Util\TDbParameterModule the database module providing runtime roles and rules */ |
||
| 215 | private $_dbParameter; |
||
| 216 | |||
| 217 | /** @var numeric the priority of the module Rule, usually these are Allow User As Owner */ |
||
| 218 | private $_parameter = 'configuration:TPermissionsManager:runtime'; |
||
| 219 | |||
| 220 | /** |
||
| 221 | * @returtn ?TPermissionsManager The PermissionsManager for the application. |
||
| 222 | */ |
||
| 223 | public static function getManager(): ?TPermissionsManager |
||
| 224 | { |
||
| 225 | $app = Prado::getApplication(); |
||
| 226 | if ($app) { |
||
| 227 | $modules = $app->getModulesByType(self::class); |
||
| 228 | if (count($modules)) { |
||
| 229 | return array_values($modules)[0]; |
||
| 230 | } |
||
| 231 | } |
||
| 232 | return null; |
||
| 233 | } |
||
| 234 | |||
| 235 | /** |
||
| 236 | * @param \Prado\Security\Permissions\TPermissionsManager $manager |
||
| 237 | * @return TPermissionEvent[] the dynamic events to have authorization |
||
| 238 | */ |
||
| 239 | public function getPermissions($manager) |
||
| 240 | { |
||
| 241 | return [ |
||
| 242 | new TPermissionEvent(static::PERM_PERMISSIONS_SHELL, 'Activates permissions shell commands.', 'dyRegisterShellAction'), |
||
| 243 | new TPermissionEvent(static::PERM_PERMISSIONS_MANAGE_ROLES, 'Manages Db Permissions Role Children.', ['dyAddRoleChildren', 'dyRemoveRoleChildren']), |
||
| 244 | new TPermissionEvent(static::PERM_PERMISSIONS_MANAGE_RULES, 'Manages Db Permissions Rules.', ['dyAddPermissionRule', 'dyRemovePermissionRule']), |
||
| 245 | ]; |
||
| 246 | } |
||
| 247 | |||
| 248 | /** |
||
| 249 | * @param array|TXmlElement $config the application configuration |
||
| 250 | */ |
||
| 251 | public function init($config) |
||
| 252 | { |
||
| 253 | $app = $this->getApplication(); |
||
| 254 | if (is_string($this->_dbParameter)) { |
||
| 255 | if (($dbParameter = $app->getModule($this->_dbParameter)) === null) { |
||
| 256 | throw new TConfigurationException('permissions_dbparameter_nonexistent', $this->_dbParameter); |
||
| 257 | } |
||
| 258 | if (!($dbParameter instanceof TDbParameterModule)) { |
||
| 259 | throw new TConfigurationException('permissions_dbparameter_invalid', $this->_dbParameter); |
||
| 260 | } |
||
| 261 | $this->_dbParameter = $dbParameter; |
||
| 262 | } |
||
| 263 | |||
| 264 | if ($this->_initialized) { |
||
| 265 | throw new TInvalidOperationException('permissions_init_once'); |
||
| 266 | } |
||
| 267 | $this->_initialized = true; |
||
| 268 | |||
| 269 | $manager = \WeakReference::create($this); |
||
| 270 | TComponent::attachClassBehavior(static::PERMISSIONS_BEHAVIOR, ['class' => TPermissionsBehavior::class, 'permissionsmanager' => $manager], IPermissions::class, -10); |
||
| 271 | TComponent::attachClassBehavior(static::USER_PERMISSIONS_BEHAVIOR, ['class' => TUserPermissionsBehavior::class, 'permissionsmanager' => $manager], \Prado\Security\IUser::class, -10); |
||
| 272 | TComponent::attachClassBehavior(static::PERMISSIONS_CONFIG_BEHAVIOR, ['class' => TPermissionsConfigurationBehavior::class, 'permissionsmanager' => $manager], \Prado\Web\Services\TPageConfiguration::class, -10); |
||
| 273 | |||
| 274 | $this->loadPermissionsData($config); |
||
| 275 | if ($this->_permissionFile !== null) { |
||
| 276 | if ($this->getApplication()->getConfigurationType() == TApplication::CONFIG_TYPE_PHP) { |
||
| 277 | $userFile = include $this->_permissionFile; |
||
| 278 | $this->loadPermissionsData($userFile); |
||
| 279 | } else { |
||
| 280 | $dom = new TXmlDocument(); |
||
| 281 | $dom->loadFromFile($this->_permissionFile); |
||
| 282 | $this->loadPermissionsData($dom); |
||
| 283 | } |
||
| 284 | } |
||
| 285 | if ($this->_dbParameter) { |
||
| 286 | $this->loadPermissionsData($this->_dbParameter->get($this->_parameter)); |
||
| 287 | } |
||
| 288 | |||
| 289 | foreach (array_map('strtolower', $this->getSuperRoles() ?? []) as $role) { |
||
| 290 | $this->_hierarchy[$role] = array_merge(['all'], $this->_hierarchy[$role] ?? []); |
||
| 291 | } |
||
| 292 | |||
| 293 | $app->attachEventHandler('onAuthenticationComplete', [$this, 'registerShellAction']); |
||
| 294 | |||
| 295 | parent::init($config); |
||
| 296 | } |
||
| 297 | |||
| 298 | /** |
||
| 299 | * Registers a permission name with description and preset rules. |
||
| 300 | * @param string $permissionName name of the permission |
||
| 301 | * @param string $description description of the permission |
||
| 302 | * @param null|\Prado\Security\TAuthorizationRule[] $rules |
||
| 303 | */ |
||
| 304 | public function registerPermission($permissionName, $description, $rules = null) |
||
| 305 | { |
||
| 306 | $permission = strtolower($permissionName); |
||
| 307 | $this->_descriptions[$permission] = TPropertyValue::ensureString($description); |
||
| 308 | |||
| 309 | if ($this->_autoDenyAll === true) { |
||
| 310 | $this->_autoDenyAll = 2; |
||
| 311 | $this->addPermissionRuleInternal('*', new TAuthorizationRule('deny', '*', '*', '*', '*', $this->_autoDenyAllPriority)); |
||
| 312 | } |
||
| 313 | |||
| 314 | $this->_hierarchy['all'][] = $permission; |
||
| 315 | |||
| 316 | if (!isset($this->_permissionRules[$permission])) { |
||
| 317 | $this->_permissionRules[$permission] = new TAuthorizationRuleCollection(); |
||
| 318 | } else { |
||
| 319 | throw new TInvalidOperationException('permissions_duplicate_permission', $permissionName); |
||
| 320 | } |
||
| 321 | if ($this->_autoAllowWithPermission) { |
||
| 322 | $this->_permissionRules[$permission]->add(new TAuthorizationRule('allow', '*', $permission, '*', '*', $this->_autoRulePriority)); |
||
| 323 | } |
||
| 324 | if ($this->_autoRulePresetRules && $rules) { |
||
| 325 | if (!is_array($rules)) { |
||
| 326 | $rules = [$rules]; |
||
| 327 | } |
||
| 328 | foreach ($rules as $rule) { |
||
| 329 | $this->_permissionRules[$permission]->add($rule, is_numeric($p = $rule->getPriority()) ? $p : $this->_autoRulePriority); |
||
| 330 | } |
||
| 331 | } |
||
| 332 | foreach ($this->_autoRules as $rulePerm => $rules) { |
||
| 333 | $pos = strpos($rulePerm, '*'); |
||
| 334 | if (($pos !== false && strncmp($permission, $rulePerm, $pos) === 0) || $this->isInHierarchy($rulePerm, $permission)) { |
||
| 335 | $this->_permissionRules[$permission]->mergeWith($rules); |
||
| 336 | if ($rulePerm === $permission) { |
||
| 337 | unset($this->_autoRules[$rulePerm]); |
||
| 338 | } |
||
| 339 | } |
||
| 340 | } |
||
| 341 | } |
||
| 342 | |||
| 343 | /** |
||
| 344 | * gets the short description of the permission |
||
| 345 | * @param string $permissionName name of the permission |
||
| 346 | * @return string short description of the permission |
||
| 347 | */ |
||
| 348 | public function getPermissionDescription($permissionName) |
||
| 349 | { |
||
| 350 | return $this->_descriptions[strtolower($permissionName)]; |
||
| 351 | } |
||
| 352 | |||
| 353 | /** |
||
| 354 | * Loads the roles, children, and permission rules. |
||
| 355 | * @param array|\Prado\Xml\TXmlElement $config configurations to parse |
||
| 356 | */ |
||
| 357 | public function loadPermissionsData($config) |
||
| 358 | { |
||
| 359 | $isXml = false; |
||
| 360 | if (!$config) { |
||
| 361 | return; |
||
| 362 | } |
||
| 363 | $permissions = $roles = []; |
||
| 364 | if ($config instanceof TXmlElement) { |
||
| 365 | $isXml = true; |
||
| 366 | $roles = $config->getElementsByTagName('role'); |
||
| 367 | $permissions = $config->getElementsByTagName('permissionrule'); |
||
| 368 | } elseif (is_array($config)) { |
||
| 369 | $roles = $config['roles'] ?? []; |
||
| 370 | $permissions = $config['permissionrules'] ?? []; |
||
| 371 | } |
||
| 372 | foreach ($roles as $role => $properties) { |
||
| 373 | if ($isXml) { |
||
| 374 | $properties = array_change_key_case($properties->getAttributes()->toArray()); |
||
| 375 | $role = $properties['name'] ?? ''; |
||
| 376 | $children = array_map('trim', explode(',', $properties['children'] ?? '')); |
||
| 377 | } else { |
||
| 378 | $children = $properties; |
||
| 379 | if (is_string($children)) { |
||
| 380 | $children = array_map('trim', explode(',', $children)); |
||
| 381 | } |
||
| 382 | if (!is_array($children)) { |
||
| 383 | throw new TConfigurationException('permissions_role_children_invalid', $role, is_object($children) ? $children::class : $children); |
||
| 384 | } |
||
| 385 | } |
||
| 386 | |||
| 387 | $role = strtolower($role); |
||
| 388 | $children = array_map('strtolower', array_filter($children)); |
||
| 389 | |||
| 390 | $this->_hierarchy[$role] = array_merge($this->_hierarchy[$role] ?? [], $children); |
||
| 391 | } |
||
| 392 | foreach ($permissions as $name => $properties) { |
||
| 393 | if ($isXml) { |
||
| 394 | $properties = array_change_key_case($properties->getAttributes()->toArray()); |
||
| 395 | } else { |
||
| 396 | if (!is_array($properties)) { |
||
| 397 | throw new TConfigurationException('permissions_rule_invalid', $name); |
||
| 398 | } |
||
| 399 | } |
||
| 400 | if (is_numeric($name) && (!isset($properties[0]) || !$properties[0] instanceof TAuthorizationRule)) { |
||
| 401 | $name = strtolower($properties['name'] ?? ''); |
||
| 402 | if (!$name) { |
||
| 403 | throw new TConfigurationException('permissions_rules_require_name'); |
||
| 404 | } |
||
| 405 | $class = $properties['class'] ?? TAuthorizationRule::class; |
||
| 406 | $action = $properties['action'] ?? ''; |
||
| 407 | $users = $properties['users'] ?? ''; |
||
| 408 | $roles = $properties['roles'] ?? ''; |
||
| 409 | $verb = $properties['verb'] ?? ''; |
||
| 410 | $ips = $properties['ips'] ?? ''; |
||
| 411 | $priority = $properties['priority'] ?? ''; |
||
| 412 | |||
| 413 | $rule = new $class($action, $users, $roles, $verb, $ips, $priority); |
||
| 414 | } else { |
||
| 415 | $rule = $properties; |
||
| 416 | } |
||
| 417 | $this->addPermissionRuleInternal($name, $rule); |
||
| 418 | } |
||
| 419 | } |
||
| 420 | |||
| 421 | /** |
||
| 422 | * Adds a permission rule to a permission name. Names can contain the '*' character |
||
| 423 | * and every permission with a matching name before the '*' will get the rule |
||
| 424 | * @param string $name Permission name |
||
| 425 | * @param \Prado\Security\TAuthorizationRule|\Prado\Security\TAuthorizationRule[] $rule |
||
| 426 | */ |
||
| 427 | protected function addPermissionRuleInternal($name, $rule) |
||
| 428 | { |
||
| 429 | if (!is_array($rule)) { |
||
| 430 | $rule = [$rule]; |
||
| 431 | } |
||
| 432 | if (($pos = strpos($name, '*')) !== false) { |
||
| 433 | foreach ($this->_permissionRules as $perm => $rules) { |
||
| 434 | if (strncmp($perm, $name, $pos) === 0) { |
||
| 435 | $rules->mergeWith($rule); |
||
| 436 | } |
||
| 437 | } |
||
| 438 | $this->_autoRules[$name] = array_merge($this->_autoRules[$name] ?? [], $rule); |
||
| 439 | } elseif (isset($this->_permissionRules[$name])) { |
||
| 440 | $this->_permissionRules[$name]->mergeWith($rule); |
||
| 441 | } else { |
||
| 442 | $this->_autoRules[$name] = array_merge($this->_autoRules[$name] ?? [], $rule); |
||
| 443 | } |
||
| 444 | if (isset($this->_hierarchy[$name])) { |
||
| 445 | //Push the rule down the hierarchy to any children permissions. |
||
| 446 | $set = [$name => true]; |
||
| 447 | $hierarchy = $this->_hierarchy[$name]; |
||
| 448 | while (count($hierarchy)) { |
||
| 449 | $role = array_pop($hierarchy); |
||
| 450 | if (!isset($set[$role])) { // stop recursive hierarchy and duplicate permissions |
||
| 451 | $set[$role] = true; |
||
| 452 | if (isset($this->_permissionRules[$role])) { |
||
| 453 | $this->_permissionRules[$role]->mergeWith($rule); |
||
| 454 | } |
||
| 455 | if (isset($this->_hierarchy[$role])) { |
||
| 456 | $hierarchy = array_merge($this->_hierarchy[$role], $hierarchy); |
||
| 457 | } |
||
| 458 | } |
||
| 459 | } |
||
| 460 | } |
||
| 461 | } |
||
| 462 | |||
| 463 | /** |
||
| 464 | * Removes a permission rule from a permission name. |
||
| 465 | * @param string $name |
||
| 466 | * @param \Prado\Security\TAuthorizationRule $rule |
||
| 467 | */ |
||
| 468 | protected function removePermissionRuleInternal($name, $rule) |
||
| 469 | { |
||
| 470 | if (($pos = strpos($name, '*')) !== false) { |
||
| 471 | foreach ($this->_permissionRules as $perm => $rules) { |
||
| 472 | if (strncmp($perm, $name, $pos) === 0) { |
||
| 473 | $rules->remove($rule); |
||
| 474 | } |
||
| 475 | } |
||
| 476 | } elseif (isset($this->_permissionRules[$name])) { |
||
| 477 | $this->_permissionRules[$name]->remove($rule); |
||
| 478 | } |
||
| 479 | if (isset($this->_hierarchy[$name])) { |
||
| 480 | //Push the rule down the hierarchy to any children permissions. |
||
| 481 | $set = [$name => true]; |
||
| 482 | $hierarchy = $this->_hierarchy[$name]; |
||
| 483 | while (count($hierarchy)) { |
||
| 484 | $role = array_pop($hierarchy); |
||
| 485 | if (!isset($set[$role])) { // stop recursive hierarchy and duplicate permissions |
||
| 486 | $set[$role] = true; |
||
| 487 | if (isset($this->_permissionRules[$role])) { |
||
| 488 | $this->_permissionRules[$role]->remove($rule); |
||
| 489 | } |
||
| 490 | if (isset($this->_hierarchy[$role])) { |
||
| 491 | $hierarchy = array_merge($this->_hierarchy[$role], $hierarchy); |
||
| 492 | } |
||
| 493 | } |
||
| 494 | } |
||
| 495 | } |
||
| 496 | } |
||
| 497 | |||
| 498 | /** |
||
| 499 | * @param object $sender sender of this event handler |
||
| 500 | * @param null|mixed $param parameter for the event |
||
| 501 | */ |
||
| 502 | public function registerShellAction($sender, $param) |
||
| 503 | { |
||
| 504 | if ($this->dyRegisterShellAction(false) !== true && ($app = $this->getApplication()) instanceof \Prado\Shell\TShellApplication) { |
||
| 505 | $app->addShellActionClass(['class' => TPermissionsAction::class, 'PermissionsManager' => $this]); |
||
| 506 | } |
||
| 507 | } |
||
| 508 | |||
| 509 | /** |
||
| 510 | * checks if the $permission is in the $roles hierarchy. |
||
| 511 | * @param string[] $roles the roles to check the permission |
||
| 512 | * @param string $permission the permission-role being checked for in the hierarchy |
||
| 513 | * @param array<string, bool> &$checked the roles already checked |
||
| 514 | */ |
||
| 515 | public function isInHierarchy($roles, $permission, &$checked = []) |
||
| 516 | { |
||
| 517 | if (!$roles) { |
||
| 518 | return false; |
||
| 519 | } |
||
| 520 | if (!$checked) { |
||
| 521 | if (!is_array($roles)) { |
||
| 522 | $roles = array_filter(array_map('trim', explode(',', $roles))); |
||
| 523 | } |
||
| 524 | $roles = array_map('strtolower', $roles); |
||
| 525 | $permission = strtolower($permission); |
||
| 526 | } |
||
| 527 | if (in_array($permission, $roles)) { |
||
| 528 | return true; |
||
| 529 | } |
||
| 530 | foreach ($roles as $role) { |
||
| 531 | if (!isset($checked[$role])) { |
||
| 532 | $checked[$role] = true; |
||
| 533 | if (isset($this->_hierarchy[$role]) && $this->isInHierarchy($this->_hierarchy[$role], $permission, $checked)) { |
||
| 534 | return true; |
||
| 535 | } |
||
| 536 | } |
||
| 537 | } |
||
| 538 | return false; |
||
| 539 | } |
||
| 540 | |||
| 541 | /** |
||
| 542 | * Get the roles that are runtime from the database |
||
| 543 | * @return array<string, string[]> roles and children from the database |
||
| 544 | */ |
||
| 545 | public function getDbConfigRoles() |
||
| 546 | { |
||
| 547 | if (!$this->_dbParameter || !$this->_parameter) { |
||
| 548 | return []; |
||
| 549 | } |
||
| 550 | $runtimeData = $this->_dbParameter->get($this->_parameter) ?? []; |
||
| 551 | return $runtimeData['roles'] ?? []; |
||
| 552 | } |
||
| 553 | |||
| 554 | /** |
||
| 555 | * Get the permission rules that are runtime from the database |
||
| 556 | * @return array<string, \Prado\Security\TAuthorizationRule[]> |
||
| 557 | */ |
||
| 558 | public function getDbConfigPermissionRules() |
||
| 559 | { |
||
| 560 | if (!$this->_dbParameter || !$this->_parameter) { |
||
| 561 | return []; |
||
| 562 | } |
||
| 563 | $runtimeData = $this->_dbParameter->get($this->_parameter) ?? []; |
||
| 564 | return $runtimeData['permissionrules'] ?? []; |
||
| 565 | } |
||
| 566 | |||
| 567 | /** |
||
| 568 | * This adds children to a role within the runtime context. The children |
||
| 569 | * can be a single comma separated string. |
||
| 570 | * @param string $role the role to add children |
||
| 571 | * @param string|string[] $children the children to add to the role |
||
| 572 | * @throws TInvalidDataValueException when children is not an array |
||
| 573 | * @return bool was the method successful |
||
| 574 | */ |
||
| 575 | public function addRoleChildren($role, $children) |
||
| 576 | { |
||
| 577 | if ($this->dyAddRoleChildren(false, $role, $children) === true || !$this->_dbParameter) { |
||
| 578 | return false; |
||
| 579 | } |
||
| 580 | if (is_string($children)) { |
||
| 581 | $children = array_map('trim', explode(',', $children)); |
||
| 582 | } elseif (!is_array($children)) { |
||
| 583 | throw new TInvalidDataValueException('permissions_children_invalid', is_object($children) ? $children::class : $children); |
||
| 584 | } |
||
| 585 | $role = strtolower($role); |
||
| 586 | $children = array_map('strtolower', array_filter($children)); |
||
| 587 | $this->_hierarchy[$role] = array_merge($this->_hierarchy[$role] ?? [], $children); |
||
| 588 | |||
| 589 | $runtimeData = $this->_dbParameter->get($this->_parameter) ?? []; |
||
| 590 | $runtimeData['roles'] ??= []; |
||
| 591 | $runtimeData['roles'][$role] = array_unique(array_merge($runtimeData['roles'][$role] ?? [], $children)); |
||
| 592 | $this->_dbParameter->set($this->_parameter, $runtimeData); |
||
| 593 | |||
| 594 | return true; |
||
| 595 | } |
||
| 596 | |||
| 597 | /** |
||
| 598 | * This removes children from a role within the runtime context. The children |
||
| 599 | * can be a single comma separated string. |
||
| 600 | * @param string $role the role to add children |
||
| 601 | * @param string|string[] $children the children to add to the role |
||
| 602 | * @throws TInvalidDataValueException when children is not an array |
||
| 603 | * @return bool was the method successful |
||
| 604 | */ |
||
| 605 | public function removeRoleChildren($role, $children) |
||
| 606 | { |
||
| 607 | if ($this->dyRemoveRoleChildren(false, $role, $children) === true || !$this->_dbParameter) { |
||
| 608 | return false; |
||
| 609 | } |
||
| 610 | if (is_string($children)) { |
||
| 611 | $children = array_map('trim', explode(',', $children)); |
||
| 612 | } elseif (!is_array($children)) { |
||
| 613 | throw new TInvalidDataValueException('permissions_children_invalid', is_object($children) ? $children::class : $children); |
||
| 614 | } |
||
| 615 | $role = strtolower($role); |
||
| 616 | $children = array_map('strtolower', array_filter($children)); |
||
| 617 | $this->_hierarchy[$role] = array_values(array_diff($this->_hierarchy[$role] ?? [], $children)); |
||
| 618 | if (!$this->_hierarchy[$role]) { |
||
| 619 | unset($this->_hierarchy[$role]); |
||
| 620 | } |
||
| 621 | |||
| 622 | $runtimeData = $this->_dbParameter->get($this->_parameter) ?? []; |
||
| 623 | $runtimeData['roles'][$role] = array_values(array_diff($runtimeData['roles'][$role] ?? [], $children)); |
||
| 624 | if (!$runtimeData['roles'][$role]) { |
||
| 625 | unset($runtimeData['roles'][$role]); |
||
| 626 | } |
||
| 627 | $this->_dbParameter->set($this->_parameter, $runtimeData); |
||
| 628 | return true; |
||
| 629 | } |
||
| 630 | |||
| 631 | /** |
||
| 632 | * This method adds permission rules with in the runtime context. |
||
| 633 | * @param string $permission |
||
| 634 | * @param \Prado\Security\TAuthorizationRule $rule |
||
| 635 | * @return bool was the method successful |
||
| 636 | */ |
||
| 637 | public function addPermissionRule($permission, $rule) |
||
| 638 | { |
||
| 639 | $permission = strtolower($permission); |
||
| 640 | |||
| 641 | if ($this->dyAddPermissionRule(false, $permission, $rule) === true || !$this->_dbParameter) { |
||
| 642 | return false; |
||
| 643 | } |
||
| 644 | $this->addPermissionRuleInternal($permission, $rule); |
||
| 645 | |||
| 646 | $runtimeData = $this->_dbParameter->get($this->_parameter) ?? []; |
||
| 647 | $runtimeData['permissionrules'] ??= []; |
||
| 648 | $runtimeData['permissionrules'][$permission][] = $rule; |
||
| 649 | $this->_dbParameter->set($this->_parameter, $runtimeData); |
||
| 650 | |||
| 651 | return true; |
||
| 652 | } |
||
| 653 | |||
| 654 | /** |
||
| 655 | * This method removes permission rules with in the runtime context. |
||
| 656 | * @param string $permission a permission or role to remove the rule from |
||
| 657 | * @param \Prado\Security\TAuthorizationRule $rule |
||
| 658 | * @return bool was the method successful |
||
| 659 | */ |
||
| 660 | public function removePermissionRule($permission, $rule) |
||
| 661 | { |
||
| 662 | $permission = strtolower($permission); |
||
| 663 | |||
| 664 | if ($this->dyRemovePermissionRule(false, $permission, $rule) === true || !$this->_dbParameter) { |
||
| 665 | return false; |
||
| 666 | } |
||
| 667 | |||
| 668 | $this->removePermissionRuleInternal($permission, $rule); |
||
| 669 | |||
| 670 | $runtimeData = $this->_dbParameter->get($this->_parameter) ?? []; |
||
| 671 | $runtimeData['permissionrules'] ??= []; |
||
| 672 | |||
| 673 | if (($index = array_search($rule, $runtimeData['permissionrules'][$permission] ?? [], true)) === false) { |
||
| 674 | return false; |
||
| 675 | } |
||
| 676 | unset($runtimeData['permissionrules'][$permission][$index]); |
||
| 677 | if (!$runtimeData['permissionrules'][$permission]) { |
||
| 678 | unset($runtimeData['permissionrules'][$permission]); |
||
| 679 | } else { |
||
| 680 | $runtimeData['permissionrules'][$permission] = array_values($runtimeData['permissionrules'][$permission]); |
||
| 681 | } |
||
| 682 | $this->_dbParameter->set($this->_parameter, $runtimeData); |
||
| 683 | |||
| 684 | return true; |
||
| 685 | } |
||
| 686 | |||
| 687 | /** |
||
| 688 | * Gets all the roles in the hierarchy, though may not be valid roles in the application. |
||
| 689 | * @return string[] the roles in the hierarchy. |
||
| 690 | */ |
||
| 691 | public function getHierarchyRoles() |
||
| 692 | { |
||
| 693 | return array_keys($this->_hierarchy); |
||
| 694 | } |
||
| 695 | |||
| 696 | /** |
||
| 697 | * Gets the children for a specific role in the hierarchy. |
||
| 698 | * @param string $role the role to return its children |
||
| 699 | * @return null|string[] the children of a specific role. |
||
| 700 | */ |
||
| 701 | public function getHierarchyRoleChildren($role) |
||
| 702 | { |
||
| 703 | if (!$role) { |
||
| 704 | return $this->_hierarchy; |
||
| 705 | } |
||
| 706 | return $this->_hierarchy[strtolower(TPropertyValue::ensureString($role))] ?? null; |
||
| 707 | } |
||
| 708 | |||
| 709 | /** |
||
| 710 | * @param null|string $permission |
||
| 711 | * @return null|array<string, TAuthorizationRuleCollection>|TAuthorizationRuleCollection |
||
| 712 | */ |
||
| 713 | public function getPermissionRules($permission) |
||
| 714 | { |
||
| 715 | if (is_string($permission)) { |
||
| 716 | return $this->_permissionRules[strtolower($permission)] ?? null; |
||
| 717 | } else { |
||
| 718 | return $this->_permissionRules; |
||
| 719 | } |
||
| 720 | } |
||
| 721 | |||
| 722 | /** |
||
| 723 | * All super roles will get "all" roles and thus all permissions on module init. |
||
| 724 | * @return null|string[] array of rolls that get all permissions |
||
| 725 | */ |
||
| 726 | public function getSuperRoles() |
||
| 727 | { |
||
| 728 | return $this->_superRoles; |
||
| 729 | } |
||
| 730 | |||
| 731 | /** |
||
| 732 | * sets the super roles to get all permissions. |
||
| 733 | * @param string|string[] $roles of rolls that get all permissions |
||
| 734 | * @throws \Prado\Exceptions\TInvalidOperationException when the module is initialized |
||
| 735 | */ |
||
| 736 | public function setSuperRoles($roles) |
||
| 745 | ; |
||
| 746 | } |
||
| 747 | |||
| 748 | /** |
||
| 749 | * Gets the default roles of all users. |
||
| 750 | * @return null|string[] the default roles of all users |
||
| 751 | */ |
||
| 752 | public function getDefaultRoles() |
||
| 753 | { |
||
| 754 | return $this->_defaultRoles; |
||
| 755 | } |
||
| 756 | |||
| 757 | /** |
||
| 758 | * @param string|string[] $roles the default roles of all users |
||
| 759 | * @throws \Prado\Exceptions\TInvalidOperationException when the module is initialized |
||
| 760 | */ |
||
| 761 | public function setDefaultRoles($roles) |
||
| 762 | { |
||
| 763 | if ($this->_initialized) { |
||
| 764 | throw new TInvalidOperationException('permissions_property_unchangeable', 'DefaultRoles'); |
||
| 765 | } |
||
| 766 | if (!is_array($roles)) { |
||
| 767 | $roles = array_filter(array_map('trim', explode(',', $roles))); |
||
| 768 | } |
||
| 769 | $this->_defaultRoles = $roles; |
||
| 770 | } |
||
| 771 | |||
| 772 | /** |
||
| 773 | * @return string the full path to the file storing role/rule information |
||
| 774 | */ |
||
| 775 | public function getPermissionFile() |
||
| 778 | } |
||
| 779 | |||
| 780 | /** |
||
| 781 | * @param string $value role/rule data file path (in namespace form). The file format is configuration format |
||
| 782 | * whose content is similar to that role/rule block in the module configuration. |
||
| 783 | * @throws \Prado\Exceptions\TInvalidOperationException if the module is already initialized |
||
| 784 | * @throws \Prado\Exceptions\TConfigurationException if the file is not in proper namespace format |
||
| 785 | */ |
||
| 786 | public function setPermissionFile($value) |
||
| 787 | { |
||
| 788 | if ($this->_initialized) { |
||
| 789 | throw new TInvalidOperationException('permissions_property_unchangeable', 'PermissionFile'); |
||
| 790 | } elseif (($this->_permissionFile = Prado::getPathOfNamespace($value, $this->getApplication()->getConfigurationFileExt())) === null || !is_file($this->_permissionFile)) { |
||
| 791 | throw new TConfigurationException('permissions_permissionfile_invalid', $value); |
||
| 792 | } |
||
| 793 | } |
||
| 794 | |||
| 795 | /** |
||
| 796 | * @return numeric the priority of Allow With Permission and Preset Rules, default 5 |
||
| 797 | */ |
||
| 798 | public function getAutoRulePriority() |
||
| 799 | { |
||
| 800 | return $this->_autoRulePriority; |
||
| 801 | } |
||
| 802 | |||
| 803 | /** |
||
| 804 | * @param numeric $priority the priority of Allow With Permission and Preset Rules |
||
| 805 | * @throws \Prado\Exceptions\TInvalidOperationException if the module is already initialized |
||
| 806 | */ |
||
| 807 | public function setAutoRulePriority($priority) |
||
| 808 | { |
||
| 809 | if ($this->_initialized) { |
||
| 810 | throw new TInvalidOperationException('permissions_property_unchangeable', 'AutoRulePriority'); |
||
| 811 | } |
||
| 812 | $this->_autoRulePriority = is_numeric($priority) ? $priority : (float) $priority; |
||
| 813 | } |
||
| 814 | |||
| 815 | /** |
||
| 816 | * @return bool enable Allow With Permission rule, default true |
||
| 817 | */ |
||
| 818 | public function getAutoAllowWithPermission() |
||
| 819 | { |
||
| 820 | return $this->_autoAllowWithPermission; |
||
| 821 | } |
||
| 822 | |||
| 823 | /** |
||
| 824 | * @param bool $enable enable Allow With Permission rule |
||
| 825 | * @throws \Prado\Exceptions\TInvalidOperationException if the module is already initialized |
||
| 826 | */ |
||
| 827 | public function setAutoAllowWithPermission($enable) |
||
| 828 | { |
||
| 829 | if ($this->_initialized) { |
||
| 830 | throw new TInvalidOperationException('permissions_property_unchangeable', 'AutoAllowWithPermission'); |
||
| 831 | } |
||
| 832 | $this->_autoAllowWithPermission = TPropertyValue::ensureBoolean($enable); |
||
| 833 | } |
||
| 834 | |||
| 835 | /** |
||
| 836 | * @return bool enable Module Rules, default true |
||
| 837 | */ |
||
| 838 | public function getAutoPresetRules() |
||
| 839 | { |
||
| 840 | return $this->_autoRulePresetRules; |
||
| 841 | } |
||
| 842 | |||
| 843 | /** |
||
| 844 | * @param bool $enable the priority of Allow With Permission |
||
| 845 | * @throws \Prado\Exceptions\TInvalidOperationException if the module is already initialized |
||
| 846 | */ |
||
| 847 | public function setAutoPresetRules($enable) |
||
| 848 | { |
||
| 849 | if ($this->_initialized) { |
||
| 850 | throw new TInvalidOperationException('permissions_property_unchangeable', 'AutoPresetRules'); |
||
| 851 | } |
||
| 852 | $this->_autoRulePresetRules = TPropertyValue::ensureBoolean($enable); |
||
| 853 | } |
||
| 854 | |||
| 855 | /** |
||
| 856 | * @return bool the priority of Allow With Permission, default true |
||
| 857 | */ |
||
| 858 | public function getAutoDenyAll() |
||
| 861 | } |
||
| 862 | |||
| 863 | /** |
||
| 864 | * @param bool $enable the priority of Allow With Permission |
||
| 865 | * @throws \Prado\Exceptions\TInvalidOperationException if the module is already initialized |
||
| 866 | */ |
||
| 867 | public function setAutoDenyAll($enable) |
||
| 873 | } |
||
| 874 | |||
| 875 | /** |
||
| 876 | * @return numeric the priority of Deny All rule, default 999999 |
||
| 877 | */ |
||
| 878 | public function getAutoDenyAllPriority() |
||
| 879 | { |
||
| 880 | return $this->_autoDenyAllPriority; |
||
| 881 | } |
||
| 882 | |||
| 883 | /** |
||
| 884 | * @param numeric $priority the priority of Deny All rule |
||
| 885 | * @throws \Prado\Exceptions\TInvalidOperationException if the module is already initialized |
||
| 886 | */ |
||
| 887 | public function setAutoDenyAllPriority($priority) |
||
| 893 | } |
||
| 894 | |||
| 895 | /** |
||
| 896 | * @return \Prado\Util\TDbParameterModule DbParameter instance |
||
| 897 | */ |
||
| 898 | public function getDbParameter() |
||
| 899 | { |
||
| 900 | return $this->_dbParameter; |
||
| 901 | } |
||
| 902 | |||
| 903 | /** |
||
| 904 | * @param \Prado\Security\IUserManager|string $provider the user manager module ID or the DbParameter object |
||
| 905 | * @throws \Prado\Exceptions\TInvalidOperationException if the module is already initialized |
||
| 906 | * @throws \Prado\Exceptions\TConfigurationException if the $provider is not a TDbParameterModule |
||
| 907 | */ |
||
| 908 | public function setDbParameter($provider) |
||
| 909 | { |
||
| 910 | if ($this->_initialized) { |
||
| 911 | throw new TInvalidOperationException('permissions_property_unchangeable', 'DbParameter'); |
||
| 912 | } |
||
| 913 | if ($provider !== null && !is_string($provider) && !($provider instanceof TDbParameterModule)) { |
||
| 914 | throw new TConfigurationException('permissions_dbparameter_invalid', is_object($provider) ? $provider::class : $provider); |
||
| 915 | } |
||
| 916 | $this->_dbParameter = $provider; |
||
| 917 | } |
||
| 918 | |||
| 919 | /** |
||
| 920 | * @return string name of the parameter to load |
||
| 921 | */ |
||
| 922 | public function getLoadParameter() |
||
| 925 | } |
||
| 926 | |||
| 927 | /** |
||
| 928 | * @param string $value name of the parameter to load |
||
| 929 | * @throws \Prado\Exceptions\TInvalidOperationException if the module is already initialized |
||
| 930 | */ |
||
| 931 | public function setLoadParameter($value) |
||
| 932 | { |
||
| 933 | if ($this->_initialized) { |
||
| 934 | throw new TInvalidOperationException('permissions_property_unchangeable', 'LoadParameter'); |
||
| 935 | } |
||
| 936 | $this->_parameter = $value; |
||
| 937 | } |
||
| 938 | |||
| 939 | /** |
||
| 940 | * detaches the automatic class behaviors |
||
| 941 | */ |
||
| 942 | public function __destruct() |
||
| 943 | { |
||
| 944 | TComponent::detachClassBehavior(static::PERMISSIONS_BEHAVIOR, IPermissions::class); |
||
| 945 | TComponent::detachClassBehavior(static::USER_PERMISSIONS_BEHAVIOR, \Prado\Security\IUser::class); |
||
| 946 | TComponent::detachClassBehavior(static::PERMISSIONS_CONFIG_BEHAVIOR, \Prado\Web\Services\TPageConfiguration::class); |
||
| 947 | parent::__destruct(); |
||
| 948 | } |
||
| 949 | } |
||
| 950 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths