Skip to content

Commit c1f6694

Browse files
committed
Merge branch 'dev'
2 parents 6ed3c20 + 7453a0d commit c1f6694

File tree

9 files changed

+242
-48
lines changed

9 files changed

+242
-48
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
],
1212
"require": {
1313
"php": ">=5.4.0",
14-
"illuminate/support": "4.2.x|~5.0"
14+
"illuminate/support": "4.2.x|~5.0",
15+
"illuminate/database": "4.2.x|~5.0"
1516
},
1617
"autoload": {
1718
"classmap": [

src/Kodeine/Acl/Helper/Helper.php

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,37 @@ protected function toDotPermissions(array $permissions)
3535
|
3636
*/
3737

38+
protected function parseOperator($str)
39+
{
40+
// if its an array lets use
41+
// and operator by default
42+
if (is_array($str)) {
43+
$str = implode(',', $str);
44+
}
45+
46+
if (preg_match('/([,|])(?:\s+)?/', $str, $m)) {
47+
return $m[1] == '|' ? 'or' : 'and';
48+
}
49+
50+
return false;
51+
}
52+
3853
/**
3954
* Converts strings having comma
40-
* or pipe to an array
55+
* or pipe to an array in
56+
* lowercase
4157
*
4258
* @param $str
4359
* @return array
4460
*/
4561
protected function hasDelimiterToArray($str)
4662
{
4763
if ( is_string($str) && preg_match('/[,|]/is', $str) ) {
48-
$str = preg_split('/ ?[,|] ?/', $str);
64+
return preg_split('/ ?[,|] ?/', strtolower($str));
4965
}
5066

51-
return $str;
67+
return is_array($str) ?
68+
array_filter($str, 'strtolower') : strtolower($str);
5269
}
5370

5471
/**

src/Kodeine/Acl/Middleware/HasPermission.php

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ public function handle($request, Closure $next)
3636
{
3737
$this->request = $request;
3838

39-
if ( ( ! $this->getAction('is') or $this->hasRole())
40-
and ( ! $this->getAction('can') and ! $this->getAction('protect_alias')
41-
or $this->hasPermission())
39+
if ( ( ! $this->getAction('is') or $this->hasRole() ) and
40+
( ! $this->getAction('can') or $this->hasPermission() ) and
41+
( ! $this->getAction('protect_alias') or $this->protectMethods() )
4242
) {
4343
return $next($request);
4444
}
@@ -79,11 +79,6 @@ protected function hasPermission()
7979
$request = $this->request;
8080
$do = $this->getAction('can');
8181

82-
// if method protection is needed.
83-
if ( ! $do && $this->getAction('protect_alias') ) {
84-
return $this->protectMethods();
85-
}
86-
8782
return ! $this->forbiddenRoute() && $request->user()->can($do);
8883
}
8984

src/Kodeine/Acl/Models/Eloquent/Permission.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?php namespace Kodeine\Acl\Models\Eloquent;
22

3-
use Config;
43
use Illuminate\Database\Eloquent\Model;
54

65
class Permission extends Model
@@ -10,7 +9,7 @@ class Permission extends Model
109
*
1110
* @var array
1211
*/
13-
protected $fillable = ['name', 'slug', 'description'];
12+
protected $fillable = ['name', 'slug', 'description', 'inherit_id'];
1413

1514
/**
1615
* The database table used by the model.
@@ -26,7 +25,8 @@ class Permission extends Model
2625
*/
2726
public function roles()
2827
{
29-
$model = Config::get('acl.role', 'Kodeine\Acl\Models\Eloquent\Role');
28+
$model = config('acl.role', 'Kodeine\Acl\Models\Eloquent\Role');
29+
3030
return $this->belongsToMany($model)->withTimestamps();
3131
}
3232

@@ -37,7 +37,7 @@ public function roles()
3737
*/
3838
public function users()
3939
{
40-
return $this->belongsToMany(Config::get('auth.model'))->withTimestamps();
40+
return $this->belongsToMany(config('auth.model'))->withTimestamps();
4141
}
4242

4343
/**

src/Kodeine/Acl/Models/Eloquent/Role.php

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?php namespace Kodeine\Acl\Models\Eloquent;
22

3-
use Config;
43
use Illuminate\Database\Eloquent\Model;
54
use Kodeine\Acl\Traits\HasPermission;
65

@@ -29,7 +28,7 @@ class Role extends Model
2928
*/
3029
public function users()
3130
{
32-
return $this->belongsToMany(Config::get('auth.model'))->withTimestamps();
31+
return $this->belongsToMany(config('auth.model'))->withTimestamps();
3332
}
3433

3534
/**
@@ -39,7 +38,7 @@ public function users()
3938
*/
4039
public function getPermissions()
4140
{
42-
return $this->permissions->lists('slug', 'name');
41+
return $this->getPermissionsInherited();
4342
}
4443

4544
/**
@@ -49,22 +48,64 @@ public function getPermissions()
4948
* @param array $mergePermissions
5049
* @return bool
5150
*/
52-
public function can($permission, $mergePermissions = [])
51+
public function can($permission, $operator = null, $mergePermissions = [])
5352
{
53+
$operator = is_null(null) ? $this->parseOperator($permission) : $operator;
54+
5455
$permission = $this->hasDelimiterToArray($permission);
5556
$permissions = $this->getPermissions() + $mergePermissions;
5657

5758
// make permissions to dot notation.
5859
// create.user, delete.admin etc.
5960
$permissions = $this->toDotPermissions($permissions);
6061

62+
// validate permissions array
6163
if ( is_array($permission) ) {
62-
$intersect = array_intersect_key($permissions, array_flip($permission));
6364

64-
return count($permission) == count($intersect);
65+
if ( ! in_array($operator, ['and', 'or']) ) {
66+
$e = 'Invalid operator, available operators are "and", "or".';
67+
throw new \InvalidArgumentException($e);
68+
}
69+
70+
$call = 'canWith' . ucwords($operator);
71+
72+
return $this->$call($permission, $permissions);
6573
}
6674

75+
// validate single permission
6776
return isset($permissions[$permission]) && $permissions[$permission] == true;
6877
}
6978

79+
/**
80+
* @param $permission
81+
* @param $permissions
82+
* @return bool
83+
*/
84+
protected function canWithAnd($permission, $permissions)
85+
{
86+
foreach ($permission as $check) {
87+
if ( ! in_array($check, $permissions) || ! isset($permissions[$check]) || $permissions[$check] != true ) {
88+
return false;
89+
}
90+
}
91+
92+
return true;
93+
}
94+
95+
/**
96+
* @param $permission
97+
* @param $permissions
98+
* @return bool
99+
*/
100+
protected function canWithOr($permission, $permissions)
101+
{
102+
foreach ($permission as $check) {
103+
if ( in_array($check, $permissions) && isset($permissions[$check]) && $permissions[$check] == true ) {
104+
return true;
105+
}
106+
}
107+
108+
return false;
109+
}
110+
70111
}

src/Kodeine/Acl/Traits/HasPermission.php

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
trait HasPermission
66
{
7-
use HasUserPermission, Helper;
7+
use HasUserPermission, HasPermissionInheritance, Helper;
88

99
/*
1010
|----------------------------------------------------------------------
@@ -20,7 +20,8 @@ trait HasPermission
2020
*/
2121
public function permissions()
2222
{
23-
$model = \Config::get('acl.permission', 'Kodeine\Acl\Models\Eloquent\Permission');
23+
$model = config('acl.permission', 'Kodeine\Acl\Models\Eloquent\Permission');
24+
2425
return $this->belongsToMany($model)->withTimestamps();
2526
}
2627

@@ -33,7 +34,7 @@ public function permissions()
3334
public function getPermissions()
3435
{
3536
// user permissions overridden from role.
36-
$permissions = $this->permissions->lists('slug', 'name');
37+
$permissions = $this->getPermissionsInherited();
3738

3839
// permissions based on role.
3940
foreach ($this->roles as $role) {
@@ -51,18 +52,16 @@ public function getPermissions()
5152
*/
5253
public function can($permission)
5354
{
54-
// user has its own permissions
55-
// without any role?
55+
// user permissions including
56+
// all of user role permissions
5657
$merge = $this->getPermissions();
5758

58-
// permissions based on role
59-
foreach ($this->roles as $role) {
60-
if ( $role->can($permission, $merge) ) {
61-
return true;
62-
}
63-
}
59+
// get first role and use can method
60+
// $merge already has all user role
61+
// permissions.
62+
$role = $this->roles->first();
6463

65-
return false;
64+
return ! is_null($role) && $role->can($permission, null, $merge);
6665
}
6766

6867
/**
@@ -150,15 +149,15 @@ protected function parsePermissionId($permission)
150149
{
151150
if ( is_string($permission) || is_numeric($permission) ) {
152151

153-
$model = new \Kodeine\Acl\Models\Eloquent\Permission;
152+
$model = config('acl.permission', 'Kodeine\Acl\Models\Eloquent\Permission');
154153
$key = is_numeric($permission) ? 'id' : 'name';
155-
$find = $model->where($key, $permission)->first();
154+
$alias = (new $model)->where($key, $permission)->first();
156155

157-
if ( ! is_object($find) ) {
156+
if ( ! is_object($alias) || ! $alias->exists ) {
158157
throw new \InvalidArgumentException('Specified permission ' . $key . ' does not exists.');
159158
}
160159

161-
$permission = $find->getKey();
160+
$permission = $alias->getKey();
162161
}
163162

164163
$model = '\Illuminate\Database\Eloquent\Model';
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php namespace Kodeine\Acl\Traits;
2+
3+
4+
trait HasPermissionInheritance
5+
{
6+
protected $cacheInherit;
7+
8+
/*
9+
|----------------------------------------------------------------------
10+
| Permission Inheritance Trait Methods
11+
|----------------------------------------------------------------------
12+
|
13+
*/
14+
15+
public function getPermissionsInherited()
16+
{
17+
$permissions = $this->permissions->lists('slug', 'name');
18+
$inherits = $this->permissions->lists('inherit_id', 'name');
19+
20+
foreach ($inherits as $name => $inherit_id) {
21+
if ( ! $inherit_id ) continue;
22+
23+
// get inherit row from cache else query it.
24+
$inherit = $this->getCacheInherit($inherit_id);
25+
26+
// add inherit row to cache.
27+
$this->setCacheInherit($inherit);
28+
29+
// merge inheritances
30+
// rename permission name to inherited name.
31+
if ( $inherit->exists ) {
32+
if ( isset($permissions[$inherit->name]) ) {
33+
$permissions[$inherit->name] = $permissions[$name] + $permissions[$inherit->name];
34+
} else {
35+
$permissions[$inherit->name] = $permissions[$name] + $inherit->slug;
36+
}
37+
unset($permissions[$name]);
38+
}
39+
40+
}
41+
42+
return $permissions;
43+
}
44+
45+
protected function getCacheInherit($inherit_id)
46+
{
47+
if ( isset($this->cacheInherit[$inherit_id]) ) {
48+
return $this->cacheInherit[$inherit_id];
49+
}
50+
51+
$model = config('acl.permission', 'Kodeine\Acl\Models\Eloquent\Permission');
52+
return (new $model)->where('id', $inherit_id)->first();
53+
}
54+
55+
protected function setCacheInherit($inherit)
56+
{
57+
return $this->cacheInherit[$inherit->getKey()] = $inherit;
58+
}
59+
60+
/**
61+
* Parses permission id from object or array.
62+
*
63+
* @param object|array|int $permission
64+
* @return mixed
65+
*/
66+
protected function parsePermissionId($permission)
67+
{
68+
if ( is_string($permission) || is_numeric($permission) ) {
69+
70+
$model = config('acl.permission', 'Kodeine\Acl\Models\Eloquent\Permission');
71+
$key = is_numeric($permission) ? 'id' : 'name';
72+
$alias = (new $model)->where($key, $permission)->first();
73+
74+
if ( ! is_object($alias) || ! $alias->exists ) {
75+
throw new \InvalidArgumentException('Specified permission ' . $key . ' does not exists.');
76+
}
77+
78+
$permission = $alias->getKey();
79+
}
80+
81+
$model = '\Illuminate\Database\Eloquent\Model';
82+
if ( is_object($permission) && $permission instanceof $model ) {
83+
$permission = $permission->getKey();
84+
}
85+
86+
return (int) $permission;
87+
}
88+
89+
}

0 commit comments

Comments
 (0)