mirror of
https://github.com/archtechx/tenancy.git
synced 2026-02-05 11:44:04 +00:00
Improve RLS policy creation command
This commit is contained in:
parent
9f166a59a4
commit
cb775a9fba
1 changed files with 17 additions and 16 deletions
|
|
@ -10,33 +10,36 @@ use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
use Stancl\Tenancy\Database\Concerns\BelongsToPrimaryModel;
|
use Stancl\Tenancy\Database\Concerns\BelongsToPrimaryModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and uses RLS policies for tables related to a tenant directly, or through a parent primary model's table.
|
||||||
|
*
|
||||||
|
* This command is used with Postgres + single-database tenancy.
|
||||||
|
*/
|
||||||
class CreateRLSPoliciesForTenantTables extends Command
|
class CreateRLSPoliciesForTenantTables extends Command
|
||||||
{
|
{
|
||||||
protected $signature = 'tenants:create-rls-policies';
|
protected $signature = 'tenants:create-rls-policies';
|
||||||
|
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
foreach ($this->rlsModels() as $model) {
|
foreach ($this->getModels() as $model) {
|
||||||
DB::transaction(fn () => $this->makeModelUseRls($model));
|
DB::transaction(fn () => $this->useRlsOnModel($model));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Command::SUCCESS;
|
return Command::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function rlsModels(): array
|
protected function getModels(): array
|
||||||
{
|
{
|
||||||
tenancy()->initialize($tenant = tenancy()->model()::create());
|
$tables = array_map(fn ($table) => $table->tablename, Schema::getAllTables());
|
||||||
|
$models = array_map(fn (string $table) => $this->getModelFromTable($table), $tables);
|
||||||
|
|
||||||
$rlsTables = array_map(fn ($table) => $table->tablename, Schema::getAllTables());
|
return array_filter($models);
|
||||||
|
|
||||||
tenancy()->end();
|
|
||||||
|
|
||||||
$tenant->delete();
|
|
||||||
|
|
||||||
return array_filter(array_map(fn ($table) => $this->getModelFromTable($table), $rlsTables));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function makeModelUseRls(Model $model): void
|
/**
|
||||||
|
* Make model use RLS if it belongs to a tenant directly, or through a parent primary model.
|
||||||
|
*/
|
||||||
|
protected function useRlsOnModel(Model $model): void
|
||||||
{
|
{
|
||||||
$table = $model->getTable();
|
$table = $model->getTable();
|
||||||
$tenantKey = tenancy()->tenantKeyColumn();
|
$tenantKey = tenancy()->tenantKeyColumn();
|
||||||
|
|
@ -44,13 +47,11 @@ class CreateRLSPoliciesForTenantTables extends Command
|
||||||
DB::statement("DROP POLICY IF EXISTS {$table}_rls_policy ON {$table}");
|
DB::statement("DROP POLICY IF EXISTS {$table}_rls_policy ON {$table}");
|
||||||
|
|
||||||
if (! Schema::hasColumn($table, $tenantKey)) {
|
if (! Schema::hasColumn($table, $tenantKey)) {
|
||||||
// Table is not directly related to tenant
|
// Table is not directly related to a tenant
|
||||||
if (in_array(BelongsToPrimaryModel::class, class_uses_recursive($model::class))) {
|
if (in_array(BelongsToPrimaryModel::class, class_uses_recursive($model::class))) {
|
||||||
$this->makeSecondaryModelUseRls($model);
|
$this->makeSecondaryModelUseRls($model);
|
||||||
} else {
|
} else {
|
||||||
$modelName = $model::class;
|
$this->components->info("Skipping RLS policy creation – table '$table' is not related to a tenant.");
|
||||||
|
|
||||||
$this->components->info("Table '$table' is not related to tenant. Make sure $modelName uses the BelongsToPrimaryModel trait.");
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DB::statement("CREATE POLICY {$table}_rls_policy ON {$table} USING ({$tenantKey}::TEXT = current_user);");
|
DB::statement("CREATE POLICY {$table}_rls_policy ON {$table} USING ({$tenantKey}::TEXT = current_user);");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue