1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-02-05 11:44:04 +00:00

Rework model discovery

This commit is contained in:
lukinovec 2023-06-06 15:46:50 +02:00
parent 3bfef9e2c4
commit 4175ac07bd
2 changed files with 39 additions and 11 deletions

View file

@ -5,14 +5,17 @@ declare(strict_types=1);
namespace Stancl\Tenancy; namespace Stancl\Tenancy;
use Closure; use Closure;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Traits\Macroable;
use Stancl\Tenancy\Contracts\TenancyBootstrapper;
use Stancl\Tenancy\Contracts\Tenant; use Stancl\Tenancy\Contracts\Tenant;
use Symfony\Component\Finder\Finder;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Traits\Macroable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Stancl\Tenancy\Contracts\TenancyBootstrapper;
use Stancl\Tenancy\Database\Concerns\BelongsToPrimaryModel; use Stancl\Tenancy\Database\Concerns\BelongsToPrimaryModel;
use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByIdException; use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByIdException;
use Symfony\Component\Finder\SplFileInfo;
class Tenancy class Tenancy
{ {
@ -29,6 +32,10 @@ class Tenancy
/** Is tenancy fully initialized? */ /** Is tenancy fully initialized? */
public bool $initialized = false; // todo document the difference between $tenant being set and $initialized being true (e.g. end of initialize() method) public bool $initialized = false; // todo document the difference between $tenant being set and $initialized being true (e.g. end of initialize() method)
public static array $modelDirectories = ['App/Models'];
public static Closure|null $modelDiscoveryOverride = null;
/** Initialize tenancy for the passed tenant. */ /** Initialize tenancy for the passed tenant. */
public function initialize(Tenant|int|string $tenant): void public function initialize(Tenant|int|string $tenant): void
{ {
@ -218,17 +225,35 @@ class Tenancy
return config('tenancy.identification.default_middleware', Middleware\InitializeTenancyByDomain::class); return config('tenancy.identification.default_middleware', Middleware\InitializeTenancyByDomain::class);
} }
public static function getModels(): array public static function getModels(): Collection
{ {
$tables = array_map(fn ($table) => $table->tablename, Schema::getAllTables()); if (static::$modelDiscoveryOverride) {
$models = array_map(fn (string $table) => static::getModelFromTable($table), $tables); return (static::$modelDiscoveryOverride)();
return array_filter($models);
} }
public static function getTenantModels(): array $modelFiles = Finder::create()->files()->name('*.php')->in(static::$modelDirectories)->depth('== 0');
$classes = collect($modelFiles)->map(function (SplFileInfo $file) {
$fileContents = str($file->getContents());
$class = $fileContents->after('class ')->before("\n")->explode(' ')->first();
if ($fileContents->contains('namespace ')) {
try {
return new ($fileContents->after('namespace ')->before(';')->toString() . '\\' . $class);
} catch (\Throwable $th) {
// Skip non-instantiable classes we only care about models, and those are instantiable
}
}
return null;
})->filter();
return $classes->filter(fn ($class) => in_array(Model::class, class_parents($class)));
}
public static function getTenantModels(): Collection
{ {
return array_filter(static::getModels(), fn (Model $model) => tenancy()->modelBelongsToTenant($model) || tenancy()->modelBelongsToTenantIndirectly($model)); return static::getModels()->filter(fn (Model $model) => tenancy()->modelBelongsToTenant($model) || tenancy()->modelBelongsToTenantIndirectly($model));
} }
protected static function getModelFromTable(string $table): Model|null protected static function getModelFromTable(string $table): Model|null

View file

@ -20,6 +20,7 @@ use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Stancl\Tenancy\Jobs\CreatePostgresUserForTenant; use Stancl\Tenancy\Jobs\CreatePostgresUserForTenant;
use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\Listeners\RevertToCentralContext;
use Stancl\Tenancy\Bootstrappers\Integrations\PostgresRLSBootstrapper; use Stancl\Tenancy\Bootstrappers\Integrations\PostgresRLSBootstrapper;
use Stancl\Tenancy\Tenancy;
beforeEach(function () { beforeEach(function () {
DB::purge($centralConnection = config('tenancy.database.central_connection')); DB::purge($centralConnection = config('tenancy.database.central_connection'));
@ -27,6 +28,8 @@ beforeEach(function () {
Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
Event::listen(TenancyEnded::class, RevertToCentralContext::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class);
Tenancy::$modelDirectories = [__DIR__ . '/Etc'];
// Turn RLS scoping on // Turn RLS scoping on
config(['tenancy.database.rls' => true]); config(['tenancy.database.rls' => true]);
config(['tenancy.bootstrappers' => [PostgresRLSBootstrapper::class]]); config(['tenancy.bootstrappers' => [PostgresRLSBootstrapper::class]]);