| Total Complexity | 96 | 
| Total Lines | 724 | 
| Duplicated Lines | 0 % | 
| Changes | 0 | ||
Complex classes like Permission 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 Permission, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 24 | class Permission extends DataObject implements TemplateGlobalProvider, Resettable, i18nEntityProvider  | 
            ||
| 25 | { | 
            ||
| 26 | |||
| 27 | // the (1) after Type specifies the DB default value which is needed for  | 
            ||
| 28 | // upgrades from older SilverStripe versions  | 
            ||
| 29 | private static $db = [  | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 30 | "Code" => "Varchar(255)",  | 
            ||
| 31 | "Arg" => "Int",  | 
            ||
| 32 | "Type" => "Int(1)"  | 
            ||
| 33 | ];  | 
            ||
| 34 | |||
| 35 | private static $has_one = [  | 
            ||
| 36 | "Group" => Group::class,  | 
            ||
| 37 | ];  | 
            ||
| 38 | |||
| 39 | private static $indexes = [  | 
            ||
| 40 | "Code" => true  | 
            ||
| 41 | ];  | 
            ||
| 42 | |||
| 43 | private static $defaults = [  | 
            ||
| 44 | "Type" => 1  | 
            ||
| 45 | ];  | 
            ||
| 46 | |||
| 47 | private static $table_name = "Permission";  | 
            ||
| 48 | |||
| 49 | /**  | 
            ||
| 50 | * This is the value to use for the "Type" field if a permission should be  | 
            ||
| 51 | * granted.  | 
            ||
| 52 | */  | 
            ||
| 53 | const GRANT_PERMISSION = 1;  | 
            ||
| 54 | |||
| 55 | /**  | 
            ||
| 56 | * This is the value to use for the "Type" field if a permission should be  | 
            ||
| 57 | * denied.  | 
            ||
| 58 | */  | 
            ||
| 59 | const DENY_PERMISSION = -1;  | 
            ||
| 60 | |||
| 61 | /**  | 
            ||
| 62 | * This is the value to use for the "Type" field if a permission should be  | 
            ||
| 63 | * inherited.  | 
            ||
| 64 | */  | 
            ||
| 65 | const INHERIT_PERMISSION = 0;  | 
            ||
| 66 | |||
| 67 | |||
| 68 | /**  | 
            ||
| 69 | * Method to globally disable "strict" checking, which means a permission  | 
            ||
| 70 | * will be granted if the key does not exist at all.  | 
            ||
| 71 | *  | 
            ||
| 72 | * @deprecated 4.4.0  | 
            ||
| 73 | * @var array  | 
            ||
| 74 | */  | 
            ||
| 75 | private static $declared_permissions = null;  | 
            ||
| 76 | |||
| 77 | /**  | 
            ||
| 78 | * Linear list of declared permissions in the system.  | 
            ||
| 79 | *  | 
            ||
| 80 | * @deprecated 4.4.0  | 
            ||
| 81 | * @var array  | 
            ||
| 82 | */  | 
            ||
| 83 | private static $declared_permissions_list = null;  | 
            ||
| 84 | |||
| 85 | /**  | 
            ||
| 86 | * @config  | 
            ||
| 87 | * @var $strict_checking Boolean Method to globally disable "strict" checking,  | 
            ||
| 88 | * which means a permission will be granted if the key does not exist at all.  | 
            ||
| 89 | */  | 
            ||
| 90 | private static $strict_checking = true;  | 
            ||
| 91 | |||
| 92 | /**  | 
            ||
| 93 | * Set to false to prevent the 'ADMIN' permission from implying all  | 
            ||
| 94 | * permissions in the system  | 
            ||
| 95 | *  | 
            ||
| 96 | * @config  | 
            ||
| 97 | * @var bool  | 
            ||
| 98 | */  | 
            ||
| 99 | private static $admin_implies_all = true;  | 
            ||
| 100 | |||
| 101 | /**  | 
            ||
| 102 | * a list of permission codes which doesn't appear in the Permission list  | 
            ||
| 103 |      * when make the {@link PermissionCheckboxSetField} | 
            ||
| 104 | * @config  | 
            ||
| 105 | * @var array;  | 
            ||
| 106 | */  | 
            ||
| 107 | private static $hidden_permissions = [];  | 
            ||
| 108 | |||
| 109 | /**  | 
            ||
| 110 | * @config These permissions can only be applied by ADMIN users, to prevent  | 
            ||
| 111 | * privilege escalation on group assignments and inheritance.  | 
            ||
| 112 | * @var array  | 
            ||
| 113 | */  | 
            ||
| 114 | private static $privileged_permissions = [  | 
            ||
| 115 | 'ADMIN',  | 
            ||
| 116 | 'APPLY_ROLES',  | 
            ||
| 117 | 'EDIT_PERMISSIONS'  | 
            ||
| 118 | ];  | 
            ||
| 119 | |||
| 120 | /**  | 
            ||
| 121 | * Check that the current member has the given permission.  | 
            ||
| 122 | *  | 
            ||
| 123 | * @param string|array $code Code of the permission to check (case-sensitive)  | 
            ||
| 124 | * @param string $arg Optional argument (e.g. a permissions for a specific page)  | 
            ||
| 125 | * @param int|Member $member Optional member instance or ID. If set to NULL, the permssion  | 
            ||
| 126 | * will be checked for the current user  | 
            ||
| 127 | * @param bool $strict Use "strict" checking (which means a permission  | 
            ||
| 128 | * will be granted if the key does not exist at all)?  | 
            ||
| 129 | * @return int|bool The ID of the permission record if the permission  | 
            ||
| 130 | * exists; FALSE otherwise. If "strict" checking is  | 
            ||
| 131 | * disabled, TRUE will be returned if the permission does not exist at all.  | 
            ||
| 132 | */  | 
            ||
| 133 | public static function check($code, $arg = "any", $member = null, $strict = true)  | 
            ||
| 134 |     { | 
            ||
| 135 |         if (!$member) { | 
            ||
| 136 |             if (!Security::getCurrentUser()) { | 
            ||
| 137 | return false;  | 
            ||
| 138 | }  | 
            ||
| 139 | $member = Security::getCurrentUser();  | 
            ||
| 140 | }  | 
            ||
| 141 | |||
| 142 | return self::checkMember($member, $code, $arg, $strict);  | 
            ||
| 143 | }  | 
            ||
| 144 | |||
| 145 | /**  | 
            ||
| 146 | * Permissions cache. The format is a map, where the keys are member IDs, and the values are  | 
            ||
| 147 | * arrays of permission codes.  | 
            ||
| 148 | */  | 
            ||
| 149 | private static $cache_permissions = [];  | 
            ||
| 150 | |||
| 151 | /**  | 
            ||
| 152 | * Flush the permission cache, for example if you have edited group membership or a permission record.  | 
            ||
| 153 | * @todo Call this whenever Group_Members is added to or removed from  | 
            ||
| 154 | */  | 
            ||
| 155 | public static function reset()  | 
            ||
| 158 | }  | 
            ||
| 159 | |||
| 160 | /**  | 
            ||
| 161 | * Check that the given member has the given permission.  | 
            ||
| 162 | *  | 
            ||
| 163 | * @param int|Member $member The ID of the member to check. Leave blank for the current member.  | 
            ||
| 164 | * Alternatively you can use a member object.  | 
            ||
| 165 | * @param string|array $code Code of the permission to check (case-sensitive)  | 
            ||
| 166 | * @param string $arg Optional argument (e.g. a permissions for a specific page)  | 
            ||
| 167 | * @param bool $strict Use "strict" checking (which means a permission  | 
            ||
| 168 | * will be granted if the key does not exist at all)?  | 
            ||
| 169 | * @return int|bool The ID of the permission record if the permission  | 
            ||
| 170 | * exists; FALSE otherwise. If "strict" checking is  | 
            ||
| 171 | * disabled, TRUE will be returned if the permission does not exist at all.  | 
            ||
| 172 | */  | 
            ||
| 173 | public static function checkMember($member, $code, $arg = "any", $strict = true)  | 
            ||
| 174 |     { | 
            ||
| 175 |         if (!$member) { | 
            ||
| 176 | $member = Security::getCurrentUser();  | 
            ||
| 177 | }  | 
            ||
| 178 | $memberID = ($member instanceof Member) ? $member->ID : $member;  | 
            ||
| 179 | |||
| 180 |         if (!$memberID) { | 
            ||
| 181 | return false;  | 
            ||
| 182 | }  | 
            ||
| 183 | |||
| 184 | // Turn the code into an array as we may need to add other permsissions to the set we check  | 
            ||
| 185 |         if (!is_array($code)) { | 
            ||
| 186 | $code = [$code];  | 
            ||
| 187 | }  | 
            ||
| 188 | |||
| 189 | // Check if admin should be treated as holding all permissions  | 
            ||
| 190 | $adminImpliesAll = (bool)static::config()->admin_implies_all;  | 
            ||
| 191 | |||
| 192 |         if ($arg == 'any') { | 
            ||
| 193 | // Cache the permissions in memory  | 
            ||
| 194 |             if (!isset(self::$cache_permissions[$memberID])) { | 
            ||
| 195 | self::$cache_permissions[$memberID] = self::permissions_for_member($memberID);  | 
            ||
| 196 | }  | 
            ||
| 197 |             foreach ($code as $permCode) { | 
            ||
| 198 |                 if ($permCode === 'CMS_ACCESS') { | 
            ||
| 199 |                     foreach (self::$cache_permissions[$memberID] as $perm) { | 
            ||
| 200 | //if they have admin rights OR they have an explicit access to the CMS then give permission  | 
            ||
| 201 |                         if (($adminImpliesAll && $perm == 'ADMIN') || substr($perm ?? '', 0, 11) === 'CMS_ACCESS_') { | 
            ||
| 202 | return true;  | 
            ||
| 203 | }  | 
            ||
| 204 | }  | 
            ||
| 205 |                 } elseif (substr($permCode ?? '', 0, 11) === 'CMS_ACCESS_' && !in_array('CMS_ACCESS_LeftAndMain', $code ?? [])) { | 
            ||
| 206 | //cms_access_leftandmain means access to all CMS areas  | 
            ||
| 207 | $code[] = 'CMS_ACCESS_LeftAndMain';  | 
            ||
| 208 | }  | 
            ||
| 209 | }  | 
            ||
| 210 | |||
| 211 | // if ADMIN has all privileges, then we need to push that code in  | 
            ||
| 212 |             if ($adminImpliesAll) { | 
            ||
| 213 | $code[] = "ADMIN";  | 
            ||
| 214 | }  | 
            ||
| 215 | |||
| 216 | // Multiple $code values - return true if at least one matches, ie, intersection exists  | 
            ||
| 217 | return (bool)array_intersect($code ?? [], self::$cache_permissions[$memberID]);  | 
            ||
| 218 | }  | 
            ||
| 219 | |||
| 220 | // Code filters  | 
            ||
| 221 | $codeParams = is_array($code) ? $code : [$code];  | 
            ||
| 222 | $codeClause = DB::placeholders($codeParams);  | 
            ||
| 223 | $adminParams = $adminImpliesAll ? ['ADMIN'] : [];  | 
            ||
| 224 | $adminClause = $adminImpliesAll ? ", ?" : '';  | 
            ||
| 225 | |||
| 226 | // The following code should only be used if you're not using the "any" arg. This is kind  | 
            ||
| 227 | // of obsolete functionality and could possibly be deprecated.  | 
            ||
| 228 | $groupParams = self::groupList($memberID);  | 
            ||
| 229 |         if (empty($groupParams)) { | 
            ||
| 230 | return false;  | 
            ||
| 231 | }  | 
            ||
| 232 | $groupClause = DB::placeholders($groupParams);  | 
            ||
| 233 | |||
| 234 | // Arg component  | 
            ||
| 235 | $argClause = "";  | 
            ||
| 236 | $argParams = [];  | 
            ||
| 237 |         switch ($arg) { | 
            ||
| 238 | case "any":  | 
            ||
| 239 | break;  | 
            ||
| 240 | case "all":  | 
            ||
| 241 | $argClause = " AND \"Arg\" = ?";  | 
            ||
| 242 | $argParams = [-1];  | 
            ||
| 243 | break;  | 
            ||
| 244 | default:  | 
            ||
| 245 |                 if (is_numeric($arg)) { | 
            ||
| 246 | $argClause = "AND \"Arg\" IN (?, ?) ";  | 
            ||
| 247 | $argParams = [-1, $arg];  | 
            ||
| 248 |                 } else { | 
            ||
| 249 |                     throw new \InvalidArgumentException("Permission::checkMember: bad arg '$arg'"); | 
            ||
| 250 | }  | 
            ||
| 251 | }  | 
            ||
| 252 | |||
| 253 | // Raw SQL for efficiency  | 
            ||
| 254 | $permission = DB::prepared_query(  | 
            ||
| 255 | "SELECT \"ID\"  | 
            ||
| 256 | FROM \"Permission\"  | 
            ||
| 257 | WHERE (  | 
            ||
| 258 | \"Code\" IN ($codeClause $adminClause)  | 
            ||
| 259 | AND \"Type\" = ?  | 
            ||
| 260 | AND \"GroupID\" IN ($groupClause)  | 
            ||
| 261 | $argClause  | 
            ||
| 262 | )",  | 
            ||
| 263 | array_merge(  | 
            ||
| 264 | $codeParams,  | 
            ||
| 265 | $adminParams,  | 
            ||
| 266 | [self::GRANT_PERMISSION],  | 
            ||
| 267 | $groupParams,  | 
            ||
| 268 | $argParams  | 
            ||
| 269 | )  | 
            ||
| 270 | )->value();  | 
            ||
| 271 | |||
| 272 |         if ($permission) { | 
            ||
| 273 | return $permission;  | 
            ||
| 274 | }  | 
            ||
| 275 | |||
| 276 | // Strict checking disabled?  | 
            ||
| 277 |         if (!static::config()->strict_checking || !$strict) { | 
            ||
| 278 | $hasPermission = DB::prepared_query(  | 
            ||
| 279 | "SELECT COUNT(*)  | 
            ||
| 280 | FROM \"Permission\"  | 
            ||
| 281 | WHERE (  | 
            ||
| 282 | \"Code\" IN ($codeClause) AND  | 
            ||
| 283 | \"Type\" = ?  | 
            ||
| 284 | )",  | 
            ||
| 285 | array_merge($codeParams, [self::GRANT_PERMISSION])  | 
            ||
| 286 | )->value();  | 
            ||
| 287 | |||
| 288 |             if (!$hasPermission) { | 
            ||
| 289 | return false;  | 
            ||
| 290 | }  | 
            ||
| 291 | }  | 
            ||
| 292 | |||
| 293 | return false;  | 
            ||
| 294 | }  | 
            ||
| 295 | |||
| 296 | /**  | 
            ||
| 297 | * Get all the 'any' permission codes available to the given member.  | 
            ||
| 298 | *  | 
            ||
| 299 | * @param int $memberID  | 
            ||
| 300 | * @return array  | 
            ||
| 301 | */  | 
            ||
| 302 | public static function permissions_for_member($memberID)  | 
            ||
| 333 | }  | 
            ||
| 334 | |||
| 335 | |||
| 336 | /**  | 
            ||
| 337 | * Get the list of groups that the given member belongs to.  | 
            ||
| 338 | *  | 
            ||
| 339 | * Call without an argument to get the groups that the current member  | 
            ||
| 340 | * belongs to. In this case, the results will be session-cached.  | 
            ||
| 341 | *  | 
            ||
| 342 | * @param int $memberID The ID of the member. Leave blank for the current  | 
            ||
| 343 | * member.  | 
            ||
| 344 | * @return array Returns a list of group IDs to which the member belongs  | 
            ||
| 345 | * to or NULL.  | 
            ||
| 346 | */  | 
            ||
| 347 | public static function groupList($memberID = null)  | 
            ||
| 382 | }  | 
            ||
| 383 | |||
| 384 | |||
| 385 | /**  | 
            ||
| 386 | * Grant the given permission code/arg to the given group  | 
            ||
| 387 | *  | 
            ||
| 388 | * @param int $groupID The ID of the group  | 
            ||
| 389 | * @param string $code The permission code  | 
            ||
| 390 | * @param string $arg Optional: The permission argument (e.g. a page ID).  | 
            ||
| 391 | * @returns Permission Returns the new permission object.  | 
            ||
| 392 | */  | 
            ||
