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

Associate a single role to multi-structures #1654

Closed
andreaverrecchia opened this issue Jan 5, 2021 · 11 comments · Fixed by #1804
Closed

Associate a single role to multi-structures #1654

andreaverrecchia opened this issue Jan 5, 2021 · 11 comments · Fixed by #1804
Labels

Comments

@andreaverrecchia
Copy link

Hi,

i need to associate the user with more structures, and the user role are different for every structures.

Example:

USER A => associated to Structure N.1 with profile X,
USER A => associated to Structure N.2 with profile Y,

how can I associate the different profile for each structure?

Thanks,
Andrea.

@drbyte drbyte added the question label Jan 5, 2021
@drbyte
Copy link
Collaborator

drbyte commented Jan 5, 2021

This package implements polymorphic relations between its model-has-roles/model-has-permissions tables and your application's "user" models. Your "user" models could be any models that implement the necessary contracts and traits.

Often people equate "profiles" with Roles, where a predefined group of permissions is granted.

I'm not sure what you mean by "structure" in your case. If it's multi-tenancy, it's quite easy to associate users with their own roles/permissions within separate databases for each tenant. Slightly more complex for a single-database multitenancy setup.

What do you mean by "structure" and "profile"? Real-world examples?

@andreaverrecchia
Copy link
Author

No it's not multi-tenant. For example, by structure I mean an organization. That is, a company has multiple organizations within it. The organizations are associated with the users and therefore for each of this user it has a role with different permissions.

@drbyte
Copy link
Collaborator

drbyte commented Jan 5, 2021

How are the different organizations distinguished/separated from each other? Just an id associated with a certain table? polymorphic models? Is there a one-to-many relationship between a User and an Organization? If this exists then you can extend the package to accommodate these relationships unique to your app.

How are users identified as being in control of features related to a certain organization? Do they login to (and have access to only) one org at a time vs to another org via a certain Guard? If it's guard-based, you can define roles associated to certain guards.

@andreaverrecchia
Copy link
Author

I have an organization_user table where for each user I assign the various organizations. organizations have a unique code that identifies them. Once the user logs in, he finds a screen where he has to choose the organization with which to log in.

@drbyte
Copy link
Collaborator

drbyte commented Jan 5, 2021

Simplest would be to name your roles, and maybe permissions too, with an organization prefix (probably associate them with defined ENUMs in your application), and use those everywhere you refer to a role/permission in app code.

Or, you could add more fields to the schema and extend the package to add additional relational lookup/pairing to specific organizations.

Or, you could explore "never granting Users anything" (User model), but instead only granting "organization_users", if that's a Model in your app.

@andreaverrecchia
Copy link
Author

I cannot create a prefix for each organization as it can be hundreds. At this point I add a column in model_has_roles and model_has_permission ditto for the permissions associated directly with the user. Correct? when I call, for example, $user->hasRole('role') how can I tell him that that structure must verify it?

@drbyte
Copy link
Collaborator

drbyte commented Jan 5, 2021

This 3-way pivot you're working on is not something this package does directly. As you can see, it requires you to extend the package to add all of those additional relations and logic, specific to your chosen app implementation.

Things to consider, in no particular order:

  • I cannot create a prefix for each organization as it can be hundreds.

    That may not be much different than an organization_user pivot table with hundreds.

  • the Wildcard Permissions feature, not enabled by default, but listed in the docs, allows association of users with Eloquent models. You must still create all the permissions you would ever reference, but given you probably have an Organization model already, you might find a convenient solution with this feature. See the Apache Shiro project for examples. Link is in the docs.

  • if organization_user is associated with a Model, such as OrganizationUser then perhaps instead of adding columns to model_has_roles/permissions, you might link model_type to App/Models/OrganizationUser instead of App/Models/User. Then your app might be able to check for $orgUser->hasRole() instead of $user->hasRole().

  • If you're going with adding more fields to the tables, note that hasRole() is defined in the hasRoles trait. If you wish to extend its logic, copy the trait into your model and override it there, expanding the Eloquent query logic as needed. You will probably need to override several trait methods similarly. Ditto for permissions.

@andreaverrecchia
Copy link
Author

Ok all very clear, now I reflect on which path to take.

Thank you so much.

@andreaverrecchia
Copy link
Author

andreaverrecchia commented Jan 6, 2021

Solution

I copied and pasted in the User model the basic functions from

  1. Spatie\Permission\Traits\HasRoles
  2. Spatie\Permission\Traits\HasPermissions

and i added the ->wherePivot().

My User model:

 /**
     * Get user structure role.
     */
    public function roles(): BelongsToMany
    {
        return $this->morphToMany(
            config('permission.models.role'),
            'model',
            config('permission.table_names.model_has_roles'),
            config('permission.column_names.model_morph_key'),
            'role_id'
        )**->wherePivot('organization_id', session('user. organization_id'))**;
    }

    /**
     * Get user structure direct permissions.
     */
    public function permissions(): BelongsToMany
    {
        return $this->morphToMany(
            config('permission.models.permission'),
            'model',
            config('permission.table_names.model_has_permissions'),
            config('permission.column_names.model_morph_key'),
            'permission_id'
        )**->wherePivot('organization_id', session('user. organization_id'))**;
    }

In the permission migration i added the column $table->bigInteger('organization_id');

@spatie-bot
Copy link

Dear contributor,

because this issue seems to be inactive for quite some time now, I've automatically closed it. If you feel this issue deserves some attention from my human colleagues feel free to reopen it.

@vijendra0152
Copy link

Hi I am working with same type of functionality added company_id in modal_has_role and modal_has_permission table I override following functions in my User modal

/**
     * Get user role in company.
     */
    public function roles(): BelongsToMany
    {
        $relation = $this->morphToMany(
            config('permission.models.role'),
            'model',
            config('permission.table_names.model_has_roles'),
            config('permission.column_names.model_morph_key'),
            PermissionRegistrar::$pivotRole
        )->wherePivot('company_id', session('user.company_id'));
            
        if (! PermissionRegistrar::$teams) {
            return $relation;
        }

        return $relation->wherePivot(PermissionRegistrar::$teamsKey, getPermissionsTeamId())
            ->where(function ($q) {
                $teamField = config('permission.table_names.roles').'.'.PermissionRegistrar::$teamsKey;
                $q->whereNull($teamField)->orWhere($teamField, getPermissionsTeamId());
            });
    }

    /**
     * Get user structure direct permissions.
     */
    public function permissions(): BelongsToMany
    {
        return $this->morphToMany(
            config('permission.models.permission'),
            'model',
            config('permission.table_names.model_has_permissions'),
            config('permission.column_names.model_morph_key'),
            'permission_id'
        )->wherePivot('company_id', session('user.company_id'));
    }

It's cheking fine but not able to insert company_id which are in session how I can do it please help.

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

Successfully merging a pull request may close this issue.

4 participants