From c4e191bebe6e0fc9bde8bdcb33a8ad20c2c33483 Mon Sep 17 00:00:00 2001 From: Asvae Date: Thu, 19 May 2016 14:01:08 +0300 Subject: [PATCH 1/8] Add phpunit and configuration. --- composer.json | 4 ++++ phpunit.xml | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 phpunit.xml diff --git a/composer.json b/composer.json index ff4820f..27ee018 100644 --- a/composer.json +++ b/composer.json @@ -17,5 +17,9 @@ "psr-0": { "Bican\\Roles": "src/" } + }, + "require-dev": { + "phpunit/phpunit": "^4.8", + "mockery/mockery": "^0.9.4" } } diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..c78c71d --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,20 @@ + + + + + ./tests + + + + + ./src + + + From 00ec6ab4d9a71cc453e00866469ef53c68eaf011 Mon Sep 17 00:00:00 2001 From: Asvae Date: Thu, 19 May 2016 17:29:54 +0300 Subject: [PATCH 2/8] Unit tests are bad idea: just saving my progress. Moved to separate project. --- .../Roles/Traits/HasRoleAndPermission.php | 42 +++++++++- tests/Traits/HasRoleAndPermissionTest.php | 76 +++++++++++++++++++ 2 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 tests/Traits/HasRoleAndPermissionTest.php diff --git a/src/Bican/Roles/Traits/HasRoleAndPermission.php b/src/Bican/Roles/Traits/HasRoleAndPermission.php index 840cc1c..9b059e9 100644 --- a/src/Bican/Roles/Traits/HasRoleAndPermission.php +++ b/src/Bican/Roles/Traits/HasRoleAndPermission.php @@ -29,7 +29,37 @@ trait HasRoleAndPermission */ public function roles() { - return $this->belongsToMany(config('roles.models.role'))->withTimestamps(); + return $this->belongsToMany($this->getRoleClass())->withTimestamps(); + } + + // TODO Test helpers, move down. \/ + + /** + * @var $roles \Illuminate\Database\Eloquent\Collection|null + */ + public function setRoles($roles) + { + $this->roles = $roles; + } + + /** + * Get role class name from config. + * + * @return string + */ + protected function getRoleClass() + { + return config('roles.models.role'); + } + + /** + * Get permission class name from config. + * + * @return string + */ + protected function getPermissionClass() + { + return config('roles.models.permission'); } /** @@ -39,7 +69,11 @@ public function roles() */ public function getRoles() { - return (!$this->roles) ? $this->roles = $this->roles()->get() : $this->roles; + if ($this->roles){ + return $this->roles; + } + + return $this->roles = $this->roles()->get(); } /** @@ -164,10 +198,12 @@ public function rolePermissions() throw new InvalidArgumentException('[roles.models.permission] must be an instance of \Illuminate\Database\Eloquent\Model'); } + // @formatter:off return $permissionModel::select(['permissions.*', 'permission_role.created_at as pivot_created_at', 'permission_role.updated_at as pivot_updated_at']) ->join('permission_role', 'permission_role.permission_id', '=', 'permissions.id')->join('roles', 'roles.id', '=', 'permission_role.role_id') ->whereIn('roles.id', $this->getRoles()->lists('id')->toArray()) ->orWhere('roles.level', '<', $this->level()) ->groupBy(['permissions.id', 'pivot_created_at', 'pivot_updated_at']); + // @formatter:on } /** @@ -327,7 +363,7 @@ public function detachPermission($permission) public function detachAllPermissions() { $this->permissions = null; - + return $this->userPermissions()->detach(); } diff --git a/tests/Traits/HasRoleAndPermissionTest.php b/tests/Traits/HasRoleAndPermissionTest.php new file mode 100644 index 0000000..377dcd9 --- /dev/null +++ b/tests/Traits/HasRoleAndPermissionTest.php @@ -0,0 +1,76 @@ +getMockForTrait(\Bican\Roles\Traits\HasRoleAndPermission::class, + [], 'User', true, true, true, $methods /*mocked methods*/); + } + + /** + * @covers ::roles + */ + public function test_has_roles_relation() + { + $mock = $this->getMockWithMethods([ + 'belongsToMany', + 'withTimestamps', + 'getRoleClass', + ]); + + $mock->expects($this->once()) + ->method('belongsToMany') + ->will($this->returnSelf()); + + $mock->expects($this->once()) + ->method('getRoleClass') + ->will($this->returnValue('Roles')); + + $mock->expects($this->once()) + ->method('withTimestamps') + ->will($this->returnSelf()); + + $mock->roles(); + } + + /** + * @covers ::getRoles + */ + public function test_get_roles_returns_existing_collection() + { + $mock = $this->getMockWithMethods([]); + $mock->setRoles('Collection'); + + $this->assertEquals($mock->getRoles(), 'Collection'); + } + + /** + * @covers ::getRoles + */ + public function test_get_roles_returns_new_collection_when_empty() + { + $mock = $this->getMockWithMethods([ + 'roles', + 'get', + ]); + + $mock->expects($this->once()) + ->method('roles') + ->will($this->returnSelf()); + + $mock->expects($this->once()) + ->method('get') + ->will($this->returnValue('Collection')); + + $this->assertEquals($mock->getRoles(), 'Collection'); + } +} \ No newline at end of file From 0bb38797f998600f91ad3fe5606d2f463f76cd72 Mon Sep 17 00:00:00 2001 From: Asvae Date: Thu, 19 May 2016 22:40:08 +0300 Subject: [PATCH 3/8] Remove tests --- composer.json | 4 -- phpunit.xml | 20 ------ tests/Traits/HasRoleAndPermissionTest.php | 76 ----------------------- 3 files changed, 100 deletions(-) delete mode 100644 phpunit.xml delete mode 100644 tests/Traits/HasRoleAndPermissionTest.php diff --git a/composer.json b/composer.json index 27ee018..ff4820f 100644 --- a/composer.json +++ b/composer.json @@ -17,9 +17,5 @@ "psr-0": { "Bican\\Roles": "src/" } - }, - "require-dev": { - "phpunit/phpunit": "^4.8", - "mockery/mockery": "^0.9.4" } } diff --git a/phpunit.xml b/phpunit.xml deleted file mode 100644 index c78c71d..0000000 --- a/phpunit.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - ./tests - - - - - ./src - - - diff --git a/tests/Traits/HasRoleAndPermissionTest.php b/tests/Traits/HasRoleAndPermissionTest.php deleted file mode 100644 index 377dcd9..0000000 --- a/tests/Traits/HasRoleAndPermissionTest.php +++ /dev/null @@ -1,76 +0,0 @@ -getMockForTrait(\Bican\Roles\Traits\HasRoleAndPermission::class, - [], 'User', true, true, true, $methods /*mocked methods*/); - } - - /** - * @covers ::roles - */ - public function test_has_roles_relation() - { - $mock = $this->getMockWithMethods([ - 'belongsToMany', - 'withTimestamps', - 'getRoleClass', - ]); - - $mock->expects($this->once()) - ->method('belongsToMany') - ->will($this->returnSelf()); - - $mock->expects($this->once()) - ->method('getRoleClass') - ->will($this->returnValue('Roles')); - - $mock->expects($this->once()) - ->method('withTimestamps') - ->will($this->returnSelf()); - - $mock->roles(); - } - - /** - * @covers ::getRoles - */ - public function test_get_roles_returns_existing_collection() - { - $mock = $this->getMockWithMethods([]); - $mock->setRoles('Collection'); - - $this->assertEquals($mock->getRoles(), 'Collection'); - } - - /** - * @covers ::getRoles - */ - public function test_get_roles_returns_new_collection_when_empty() - { - $mock = $this->getMockWithMethods([ - 'roles', - 'get', - ]); - - $mock->expects($this->once()) - ->method('roles') - ->will($this->returnSelf()); - - $mock->expects($this->once()) - ->method('get') - ->will($this->returnValue('Collection')); - - $this->assertEquals($mock->getRoles(), 'Collection'); - } -} \ No newline at end of file From 1287b1171649d0d46313e4fbac2f7f319f91a07d Mon Sep 17 00:00:00 2001 From: Asvae Date: Thu, 19 May 2016 22:40:43 +0300 Subject: [PATCH 4/8] Add ide helpers to Role and Permission models. --- src/Bican/Roles/Models/Permission.php | 7 +++++++ src/Bican/Roles/Models/Role.php | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/Bican/Roles/Models/Permission.php b/src/Bican/Roles/Models/Permission.php index 6834cc8..5c5a1ed 100644 --- a/src/Bican/Roles/Models/Permission.php +++ b/src/Bican/Roles/Models/Permission.php @@ -7,6 +7,13 @@ use Bican\Roles\Traits\PermissionHasRelations; use Bican\Roles\Contracts\PermissionHasRelations as PermissionHasRelationsContract; +/** + * @property integer id + * @property string name + * @property string slug + * @property string description + * @property string model + */ class Permission extends Model implements PermissionHasRelationsContract { use Slugable, PermissionHasRelations; diff --git a/src/Bican/Roles/Models/Role.php b/src/Bican/Roles/Models/Role.php index 34d70bf..1aeddda 100644 --- a/src/Bican/Roles/Models/Role.php +++ b/src/Bican/Roles/Models/Role.php @@ -7,6 +7,13 @@ use Bican\Roles\Traits\RoleHasRelations; use Bican\Roles\Contracts\RoleHasRelations as RoleHasRelationsContract; +/** + * @property integer id + * @property string name + * @property string slug + * @property string description + * @property integer level + */ class Role extends Model implements RoleHasRelationsContract { use Slugable, RoleHasRelations; From fff4bee701ee49e469e3b8e6d5bf3446a61ecf55 Mon Sep 17 00:00:00 2001 From: Asvae Date: Thu, 19 May 2016 22:42:46 +0300 Subject: [PATCH 5/8] Remove changes. --- .../Roles/Traits/HasRoleAndPermission.php | 39 ++----------------- 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/src/Bican/Roles/Traits/HasRoleAndPermission.php b/src/Bican/Roles/Traits/HasRoleAndPermission.php index 9b059e9..4af08bc 100644 --- a/src/Bican/Roles/Traits/HasRoleAndPermission.php +++ b/src/Bican/Roles/Traits/HasRoleAndPermission.php @@ -29,38 +29,9 @@ trait HasRoleAndPermission */ public function roles() { - return $this->belongsToMany($this->getRoleClass())->withTimestamps(); + return $this->belongsToMany(config('roles.models.role'))->withTimestamps(); } - // TODO Test helpers, move down. \/ - - /** - * @var $roles \Illuminate\Database\Eloquent\Collection|null - */ - public function setRoles($roles) - { - $this->roles = $roles; - } - - /** - * Get role class name from config. - * - * @return string - */ - protected function getRoleClass() - { - return config('roles.models.role'); - } - - /** - * Get permission class name from config. - * - * @return string - */ - protected function getPermissionClass() - { - return config('roles.models.permission'); - } /** * Get all roles as collection. @@ -69,11 +40,7 @@ protected function getPermissionClass() */ public function getRoles() { - if ($this->roles){ - return $this->roles; - } - - return $this->roles = $this->roles()->get(); + return (!$this->roles) ? $this->roles = $this->roles()->get() : $this->roles; } /** @@ -127,7 +94,7 @@ public function isAll($role) } /** - * Check if the user has role. + * Check if the user has role by either slug or id. * * @param int|string $role * @return bool From 4f6b189f529be1985a1663a06716c54e14b3c5ce Mon Sep 17 00:00:00 2001 From: Asvae Date: Fri, 20 May 2016 01:35:20 +0300 Subject: [PATCH 6/8] Add role to $user->is() arguments. Reformatting here and there. --- .../Roles/Traits/HasRoleAndPermission.php | 94 ++++++++++++------- 1 file changed, 60 insertions(+), 34 deletions(-) diff --git a/src/Bican/Roles/Traits/HasRoleAndPermission.php b/src/Bican/Roles/Traits/HasRoleAndPermission.php index 4af08bc..ac10c45 100644 --- a/src/Bican/Roles/Traits/HasRoleAndPermission.php +++ b/src/Bican/Roles/Traits/HasRoleAndPermission.php @@ -2,6 +2,7 @@ namespace Bican\Roles\Traits; +use Bican\Roles\Models\Role; use Illuminate\Support\Str; use Illuminate\Database\Eloquent\Model; use InvalidArgumentException; @@ -32,7 +33,6 @@ public function roles() return $this->belongsToMany(config('roles.models.role'))->withTimestamps(); } - /** * Get all roles as collection. * @@ -40,14 +40,14 @@ public function roles() */ public function getRoles() { - return (!$this->roles) ? $this->roles = $this->roles()->get() : $this->roles; + return (! $this->roles) ? $this->roles = $this->roles()->get() : $this->roles; } /** * Check if the user has a role or roles. * - * @param int|string|array $role - * @param bool $all + * @param int|string|array|\Bican\Roles\Models\Role $role + * @param bool $all * @return bool */ public function is($role, $all = false) @@ -62,7 +62,7 @@ public function is($role, $all = false) /** * Check if the user has at least one role. * - * @param int|string|array $role + * @param int|string|array|\Bican\Roles\Models\Role $role * @return bool */ public function isOne($role) @@ -79,13 +79,13 @@ public function isOne($role) /** * Check if the user has all roles. * - * @param int|string|array $role + * @param int|string|array|\Bican\Roles\Models\Role $role * @return bool */ public function isAll($role) { foreach ($this->getArrayFrom($role) as $role) { - if (!$this->hasRole($role)) { + if (! $this->hasRole($role)) { return false; } } @@ -94,14 +94,18 @@ public function isAll($role) } /** - * Check if the user has role by either slug or id. + * Check if the user has role. * - * @param int|string $role + * @param int|string|\Bican\Roles\Models\Role $role * @return bool */ public function hasRole($role) { return $this->getRoles()->contains(function ($key, $value) use ($role) { + if ($role instanceof Role) { + return $value->id == $role->id; + } + return $role == $value->id || Str::is($role, $value->slug); }); } @@ -114,7 +118,7 @@ public function hasRole($role) */ public function attachRole($role) { - return (!$this->getRoles()->contains($role)) ? $this->roles()->attach($role) : true; + return (! $this->getRoles()->contains($role)) ? $this->roles()->attach($role) : true; } /** @@ -161,16 +165,20 @@ public function rolePermissions() { $permissionModel = app(config('roles.models.permission')); - if (!$permissionModel instanceof Model) { + if (! $permissionModel instanceof Model) { throw new InvalidArgumentException('[roles.models.permission] must be an instance of \Illuminate\Database\Eloquent\Model'); } - // @formatter:off - return $permissionModel::select(['permissions.*', 'permission_role.created_at as pivot_created_at', 'permission_role.updated_at as pivot_updated_at']) - ->join('permission_role', 'permission_role.permission_id', '=', 'permissions.id')->join('roles', 'roles.id', '=', 'permission_role.role_id') - ->whereIn('roles.id', $this->getRoles()->lists('id')->toArray()) ->orWhere('roles.level', '<', $this->level()) - ->groupBy(['permissions.id', 'pivot_created_at', 'pivot_updated_at']); - // @formatter:on + return $permissionModel::select([ + 'permissions.*', + 'permission_role.created_at as pivot_created_at', + 'permission_role.updated_at as pivot_updated_at', + ]) + ->join('permission_role', 'permission_role.permission_id', '=', 'permissions.id') + ->join('roles', 'roles.id', '=', 'permission_role.role_id') + ->whereIn('roles.id', $this->getRoles()->pluck('id')->toArray()) + ->orWhere('roles.level', '<', $this->level()) + ->groupBy(['permissions.id', 'pivot_created_at', 'pivot_updated_at']); } /** @@ -190,14 +198,16 @@ public function userPermissions() */ public function getPermissions() { - return (!$this->permissions) ? $this->permissions = $this->rolePermissions()->get()->merge($this->userPermissions()->get()) : $this->permissions; + return (! $this->permissions) ? $this->permissions = $this->rolePermissions() + ->get() + ->merge($this->userPermissions()->get()) : $this->permissions; } /** * Check if the user has a permission or permissions. * * @param int|string|array $permission - * @param bool $all + * @param bool $all * @return bool */ public function can($permission, $all = false) @@ -235,7 +245,7 @@ public function canOne($permission) public function canAll($permission) { foreach ($this->getArrayFrom($permission) as $permission) { - if (!$this->hasPermission($permission)) { + if (! $this->hasPermission($permission)) { return false; } } @@ -251,7 +261,9 @@ public function canAll($permission) */ public function hasPermission($permission) { - return $this->getPermissions()->contains(function ($key, $value) use ($permission) { + return $this->getPermissions()->contains(function ($key, $value) use ( + $permission + ) { return $permission == $value->id || Str::is($permission, $value->slug); }); } @@ -259,13 +271,18 @@ public function hasPermission($permission) /** * Check if the user is allowed to manipulate with entity. * - * @param string $providedPermission + * @param string $providedPermission * @param \Illuminate\Database\Eloquent\Model $entity - * @param bool $owner - * @param string $ownerColumn + * @param bool $owner + * @param string $ownerColumn * @return bool */ - public function allowed($providedPermission, Model $entity, $owner = true, $ownerColumn = 'user_id') + public function allowed( + $providedPermission, + Model $entity, + $owner = true, + $ownerColumn = 'user_id' + ) { if ($this->isPretendEnabled()) { return $this->pretend('allowed'); @@ -281,16 +298,14 @@ public function allowed($providedPermission, Model $entity, $owner = true, $owne /** * Check if the user is allowed to manipulate with provided entity. * - * @param string $providedPermission + * @param string $providedPermission * @param \Illuminate\Database\Eloquent\Model $entity * @return bool */ protected function isAllowed($providedPermission, Model $entity) { foreach ($this->getPermissions() as $permission) { - if ($permission->model != '' && get_class($entity) == $permission->model - && ($permission->id == $providedPermission || $permission->slug === $providedPermission) - ) { + if ($permission->model != '' && get_class($entity) == $permission->model && ($permission->id == $providedPermission || $permission->slug === $providedPermission)) { return true; } } @@ -306,7 +321,8 @@ protected function isAllowed($providedPermission, Model $entity) */ public function attachPermission($permission) { - return (!$this->getPermissions()->contains($permission)) ? $this->userPermissions()->attach($permission) : true; + return (! $this->getPermissions()->contains($permission)) ? $this->userPermissions() + ->attach($permission) : true; } /** @@ -359,7 +375,7 @@ private function pretend($option) * Get method name. * * @param string $methodName - * @param bool $all + * @param bool $all * @return string */ private function getMethodName($methodName, $all) @@ -375,14 +391,22 @@ private function getMethodName($methodName, $all) */ private function getArrayFrom($argument) { - return (!is_array($argument)) ? preg_split('/ ?[,|] ?/', $argument) : $argument; + if (is_array($argument)) { + return $argument; + } + + if (is_string($argument)) { + return preg_split('/ ?[,|] ?/', $argument); + } + + return [$argument]; } /** * Handle dynamic method calls. * * @param string $method - * @param array $parameters + * @param array $parameters * @return mixed */ public function __call($method, $parameters) @@ -392,7 +416,9 @@ public function __call($method, $parameters) } elseif (starts_with($method, 'can')) { return $this->can(snake_case(substr($method, 3), config('roles.separator'))); } elseif (starts_with($method, 'allowed')) { - return $this->allowed(snake_case(substr($method, 7), config('roles.separator')), $parameters[0], (isset($parameters[1])) ? $parameters[1] : true, (isset($parameters[2])) ? $parameters[2] : 'user_id'); + return $this->allowed(snake_case(substr($method, 7), config('roles.separator')), + $parameters[0], (isset($parameters[1])) ? $parameters[1] : true, + (isset($parameters[2])) ? $parameters[2] : 'user_id'); } return parent::__call($method, $parameters); From 63e39999277951b4e9b8c904e725acfb139aaa49 Mon Sep 17 00:00:00 2001 From: Asvae Date: Fri, 20 May 2016 15:58:42 +0300 Subject: [PATCH 7/8] Permission can be checked by model. --- src/Bican/Roles/Traits/HasRoleAndPermission.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Bican/Roles/Traits/HasRoleAndPermission.php b/src/Bican/Roles/Traits/HasRoleAndPermission.php index ac10c45..eba45b4 100644 --- a/src/Bican/Roles/Traits/HasRoleAndPermission.php +++ b/src/Bican/Roles/Traits/HasRoleAndPermission.php @@ -2,7 +2,6 @@ namespace Bican\Roles\Traits; -use Bican\Roles\Models\Role; use Illuminate\Support\Str; use Illuminate\Database\Eloquent\Model; use InvalidArgumentException; @@ -102,7 +101,7 @@ public function isAll($role) public function hasRole($role) { return $this->getRoles()->contains(function ($key, $value) use ($role) { - if ($role instanceof Role) { + if ($role instanceof Model) { return $value->id == $role->id; } @@ -261,9 +260,11 @@ public function canAll($permission) */ public function hasPermission($permission) { - return $this->getPermissions()->contains(function ($key, $value) use ( - $permission - ) { + return $this->getPermissions()->contains(function ($key, $value) use ($permission) { + if ($permission instanceof Model) { + return $value->id == $permission->id; + } + return $permission == $value->id || Str::is($permission, $value->slug); }); } From aea06b19c8832b81943795c90f6c3681a2b439ee Mon Sep 17 00:00:00 2001 From: Asvae Date: Fri, 20 May 2016 16:34:44 +0300 Subject: [PATCH 8/8] Fix readme to show tests. --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 31deb2c..865e34b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Roles And Permissions For Laravel 5 +[![Build Status](https://travis-ci.org/Asvae/bican-roles-test.svg)](https://travis-ci.org/Asvae/bican-roles-test) + Powerful package for handling roles and permissions in Laravel 5 (5.1 and also 5.0). - [Installation](#installation) @@ -386,6 +388,11 @@ public function render($request, Exception $e) You can change connection for models, slug separator, models path and there is also a handy pretend feature. Have a look at config file for more information. +## Tests + +Tests are handled by [external package](https://github.com/Asvae/bican-roles-test) as it's not viable to test the library +outside of laravel framework. + ## More Information For more information, please have a look at [HasRoleAndPermission](https://github.com/romanbican/roles/blob/master/src/Bican/Roles/Contracts/HasRoleAndPermission.php) contract.