├── .phpunit.result.cache ├── LICENSE ├── composer.json ├── composer.lock └── src ├── Entrust ├── Contracts │ ├── EntrustPermissionInterface.php │ ├── EntrustRoleInterface.php │ └── EntrustUserInterface.php ├── Entrust.php ├── EntrustFacade.php ├── EntrustPermission.php ├── EntrustRole.php ├── EntrustServiceProvider.php ├── Middleware │ ├── EntrustAbility.php │ ├── EntrustPermission.php │ └── EntrustRole.php └── Traits │ ├── EntrustPermissionTrait.php │ ├── EntrustRoleTrait.php │ └── EntrustUserTrait.php ├── commands └── MigrationCommand.php ├── config └── config.php └── views └── generators └── migration.blade.php /.phpunit.result.cache: -------------------------------------------------------------------------------- 1 | {"version":1,"defects":{"EntrustTest::testRouteNeedsRole":5,"EntrustTest::testRouteNeedsPermission":5,"EntrustTest::testRouteNeedsRoleOrPermission":5,"EntrustUserTest::testCan":8,"EntrustUserTest::testCanWithPlaceholderSupport":8,"EntrustUserTest::testAbilityShouldReturnBoolean":8,"EntrustUserTest::testAbilityShouldReturnArray":8,"EntrustUserTest::testAbilityShouldReturnBoth":8,"EntrustUserTest::testAbilityShouldAcceptStrings":8,"EntrustUserTest::testAbilityDefaultOptions":8,"EntrustUserTest::testAttachRole":5,"EntrustUserTest::testDetachRole":5,"EntrustUserTest::testAttachRoles":5,"EntrustUserTest::testDetachRoles":5,"EntrustUserTest::testDetachAllRoles":5},"times":{"EntrustTest::testHasRole":0.005,"EntrustTest::testCan":0,"EntrustTest::testUser":0.001,"EntrustTest::testRouteNeedsRole":0.001,"EntrustTest::testRouteNeedsPermission":0,"EntrustTest::testRouteNeedsRoleOrPermission":0,"EntrustUserTest::testRoles":0.001,"EntrustUserTest::testHasRole":0.002,"EntrustUserTest::testCan":0.003,"EntrustUserTest::testCanWithPlaceholderSupport":0,"EntrustUserTest::testAbilityShouldReturnBoolean":0.001,"EntrustUserTest::testAbilityShouldReturnArray":0.001,"EntrustUserTest::testAbilityShouldReturnBoth":0.001,"EntrustUserTest::testAbilityShouldAcceptStrings":0,"EntrustUserTest::testAbilityDefaultOptions":0.001,"EntrustUserTest::testAbilityShouldThrowInvalidArgumentException":0,"EntrustUserTest::testAttachRole":0.001,"EntrustUserTest::testDetachRole":0,"EntrustUserTest::testAttachRoles":0,"EntrustUserTest::testDetachRoles":0,"EntrustUserTest::testDetachAllRoles":0.001,"EntrustAbilityTest::testHandle_IsGuestWithNoAbility_ShouldAbort403":0.002,"EntrustAbilityTest::testHandle_IsGuestWithAbility_ShouldAbort403":0.001,"EntrustAbilityTest::testHandle_IsLoggedInWithNoAbility_ShouldAbort403":0,"EntrustAbilityTest::testHandle_IsLoggedInWithAbility_ShouldNotAbort":0,"EntrustPermissionTest::testHandle_IsGuestWithNoPermission_ShouldAbort403":0,"EntrustPermissionTest::testHandle_IsGuestWithPermission_ShouldAbort403":0,"EntrustPermissionTest::testHandle_IsLoggedInWithNoPermission_ShouldAbort403":0,"EntrustPermissionTest::testHandle_IsLoggedInWithPermission_ShouldNotAbort":0,"EntrustRoleTest::testHandle_IsGuestWithMismatchingRole_ShouldAbort403":0,"EntrustRoleTest::testHandle_IsGuestWithMatchingRole_ShouldAbort403":0,"EntrustRoleTest::testHandle_IsLoggedInWithMismatchRole_ShouldAbort403":0,"EntrustRoleTest::testHandle_IsLoggedInWithMatchingRole_ShouldNotAbort":0,"EntrustTest::testFilterGeneratedByRouteNeedsRoleOrPermission#0":0.001,"EntrustTest::testFilterGeneratedByRouteNeedsRoleOrPermission#1":0,"EntrustTest::testFilterGeneratedByRouteNeedsRoleOrPermission#2":0,"EntrustTest::testFilterGeneratedByRouteNeedsRoleOrPermission#3":0,"EntrustTest::testFilterGeneratedByRouteNeedsRoleOrPermission#4":0,"EntrustTest::testFilterGeneratedByRouteNeedsRoleOrPermission#5":0,"EntrustTest::testFilterGeneratedByRouteNeedsRoleOrPermission#6":0,"EntrustTest::testFilterGeneratedByRouteNeedsRoleOrPermission#7":0,"EntrustTest::testFilterGeneratedByRouteNeedsRoleOrPermission#8":0,"EntrustTest::testFilterGeneratedByRouteNeedsRoleOrPermission#9":0,"EntrustTest::testFilterGeneratedByRouteNeedsRoleOrPermission#10":0,"EntrustTest::testFilterGeneratedByRouteNeedsRoleOrPermission#11":0,"EntrustTest::testFilterGeneratedByRouteNeedsRole#0":0.002,"EntrustTest::testFilterGeneratedByRouteNeedsRole#1":0,"EntrustTest::testFilterGeneratedByRouteNeedsRole#2":0,"EntrustTest::testFilterGeneratedByRouteNeedsPermission#0":0.001,"EntrustTest::testFilterGeneratedByRouteNeedsPermission#1":0,"EntrustTest::testFilterGeneratedByRouteNeedsPermission#2":0}} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sunergix/entrust-permissions", 3 | "description": "This package provides a flexible way to add Role-based Permissions to Laravel. Supports laravel 5|6|7|8", 4 | "keywords": ["laravel","illuminate","auth","roles","acl","permission"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Zizaco Zizuini", 9 | "email": "zizaco@gmail.com" 10 | }, 11 | { 12 | "name": "Andrew Elkins", 13 | "homepage": "http://andrewelkins.com" 14 | }, 15 | { 16 | "name": "Ben Batschelet", 17 | "homepage": "http://github.com/bbatsche" 18 | }, 19 | { 20 | "name": "Michele Angioni", 21 | "email": "michele.angioni@gmail.com" 22 | }, 23 | { 24 | "name": "Edwin Karanja", 25 | "email": "edwinkaranja4@gmail.com" 26 | } 27 | ], 28 | "require": { 29 | "php": "^8.2", 30 | "illuminate/console": "^11", 31 | "illuminate/support": "^11", 32 | "illuminate/cache": "^11", 33 | "illuminate/database": "^11" 34 | }, 35 | "require-dev": { 36 | "phpunit/phpunit": "^11", 37 | "mockery/mockery": "^1.5" 38 | }, 39 | "autoload": { 40 | "classmap": [ 41 | "src/commands" 42 | ], 43 | "psr-4": { 44 | "Zizaco\\Entrust\\": "src/Entrust/" 45 | } 46 | }, 47 | "extra":{ 48 | "laravel":{ 49 | "providers":[ 50 | "Zizaco\\Entrust\\EntrustServiceProvider" 51 | ], 52 | "aliases":{ 53 | "Entrust": "Zizaco\\Entrust\\EntrustFacade" 54 | } 55 | } 56 | }, 57 | "autoload-dev": { 58 | "classmap": [ 59 | "tests/Middleware/MiddlewareTest.php" 60 | ] 61 | }, 62 | "minimum-stability": "stable" 63 | } 64 | -------------------------------------------------------------------------------- /src/Entrust/Contracts/EntrustPermissionInterface.php: -------------------------------------------------------------------------------- 1 | app = $app; 30 | } 31 | 32 | /** 33 | * Checks if the current user has a role by its name 34 | * 35 | * @param string $name Role name. 36 | * 37 | * @return bool 38 | */ 39 | public function hasRole($role, $requireAll = false) 40 | { 41 | if ($user = $this->user()) { 42 | return $user->hasRole($role, $requireAll); 43 | } 44 | 45 | return false; 46 | } 47 | 48 | /** 49 | * Check if the current user has a permission by its name 50 | * 51 | * @param string $permission Permission string. 52 | * 53 | * @return bool 54 | */ 55 | public function can($permission, $requireAll = false) 56 | { 57 | if ($user = $this->user()) { 58 | return $user->can($permission, $requireAll); 59 | } 60 | 61 | return false; 62 | } 63 | 64 | /** 65 | * Check if the current user has a role or permission by its name 66 | * 67 | * @param array|string $roles The role(s) needed. 68 | * @param array|string $permissions The permission(s) needed. 69 | * @param array $options The Options. 70 | * 71 | * @return bool 72 | */ 73 | public function ability($roles, $permissions, $options = []) 74 | { 75 | if ($user = $this->user()) { 76 | return $user->ability($roles, $permissions, $options); 77 | } 78 | 79 | return false; 80 | } 81 | 82 | /** 83 | * Get the currently authenticated user or null. 84 | * 85 | * @return Illuminate\Auth\UserInterface|null 86 | */ 87 | public function user() 88 | { 89 | return $this->app->auth->user(); 90 | } 91 | 92 | /** 93 | * Filters a route for a role or set of roles. 94 | * 95 | * If the third parameter is null then abort with status code 403. 96 | * Otherwise the $result is returned. 97 | * 98 | * @param string $route Route pattern. i.e: "admin/*" 99 | * @param array|string $roles The role(s) needed 100 | * @param mixed $result i.e: Redirect::to('/') 101 | * @param bool $requireAll User must have all roles 102 | * 103 | * @return mixed 104 | */ 105 | public function routeNeedsRole($route, $roles, $result = null, $requireAll = true) 106 | { 107 | $filterName = is_array($roles) ? implode('_', $roles) : $roles; 108 | $filterName .= '_'.substr(md5($route), 0, 6); 109 | 110 | $closure = function () use ($roles, $result, $requireAll) { 111 | $hasRole = $this->hasRole($roles, $requireAll); 112 | 113 | if (!$hasRole) { 114 | return empty($result) ? $this->app->abort(403) : $result; 115 | } 116 | }; 117 | 118 | // Same as Route::filter, registers a new filter 119 | $this->app->router->filter($filterName, $closure); 120 | 121 | // Same as Route::when, assigns a route pattern to the 122 | // previously created filter. 123 | $this->app->router->when($route, $filterName); 124 | } 125 | 126 | /** 127 | * Filters a route for a permission or set of permissions. 128 | * 129 | * If the third parameter is null then abort with status code 403. 130 | * Otherwise the $result is returned. 131 | * 132 | * @param string $route Route pattern. i.e: "admin/*" 133 | * @param array|string $permissions The permission(s) needed 134 | * @param mixed $result i.e: Redirect::to('/') 135 | * @param bool $requireAll User must have all permissions 136 | * 137 | * @return mixed 138 | */ 139 | public function routeNeedsPermission($route, $permissions, $result = null, $requireAll = true) 140 | { 141 | $filterName = is_array($permissions) ? implode('_', $permissions) : $permissions; 142 | $filterName .= '_'.substr(md5($route), 0, 6); 143 | 144 | $closure = function () use ($permissions, $result, $requireAll) { 145 | $hasPerm = $this->can($permissions, $requireAll); 146 | 147 | if (!$hasPerm) { 148 | return empty($result) ? $this->app->abort(403) : $result; 149 | } 150 | }; 151 | 152 | // Same as Route::filter, registers a new filter 153 | $this->app->router->filter($filterName, $closure); 154 | 155 | // Same as Route::when, assigns a route pattern to the 156 | // previously created filter. 157 | $this->app->router->when($route, $filterName); 158 | } 159 | 160 | /** 161 | * Filters a route for role(s) and/or permission(s). 162 | * 163 | * If the third parameter is null then abort with status code 403. 164 | * Otherwise the $result is returned. 165 | * 166 | * @param string $route Route pattern. i.e: "admin/*" 167 | * @param array|string $roles The role(s) needed 168 | * @param array|string $permissions The permission(s) needed 169 | * @param mixed $result i.e: Redirect::to('/') 170 | * @param bool $requireAll User must have all roles and permissions 171 | * 172 | * @return void 173 | */ 174 | public function routeNeedsRoleOrPermission($route, $roles, $permissions, $result = null, $requireAll = false) 175 | { 176 | $filterName = is_array($roles) ? implode('_', $roles) : $roles; 177 | $filterName .= '_'.(is_array($permissions) ? implode('_', $permissions) : $permissions); 178 | $filterName .= '_'.substr(md5($route), 0, 6); 179 | 180 | $closure = function () use ($roles, $permissions, $result, $requireAll) { 181 | $hasRole = $this->hasRole($roles, $requireAll); 182 | $hasPerms = $this->can($permissions, $requireAll); 183 | 184 | if ($requireAll) { 185 | $hasRolePerm = $hasRole && $hasPerms; 186 | } else { 187 | $hasRolePerm = $hasRole || $hasPerms; 188 | } 189 | 190 | if (!$hasRolePerm) { 191 | return empty($result) ? $this->app->abort(403) : $result; 192 | } 193 | }; 194 | 195 | // Same as Route::filter, registers a new filter 196 | $this->app->router->filter($filterName, $closure); 197 | 198 | // Same as Route::when, assigns a route pattern to the 199 | // previously created filter. 200 | $this->app->router->when($route, $filterName); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/Entrust/EntrustFacade.php: -------------------------------------------------------------------------------- 1 | table = Config::get('entrust.permissions_table'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Entrust/EntrustRole.php: -------------------------------------------------------------------------------- 1 | table = Config::get('entrust.roles_table'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Entrust/EntrustServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 32 | __DIR__.'/../config/config.php' => app()->basePath() . '/config/entrust.php', 33 | ]); 34 | 35 | // Register commands 36 | $this->commands('command.entrust.migration'); 37 | 38 | // Register blade directives 39 | $this->bladeDirectives(); 40 | } 41 | 42 | /** 43 | * Register the service provider. 44 | * 45 | * @return void 46 | */ 47 | public function register() 48 | { 49 | $this->registerEntrust(); 50 | 51 | $this->registerCommands(); 52 | 53 | $this->mergeConfig(); 54 | } 55 | 56 | /** 57 | * Register the blade directives 58 | * 59 | * @return void 60 | */ 61 | private function bladeDirectives() 62 | { 63 | if (!class_exists('\Blade')) return; 64 | 65 | // Call to Entrust::hasRole 66 | Blade::directive('role', function($expression) { 67 | return ""; 68 | }); 69 | 70 | Blade::directive('endrole', function($expression) { 71 | return ""; 72 | }); 73 | 74 | // Call to Entrust::can 75 | Blade::directive('permission', function($expression) { 76 | return ""; 77 | }); 78 | 79 | Blade::directive('endpermission', function($expression) { 80 | return ""; 81 | }); 82 | 83 | // Call to Entrust::ability 84 | Blade::directive('ability', function($expression) { 85 | return ""; 86 | }); 87 | 88 | Blade::directive('endability', function($expression) { 89 | return ""; 90 | }); 91 | } 92 | 93 | /** 94 | * Register the application bindings. 95 | * 96 | * @return void 97 | */ 98 | private function registerEntrust() 99 | { 100 | $this->app->bind('entrust', function ($app) { 101 | return new Entrust($app); 102 | }); 103 | 104 | $this->app->alias('entrust', 'Zizaco\Entrust\Entrust'); 105 | } 106 | 107 | /** 108 | * Register the artisan commands. 109 | * 110 | * @return void 111 | */ 112 | private function registerCommands() 113 | { 114 | $this->app->singleton('command.entrust.migration', function ($app) { 115 | return new MigrationCommand(); 116 | }); 117 | } 118 | 119 | /** 120 | * Merges user's and entrust's configs. 121 | * 122 | * @return void 123 | */ 124 | private function mergeConfig() 125 | { 126 | $this->mergeConfigFrom( 127 | __DIR__.'/../config/config.php', 'entrust' 128 | ); 129 | } 130 | 131 | /** 132 | * Get the services provided. 133 | * 134 | * @return array 135 | */ 136 | public function provides() 137 | { 138 | return [ 139 | 'command.entrust.migration' 140 | ]; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/Entrust/Middleware/EntrustAbility.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 28 | } 29 | 30 | /** 31 | * Handle an incoming request. 32 | * 33 | * @param \Illuminate\Http\Request $request 34 | * @param Closure $next 35 | * @param $roles 36 | * @param $permissions 37 | * @param bool $validateAll 38 | * @return mixed 39 | */ 40 | public function handle($request, Closure $next, $roles, $permissions, $validateAll = false) 41 | { 42 | if (!is_array($roles)) { 43 | // Convert $roles to an empty string if it's null or not a string 44 | $roles = $roles ?? ''; 45 | $roles = explode(self::DELIMITER, $roles); 46 | } 47 | 48 | if (!is_array($permissions)) { 49 | // Convert $permissions to an empty string if it's null or not a string 50 | $permissions = $permissions ?? ''; 51 | $permissions = explode(self::DELIMITER, $permissions); 52 | } 53 | 54 | if (!is_bool($validateAll)) { 55 | $validateAll = filter_var($validateAll, FILTER_VALIDATE_BOOLEAN); 56 | } 57 | 58 | if ($this->auth->guest() || !$request->user()->ability($roles, $permissions, [ 'validate_all' => $validateAll ])) { 59 | abort(403); 60 | } 61 | 62 | return $next($request); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Entrust/Middleware/EntrustPermission.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 28 | } 29 | 30 | /** 31 | * Handle an incoming request. 32 | * 33 | * @param \Illuminate\Http\Request $request 34 | * @param Closure $next 35 | * @param $permissions 36 | * @return mixed 37 | */ 38 | public function handle($request, Closure $next, $permissions) 39 | { 40 | if (!is_array($permissions)) { 41 | // Convert $permissions to an empty string if it's null or not a string 42 | $permissions = $permissions ?? ''; 43 | $permissions = explode(self::DELIMITER, $permissions); 44 | } 45 | 46 | 47 | if ($this->auth->guest() || !$request->user()->can($permissions)) { 48 | abort(403); 49 | } 50 | 51 | return $next($request); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Entrust/Middleware/EntrustRole.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 28 | } 29 | 30 | /** 31 | * Handle an incoming request. 32 | * 33 | * @param \Illuminate\Http\Request $request 34 | * @param Closure $next 35 | * @param $roles 36 | * @return mixed 37 | */ 38 | public function handle($request, Closure $next, $roles) 39 | { 40 | 41 | if (!is_array($roles)) { 42 | // Convert $roles to an empty string if it's null or not a string 43 | $roles = $roles ?? ''; 44 | $roles = explode(self::DELIMITER, $roles); 45 | } 46 | 47 | if ($this->auth->guest() || !$request->user()->hasRole($roles)) { 48 | abort(403); 49 | } 50 | 51 | return $next($request); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Entrust/Traits/EntrustPermissionTrait.php: -------------------------------------------------------------------------------- 1 | belongsToMany(Config::get('entrust.role'), Config::get('entrust.permission_role_table'), Config::get('entrust.permission_foreign_key'), Config::get('entrust.role_foreign_key')); 23 | } 24 | 25 | /** 26 | * Boot the permission model 27 | * Attach event listener to remove the many-to-many records when trying to delete 28 | * Will NOT delete any records if the permission model uses soft deletes. 29 | * 30 | * @return void|bool 31 | */ 32 | public static function boot() 33 | { 34 | parent::boot(); 35 | 36 | static::deleting(function($permission) { 37 | if (!method_exists(Config::get('entrust.permission'), 'bootSoftDeletes')) { 38 | $permission->roles()->sync([]); 39 | } 40 | 41 | return true; 42 | }); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Entrust/Traits/EntrustRoleTrait.php: -------------------------------------------------------------------------------- 1 | primaryKey; 21 | $cacheKey = 'entrust_permissions_for_role_' . $this->$rolePrimaryKey; 22 | if (Cache::getStore() instanceof TaggableStore) { 23 | return Cache::tags(Config::get('entrust.permission_role_table'))->remember($cacheKey, Config::get('cache.ttl', 60), function () { 24 | return $this->perms()->get(); 25 | }); 26 | } else return $this->perms()->get(); 27 | } 28 | 29 | public function save(array $options = []) 30 | { //both inserts and updates 31 | if (!parent::save($options)) { 32 | return false; 33 | } 34 | if (Cache::getStore() instanceof TaggableStore) { 35 | Cache::tags(Config::get('entrust.permission_role_table'))->flush(); 36 | } 37 | return true; 38 | } 39 | 40 | public function delete(array $options = []) 41 | { //soft or hard 42 | if (!parent::delete($options)) { 43 | return false; 44 | } 45 | if (Cache::getStore() instanceof TaggableStore) { 46 | Cache::tags(Config::get('entrust.permission_role_table'))->flush(); 47 | } 48 | return true; 49 | } 50 | 51 | public function restore() 52 | { //soft delete undo's 53 | if (!parent::restore()) { 54 | return false; 55 | } 56 | if (Cache::getStore() instanceof TaggableStore) { 57 | Cache::tags(Config::get('entrust.permission_role_table'))->flush(); 58 | } 59 | return true; 60 | } 61 | 62 | /** 63 | * Many-to-Many relations with the user model. 64 | * 65 | * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany 66 | */ 67 | public function users() 68 | { 69 | return $this->belongsToMany(Config::get('auth.providers.users.model'), Config::get('entrust.role_user_table'), Config::get('entrust.role_foreign_key'), Config::get('entrust.user_foreign_key')); 70 | } 71 | 72 | /** 73 | * Many-to-Many relations with the permission model. 74 | * Named "perms" for backwards compatibility. Also because "perms" is short and sweet. 75 | * 76 | * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany 77 | */ 78 | public function perms() 79 | { 80 | return $this->belongsToMany(Config::get('entrust.permission'), Config::get('entrust.permission_role_table'), Config::get('entrust.role_foreign_key'), Config::get('entrust.permission_foreign_key')); 81 | } 82 | 83 | /** 84 | * Boot the role model 85 | * Attach event listener to remove the many-to-many records when trying to delete 86 | * Will NOT delete any records if the role model uses soft deletes. 87 | * 88 | * @return void|bool 89 | */ 90 | public static function boot() 91 | { 92 | parent::boot(); 93 | 94 | static::deleting(function ($role) { 95 | if (!method_exists(Config::get('entrust.role'), 'bootSoftDeletes')) { 96 | $role->users()->sync([]); 97 | $role->perms()->sync([]); 98 | } 99 | 100 | return true; 101 | }); 102 | } 103 | 104 | /** 105 | * Checks if the role has a permission by its name. 106 | * 107 | * @param string|array $name Permission name or array of permission names. 108 | * @param bool $requireAll All permissions in the array are required. 109 | * 110 | * @return bool 111 | */ 112 | public function hasPermission($name, $requireAll = false) 113 | { 114 | if (is_array($name)) { 115 | foreach ($name as $permissionName) { 116 | $hasPermission = $this->hasPermission($permissionName); 117 | 118 | if ($hasPermission && !$requireAll) { 119 | return true; 120 | } elseif (!$hasPermission && $requireAll) { 121 | return false; 122 | } 123 | } 124 | 125 | // If we've made it this far and $requireAll is FALSE, then NONE of the permissions were found 126 | // If we've made it this far and $requireAll is TRUE, then ALL of the permissions were found. 127 | // Return the value of $requireAll; 128 | return $requireAll; 129 | } else { 130 | foreach ($this->cachedPermissions() as $permission) { 131 | if ($permission->name == $name) { 132 | return true; 133 | } 134 | } 135 | } 136 | 137 | return false; 138 | } 139 | 140 | /** 141 | * Save the inputted permissions. 142 | * 143 | * @param mixed $inputPermissions 144 | * 145 | * @return void 146 | */ 147 | public function savePermissions($inputPermissions) 148 | { 149 | if (!empty($inputPermissions)) { 150 | $this->perms()->sync($inputPermissions); 151 | } else { 152 | $this->perms()->detach(); 153 | } 154 | 155 | if (Cache::getStore() instanceof TaggableStore) { 156 | Cache::tags(Config::get('entrust.permission_role_table'))->flush(); 157 | } 158 | } 159 | 160 | /** 161 | * Attach permission to current role. 162 | * 163 | * @param object|array $permission 164 | * 165 | * @return void 166 | */ 167 | public function attachPermission($permission) 168 | { 169 | if (is_object($permission)) { 170 | $permission = $permission->getKey(); 171 | } 172 | 173 | if (is_array($permission)) { 174 | return $this->attachPermissions($permission); 175 | } 176 | 177 | $this->perms()->attach($permission); 178 | } 179 | 180 | /** 181 | * Detach permission from current role. 182 | * 183 | * @param object|array $permission 184 | * 185 | * @return void 186 | */ 187 | public function detachPermission($permission) 188 | { 189 | if (is_object($permission)) { 190 | $permission = $permission->getKey(); 191 | } 192 | 193 | if (is_array($permission)) { 194 | return $this->detachPermissions($permission); 195 | } 196 | 197 | $this->perms()->detach($permission); 198 | } 199 | 200 | /** 201 | * Attach multiple permissions to current role. 202 | * 203 | * @param mixed $permissions 204 | * 205 | * @return void 206 | */ 207 | public function attachPermissions($permissions) 208 | { 209 | foreach ($permissions as $permission) { 210 | $this->attachPermission($permission); 211 | } 212 | } 213 | 214 | /** 215 | * Detach multiple permissions from current role 216 | * 217 | * @param mixed $permissions 218 | * 219 | * @return void 220 | */ 221 | public function detachPermissions($permissions = null) 222 | { 223 | if (!$permissions) $permissions = $this->perms()->get(); 224 | 225 | foreach ($permissions as $permission) { 226 | $this->detachPermission($permission); 227 | } 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/Entrust/Traits/EntrustUserTrait.php: -------------------------------------------------------------------------------- 1 | primaryKey; 28 | $cacheKey = 'entrust_roles_for_user_'.$this->$userPrimaryKey; 29 | if(Cache::getStore() instanceof TaggableStore) { 30 | return Cache::tags(Config::get('entrust.role_user_table'))->remember($cacheKey, Config::get('cache.ttl'), function () { 31 | return $this->roles()->get(); 32 | }); 33 | } 34 | else return $this->roles()->get(); 35 | } 36 | 37 | /** 38 | * {@inheritDoc} 39 | */ 40 | public function save(array $options = []) 41 | { //both inserts and updates 42 | if(Cache::getStore() instanceof TaggableStore) { 43 | Cache::tags(Config::get('entrust.role_user_table'))->flush(); 44 | } 45 | return parent::save($options); 46 | } 47 | 48 | /** 49 | * {@inheritDoc} 50 | */ 51 | public function delete(array $options = []) 52 | { //soft or hard 53 | $result = parent::delete($options); 54 | if(Cache::getStore() instanceof TaggableStore) { 55 | Cache::tags(Config::get('entrust.role_user_table'))->flush(); 56 | } 57 | return $result; 58 | } 59 | 60 | /** 61 | * {@inheritDoc} 62 | */ 63 | public function restore() 64 | { //soft delete undo's 65 | $result = parent::restore(); 66 | if(Cache::getStore() instanceof TaggableStore) { 67 | Cache::tags(Config::get('entrust.role_user_table'))->flush(); 68 | } 69 | return $result; 70 | } 71 | 72 | /** 73 | * Many-to-Many relations with Role. 74 | * 75 | * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany 76 | */ 77 | public function roles() 78 | { 79 | 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')); 80 | } 81 | 82 | /** 83 | * Boot the user model 84 | * Attach event listener to remove the many-to-many records when trying to delete 85 | * Will NOT delete any records if the user model uses soft deletes. 86 | * 87 | * @return void|bool 88 | */ 89 | public static function boot() 90 | { 91 | parent::boot(); 92 | 93 | static::deleting(function($user) { 94 | if (!method_exists(Config::get('auth.providers.users.model'), 'bootSoftDeletes')) { 95 | $user->roles()->sync([]); 96 | } 97 | 98 | return true; 99 | }); 100 | } 101 | 102 | /** 103 | * Checks if the user has a role by its name. 104 | * 105 | * @param string|array $name Role name or array of role names. 106 | * @param bool $requireAll All roles in the array are required. 107 | * 108 | * @return bool 109 | */ 110 | public function hasRole($name, $requireAll = false) 111 | { 112 | if (is_array($name)) { 113 | foreach ($name as $roleName) { 114 | $hasRole = $this->hasRole($roleName); 115 | 116 | if ($hasRole && !$requireAll) { 117 | return true; 118 | } elseif (!$hasRole && $requireAll) { 119 | return false; 120 | } 121 | } 122 | 123 | // If we've made it this far and $requireAll is FALSE, then NONE of the roles were found 124 | // If we've made it this far and $requireAll is TRUE, then ALL of the roles were found. 125 | // Return the value of $requireAll; 126 | return $requireAll; 127 | } else { 128 | foreach ($this->cachedRoles() as $role) { 129 | if ($role->name == $name) { 130 | return true; 131 | } 132 | } 133 | } 134 | 135 | return false; 136 | } 137 | 138 | /** 139 | * Check if user has a permission by its name. 140 | * 141 | * @param string|array $permission Permission string or array of permissions. 142 | * @param bool $requireAll All permissions in the array are required. 143 | * 144 | * @return bool 145 | */ 146 | public function can($permission, $requireAll = false) 147 | { 148 | if (is_array($permission)) { 149 | foreach ($permission as $permName) { 150 | $hasPerm = $this->can($permName); 151 | 152 | if ($hasPerm && !$requireAll) { 153 | return true; 154 | } elseif (!$hasPerm && $requireAll) { 155 | return false; 156 | } 157 | } 158 | 159 | // If we've made it this far and $requireAll is FALSE, then NONE of the perms were found 160 | // If we've made it this far and $requireAll is TRUE, then ALL of the perms were found. 161 | // Return the value of $requireAll; 162 | return $requireAll; 163 | } else { 164 | foreach ($this->cachedRoles() as $role) { 165 | // Validate against the Permission table 166 | foreach ($role->cachedPermissions() as $perm) { 167 | if (Str::is( $permission, $perm->name) ) { 168 | return true; 169 | } 170 | } 171 | } 172 | } 173 | 174 | return false; 175 | } 176 | 177 | /** 178 | * Checks role(s) and permission(s). 179 | * 180 | * @param string|array $roles Array of roles or comma separated string 181 | * @param string|array $permissions Array of permissions or comma separated string. 182 | * @param array $options validate_all (true|false) or return_type (boolean|array|both) 183 | * 184 | * @throws \InvalidArgumentException 185 | * 186 | * @return array|bool 187 | */ 188 | public function ability($roles, $permissions, $options = []) 189 | { 190 | // Convert string to array if that's what is passed in. 191 | if (!is_array($roles)) { 192 | $roles = explode(',', $roles); 193 | } 194 | if (!is_array($permissions)) { 195 | $permissions = explode(',', $permissions); 196 | } 197 | 198 | // Set up default values and validate options. 199 | if (!isset($options['validate_all'])) { 200 | $options['validate_all'] = false; 201 | } else { 202 | if ($options['validate_all'] !== true && $options['validate_all'] !== false) { 203 | throw new InvalidArgumentException(); 204 | } 205 | } 206 | if (!isset($options['return_type'])) { 207 | $options['return_type'] = 'boolean'; 208 | } else { 209 | if ($options['return_type'] != 'boolean' && 210 | $options['return_type'] != 'array' && 211 | $options['return_type'] != 'both') { 212 | throw new InvalidArgumentException(); 213 | } 214 | } 215 | 216 | // Loop through roles and permissions and check each. 217 | $checkedRoles = []; 218 | $checkedPermissions = []; 219 | foreach ($roles as $role) { 220 | $checkedRoles[$role] = $this->hasRole($role); 221 | } 222 | foreach ($permissions as $permission) { 223 | $checkedPermissions[$permission] = $this->can($permission); 224 | } 225 | 226 | // If validate all and there is a false in either 227 | // Check that if validate all, then there should not be any false. 228 | // Check that if not validate all, there must be at least one true. 229 | if(($options['validate_all'] && !(in_array(false,$checkedRoles) || in_array(false,$checkedPermissions))) || 230 | (!$options['validate_all'] && (in_array(true,$checkedRoles) || in_array(true,$checkedPermissions)))) { 231 | $validateAll = true; 232 | } else { 233 | $validateAll = false; 234 | } 235 | 236 | // Return based on option 237 | if ($options['return_type'] == 'boolean') { 238 | return $validateAll; 239 | } elseif ($options['return_type'] == 'array') { 240 | return ['roles' => $checkedRoles, 'permissions' => $checkedPermissions]; 241 | } else { 242 | return [$validateAll, ['roles' => $checkedRoles, 'permissions' => $checkedPermissions]]; 243 | } 244 | 245 | } 246 | 247 | /** 248 | * Alias to eloquent many-to-many relation's attach() method. 249 | * 250 | * @param mixed $role 251 | */ 252 | public function attachRole($role) 253 | { 254 | if(is_object($role)) { 255 | $role = $role->getKey(); 256 | } 257 | 258 | if(is_array($role)) { 259 | $role = $role['id']; 260 | } 261 | 262 | $this->roles()->attach($role); 263 | } 264 | 265 | /** 266 | * Alias to eloquent many-to-many relation's detach() method. 267 | * 268 | * @param mixed $role 269 | */ 270 | public function detachRole($role) 271 | { 272 | if (is_object($role)) { 273 | $role = $role->getKey(); 274 | } 275 | 276 | if (is_array($role)) { 277 | $role = $role['id']; 278 | } 279 | 280 | $this->roles()->detach($role); 281 | } 282 | 283 | /** 284 | * Attach multiple roles to a user 285 | * 286 | * @param mixed $roles 287 | */ 288 | public function attachRoles($roles) 289 | { 290 | foreach ($roles as $role) { 291 | $this->attachRole($role); 292 | } 293 | } 294 | 295 | /** 296 | * Detach multiple roles from a user 297 | * 298 | * @param mixed $roles 299 | */ 300 | public function detachRoles($roles=null) 301 | { 302 | if (!$roles) $roles = $this->roles()->get(); 303 | 304 | foreach ($roles as $role) { 305 | $this->detachRole($role); 306 | } 307 | } 308 | 309 | /** 310 | *Filtering users according to their role 311 | * 312 | *@param string $role 313 | *@return users collection 314 | */ 315 | public function scopeWithRole($query, $role) 316 | { 317 | return $query->whereHas('roles', function ($query) use ($role) 318 | { 319 | $query->where('name', $role); 320 | }); 321 | } 322 | 323 | } 324 | -------------------------------------------------------------------------------- /src/commands/MigrationCommand.php: -------------------------------------------------------------------------------- 1 | handle(); 38 | } 39 | 40 | /** 41 | * Execute the console command for Laravel 5.5+. 42 | * 43 | * @return void 44 | */ 45 | public function handle() 46 | { 47 | $this->laravel->view->addNamespace('entrust', substr(__DIR__, 0, -8).'views'); 48 | 49 | $rolesTable = Config::get('entrust.roles_table'); 50 | $roleUserTable = Config::get('entrust.role_user_table'); 51 | $permissionsTable = Config::get('entrust.permissions_table'); 52 | $permissionRoleTable = Config::get('entrust.permission_role_table'); 53 | 54 | $this->line(''); 55 | $this->info( "Tables: $rolesTable, $roleUserTable, $permissionsTable, $permissionRoleTable" ); 56 | 57 | $message = "A migration that creates '$rolesTable', '$roleUserTable', '$permissionsTable', '$permissionRoleTable'". 58 | " tables will be created in database/migrations directory"; 59 | 60 | $this->comment($message); 61 | $this->line(''); 62 | 63 | if ($this->confirm("Proceed with the migration creation? [Yes|no]", "Yes")) { 64 | 65 | $this->line(''); 66 | 67 | $this->info("Creating migration..."); 68 | if ($this->createMigration($rolesTable, $roleUserTable, $permissionsTable, $permissionRoleTable)) { 69 | 70 | $this->info("Migration successfully created!"); 71 | } else { 72 | $this->error( 73 | "Couldn't create migration.\n Check the write permissions". 74 | " within the database/migrations directory." 75 | ); 76 | } 77 | 78 | $this->line(''); 79 | 80 | } 81 | } 82 | 83 | /** 84 | * Create the migration. 85 | * 86 | * @param string $name 87 | * 88 | * @return bool 89 | */ 90 | protected function createMigration($rolesTable, $roleUserTable, $permissionsTable, $permissionRoleTable) 91 | { 92 | $migrationFile = base_path("/database/migrations")."/".date('Y_m_d_His')."_entrust_setup_tables.php"; 93 | 94 | $userModelName = Config::get('auth.providers.users.model'); 95 | $userModel = new $userModelName(); 96 | $usersTable = $userModel->getTable(); 97 | $userKeyName = $userModel->getKeyName(); 98 | 99 | $data = compact('rolesTable', 'roleUserTable', 'permissionsTable', 'permissionRoleTable', 'usersTable', 'userKeyName'); 100 | 101 | $output = $this->laravel->view->make('entrust::generators.migration')->with($data)->render(); 102 | 103 | if (!file_exists($migrationFile) && $fs = fopen($migrationFile, 'x')) { 104 | fwrite($fs, $output); 105 | fclose($fs); 106 | return true; 107 | } 108 | 109 | return false; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/config/config.php: -------------------------------------------------------------------------------- 1 | 'App\Role', 23 | 24 | /* 25 | |-------------------------------------------------------------------------- 26 | | Entrust Roles Table 27 | |-------------------------------------------------------------------------- 28 | | 29 | | This is the roles table used by Entrust to save roles to the database. 30 | | 31 | */ 32 | 'roles_table' => 'roles', 33 | 34 | /* 35 | |-------------------------------------------------------------------------- 36 | | Entrust role foreign key 37 | |-------------------------------------------------------------------------- 38 | | 39 | | This is the role foreign key used by Entrust to make a proper 40 | | relation between permissions and roles & roles and users 41 | | 42 | */ 43 | 'role_foreign_key' => 'role_id', 44 | 45 | /* 46 | |-------------------------------------------------------------------------- 47 | | Application User Model 48 | |-------------------------------------------------------------------------- 49 | | 50 | | This is the User model used by Entrust to create correct relations. 51 | | Update the User if it is in a different namespace. 52 | | 53 | */ 54 | 'user' => 'App\User', 55 | 56 | /* 57 | |-------------------------------------------------------------------------- 58 | | Application Users Table 59 | |-------------------------------------------------------------------------- 60 | | 61 | | This is the users table used by the application to save users to the 62 | | database. 63 | | 64 | */ 65 | 'users_table' => 'users', 66 | 67 | /* 68 | |-------------------------------------------------------------------------- 69 | | Entrust role_user Table 70 | |-------------------------------------------------------------------------- 71 | | 72 | | This is the role_user table used by Entrust to save assigned roles to the 73 | | database. 74 | | 75 | */ 76 | 'role_user_table' => 'role_user', 77 | 78 | /* 79 | |-------------------------------------------------------------------------- 80 | | Entrust user foreign key 81 | |-------------------------------------------------------------------------- 82 | | 83 | | This is the user foreign key used by Entrust to make a proper 84 | | relation between roles and users 85 | | 86 | */ 87 | 'user_foreign_key' => 'user_id', 88 | 89 | /* 90 | |-------------------------------------------------------------------------- 91 | | Entrust Permission Model 92 | |-------------------------------------------------------------------------- 93 | | 94 | | This is the Permission model used by Entrust to create correct relations. 95 | | Update the permission if it is in a different namespace. 96 | | 97 | */ 98 | 'permission' => 'App\Permission', 99 | 100 | /* 101 | |-------------------------------------------------------------------------- 102 | | Entrust Permissions Table 103 | |-------------------------------------------------------------------------- 104 | | 105 | | This is the permissions table used by Entrust to save permissions to the 106 | | database. 107 | | 108 | */ 109 | 'permissions_table' => 'permissions', 110 | 111 | /* 112 | |-------------------------------------------------------------------------- 113 | | Entrust permission_role Table 114 | |-------------------------------------------------------------------------- 115 | | 116 | | This is the permission_role table used by Entrust to save relationship 117 | | between permissions and roles to the database. 118 | | 119 | */ 120 | 'permission_role_table' => 'permission_role', 121 | 122 | /* 123 | |-------------------------------------------------------------------------- 124 | | Entrust permission foreign key 125 | |-------------------------------------------------------------------------- 126 | | 127 | | This is the permission foreign key used by Entrust to make a proper 128 | | relation between permissions and roles 129 | | 130 | */ 131 | 'permission_foreign_key' => 'permission_id', 132 | ]; 133 | -------------------------------------------------------------------------------- /src/views/generators/migration.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | use Illuminate\Database\Migrations\Migration; 4 | use Illuminate\Database\Schema\Blueprint; 5 | 6 | class EntrustSetupTables extends Migration 7 | { 8 | /** 9 | * Run the migrations. 10 | * 11 | * @return void 12 | */ 13 | public function up() 14 | { 15 | DB::beginTransaction(); 16 | 17 | // Create table for storing roles 18 | Schema::create('{{ $rolesTable }}', function (Blueprint $table) { 19 | $table->increments('id'); 20 | $table->string('name')->unique(); 21 | $table->string('display_name')->nullable(); 22 | $table->string('description')->nullable(); 23 | $table->timestamps(); 24 | }); 25 | 26 | // Create table for associating roles to users (Many-to-Many) 27 | Schema::create('{{ $roleUserTable }}', function (Blueprint $table) { 28 | $table->integer('user_id')->unsigned(); 29 | $table->integer('role_id')->unsigned(); 30 | 31 | $table->foreign('user_id')->references('{{ $userKeyName }}')->on('{{ $usersTable }}') 32 | ->onUpdate('cascade')->onDelete('cascade'); 33 | $table->foreign('role_id')->references('id')->on('{{ $rolesTable }}') 34 | ->onUpdate('cascade')->onDelete('cascade'); 35 | 36 | $table->primary(['user_id', 'role_id']); 37 | }); 38 | 39 | // Create table for storing permissions 40 | Schema::create('{{ $permissionsTable }}', function (Blueprint $table) { 41 | $table->increments('id'); 42 | $table->string('name')->unique(); 43 | $table->string('display_name')->nullable(); 44 | $table->string('description')->nullable(); 45 | $table->timestamps(); 46 | }); 47 | 48 | // Create table for associating permissions to roles (Many-to-Many) 49 | Schema::create('{{ $permissionRoleTable }}', function (Blueprint $table) { 50 | $table->integer('permission_id')->unsigned(); 51 | $table->integer('role_id')->unsigned(); 52 | 53 | $table->foreign('permission_id')->references('id')->on('{{ $permissionsTable }}') 54 | ->onUpdate('cascade')->onDelete('cascade'); 55 | $table->foreign('role_id')->references('id')->on('{{ $rolesTable }}') 56 | ->onUpdate('cascade')->onDelete('cascade'); 57 | 58 | $table->primary(['permission_id', 'role_id']); 59 | }); 60 | 61 | DB::commit(); 62 | } 63 | 64 | /** 65 | * Reverse the migrations. 66 | * 67 | * @return void 68 | */ 69 | public function down() 70 | { 71 | Schema::drop('{{ $permissionRoleTable }}'); 72 | Schema::drop('{{ $permissionsTable }}'); 73 | Schema::drop('{{ $roleUserTable }}'); 74 | Schema::drop('{{ $rolesTable }}'); 75 | } 76 | } 77 | --------------------------------------------------------------------------------