Laravel-permission: Role and permission events

Created on 31 May 2018  路  5Comments  路  Source: spatie/laravel-permission

I'd like to listen for events for Eloquent model that use HasRole or HasPermissions traits.

Examples:

  • "i assign Moderator role to John" -> RoleAssigned event fired
  • "i revoke Moderator role to Mike" -> RoleRevoked event fired

Code sample:
`class User {
use HasRoles;

protected $dispatchesEvents = [
'role_assigned' => RoleAssigned::class,
'role_revoked' => RoleRevoked::class
];`

Is it possibile?

Most helpful comment

You could quite easily use the same method to fire events instead:

namespace App\Models\Traits;

use Spatie\Permission\Traits\HasRoles;

/**
 * @mixin \App\Models\BaseModel
 */
trait HasRolesTrait
{
    use HasRoles {
        assignRole as protected originalAssignRole;
        removeRole as protected originalRemoveRole;
        syncRoles as protected originalSyncRoles;
    }

    /**
     * @param mixed ...$roles
     * @return $this
     */
    public function assignRole(...$roles)
    {
        $this->originalAssignRole(...$roles);

        $this->fireRoleAssignedEvent($roles);

        return $this;
    }

    /**
     * @param $role
     * @return bool
     */
    public function fireRoleAssignedEvent($role)
    {
        if (is_iterable($role)) {
            return array_walk($role, [$this, 'fireRoleAssignedEvent']);
        }

        event(new RoleAssignedEvent($this, $this->getStoredRole($role)));

        return true;
    }

    /**
     * @param $role
     * @return $this
     */
    public function removeRole($role)
    {
        $this->originalRemoveRole($role);

        $this->fireRoleRemovedEvent($role);

        return $this;
    }

    /**
     * @param $role
     * @return bool
     */
    public function fireRoleRemovedEvent($role)
    {
        if (is_iterable($role)) {
            return array_walk($role, [$this, 'fireRoleRemovedEvent']);
        }

        event(new RoleRemovedEvent($this, $this->getStoredRole($role)));

        return true;
    }
}

All 5 comments

You might find the proposed customizations in https://github.com/spatie/laravel-permission/pull/724 useful for your situation.

Thank you

I found the easiest way was to overload the trait, in this example i'm using Spatie's activity logger to log every action:

namespace App\Models\Traits;

use Illuminate\Support\Facades\Auth;
use Spatie\Permission\Traits\HasRoles;

/**
 * @mixin \App\Models\BaseModel
 */
trait HasRolesTrait
{
    use HasRoles {
        assignRole as protected originalAssignRole;
        removeRole as protected originalRemoveRole;
        syncRoles as protected originalSyncRoles;
    }

    /**
     * @param mixed ...$roles
     * @return $this
     */
    public function assignRole(...$roles)
    {
        $this->originalAssignRole(...$roles);

        $this->logRoleAssigned($roles);

        return $this;
    }

    /**
     * @param $role
     * @return bool
     */
    public function logRoleAssigned($role): bool
    {
        if (is_array($role)) {
            return array_walk($role, [$this, 'logRoleAssigned']);
        }

        $role = $this->getStoredRole($role);

        activity()
            ->useLog('role_assigned')
            ->causedBy(Auth::user())
            ->performedOn($this)
            ->withProperties([
                'role_name' => $role->name
            ])
            ->log(':subject.name was assigned the role :properties.role_name by :causer.name');

        return true;
    }

    /**
     * @param $role
     */
    public function removeRole($role)
    {
        $this->originalRemoveRole($role);
    }

    /**
     * @param $role
     * @return bool
     */
    public function logRoleRemoved($role): bool
    {
        if (is_iterable($role)) {
            return array_walk($role, [$this, 'logRoleRemoved']);
        }

        $role = $this->getStoredRole($role);

        activity()
            ->useLog('role_removed')
            ->causedBy(Auth::user())
            ->performedOn($this)
            ->withProperties([
                'role_name' => $role->name
            ])
            ->log(':subject.name was removed from the role :properties.role_name by :causer.name');

        return true;
    }
}

You could quite easily use the same method to fire events instead:

namespace App\Models\Traits;

use Spatie\Permission\Traits\HasRoles;

/**
 * @mixin \App\Models\BaseModel
 */
trait HasRolesTrait
{
    use HasRoles {
        assignRole as protected originalAssignRole;
        removeRole as protected originalRemoveRole;
        syncRoles as protected originalSyncRoles;
    }

    /**
     * @param mixed ...$roles
     * @return $this
     */
    public function assignRole(...$roles)
    {
        $this->originalAssignRole(...$roles);

        $this->fireRoleAssignedEvent($roles);

        return $this;
    }

    /**
     * @param $role
     * @return bool
     */
    public function fireRoleAssignedEvent($role)
    {
        if (is_iterable($role)) {
            return array_walk($role, [$this, 'fireRoleAssignedEvent']);
        }

        event(new RoleAssignedEvent($this, $this->getStoredRole($role)));

        return true;
    }

    /**
     * @param $role
     * @return $this
     */
    public function removeRole($role)
    {
        $this->originalRemoveRole($role);

        $this->fireRoleRemovedEvent($role);

        return $this;
    }

    /**
     * @param $role
     * @return bool
     */
    public function fireRoleRemovedEvent($role)
    {
        if (is_iterable($role)) {
            return array_walk($role, [$this, 'fireRoleRemovedEvent']);
        }

        event(new RoleRemovedEvent($this, $this->getStoredRole($role)));

        return true;
    }
}

Thank you @robjbrain

Was this page helpful?
0 / 5 - 0 ratings

Related issues

younus93 picture younus93  路  4Comments

wreighsantos picture wreighsantos  路  4Comments

ghost picture ghost  路  3Comments

bhulsman picture bhulsman  路  3Comments

ergonomicus picture ergonomicus  路  3Comments