--- created: 2025-01-31 10:42 updated: 2025-07-04 07:36 --- ### Dynamic Tenancy Scoping BelongsToRelation Trait ```php trait BelongsToRelation { public static function bootBelongsToRelation(): void { if (static::belongsDirectlyToRelation()) { static::addGlobalScope(new RelationScope()); return; } static::addGlobalScope(new RelationThroughScope()); } public static function belongsDirectlyToRelation(): bool { return !static::getRelationThroughRelationship(); } abstract public static function getRelationThroughRelationship(): ?string; public function relation(): BelongsTo { return $this->belongsTo(Relation::class); } } ``` RelationScope ```php class RelationScope implements Scope { public function apply(Builder $builder, Model $model): void { if (!Bouncer::inRelationScope()) { return; } $builder->where($model->qualifyColumn('relation_id'), Bouncer::getRelationId()); if (method_exists($model, 'modifyRelationScope')) { $model->modifyRelationScope($builder); } } public function extend(Builder $builder): void { $builder->macro('withoutRelationScope', function (Builder $builder) { return $builder->withoutGlobalScope($this); }); $builder->macro('withOutsideRelationScope', function (Builder $builder, string $relations) { return $builder->with([$relations => fn($query) => $query->withoutWarehouseScope()]); }); } } ``` RelationThroughScope ```php class RelationThroughScope implements Scope { public function apply(Builder $builder, Model $model): void { if (!Bouncer::inRelationScope()) { return; } $builder->whereHas($builder->getModel()->getRelationThroughRelationship()); } public function extend(Builder $builder): void { $builder->macro('withoutRelationScope', function (Builder $builder) { return $builder->withoutGlobalScope($this); }); } } ```