diff --git a/src/Entrust/Traits/EntrustUserTrait.php b/src/Entrust/Traits/EntrustUserTrait.php index 67e7cbe8..b4ee54b0 100644 --- a/src/Entrust/Traits/EntrustUserTrait.php +++ b/src/Entrust/Traits/EntrustUserTrait.php @@ -1,113 +1,98 @@ -primaryKey; - $cacheKey = 'entrust_roles_for_user_'.$this->$userPrimaryKey; - if(Cache::getStore() instanceof TaggableStore) { - return Cache::tags(Config::get('entrust.role_user_table'))->remember($cacheKey, Config::get('cache.ttl'), function () { - return $this->roles()->get(); - }); + $cacheKey = 'entrust_roles_for_user_'.$this->{$this->primaryKey}; + + if (Cache::getStore() instanceof TaggableStore) { + return Cache::tags(Config::get('entrust.role_user_table')) + ->remember($cacheKey, Config::get('cache.ttl'), function () { + return $this->roles()->get(); + }); } - else return $this->roles()->get(); + + return $this->roles()->get(); } /** * {@inheritDoc} */ - public function save(array $options = []) - { //both inserts and updates - if(Cache::getStore() instanceof TaggableStore) { - Cache::tags(Config::get('entrust.role_user_table'))->flush(); - } + public function save(array $options = []): bool + { + $this->flushRoleCache(); return parent::save($options); } /** * {@inheritDoc} */ - public function delete(array $options = []) - { //soft or hard + public function delete(array $options = []): bool + { $result = parent::delete($options); - if(Cache::getStore() instanceof TaggableStore) { - Cache::tags(Config::get('entrust.role_user_table'))->flush(); - } + $this->flushRoleCache(); return $result; } /** * {@inheritDoc} */ - public function restore() - { //soft delete undo's + public function restore(): ?bool + { $result = parent::restore(); - if(Cache::getStore() instanceof TaggableStore) { - Cache::tags(Config::get('entrust.role_user_table'))->flush(); - } + $this->flushRoleCache(); return $result; } /** * Many-to-Many relations with Role. - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ - public function roles() + public function roles(): BelongsToMany { - return $this->belongsToMany(Config::get('entrust.role'), Config::get('entrust.role_user_table'), Config::get('entrust.user_foreign_key'), Config::get('entrust.role_foreign_key')); + return $this->belongsToMany( + Config::get('entrust.role'), + Config::get('entrust.role_user_table'), + Config::get('entrust.user_foreign_key'), + Config::get('entrust.role_foreign_key') + ); } /** - * Boot the user model - * Attach event listener to remove the many-to-many records when trying to delete - * Will NOT delete any records if the user model uses soft deletes. - * - * @return void|bool + * Boot the user model. */ - public static function boot() + public static function bootEntrustUserTrait(): void { - parent::boot(); - - static::deleting(function($user) { + static::deleting(function ($user) { if (!method_exists(Config::get('auth.providers.users.model'), 'bootSoftDeletes')) { - $user->roles()->sync([]); + $user->roles()->detach(); } - - return true; }); } /** - * Checks if the user has a role by its name. - * - * @param string|array $name Role name or array of role names. - * @param bool $requireAll All roles in the array are required. - * - * @return bool + * Check if user has a role. */ - public function hasRole($name, $requireAll = false) + public function hasRole($name, bool $requireAll = false): bool { if (is_array($name)) { foreach ($name as $roleName) { @@ -115,20 +100,19 @@ public function hasRole($name, $requireAll = false) if ($hasRole && !$requireAll) { return true; - } elseif (!$hasRole && $requireAll) { + } + + if (!$hasRole && $requireAll) { return false; } } - // If we've made it this far and $requireAll is FALSE, then NONE of the roles were found - // If we've made it this far and $requireAll is TRUE, then ALL of the roles were found. - // Return the value of $requireAll; return $requireAll; - } else { - foreach ($this->cachedRoles() as $role) { - if ($role->name == $name) { - return true; - } + } + + foreach ($this->cachedRoles() as $role) { + if ($role->name === $name) { + return true; } } @@ -136,14 +120,9 @@ public function hasRole($name, $requireAll = false) } /** - * Check if user has a permission by its name. - * - * @param string|array $permission Permission string or array of permissions. - * @param bool $requireAll All permissions in the array are required. - * - * @return bool + * Check if user has a permission. */ - public function can($permission, $requireAll = false) + public function can($permission, bool $requireAll = false): bool { if (is_array($permission)) { foreach ($permission as $permName) { @@ -151,22 +130,20 @@ public function can($permission, $requireAll = false) if ($hasPerm && !$requireAll) { return true; - } elseif (!$hasPerm && $requireAll) { + } + + if (!$hasPerm && $requireAll) { return false; } } - // If we've made it this far and $requireAll is FALSE, then NONE of the perms were found - // If we've made it this far and $requireAll is TRUE, then ALL of the perms were found. - // Return the value of $requireAll; return $requireAll; - } else { - foreach ($this->cachedRoles() as $role) { - // Validate against the Permission table - foreach ($role->cachedPermissions() as $perm) { - if (Str::is( $permission, $perm->name) ) { - return true; - } + } + + foreach ($this->cachedRoles() as $role) { + foreach ($role->cachedPermissions() as $perm) { + if (Str::is($permission, $perm->name)) { + return true; } } } @@ -175,149 +152,157 @@ public function can($permission, $requireAll = false) } /** - * Checks role(s) and permission(s). - * - * @param string|array $roles Array of roles or comma separated string - * @param string|array $permissions Array of permissions or comma separated string. - * @param array $options validate_all (true|false) or return_type (boolean|array|both) - * - * @throws \InvalidArgumentException - * - * @return array|bool + * Check user abilities. */ - public function ability($roles, $permissions, $options = []) + public function ability($roles, $permissions, array $options = []): array|bool { - // Convert string to array if that's what is passed in. - if (!is_array($roles)) { - $roles = explode(',', $roles); - } - if (!is_array($permissions)) { - $permissions = explode(',', $permissions); - } + $roles = is_array($roles) ? $roles : explode(',', $roles); + $permissions = is_array($permissions) ? $permissions : explode(',', $permissions); - // Set up default values and validate options. - if (!isset($options['validate_all'])) { - $options['validate_all'] = false; - } else { - if ($options['validate_all'] !== true && $options['validate_all'] !== false) { - throw new InvalidArgumentException(); - } - } - if (!isset($options['return_type'])) { - $options['return_type'] = 'boolean'; - } else { - if ($options['return_type'] != 'boolean' && - $options['return_type'] != 'array' && - $options['return_type'] != 'both') { - throw new InvalidArgumentException(); - } - } + $options = $this->validateAbilityOptions($options); - // Loop through roles and permissions and check each. - $checkedRoles = []; - $checkedPermissions = []; - foreach ($roles as $role) { - $checkedRoles[$role] = $this->hasRole($role); - } - foreach ($permissions as $permission) { - $checkedPermissions[$permission] = $this->can($permission); - } + $checkedRoles = $this->checkRoles($roles); + $checkedPermissions = $this->checkPermissions($permissions); - // If validate all and there is a false in either - // Check that if validate all, then there should not be any false. - // Check that if not validate all, there must be at least one true. - if(($options['validate_all'] && !(in_array(false,$checkedRoles) || in_array(false,$checkedPermissions))) || - (!$options['validate_all'] && (in_array(true,$checkedRoles) || in_array(true,$checkedPermissions)))) { - $validateAll = true; - } else { - $validateAll = false; - } + $validateAll = $this->determineValidationResult($checkedRoles, $checkedPermissions, $options['validate_all']); - // Return based on option - if ($options['return_type'] == 'boolean') { - return $validateAll; - } elseif ($options['return_type'] == 'array') { - return ['roles' => $checkedRoles, 'permissions' => $checkedPermissions]; - } else { - return [$validateAll, ['roles' => $checkedRoles, 'permissions' => $checkedPermissions]]; - } + return $this->formatAbilityResult($validateAll, $checkedRoles, $checkedPermissions, $options['return_type']); + } + + /** + * Attach a role to user. + */ + public function attachRole($role): void + { + $this->roles()->attach($this->parseRoleId($role)); + } + /** + * Detach a role from user. + */ + public function detachRole($role): void + { + $this->roles()->detach($this->parseRoleId($role)); } /** - * Alias to eloquent many-to-many relation's attach() method. - * - * @param mixed $role + * Attach multiple roles to user. */ - public function attachRole($role) + public function attachRoles($roles): void { - if(is_object($role)) { - $role = $role->getKey(); + foreach ($roles as $role) { + $this->attachRole($role); } + } + + /** + * Detach multiple roles from user. + */ + public function detachRoles($roles = null): void + { + $roles = $roles ?: $this->roles()->get(); - if(is_array($role)) { - $role = $role['id']; + foreach ($roles as $role) { + $this->detachRole($role); } + } - $this->roles()->attach($role); + /** + * Filter users by role. + */ + public function scopeWithRole($query, $role) + { + return $query->whereHas('roles', function ($query) use ($role) { + $query->where('name', $role); + }); + } + + /** + * Flush role cache. + */ + protected function flushRoleCache(): void + { + if (Cache::getStore() instanceof TaggableStore) { + Cache::tags(Config::get('entrust.role_user_table'))->flush(); + } } /** - * Alias to eloquent many-to-many relation's detach() method. - * - * @param mixed $role + * Parse role ID from various inputs. */ - public function detachRole($role) + protected function parseRoleId($role): mixed { if (is_object($role)) { - $role = $role->getKey(); + return $role->getKey(); } if (is_array($role)) { - $role = $role['id']; + return $role['id']; } - $this->roles()->detach($role); + return $role; } /** - * Attach multiple roles to a user - * - * @param mixed $roles + * Validate ability options. */ - public function attachRoles($roles) + protected function validateAbilityOptions(array $options): array { - foreach ($roles as $role) { - $this->attachRole($role); + $options['validate_all'] = $options['validate_all'] ?? false; + $options['return_type'] = $options['return_type'] ?? 'boolean'; + + if (!in_array($options['return_type'], ['boolean', 'array', 'both'], true)) { + throw new InvalidArgumentException('Invalid return type'); } + + return $options; } /** - * Detach multiple roles from a user - * - * @param mixed $roles + * Check roles for ability. */ - public function detachRoles($roles=null) + protected function checkRoles(array $roles): array { - if (!$roles) $roles = $this->roles()->get(); - + $checked = []; foreach ($roles as $role) { - $this->detachRole($role); + $checked[$role] = $this->hasRole($role); } + return $checked; } /** - *Filtering users according to their role - * - *@param string $role - *@return users collection + * Check permissions for ability. */ - public function scopeWithRole($query, $role) + protected function checkPermissions(array $permissions): array { - return $query->whereHas('roles', function ($query) use ($role) - { - $query->where('name', $role); - }); + $checked = []; + foreach ($permissions as $permission) { + $checked[$permission] = $this->can($permission); + } + return $checked; } + /** + * Determine validation result. + */ + protected function determineValidationResult(array $checkedRoles, array $checkedPermissions, bool $validateAll): bool + { + if ($validateAll) { + return !in_array(false, $checkedRoles, true) && !in_array(false, $checkedPermissions, true); + } + + return in_array(true, $checkedRoles, true) || in_array(true, $checkedPermissions, true); + } + + /** + * Format ability result. + */ + protected function formatAbilityResult(bool $validateAll, array $checkedRoles, array $checkedPermissions, string $returnType): array|bool + { + return match ($returnType) { + 'array' => ['roles' => $checkedRoles, 'permissions' => $checkedPermissions], + 'both' => [$validateAll, ['roles' => $checkedRoles, 'permissions' => $checkedPermissions]], + default => $validateAll, + }; + } }