-
-
Notifications
You must be signed in to change notification settings - Fork 446
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
Add Many‑to‑Many Relationship Support (e.g., HasTenants trait) #1313
Comments
Did ChatGPT write this text? Despite all of those words I have no idea what you're actually trying to say. |
Yeah I was being lazy, my bad. I'm trying to do a Many users to Many tenants. Where one user could have access to many tenants instead of being tied to only one. I think I got it working, but it'd be cool to have it in the package directly as a trait. I'd be happy to open a PR. |
You still haven't said what types of mappings you're talking about. Is this referencing resource syncing? |
I'm referring to a many-to-many relationship with the tenant model in a single database. Any model (User, Post, Invoice, etc.) can be attached to one or more tenants via a single pivot table. The trait would automatically apply a global scope to filter models by the currently active tenant. Automatic Attachment: When creating a new model instance, if no tenant is specified, the trait could automatically associate it with the current tenant. This what I did: Trait: <?php
declare(strict_types=1);
namespace App\Tenancy\Traits;
use App\Tenancy\Database\TenantMorphScope;
trait HasTenants
{
/**
* The name of the pivot table used for the polymorphic relationship.
*/
public static $tenantPivotTable = 'tenantables';
/**
* The foreign key on the pivot table that references the tenant model.
*/
public static $tenantForeignKey = 'tenant_id';
/**
* The morph name used for this polymorphic relation.
*/
public static $morphName = 'tenantable';
/**
* The name of the column on the tenantables table that references the tenantable model.
*/
public static $tenantableIdColumn = 'tenantable_id';
/**
* Define a polymorphic many-to-many relationship with the Tenant model.
*
* This assumes your tenant model is set in your config at:
* config('tenancy.tenant_model')
*/
public function tenants()
{
return $this->morphToMany(
config('tenancy.tenant_model'),
static::$morphName, // The morph name used for this polymorphic relation
static::$tenantPivotTable, // The pivot table name (tenantables)
static::$tenantableIdColumn, // The local key on the pivot table (User's integer ID)
static::$tenantForeignKey, // The foreign key on the pivot table (Tenant's UUID)
);
}
/**
* Boot the trait to add a global scope and automatically attach the current tenant.
*/
public static function bootHasTenants()
{
// Add a global scope so that queries on models using this trait are
// automatically filtered to include only those associated with the current tenant.
static::addGlobalScope(new TenantMorphScope);
// When a new model is created, automatically attach the current tenant
// if tenancy is initialized and no tenant has been attached yet.
static::created(function ($model) {
if (function_exists('tenancy') && tenancy()->initialized) {
if (!$model->relationLoaded('tenants') || $model->tenants->isEmpty()) {
$model->tenants()->attach(tenant()->getTenantKey());
}
}
});
}
} Scope: <?php
declare(strict_types=1);
namespace App\Tenancy\Database;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class TenantMorphScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
// If tenancy isn't initialized, don't apply the scope
if (! function_exists('tenancy') || ! tenancy()->initialized) {
return;
}
// Filter by models that have a tenant matching the current tenant's ID
$builder->whereHas('tenants', function (Builder $query) {
$query->where('id', tenant()->getTenantKey());
});
}
public function extend(Builder $builder)
{
// Provide a convenient macro to remove this global scope
$builder->macro('withoutTenancy', function (Builder $builder) {
return $builder->withoutGlobalScope($this);
});
}
} It'd be cool if it's already built in the package. And I'd be happy to open a PR for it! |
Description
It would be great if the tenancy package provided a trait that automatically handles tenant associations for any model using a polymorphic many‑to‑many pivot table (e.g.,
tenantables
). This approach would allow developers to attach multiple tenants to a variety of models without having to maintain a dedicatedtenant_id
column on each table. The trait would:Why this should be added
User
), a polymorphic approach allows multiple models (e.g.,User
,Post
,Invoice
) to share the same pivot structure.This feature would offer a more generalized, out‑of‑the‑box approach for developers needing multi‑tenant logic on multiple models.
The text was updated successfully, but these errors were encountered: