hipsterjazzbo / Landlord

A simple, single database multi-tenancy solution for Laravel 5.2+
MIT License
614 stars 138 forks source link

Many-to-many? #58

Closed torkiljohnsen closed 7 years ago

torkiljohnsen commented 7 years ago

Could it be nice to also have a trait that supports many-to-many relation between tenant and another resource?

For instance if a have a table of features and each tenant can activate/deactivate that feature? Pivot table would hold feature_id and tenant_id for instance.

Would be nice when getting a list of features that these are automatically scoped by tenant by a trait, say BelongsToManyTenants perhaps?

… or is this better solved in some other way I have not thought of?

jpmurray commented 7 years ago

I'd really be interested in this, or knowing if it can be achieved already!

lasseeee commented 7 years ago

Since it's a pivot table the data would always be accessed through an already scoped model, so there would be no need to put tenant_id on the pivot table directly, or am I missing something?

torkiljohnsen commented 7 years ago

The features model would not be scoped, the pivot table is what defines the scope.

I would have three tables in this example:

Getting all features for a tenant would look something like this:

$features = Features::whereHas('tenant', function ($query) use ($tenantId) {
    $query->where('id', $tenantId);
})->get();

Ideally I would not want to be querying tenancy manually like this, it should work automatically.

One option which could work, would be to att a model for, and access features though, the pivot table?

tsalufe commented 7 years ago

This might work(I didn't test it). In your Feature class, add

public static function bootBelongsToTenantThroughPivot() {
          static::addGlobalScope('tenant', function (Builder $builder) {
                $builder->join('tenant_features', 'tenant_features.feature_id', '=', 'features.id')->select('features.*')->where('tenant_id', \Auth::user()->tenant_id);
           });
}

It basically use the same idea(check src/BelongsToTenants.php src/TenantManager.php) as Landlord to insert tenant_id filter for every query. Then you can call Features::get() to get features for logged in user/tenant.

hipsterjazzbo commented 7 years ago

That isn't what this package is for. This package is for preventing data that belongs to Tenant A form leaking into queries run for Tenant B.

What you're trying to do is just a basic many-to-many anyway. You don't need this package, just do this:

class Tenant extends Model
{
    public function features() {
        return $this->belongsToMany(Feature::class);
    }
}

and then:

$tenant = Tenant::find(1);

$tenant->features();
vesper8 commented 6 years ago

Not sure why I am having this problem too. My pivot table does have the trait on it. But it wasn't applying the tenant scope like the rest of my tables.

I should add that I'm doing something unconventional, I do not use the primary key (id) to make my joins. And as such my "keys" are not unique in the table, they are only unique when combined with the the tenant_id so you could say I use composite primary keys.

I was able to fix my problem by doing this

    public function posts()
    {
        return $this->belongsToMany('Post', 'post_user', 'user_id', 'post_id', 'another_id', 'another_id')
        ->where('post_user.tenant_id', \Landlord::getTenants()->first());
    }