| 393 | public static function grant($groupID, $code, $arg = "any")  | 
            ||
| 394 |     { | 
            ||
| 395 | $permissions = Permission::get()->filter(['GroupID' => $groupID, 'Code' => $code]);  | 
            ||
| 396 | |||
| 397 |         if ($permissions && $permissions->count() > 0) { | 
            ||
| 398 | $perm = $permissions->last();  | 
            ||
| 399 |         } else { | 
            ||
| 400 | $perm = new Permission();  | 
            ||
| 401 | $perm->GroupID = $groupID;  | 
            ||
| 402 | $perm->Code = $code;  | 
            ||
| 403 | }  | 
            ||
| 404 | |||
| 405 | $perm->Type = self::GRANT_PERMISSION;  | 
            ||
| 406 | |||
| 407 | // Arg component  | 
            ||
| 408 |         switch ($arg) { | 
            ||
| 409 | case "any":  | 
            ||
| 410 | break;  | 
            ||
| 411 | case "all":  | 
            ||
| 412 | $perm->Arg = -1;  | 
            ||
| 413 | break;  | 
            ||
| 414 | default:  | 
            ||
| 415 |                 if (is_numeric($arg)) { | 
            ||
| 416 | $perm->Arg = $arg;  | 
            ||
| 417 |                 } else { | 
            ||
| 418 |                     throw new \InvalidArgumentException("Permission::checkMember: bad arg '$arg'"); | 
            ||
| 419 | }  | 
            ||
| 420 | }  | 
            ||
| 421 | |||
| 422 | $perm->write();  | 
            ||
| 423 | return $perm;  | 
            ||
| 424 | }  | 
            ||
| 425 | |||
| 426 | |||
| 427 | /**  | 
            ||
| 428 | * Deny the given permission code/arg to the given group  | 
            ||
| 429 | *  | 
            ||
| 430 | * @param int $groupID The ID of the group  | 
            ||
| 431 | * @param string $code The permission code  | 
            ||
| 432 | * @param string $arg Optional: The permission argument (e.g. a page ID).  | 
            ||
| 433 | * @returns Permission Returns the new permission object.  | 
            ||
| 434 | */  | 
            ||
| 435 | public static function deny($groupID, $code, $arg = "any")  | 
            ||
| 466 | }  | 
            ||
| 467 | |||
| 468 | /**  | 
            ||
| 469 | * Returns all members for a specific permission.  | 
            ||
| 470 | *  | 
            ||
| 471 | * @param string|array $code Either a single permission code, or a list of permission codes  | 
            ||
| 472 | * @return SS_List Returns a set of member that have the specified  | 
            ||
| 473 | * permission.  | 
            ||
| 474 | */  | 
            ||
| 475 | public static function get_members_by_permission($code)  | 
            ||
| 476 |     { | 
            ||
| 477 | $toplevelGroups = self::get_groups_by_permission($code);  | 
            ||
| 478 |         if (!$toplevelGroups) { | 
            ||
| 479 | return new ArrayList();  | 
            ||
| 480 | }  | 
            ||
| 481 | |||
| 482 | $groupIDs = [];  | 
            ||
| 483 |         foreach ($toplevelGroups as $group) { | 
            ||
| 484 | $familyIDs = $group->collateFamilyIDs();  | 
            ||
| 485 |             if (is_array($familyIDs)) { | 
            ||
| 486 | $groupIDs = array_merge($groupIDs, array_values($familyIDs ?? []));  | 
            ||
| 487 | }  | 
            ||
| 488 | }  | 
            ||
| 489 | |||
| 490 |         if (empty($groupIDs)) { | 
            ||
| 491 | return new ArrayList();  | 
            ||
| 492 | }  | 
            ||
| 493 | |||
| 494 | $groupClause = DB::placeholders($groupIDs);  | 
            ||
| 495 | /** @skipUpgrade */  | 
            ||
| 496 | $members = Member::get()  | 
            ||
| 497 | ->where(["\"Group\".\"ID\" IN ($groupClause)" => $groupIDs])  | 
            ||
| 498 |             ->leftJoin("Group_Members", '"Member"."ID" = "Group_Members"."MemberID"') | 
            ||
| 499 |             ->leftJoin("Group", '"Group_Members"."GroupID" = "Group"."ID"'); | 
            ||
| 500 | |||
| 501 | return $members;  | 
            ||
| 502 | }  | 
            ||
| 503 | |||
| 504 | /**  | 
            ||
| 505 | * Return all of the groups that have one of the given permission codes  | 
            ||
| 506 | * @param array|string $codes Either a single permission code, or an array of permission codes  | 
            ||
| 507 | * @return SS_List The matching group objects  | 
            ||
| 508 | */  | 
            ||
| 509 | public static function get_groups_by_permission($codes)  | 
            ||
| 510 |     { | 
            ||
| 511 | $codeParams = is_array($codes) ? $codes : [$codes];  | 
            ||
| 512 | $codeClause = DB::placeholders($codeParams);  | 
            ||
| 513 | |||
| 514 | // Via Roles are groups that have the permission via a role  | 
            ||
| 515 | /** @skipUpgrade */  | 
            ||
| 516 | return Group::get()  | 
            ||
| 517 | ->where([  | 
            ||
| 518 | "\"PermissionRoleCode\".\"Code\" IN ($codeClause) OR \"Permission\".\"Code\" IN ($codeClause)"  | 
            ||
| 519 | => array_merge($codeParams, $codeParams)  | 
            ||
| 520 | ])  | 
            ||
| 521 |             ->leftJoin('Permission', "\"Permission\".\"GroupID\" = \"Group\".\"ID\"") | 
            ||
| 522 |             ->leftJoin('Group_Roles', "\"Group_Roles\".\"GroupID\" = \"Group\".\"ID\"") | 
            ||
| 523 |             ->leftJoin('PermissionRole', "\"Group_Roles\".\"PermissionRoleID\" = \"PermissionRole\".\"ID\"") | 
            ||
| 524 |             ->leftJoin('PermissionRoleCode', "\"PermissionRoleCode\".\"RoleID\" = \"PermissionRole\".\"ID\""); | 
            ||
| 525 | }  | 
            ||
| 526 | |||
| 527 | |||
| 528 | /**  | 
            ||
| 529 | * Get a list of all available permission codes, both defined through the  | 
            ||
| 530 |      * {@link PermissionProvider} interface, and all not explicitly defined codes existing | 
            ||
| 531 |      * as a {@link Permission} database record. By default, the results are | 
            ||
| 532 |      * grouped as denoted by {@link Permission_Group}. | 
            ||
| 533 | *  | 
            ||
| 534 | * @param bool $grouped Group results into an array of permission groups.  | 
            ||
| 535 | * @return array Returns an array of all available permission codes. The  | 
            ||
| 536 | * array indices are the permission codes as used in  | 
            ||
| 537 |      *  {@link Permission::check()}. The value is a description | 
            ||
| 538 | * suitable for using in an interface.  | 
            ||
| 539 | */  | 
            ||
| 540 | public static function get_codes($grouped = true)  | 
            ||
| 541 |     { | 
            ||
| 542 |         $classes = ClassInfo::implementorsOf('SilverStripe\\Security\\PermissionProvider'); | 
            ||
| 543 | |||
| 544 | $allCodes = [];  | 
            ||
| 545 | $adminCategory = _t(__CLASS__ . '.AdminGroup', 'Administrator');  | 
            ||
| 546 | $allCodes[$adminCategory]['ADMIN'] = [  | 
            ||
| 547 | 'name' => _t(__CLASS__ . '.FULLADMINRIGHTS', 'Full administrative rights'),  | 
            ||
| 548 | 'help' => _t(  | 
            ||
| 549 | 'SilverStripe\\Security\\Permission.FULLADMINRIGHTS_HELP',  | 
            ||
| 550 | 'Implies and overrules all other assigned permissions.'  | 
            ||
| 551 | ),  | 
            ||
| 552 | 'sort' => 100000  | 
            ||
| 553 | ];  | 
            ||
| 554 | |||
| 555 |         if ($classes) { | 
            ||
| 556 |             foreach ($classes as $class) { | 
            ||
| 557 | $SNG = singleton($class);  | 
            ||
| 558 |                 if ($SNG instanceof TestOnly) { | 
            ||
| 559 | continue;  | 
            ||
| 560 | }  | 
            ||
| 561 | |||
| 562 | $someCodes = $SNG->providePermissions();  | 
            ||
| 563 |                 if ($someCodes) { | 
            ||
| 564 |                     foreach ($someCodes as $k => $v) { | 
            ||
| 565 |                         if (is_array($v)) { | 
            ||
| 566 | // There must be a category and name key.  | 
            ||
| 567 |                             if (!isset($v['category'])) { | 
            ||
| 568 | user_error(  | 
            ||
| 569 | "The permission $k must have a category key",  | 
            ||
| 570 | E_USER_WARNING  | 
            ||
| 571 | );  | 
            ||
| 572 | }  | 
            ||
| 573 |                             if (!isset($v['name'])) { | 
            ||
| 574 | user_error(  | 
            ||
| 575 | "The permission $k must have a name key",  | 
            ||
| 576 | E_USER_WARNING  | 
            ||
| 577 | );  | 
            ||
| 578 | }  | 
            ||
| 579 | |||
| 580 |                             if (!isset($allCodes[$v['category']])) { | 
            ||
| 581 | $allCodes[$v['category']] = [];  | 
            ||
| 582 | }  | 
            ||
| 583 | |||
| 584 | $allCodes[$v['category']][$k] = [  | 
            ||
| 585 | 'name' => $v['name'],  | 
            ||
| 586 | 'help' => isset($v['help']) ? $v['help'] : null,  | 
            ||
| 587 | 'sort' => isset($v['sort']) ? $v['sort'] : 0  | 
            ||
| 588 | ];  | 
            ||
| 589 |                         } else { | 
            ||
| 590 | $allCodes['Other'][$k] = [  | 
            ||
| 591 | 'name' => $v,  | 
            ||
| 592 | 'help' => null,  | 
            ||
| 593 | 'sort' => 0  | 
            ||
| 594 | ];  | 
            ||
| 595 | }  | 
            ||
| 596 | }  | 
            ||
| 597 | }  | 
            ||
| 598 | }  | 
            ||
| 599 | }  | 
            ||
| 600 | |||
| 601 | $flatCodeArray = [];  | 
            ||
| 602 |         foreach ($allCodes as $category) { | 
            ||
| 603 |             foreach ($category as $code => $permission) { | 
            ||
| 604 | $flatCodeArray[] = $code;  | 
            ||
| 605 | }  | 
            ||
| 606 | }  | 
            ||
| 607 |         $otherPerms = DB::query("SELECT DISTINCT \"Code\" From \"Permission\" WHERE \"Code\" != ''")->column(); | 
            ||
| 608 | |||
| 609 |         if ($otherPerms) { | 
            ||
| 610 |             foreach ($otherPerms as $otherPerm) { | 
            ||
| 611 |                 if (!in_array($otherPerm, $flatCodeArray ?? [])) { | 
            ||
| 612 | $allCodes['Other'][$otherPerm] = [  | 
            ||
| 613 | 'name' => $otherPerm,  | 
            ||
| 614 | 'help' => null,  | 
            ||
| 615 | 'sort' => 0  | 
            ||
| 616 | ];  | 
            ||
| 617 | }  | 
            ||
| 618 | }  | 
            ||
| 619 | }  | 
            ||
| 620 | |||
| 621 | // Don't let people hijack ADMIN rights  | 
            ||
| 622 |         if (!Permission::check("ADMIN")) { | 
            ||
| 623 | unset($allCodes['ADMIN']);  | 
            ||
| 624 | }  | 
            ||
| 625 | |||
| 626 | ksort($allCodes);  | 
            ||
| 627 | |||
| 628 | $returnCodes = [];  | 
            ||
| 629 |         foreach ($allCodes as $category => $permissions) { | 
            ||
| 630 |             if ($grouped) { | 
            ||
| 631 | uasort($permissions, [__CLASS__, 'sort_permissions']);  | 
            ||
| 632 | $returnCodes[$category] = $permissions;  | 
            ||
| 633 |             } else { | 
            ||
| 634 | $returnCodes = array_merge($returnCodes, $permissions);  | 
            ||
| 635 | }  | 
            ||
| 636 | }  | 
            ||
| 637 | |||
| 638 | return $returnCodes;  | 
            ||
| 639 | }  | 
            ||
| 640 | |||
| 641 | /**  | 
            ||
| 642 | * Sort permissions based on their sort value, or name  | 
            ||
| 643 | *  | 
            ||
| 644 | * @param array $a  | 
            ||
| 645 | * @param array $b  | 
            ||
| 646 | * @return int  | 
            ||
| 647 | */  | 
            ||
| 648 | public static function sort_permissions($a, $b)  | 
            ||
| 649 |     { | 
            ||
| 650 |         if ($a['sort'] == $b['sort']) { | 
            ||
| 651 | // Same sort value, do alpha instead  | 
            ||
| 652 | return strcmp($a['name'] ?? '', $b['name'] ?? '');  | 
            ||
| 653 |         } else { | 
            ||
| 654 | // Just numeric.  | 
            ||
| 655 | return $a['sort'] < $b['sort'] ? -1 : 1;  | 
            ||
| 656 | }  | 
            ||
| 657 | }  | 
            ||
| 658 | |||
| 659 | /**  | 
            ||
| 660 | * Get a linear list of the permissions in the system.  | 
            ||
| 661 | *  | 
            ||
| 662 | * @return array Linear list of declared permissions in the system.  | 
            ||
| 663 | * @deprecated 4.4.0  | 
            ||
| 664 | */  | 
            ||
| 665 | public static function get_declared_permissions_list()  | 
            ||
| 666 |     { | 
            ||
| 667 |         if (!self::$declared_permissions) { | 
            ||
| 668 | return null;  | 
            ||
| 669 | }  | 
            ||
| 670 | |||
| 671 |         if (self::$declared_permissions_list) { | 
            ||
| 672 | return self::$declared_permissions_list;  | 
            ||
| 673 | }  | 
            ||
| 674 | |||
| 675 | self::$declared_permissions_list = [];  | 
            ||
| 676 | |||
| 677 | self::traverse_declared_permissions(self::$declared_permissions, self::$declared_permissions_list);  | 
            ||
| 678 | |||
| 679 | return self::$declared_permissions_list;  | 
            ||
| 680 | }  | 
            ||
| 681 | |||
| 682 | /**  | 
            ||
| 683 | * Look up the human-readable title for the permission as defined by <code>Permission::declare_permissions</code>  | 
            ||
| 684 | *  | 
            ||
| 685 | * @param string $perm Permission code  | 
            ||
| 686 | * @return string Label for the given permission, or the permission itself if the label doesn't exist  | 
            ||
| 687 | * @deprecated 4.4.0  | 
            ||
| 688 | */  | 
            ||
| 689 | public static function get_label_for_permission($perm)  | 
            ||
| 690 |     { | 
            ||
| 691 | $list = self::get_declared_permissions_list();  | 
            ||
| 692 |         if (array_key_exists($perm, $list ?? [])) { | 
            ||
| 693 | return $list[$perm];  | 
            ||
| 694 | }  | 
            ||
| 695 | return $perm;  | 
            ||
| 696 | }  | 
            ||
| 697 | |||
| 698 | /**  | 
            ||
| 699 | * Recursively traverse the nested list of declared permissions and create  | 
            ||
| 700 | * a linear list.  | 
            ||
| 701 | *  | 
            ||
| 702 | * @param array $declared Nested structure of permissions.  | 
            ||
| 703 | * @param array $list List of permissions in the structure. The result will be  | 
            ||
| 704 | * written to this array.  | 
            ||
| 705 | * @deprecated 4.4.0  | 
            ||
| 706 | */  | 
            ||
| 707 | protected static function traverse_declared_permissions($declared, &$list)  | 
            ||
| 708 |     { | 
            ||
| 709 |         if (!is_array($declared)) { | 
            ||
| 710 | return;  | 
            ||
| 711 | }  | 
            ||
| 712 | |||
| 713 |         foreach ($declared as $perm => $value) { | 
            ||
| 714 |             if ($value instanceof Permission_Group) { | 
            ||
| 715 | $list[] = $value->getName();  | 
            ||
| 716 | self::traverse_declared_permissions($value->getPermissions(), $list);  | 
            ||
| 717 |             } else { | 
            ||
| 718 | $list[$perm] = $value;  | 
            ||
| 719 | }  | 
            ||
| 720 | }  | 
            ||
| 721 | }  | 
            ||
| 722 | |||
| 723 | public function onBeforeWrite()  | 
            ||
| 729 | }  | 
            ||
| 730 | |||
| 731 | public static function get_template_global_variables()  | 
            ||
| 732 |     { | 
            ||
| 733 | return [  | 
            ||
| 734 | 'HasPerm' => 'check'  | 
            ||
| 735 | ];  | 
            ||
| 736 | }  | 
            ||
| 737 | |||
| 738 | public function provideI18nEntities()  | 
            ||
| 748 | }  | 
            ||
| 749 | }  | 
            ||
| 750 |