Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@
'menu' => [
'cache' => [
// enable cache or not
'enable' => false,
'enable' => true,
'store' => 'file',
],

Expand Down
12 changes: 6 additions & 6 deletions src/Grid/Exporters/AbstractExporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -221,20 +221,20 @@ public function buildData(?int $page = null, ?int $perPage = null)
* @param Collection $data
* @return array
*/
protected function normalize(Collection $data)
protected function normalize(Collection $data): array
{
$data = $data->toArray();
foreach ($data as &$row) {
$row = Arr::dot($row);

$result = [];
foreach ($data as $item) {
$row = Arr::dot((array) $item);
foreach ($row as &$v) {
if (is_array($v) || is_object($v)) {
$v = json_encode($v, JSON_UNESCAPED_UNICODE);
}
}
$result[] = $row;
}

return $data;
return $result;
}

/**
Expand Down
74 changes: 59 additions & 15 deletions src/Models/Role.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Support\Collection;

class Role extends Model
{
Expand Down Expand Up @@ -79,12 +80,28 @@ public function menus(): BelongsToMany
/**
* Check user has permission.
*
* @param $permission
* @param string|null $permission
* @return bool
*/
public function can(?string $permission): bool
{
return $this->permissions()->where('slug', $permission)->exists();
if (! $permission) {
return false;
}

return $this->getCachedPermissionsSlugs()->has($permission);
}

/**
* Get cached permissions slugs collection.
*
* @return Collection
*/
protected function getCachedPermissionsSlugs(): Collection
{
return once(function () {
return $this->permissions()->pluck('slug')->flip();
});
}

/**
Expand All @@ -106,24 +123,43 @@ public function cannot(?string $permission): bool
*/
public static function getPermissionId(array $roleIds)
{
if (! $roleIds) {
if (empty($roleIds)) {
return collect();
}
$related = config('admin.database.role_permissions_table');

$model = new static();
$keyName = $model->getKeyName();
sort($roleIds);
$cacheKey = 'admin.role_permissions.'.md5(implode(',', $roleIds));

return $model->newQuery()
->leftJoin($related, $keyName, '=', 'role_id')
->whereIn($keyName, $roleIds)
->get(['permission_id', 'role_id'])
->groupBy('role_id')
->map(function ($v) {
$v = $v instanceof Arrayable ? $v->toArray() : $v;
return cache()->remember($cacheKey, 3600, function () use ($roleIds) {
$related = config('admin.database.role_permissions_table');
$model = new static();
$keyName = $model->getKeyName();

return array_column($v, 'permission_id');
});
return $model->newQuery()
->leftJoin($related, $keyName, '=', 'role_id')
->whereIn($keyName, $roleIds)
->get(['permission_id', 'role_id'])
->groupBy('role_id')
->map(function ($v) {
$v = $v instanceof Arrayable ? $v->toArray() : $v;

return array_column($v, 'permission_id');
});
});
}

/**
* Clear role permissions cache.
*
* @return void
*/
public static function clearPermissionCache()
{
$store = cache()->getStore();

if (method_exists($store, 'forgetByPrefix')) {
$store->forgetByPrefix('admin.role_permissions.');
}
}

/**
Expand All @@ -149,5 +185,13 @@ protected static function boot()

$model->permissions()->detach();
});

static::saved(function () {
static::clearPermissionCache();
});

static::deleted(function () {
static::clearPermissionCache();
});
}
}
89 changes: 65 additions & 24 deletions src/Traits/HasPermissions.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ trait HasPermissions
/**
* Get all permissions of user.
*
* @return mixed
* @return Collection
*/
public function allPermissions(): Collection
{
Expand All @@ -28,11 +28,49 @@ public function allPermissions(): Collection
->keyBy($this->getKeyName());
}

/**
* Get permissions map for fast lookup.
*
* @return array
*/
protected function getPermissionsMap(): array
{
return once(function () {
$slugs = [];
$ids = [];
foreach ($this->allPermissions() as $perm) {
$slugs[$perm->slug] = true;
$ids[$perm->id] = true;
}

return ['slugs' => $slugs, 'ids' => $ids];
});
}

/**
* Get roles map for fast lookup.
*
* @return array
*/
protected function getRolesMap(): array
{
return once(function () {
$slugs = [];
$ids = [];
foreach ($this->roles as $role) {
$slugs[$role->slug] = true;
$ids[$role->id] = true;
}

return ['slugs' => $slugs, 'ids' => $ids];
});
}

/**
* Check if user has permission.
*
* @param $ability
* @param array|mixed $arguments
* @param string|int $ability
* @param array|mixed $paramters
* @return bool
*/
public function can($ability, $paramters = []): bool
Expand All @@ -45,18 +83,15 @@ public function can($ability, $paramters = []): bool
return true;
}

$permissions = $this->allPermissions();
$map = $this->getPermissionsMap();

return $permissions->pluck('slug')->contains($ability) ?:
$permissions
->pluck('id')
->contains($ability);
return isset($map['slugs'][$ability]) || isset($map['ids'][$ability]);
}

/**
* Check if user has no permission.
*
* @param $permission
* @param string $permission
* @return bool
*/
public function cannot(string $permission): bool
Expand All @@ -67,7 +102,7 @@ public function cannot(string $permission): bool
/**
* Check if user is administrator.
*
* @return mixed
* @return bool
*/
public function isAdministrator(): bool
{
Expand All @@ -80,39 +115,45 @@ public function isAdministrator(): bool
/**
* Check if user is $role.
*
* @param string $role
* @return mixed
* @param string|int $role
* @return bool
*/
public function isRole(string $role): bool
public function isRole(string|int $role): bool
{
/* @var Collection $roles */
$roles = $this->roles;
$map = $this->getRolesMap();

return $roles->pluck('slug')->contains($role) ?:
$roles->pluck('id')->contains($role);
return isset($map['slugs'][$role]) || isset($map['ids'][$role]);
}

/**
* Check if user in $roles.
*
* @param string|array|Arrayable $roles
* @return mixed
* @return bool
*/
public function inRoles($roles = []): bool
{
/* @var Collection $all */
$all = $this->roles;

$roles = Helper::array($roles);

return $all->pluck('slug')->intersect($roles)->isNotEmpty() ?:
$all->pluck('id')->intersect($roles)->isNotEmpty();
if (empty($roles)) {
return false;
}

$map = $this->getRolesMap();

foreach ($roles as $role) {
if (isset($map['slugs'][$role]) || isset($map['ids'][$role])) {
return true;
}
}

return false;
}

/**
* If visible for roles.
*
* @param $roles
* @param array $roles
* @return bool
*/
public function visible($roles = []): bool
Expand Down