Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4 events for adding and removing roles or permissions #2742

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

sven-wegner
Copy link

First of all: This is my first pull request. If everything is not correct, please give me feedback!

Why I created this pull request

In my company we have an API and a UI. If changes have been made to permissions or roles (e.g. because an additional service has been booked), the UI wants to be informed about this. In my opinion, events are perfect for this!

Unfortunately, this package does not currently offer such events, as the HasRoles::roles() and HasPermissions::permissions() methods do not fire any. There is also no observer, as there is no Model class for the pivot table.

This pull request adds 4 events PermissionAttached, PermissionDetached, RoleAttached and RoleDetached for adding and removing roles or permission.

You can then have a listener listen to these in the main instance or work directly with sockets.

@sven-wegner
Copy link
Author

@parallels999 You're absolutely right. I added it.

@votkapower
Copy link

votkapower commented Nov 4, 2024

This will work only when giving programaticly roles/permissions, but when used in tool like Laravel Nova or some other tool where a record is added to the pivot table, events will not be fired.

I used a approach of PivotTable model and emit event against its created & deleted hooks, which doesnt care how you add or sync the permissions, its looks the pivot events and then fires evets.

I'm writing this so others can try it if they need it:

Overide the permisison relation on the HasPermissions Trait:

 public function permissions(): BelongsToMany
    {
      // ... 
        return $relation = $this->morphToMany(
            config('permission.models.permission'),
            'model',
            config('permission.table_names.model_has_permissions'),
            config('permission.column_names.model_morph_key'),
            PermissionRegistrar::$pivotPermission
        )->using(\App\Models\Pivots\ModelHasPermissions::class); // Use custom pivot class here
    }

ModelHasPermissions Extends the Pivot table :

use Illuminate\Database\Eloquent\Relations\MorphPivot;
class ModelHasPermissions extends MorphPivot
{
 // ..
}

And create observer ModelHasPermissionsObserver:

class ModelHasPermissionsObserver
{
    public function created(ModelHasPermissions $pivot)
    { 
        event(new PermissionAttached($pivot->model, $pivot->permission));
    }

    public function deleted(ModelHasPermissions $pivot)
    { 
        event(new PermissionRemoved($model, $pivot->permission));
    }
}

Observe for changes in AppServiceProvider:

 ModelHasPermissions::observe(ModelHasPermissionsObserver::class);

You can do the same for the roles.
Maybe you can also incorporate this in this PR, so we have both?
I hope it helps.

@drbyte
Copy link
Collaborator

drbyte commented Nov 5, 2024

Maybe you can also incorporate this in this PR, so we have both?

Wouldn't both be redundant, and result in firing events twice?

@drbyte
Copy link
Collaborator

drbyte commented Nov 8, 2024

Looking further, MorphbyMany(...)->using(...) allows ->using(null) to be passed for default operation.
So, we could probably introduce a config like permission.models.pivots.model_has_permissions which defaults to null, but could let someone declare a specific pivot model.

The downside to specifying a pivot model is that it introduces an extra db query. But the upside is that you can register observers to it.

@sven-wegner
Copy link
Author

@votkapower Sure I can override the method, but I would prefer if the package provides this configuration or the event itself :)

@drbyte This is also a very good idea and would be easy to implement. I would like both. Which idea do we want to give a chance? :)

@drbyte
Copy link
Collaborator

drbyte commented Jan 31, 2025

Looking further, MorphbyMany(...)->using(...) allows ->using(null) to be passed for default operation. So, we could probably introduce a config like permission.models.pivots.model_has_permissions which defaults to null, but could let someone declare a specific pivot model.

The downside to specifying a pivot model is that it introduces an extra db query. But the upside is that you can register observers to it.

@sven-wegner I'd like to avoid directly firing events in the traits, and instead use an Observer.

eg:

  • config('permission.models.pivots.model_has_permissions') defaults to null
  • But we provide a Pivot model that could be specified
  • And we provide an observer that could be registered in the user's own app, to watch that Pivot model.

That way if one's app needs the events, they can specify the pivot model and register the observer, and then respond to the events as desired. And if their app doesn't need these events, they can avoid the extra DB Query that the pivot introduces.

And, if they wanted to Observe against fewer events, they could extend and then override the provided Observer, adjusting whatever they need.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants