mirror of
https://github.com/archtechx/tenancy.git
synced 2025-12-12 17:44:04 +00:00
phpstan, global_cache, resolver improvements, InitializationHelpers trait
This commit is contained in:
parent
fd65cf1754
commit
87212e5390
35 changed files with 170 additions and 231 deletions
|
|
@ -10,6 +10,7 @@ parameters:
|
||||||
|
|
||||||
universalObjectCratesClasses:
|
universalObjectCratesClasses:
|
||||||
- Illuminate\Routing\Route
|
- Illuminate\Routing\Route
|
||||||
|
- Illuminate\Database\Eloquent\Model
|
||||||
|
|
||||||
ignoreErrors:
|
ignoreErrors:
|
||||||
-
|
-
|
||||||
|
|
@ -20,6 +21,14 @@ parameters:
|
||||||
message: '#invalid type Laravel\\Telescope\\IncomingEntry#'
|
message: '#invalid type Laravel\\Telescope\\IncomingEntry#'
|
||||||
paths:
|
paths:
|
||||||
- src/Features/TelescopeTags.php
|
- src/Features/TelescopeTags.php
|
||||||
|
-
|
||||||
|
message: '#Parameter \#1 \$key of method Illuminate\\Contracts\\Cache\\Repository::put\(\) expects string#'
|
||||||
|
paths:
|
||||||
|
- src/helpers.php
|
||||||
|
-
|
||||||
|
message: '#PHPDoc tag \@param has invalid value \(dynamic#'
|
||||||
|
paths:
|
||||||
|
- src/helpers.php
|
||||||
|
|
||||||
checkMissingIterableValueType: false
|
checkMissingIterableValueType: false
|
||||||
treatPhpDocTypesAsCertain: false
|
treatPhpDocTypesAsCertain: false
|
||||||
|
|
|
||||||
|
|
@ -8,24 +8,11 @@ use Illuminate\Console\Command;
|
||||||
|
|
||||||
class Install extends Command
|
class Install extends Command
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'tenancy:install';
|
protected $signature = 'tenancy:install';
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Install stancl/tenancy.';
|
protected $description = 'Install stancl/tenancy.';
|
||||||
|
|
||||||
/**
|
public function handle(): void
|
||||||
* Execute the console command.
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
{
|
||||||
$this->comment('Installing stancl/tenancy...');
|
$this->comment('Installing stancl/tenancy...');
|
||||||
$this->callSilent('vendor:publish', [
|
$this->callSilent('vendor:publish', [
|
||||||
|
|
|
||||||
|
|
@ -15,30 +15,15 @@ class Link extends Command
|
||||||
{
|
{
|
||||||
use HasATenantsOption;
|
use HasATenantsOption;
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command signature.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'tenants:link
|
protected $signature = 'tenants:link
|
||||||
{--tenants=* : The tenant(s) to run the command for. Default: all}
|
{--tenants=* : The tenant(s) to run the command for. Default: all}
|
||||||
{--relative : Create the symbolic link using relative paths}
|
{--relative : Create the symbolic link using relative paths}
|
||||||
{--force : Recreate existing symbolic links}
|
{--force : Recreate existing symbolic links}
|
||||||
{--remove : Remove symbolic links}';
|
{--remove : Remove symbolic links}';
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Create or remove tenant symbolic links.';
|
protected $description = 'Create or remove tenant symbolic links.';
|
||||||
|
|
||||||
/**
|
public function handle(): void
|
||||||
* Execute the console command.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
{
|
||||||
$tenants = $this->getTenants();
|
$tenants = $this->getTenants();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ namespace Stancl\Tenancy\Commands;
|
||||||
use Illuminate\Contracts\Events\Dispatcher;
|
use Illuminate\Contracts\Events\Dispatcher;
|
||||||
use Illuminate\Database\Console\Migrations\MigrateCommand;
|
use Illuminate\Database\Console\Migrations\MigrateCommand;
|
||||||
use Illuminate\Database\Migrations\Migrator;
|
use Illuminate\Database\Migrations\Migrator;
|
||||||
use Stancl\Tenancy\Concerns\DealsWithMigrations;
|
|
||||||
use Stancl\Tenancy\Concerns\ExtendsLaravelCommand;
|
use Stancl\Tenancy\Concerns\ExtendsLaravelCommand;
|
||||||
use Stancl\Tenancy\Concerns\HasATenantsOption;
|
use Stancl\Tenancy\Concerns\HasATenantsOption;
|
||||||
use Stancl\Tenancy\Events\DatabaseMigrated;
|
use Stancl\Tenancy\Events\DatabaseMigrated;
|
||||||
|
|
@ -15,7 +14,7 @@ use Stancl\Tenancy\Events\MigratingDatabase;
|
||||||
|
|
||||||
class Migrate extends MigrateCommand
|
class Migrate extends MigrateCommand
|
||||||
{
|
{
|
||||||
use HasATenantsOption, DealsWithMigrations, ExtendsLaravelCommand;
|
use HasATenantsOption, ExtendsLaravelCommand;
|
||||||
|
|
||||||
protected $description = 'Run migrations for tenant(s)';
|
protected $description = 'Run migrations for tenant(s)';
|
||||||
|
|
||||||
|
|
@ -31,10 +30,7 @@ class Migrate extends MigrateCommand
|
||||||
$this->specifyParameters();
|
$this->specifyParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function handle(): int
|
||||||
* Execute the console command.
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
{
|
||||||
foreach (config('tenancy.migration_parameters') as $parameter => $value) {
|
foreach (config('tenancy.migration_parameters') as $parameter => $value) {
|
||||||
if (! $this->input->hasParameterOption($parameter)) {
|
if (! $this->input->hasParameterOption($parameter)) {
|
||||||
|
|
@ -43,10 +39,10 @@ class Migrate extends MigrateCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $this->confirmToProceed()) {
|
if (! $this->confirmToProceed()) {
|
||||||
return;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tenancy()->runForMultiple($this->option('tenants'), function ($tenant) {
|
tenancy()->runForMultiple($this->getTenants(), function ($tenant) {
|
||||||
$this->line("Tenant: {$tenant->getTenantKey()}");
|
$this->line("Tenant: {$tenant->getTenantKey()}");
|
||||||
|
|
||||||
event(new MigratingDatabase($tenant));
|
event(new MigratingDatabase($tenant));
|
||||||
|
|
@ -56,5 +52,7 @@ class Migrate extends MigrateCommand
|
||||||
|
|
||||||
event(new DatabaseMigrated($tenant));
|
event(new DatabaseMigrated($tenant));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,19 +5,13 @@ declare(strict_types=1);
|
||||||
namespace Stancl\Tenancy\Commands;
|
namespace Stancl\Tenancy\Commands;
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Stancl\Tenancy\Concerns\DealsWithMigrations;
|
|
||||||
use Stancl\Tenancy\Concerns\HasATenantsOption;
|
use Stancl\Tenancy\Concerns\HasATenantsOption;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
|
||||||
final class MigrateFresh extends Command
|
final class MigrateFresh extends Command
|
||||||
{
|
{
|
||||||
use HasATenantsOption, DealsWithMigrations;
|
use HasATenantsOption;
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Drop all tables and re-run all migrations for tenant(s)';
|
protected $description = 'Drop all tables and re-run all migrations for tenant(s)';
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
|
|
@ -29,12 +23,9 @@ final class MigrateFresh extends Command
|
||||||
$this->setName('tenants:migrate-fresh');
|
$this->setName('tenants:migrate-fresh');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function handle(): void
|
||||||
* Execute the console command.
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
{
|
||||||
tenancy()->runForMultiple($this->option('tenants'), function ($tenant) {
|
tenancy()->runForMultiple($this->getTenants(), function ($tenant) {
|
||||||
$this->info('Dropping tables.');
|
$this->info('Dropping tables.');
|
||||||
$this->call('db:wipe', array_filter([
|
$this->call('db:wipe', array_filter([
|
||||||
'--database' => 'tenant',
|
'--database' => 'tenant',
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ namespace Stancl\Tenancy\Commands;
|
||||||
|
|
||||||
use Illuminate\Database\Console\Migrations\RollbackCommand;
|
use Illuminate\Database\Console\Migrations\RollbackCommand;
|
||||||
use Illuminate\Database\Migrations\Migrator;
|
use Illuminate\Database\Migrations\Migrator;
|
||||||
use Stancl\Tenancy\Concerns\DealsWithMigrations;
|
|
||||||
use Stancl\Tenancy\Concerns\ExtendsLaravelCommand;
|
use Stancl\Tenancy\Concerns\ExtendsLaravelCommand;
|
||||||
use Stancl\Tenancy\Concerns\HasATenantsOption;
|
use Stancl\Tenancy\Concerns\HasATenantsOption;
|
||||||
use Stancl\Tenancy\Events\DatabaseRolledBack;
|
use Stancl\Tenancy\Events\DatabaseRolledBack;
|
||||||
|
|
@ -14,25 +13,10 @@ use Stancl\Tenancy\Events\RollingBackDatabase;
|
||||||
|
|
||||||
class Rollback extends RollbackCommand
|
class Rollback extends RollbackCommand
|
||||||
{
|
{
|
||||||
use HasATenantsOption, DealsWithMigrations, ExtendsLaravelCommand;
|
use HasATenantsOption, ExtendsLaravelCommand;
|
||||||
|
|
||||||
protected static function getTenantCommandName(): string
|
|
||||||
{
|
|
||||||
return 'tenants:rollback';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Rollback migrations for tenant(s).';
|
protected $description = 'Rollback migrations for tenant(s).';
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new command instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct(Migrator $migrator)
|
public function __construct(Migrator $migrator)
|
||||||
{
|
{
|
||||||
parent::__construct($migrator);
|
parent::__construct($migrator);
|
||||||
|
|
@ -40,10 +24,7 @@ class Rollback extends RollbackCommand
|
||||||
$this->specifyTenantSignature();
|
$this->specifyTenantSignature();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function handle(): int
|
||||||
* Execute the console command.
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
{
|
||||||
foreach (config('tenancy.migration_parameters') as $parameter => $value) {
|
foreach (config('tenancy.migration_parameters') as $parameter => $value) {
|
||||||
if (! $this->input->hasParameterOption($parameter)) {
|
if (! $this->input->hasParameterOption($parameter)) {
|
||||||
|
|
@ -52,7 +33,7 @@ class Rollback extends RollbackCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $this->confirmToProceed()) {
|
if (! $this->confirmToProceed()) {
|
||||||
return;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tenancy()->runForMultiple($this->option('tenants'), function ($tenant) {
|
tenancy()->runForMultiple($this->option('tenants'), function ($tenant) {
|
||||||
|
|
@ -65,5 +46,12 @@ class Rollback extends RollbackCommand
|
||||||
|
|
||||||
event(new DatabaseRolledBack($tenant));
|
event(new DatabaseRolledBack($tenant));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function getTenantCommandName(): string
|
||||||
|
{
|
||||||
|
return 'tenants:rollback';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,27 +11,14 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
||||||
|
|
||||||
class Run extends Command
|
class Run extends Command
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Run a command for tenant(s)';
|
protected $description = 'Run a command for tenant(s)';
|
||||||
|
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'tenants:run {commandname : The artisan command.}
|
protected $signature = 'tenants:run {commandname : The artisan command.}
|
||||||
{--tenants=* : The tenant(s) to run the command for. Default: all}';
|
{--tenants=* : The tenant(s) to run the command for. Default: all}';
|
||||||
|
|
||||||
/**
|
public function handle(): void
|
||||||
* Execute the console command.
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
{
|
||||||
$argvInput = $this->ArgvInput();
|
$argvInput = $this->argvInput();
|
||||||
tenancy()->runForMultiple($this->option('tenants'), function ($tenant) use ($argvInput) {
|
tenancy()->runForMultiple($this->option('tenants'), function ($tenant) use ($argvInput) {
|
||||||
$this->line("Tenant: {$tenant->getTenantKey()}");
|
$this->line("Tenant: {$tenant->getTenantKey()}");
|
||||||
|
|
||||||
|
|
@ -41,10 +28,7 @@ class Run extends Command
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function argvInput(): ArgvInput
|
||||||
* Get command as ArgvInput instance.
|
|
||||||
*/
|
|
||||||
protected function ArgvInput(): ArgvInput
|
|
||||||
{
|
{
|
||||||
// Convert string command to array
|
// Convert string command to array
|
||||||
$subCommand = explode(' ', $this->argument('commandname'));
|
$subCommand = explode(' ', $this->argument('commandname'));
|
||||||
|
|
|
||||||
|
|
@ -14,29 +14,16 @@ class Seed extends SeedCommand
|
||||||
{
|
{
|
||||||
use HasATenantsOption;
|
use HasATenantsOption;
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'Seed tenant database(s).';
|
protected $description = 'Seed tenant database(s).';
|
||||||
|
|
||||||
protected $name = 'tenants:seed';
|
protected $name = 'tenants:seed';
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new command instance.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct(ConnectionResolverInterface $resolver)
|
public function __construct(ConnectionResolverInterface $resolver)
|
||||||
{
|
{
|
||||||
parent::__construct($resolver);
|
parent::__construct($resolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function handle(): int
|
||||||
* Execute the console command.
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
{
|
||||||
foreach (config('tenancy.seeder_parameters') as $parameter => $value) {
|
foreach (config('tenancy.seeder_parameters') as $parameter => $value) {
|
||||||
if (! $this->input->hasParameterOption($parameter)) {
|
if (! $this->input->hasParameterOption($parameter)) {
|
||||||
|
|
@ -45,7 +32,7 @@ class Seed extends SeedCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $this->confirmToProceed()) {
|
if (! $this->confirmToProceed()) {
|
||||||
return;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tenancy()->runForMultiple($this->option('tenants'), function ($tenant) {
|
tenancy()->runForMultiple($this->option('tenants'), function ($tenant) {
|
||||||
|
|
@ -58,5 +45,7 @@ class Seed extends SeedCommand
|
||||||
|
|
||||||
event(new DatabaseSeeded($tenant));
|
event(new DatabaseSeeded($tenant));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,24 +9,11 @@ use Stancl\Tenancy\Contracts\Tenant;
|
||||||
|
|
||||||
class TenantList extends Command
|
class TenantList extends Command
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* The name and signature of the console command.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $signature = 'tenants:list';
|
protected $signature = 'tenants:list';
|
||||||
|
|
||||||
/**
|
|
||||||
* The console command description.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description = 'List tenants.';
|
protected $description = 'List tenants.';
|
||||||
|
|
||||||
/**
|
public function handle(): void
|
||||||
* Execute the console command.
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
{
|
||||||
$this->info('Listing all tenants.');
|
$this->info('Listing all tenants.');
|
||||||
tenancy()
|
tenancy()
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,12 @@ namespace Stancl\Tenancy\Concerns;
|
||||||
|
|
||||||
trait DealsWithMigrations
|
trait DealsWithMigrations
|
||||||
{
|
{
|
||||||
protected function getMigrationPaths()
|
protected function getMigrationPaths(): array
|
||||||
{
|
{
|
||||||
if ($this->input->hasOption('path') && $this->input->getOption('path')) {
|
if ($this->input->hasOption('path') && $this->input->getOption('path')) {
|
||||||
return parent::getMigrationPaths();
|
return parent::getMigrationPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
return database_path('migrations/tenant');
|
return [database_path('migrations/tenant')];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,12 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Stancl\Tenancy\Contracts;
|
namespace Stancl\Tenancy\Contracts;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
interface UniqueIdentifierGenerator
|
interface UniqueIdentifierGenerator
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Generate a unique identifier.
|
* Generate a unique identifier for a model.
|
||||||
*/
|
*/
|
||||||
public static function generate($resource): string;
|
public static function generate(Model $model): string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ use Stancl\Tenancy\Contracts\Domain;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property-read Domain[]|\Illuminate\Database\Eloquent\Collection $domains
|
* @property-read Domain[]|\Illuminate\Database\Eloquent\Collection $domains
|
||||||
|
* @mixin \Illuminate\Database\Eloquent\Model
|
||||||
|
* @mixin \Stancl\Tenancy\Contracts\Tenant
|
||||||
*/
|
*/
|
||||||
trait HasDomains
|
trait HasDomains
|
||||||
{
|
{
|
||||||
|
|
|
||||||
19
src/Database/Concerns/InitializationHelpers.php
Normal file
19
src/Database/Concerns/InitializationHelpers.php
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Stancl\Tenancy\Database\Concerns;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mixin \Stancl\Tenancy\Contracts\Tenant
|
||||||
|
*/
|
||||||
|
trait InitializationHelpers
|
||||||
|
{
|
||||||
|
public function enter(): void
|
||||||
|
{
|
||||||
|
tenancy()->initialize($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function leave(): void
|
||||||
|
{
|
||||||
|
tenancy()->end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,7 @@ class Tenant extends Model implements Contracts\Tenant
|
||||||
Concerns\HasDataColumn,
|
Concerns\HasDataColumn,
|
||||||
Concerns\HasInternalKeys,
|
Concerns\HasInternalKeys,
|
||||||
Concerns\TenantRun,
|
Concerns\TenantRun,
|
||||||
|
Concerns\InitializationHelpers,
|
||||||
Concerns\InvalidatesResolverCache;
|
Concerns\InvalidatesResolverCache;
|
||||||
|
|
||||||
protected $table = 'tenants';
|
protected $table = 'tenants';
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,7 @@ use Stancl\Tenancy\Tenancy;
|
||||||
|
|
||||||
abstract class TenancyEvent
|
abstract class TenancyEvent
|
||||||
{
|
{
|
||||||
/** @var Tenancy */
|
public function __construct(
|
||||||
public $tenancy;
|
public Tenancy $tenancy,
|
||||||
|
) {}
|
||||||
public function __construct(Tenancy $tenancy)
|
|
||||||
{
|
|
||||||
$this->tenancy = $tenancy;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,18 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Stancl\Tenancy\Middleware;
|
namespace Stancl\Tenancy\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException;
|
use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException;
|
||||||
use Stancl\Tenancy\Contracts\TenantResolver;
|
use Stancl\Tenancy\Contracts\TenantResolver;
|
||||||
use Stancl\Tenancy\Tenancy;
|
use Stancl\Tenancy\Tenancy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property Tenancy $tenancy
|
||||||
|
* @property TenantResolver $resolver
|
||||||
|
*/
|
||||||
abstract class IdentificationMiddleware
|
abstract class IdentificationMiddleware
|
||||||
{
|
{
|
||||||
/** @var callable */
|
public static ?Closure $onFail = null;
|
||||||
public static $onFail;
|
|
||||||
|
|
||||||
/** @var Tenancy */
|
|
||||||
protected $tenancy;
|
|
||||||
|
|
||||||
/** @var TenantResolver */
|
|
||||||
protected $resolver;
|
|
||||||
|
|
||||||
public function initializeTenancy($request, $next, ...$resolverArguments)
|
public function initializeTenancy($request, $next, ...$resolverArguments)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,32 +5,21 @@ declare(strict_types=1);
|
||||||
namespace Stancl\Tenancy\Middleware;
|
namespace Stancl\Tenancy\Middleware;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Stancl\Tenancy\Resolvers\DomainTenantResolver;
|
use Stancl\Tenancy\Resolvers\DomainTenantResolver;
|
||||||
use Stancl\Tenancy\Tenancy;
|
use Stancl\Tenancy\Tenancy;
|
||||||
|
|
||||||
class InitializeTenancyByDomain extends IdentificationMiddleware
|
class InitializeTenancyByDomain extends IdentificationMiddleware
|
||||||
{
|
{
|
||||||
/** @var callable|null */
|
public static ?Closure $onFail = null;
|
||||||
public static $onFail;
|
|
||||||
|
|
||||||
/** @var Tenancy */
|
public function __construct(
|
||||||
protected $tenancy;
|
protected Tenancy $tenancy,
|
||||||
|
protected DomainTenantResolver $resolver,
|
||||||
|
) {}
|
||||||
|
|
||||||
/** @var DomainTenantResolver */
|
/** @return \Illuminate\Http\Response|mixed */
|
||||||
protected $resolver;
|
public function handle(Request $request, Closure $next): mixed
|
||||||
|
|
||||||
public function __construct(Tenancy $tenancy, DomainTenantResolver $resolver)
|
|
||||||
{
|
|
||||||
$this->tenancy = $tenancy;
|
|
||||||
$this->resolver = $resolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle an incoming request.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
*/
|
|
||||||
public function handle($request, Closure $next)
|
|
||||||
{
|
{
|
||||||
return $this->initializeTenancy(
|
return $this->initializeTenancy(
|
||||||
$request,
|
$request,
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,13 @@ declare(strict_types=1);
|
||||||
namespace Stancl\Tenancy\Middleware;
|
namespace Stancl\Tenancy\Middleware;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class InitializeTenancyByDomainOrSubdomain
|
class InitializeTenancyByDomainOrSubdomain
|
||||||
{
|
{
|
||||||
/**
|
/** @return \Illuminate\Http\Response|mixed */
|
||||||
* Handle an incoming request.
|
public function handle(Request $request, Closure $next): mixed
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
*/
|
|
||||||
public function handle($request, Closure $next)
|
|
||||||
{
|
{
|
||||||
if ($this->isSubdomain($request->getHost())) {
|
if ($this->isSubdomain($request->getHost())) {
|
||||||
return app(InitializeTenancyBySubdomain::class)->handle($request, $next);
|
return app(InitializeTenancyBySubdomain::class)->handle($request, $next);
|
||||||
|
|
|
||||||
|
|
@ -16,22 +16,15 @@ use Stancl\Tenancy\Tenancy;
|
||||||
|
|
||||||
class InitializeTenancyByPath extends IdentificationMiddleware
|
class InitializeTenancyByPath extends IdentificationMiddleware
|
||||||
{
|
{
|
||||||
/** @var callable|null */
|
public static ?Closure $onFail = null;
|
||||||
public static $onFail;
|
|
||||||
|
|
||||||
/** @var Tenancy */
|
public function __construct(
|
||||||
protected $tenancy;
|
protected Tenancy $tenancy,
|
||||||
|
protected PathTenantResolver $resolver,
|
||||||
|
) {}
|
||||||
|
|
||||||
/** @var PathTenantResolver */
|
/** @return \Illuminate\Http\Response|mixed */
|
||||||
protected $resolver;
|
public function handle(Request $request, Closure $next): mixed
|
||||||
|
|
||||||
public function __construct(Tenancy $tenancy, PathTenantResolver $resolver)
|
|
||||||
{
|
|
||||||
$this->tenancy = $tenancy;
|
|
||||||
$this->resolver = $resolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handle(Request $request, Closure $next)
|
|
||||||
{
|
{
|
||||||
/** @var Route $route */
|
/** @var Route $route */
|
||||||
$route = $request->route();
|
$route = $request->route();
|
||||||
|
|
|
||||||
|
|
@ -11,33 +11,17 @@ use Stancl\Tenancy\Tenancy;
|
||||||
|
|
||||||
class InitializeTenancyByRequestData extends IdentificationMiddleware
|
class InitializeTenancyByRequestData extends IdentificationMiddleware
|
||||||
{
|
{
|
||||||
/** @var string|null */
|
public static string $header = 'X-Tenant';
|
||||||
public static $header = 'X-Tenant';
|
public static string $queryParameter = 'tenant';
|
||||||
|
public static ?Closure $onFail = null;
|
||||||
|
|
||||||
/** @var string|null */
|
public function __construct(
|
||||||
public static $queryParameter = 'tenant';
|
protected Tenancy $tenancy,
|
||||||
|
protected RequestDataTenantResolver $resolver,
|
||||||
|
) {}
|
||||||
|
|
||||||
/** @var callable|null */
|
/** @return \Illuminate\Http\Response|mixed */
|
||||||
public static $onFail;
|
public function handle(Request $request, Closure $next): mixed
|
||||||
|
|
||||||
/** @var Tenancy */
|
|
||||||
protected $tenancy;
|
|
||||||
|
|
||||||
/** @var TenantResolver */
|
|
||||||
protected $resolver;
|
|
||||||
|
|
||||||
public function __construct(Tenancy $tenancy, RequestDataTenantResolver $resolver)
|
|
||||||
{
|
|
||||||
$this->tenancy = $tenancy;
|
|
||||||
$this->resolver = $resolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle an incoming request.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
*/
|
|
||||||
public function handle($request, Closure $next)
|
|
||||||
{
|
{
|
||||||
if ($request->method() !== 'OPTIONS') {
|
if ($request->method() !== 'OPTIONS') {
|
||||||
return $this->initializeTenancy($request, $next, $this->getPayload($request));
|
return $this->initializeTenancy($request, $next, $this->getPayload($request));
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ namespace Stancl\Tenancy\Middleware;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Stancl\Tenancy\Exceptions\NotASubdomainException;
|
use Stancl\Tenancy\Exceptions\NotASubdomainException;
|
||||||
|
|
@ -21,15 +22,10 @@ class InitializeTenancyBySubdomain extends InitializeTenancyByDomain
|
||||||
*/
|
*/
|
||||||
public static $subdomainIndex = 0;
|
public static $subdomainIndex = 0;
|
||||||
|
|
||||||
/** @var callable|null */
|
public static ?Closure $onFail = null;
|
||||||
public static $onFail;
|
|
||||||
|
|
||||||
/**
|
/** @return Response|mixed */
|
||||||
* Handle an incoming request.
|
public function handle(Request $request, Closure $next): mixed
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
*/
|
|
||||||
public function handle($request, Closure $next)
|
|
||||||
{
|
{
|
||||||
$subdomain = $this->makeSubdomain($request->getHost());
|
$subdomain = $this->makeSubdomain($request->getHost());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,11 @@ class PreventAccessFromCentralDomains
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Set this property if you want to customize the on-fail behavior.
|
* Set this property if you want to customize the on-fail behavior.
|
||||||
*
|
|
||||||
* @var callable|null
|
|
||||||
*/
|
*/
|
||||||
public static $abortRequest;
|
public static ?Closure $abortRequest;
|
||||||
|
|
||||||
public function handle(Request $request, Closure $next)
|
/** @return \Illuminate\Http\Response|mixed */
|
||||||
|
public function handle(Request $request, Closure $next): mixed
|
||||||
{
|
{
|
||||||
if (in_array($request->getHost(), config('tenancy.central_domains'))) {
|
if (in_array($request->getHost(), config('tenancy.central_domains'))) {
|
||||||
$abortRequest = static::$abortRequest ?? function () {
|
$abortRequest = static::$abortRequest ?? function () {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,8 @@ class ScopeSessions
|
||||||
{
|
{
|
||||||
public static $tenantIdKey = '_tenant_id';
|
public static $tenantIdKey = '_tenant_id';
|
||||||
|
|
||||||
public function handle(Request $request, Closure $next)
|
/** @return \Illuminate\Http\Response|mixed */
|
||||||
|
public function handle(Request $request, Closure $next): mixed
|
||||||
{
|
{
|
||||||
if (! tenancy()->initialized) {
|
if (! tenancy()->initialized) {
|
||||||
throw new TenancyNotInitializedException('Tenancy needs to be initialized before the session scoping middleware is executed');
|
throw new TenancyNotInitializedException('Tenancy needs to be initialized before the session scoping middleware is executed');
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ abstract class CachedTenantResolver implements TenantResolver
|
||||||
|
|
||||||
abstract public function resolveWithoutCache(mixed ...$args): Tenant;
|
abstract public function resolveWithoutCache(mixed ...$args): Tenant;
|
||||||
|
|
||||||
public function resolved(Tenant $tenant, ...$args): void
|
public function resolved(Tenant $tenant, mixed ...$args): void
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ class DomainTenantResolver extends Contracts\CachedTenantResolver
|
||||||
{
|
{
|
||||||
$domain = $args[0];
|
$domain = $args[0];
|
||||||
|
|
||||||
/** @var Tenant|null $tenant */
|
|
||||||
$tenant = config('tenancy.tenant_model')::query()
|
$tenant = config('tenancy.tenant_model')::query()
|
||||||
->whereHas('domains', fn (Builder $query) => $query->where('domain', $domain))
|
->whereHas('domains', fn (Builder $query) => $query->where('domain', $domain))
|
||||||
->with('domains')
|
->with('domains')
|
||||||
|
|
@ -39,7 +38,7 @@ class DomainTenantResolver extends Contracts\CachedTenantResolver
|
||||||
throw new TenantCouldNotBeIdentifiedOnDomainException($args[0]);
|
throw new TenantCouldNotBeIdentifiedOnDomainException($args[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resolved(Tenant $tenant, ...$args): void
|
public function resolved(Tenant $tenant, mixed ...$args): void
|
||||||
{
|
{
|
||||||
$this->setCurrentDomain($tenant, $args[0]);
|
$this->setCurrentDomain($tenant, $args[0]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ class PathTenantResolver extends Contracts\CachedTenantResolver
|
||||||
/** @var Route $route */
|
/** @var Route $route */
|
||||||
$route = $args[0];
|
$route = $args[0];
|
||||||
|
|
||||||
if ($id = $route->parameter(static::$tenantParameterName)) {
|
if ($id = (string) $route->parameter(static::$tenantParameterName)) {
|
||||||
$route->forgetParameter(static::$tenantParameterName);
|
$route->forgetParameter(static::$tenantParameterName);
|
||||||
|
|
||||||
if ($tenant = tenancy()->find($id)) {
|
if ($tenant = tenancy()->find($id)) {
|
||||||
|
|
@ -37,7 +37,7 @@ class PathTenantResolver extends Contracts\CachedTenantResolver
|
||||||
public function getArgsForTenant(Tenant $tenant): array
|
public function getArgsForTenant(Tenant $tenant): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
[$tenant->id],
|
[$tenant->getTenantKey()],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class RequestDataTenantResolver extends Contracts\CachedTenantResolver
|
||||||
|
|
||||||
public function resolveWithoutCache(mixed ...$args): Tenant
|
public function resolveWithoutCache(mixed ...$args): Tenant
|
||||||
{
|
{
|
||||||
$payload = $args[0];
|
$payload = (string) $args[0];
|
||||||
|
|
||||||
if ($payload && $tenant = tenancy()->find($payload)) {
|
if ($payload && $tenant = tenancy()->find($payload)) {
|
||||||
return $tenant;
|
return $tenant;
|
||||||
|
|
@ -29,7 +29,7 @@ class RequestDataTenantResolver extends Contracts\CachedTenantResolver
|
||||||
public function getArgsForTenant(Tenant $tenant): array
|
public function getArgsForTenant(Tenant $tenant): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
[$tenant->id],
|
[$tenant->getTenantKey()],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Stancl\Tenancy;
|
namespace Stancl\Tenancy;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Ramsey\Uuid\Uuid;
|
use Ramsey\Uuid\Uuid;
|
||||||
use Stancl\Tenancy\Contracts\UniqueIdentifierGenerator;
|
use Stancl\Tenancy\Contracts\UniqueIdentifierGenerator;
|
||||||
|
|
||||||
|
|
@ -11,7 +12,7 @@ use Stancl\Tenancy\Contracts\UniqueIdentifierGenerator;
|
||||||
|
|
||||||
class UUIDGenerator implements UniqueIdentifierGenerator
|
class UUIDGenerator implements UniqueIdentifierGenerator
|
||||||
{
|
{
|
||||||
public static function generate($resource): string
|
public static function generate(Model $model): string
|
||||||
{
|
{
|
||||||
return Uuid::uuid4()->toString();
|
return Uuid::uuid4()->toString();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Stancl\Tenancy\CacheManager;
|
||||||
use Stancl\Tenancy\Contracts\Tenant;
|
use Stancl\Tenancy\Contracts\Tenant;
|
||||||
use Stancl\Tenancy\Tenancy;
|
use Stancl\Tenancy\Tenancy;
|
||||||
|
|
||||||
|
|
@ -35,6 +36,7 @@ if (! function_exists('tenant')) {
|
||||||
|
|
||||||
if (! function_exists('tenant_asset')) {
|
if (! function_exists('tenant_asset')) {
|
||||||
// todo docblock
|
// todo docblock
|
||||||
|
// todo add an option to generate paths respecting the ASSET_URL
|
||||||
function tenant_asset(string|null $asset): string
|
function tenant_asset(string|null $asset): string
|
||||||
{
|
{
|
||||||
return route('stancl.tenancy.asset', ['path' => $asset]);
|
return route('stancl.tenancy.asset', ['path' => $asset]);
|
||||||
|
|
@ -42,17 +44,43 @@ if (! function_exists('tenant_asset')) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! function_exists('global_asset')) {
|
if (! function_exists('global_asset')) {
|
||||||
function global_asset(string $asset) // todo types, also inside the globalUrl implementation
|
function global_asset(string $asset): string
|
||||||
{
|
{
|
||||||
return app('globalUrl')->asset($asset);
|
return app('globalUrl')->asset($asset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! function_exists('global_cache')) {
|
if (! function_exists('global_cache')) {
|
||||||
function global_cache()
|
/**
|
||||||
|
* Get / set the specified cache value in the global cache store.
|
||||||
|
*
|
||||||
|
* If an array is passed, we'll assume you want to put to the cache.
|
||||||
|
*
|
||||||
|
* @param dynamic key|key,default|data,expiration|null
|
||||||
|
* @return mixed|\Illuminate\Cache\CacheManager
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
function global_cache(): mixed
|
||||||
{
|
{
|
||||||
|
$arguments = func_get_args();
|
||||||
|
|
||||||
|
if (empty($arguments)) {
|
||||||
return app('globalCache');
|
return app('globalCache');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_string($arguments[0])) {
|
||||||
|
return app('globalCache')->get(...$arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($arguments[0])) {
|
||||||
|
throw new InvalidArgumentException(
|
||||||
|
'When setting a value in the cache, you must pass an array of key / value pairs.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return app('globalCache')->put(key($arguments[0]), reset($arguments[0]), $arguments[1] ?? null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! function_exists('tenant_route')) {
|
if (! function_exists('tenant_route')) {
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ test('tenant can be identified by domain', function () {
|
||||||
|
|
||||||
test('onfail logic can be customized', function () {
|
test('onfail logic can be customized', function () {
|
||||||
InitializeTenancyByDomain::$onFail = function () {
|
InitializeTenancyByDomain::$onFail = function () {
|
||||||
return 'foo';
|
return response('foo');
|
||||||
};
|
};
|
||||||
|
|
||||||
pest()
|
pest()
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ use Stancl\Tenancy\Database\Concerns\HasDatabase;
|
||||||
use Stancl\Tenancy\Database\Concerns\HasDomains;
|
use Stancl\Tenancy\Database\Concerns\HasDomains;
|
||||||
use Stancl\Tenancy\Database\Models;
|
use Stancl\Tenancy\Database\Models;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method static static create(array $attributes = [])
|
||||||
|
*/
|
||||||
class Tenant extends Models\Tenant implements TenantWithDatabase
|
class Tenant extends Models\Tenant implements TenantWithDatabase
|
||||||
{
|
{
|
||||||
use HasDatabase, HasDomains;
|
use HasDatabase, HasDomains;
|
||||||
|
|
|
||||||
|
|
@ -50,3 +50,17 @@ test('global cache manager stores data in global cache', function () {
|
||||||
expect(cache('def'))->toBe('ghi');
|
expect(cache('def'))->toBe('ghi');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('the global_cache helper supports the same syntax as the cache helper', function () {
|
||||||
|
$tenant = Tenant::create();
|
||||||
|
$tenant->enter();
|
||||||
|
|
||||||
|
expect(cache('foo'))->toBe(null); // tenant cache is empty
|
||||||
|
|
||||||
|
global_cache(['foo' => 'bar']);
|
||||||
|
expect(global_cache('foo'))->toBe('bar');
|
||||||
|
|
||||||
|
global_cache()->set('foo', 'baz');
|
||||||
|
expect(global_cache()->get('foo'))->toBe('baz');
|
||||||
|
|
||||||
|
expect(cache('foo'))->toBe(null); // tenant cache is not affected
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ test('exception is thrown when tenant cannot be identified by path', function ()
|
||||||
|
|
||||||
test('onfail logic can be customized', function () {
|
test('onfail logic can be customized', function () {
|
||||||
InitializeTenancyByPath::$onFail = function () {
|
InitializeTenancyByPath::$onFail = function () {
|
||||||
return 'foo';
|
return response('foo');
|
||||||
};
|
};
|
||||||
|
|
||||||
pest()
|
pest()
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ test('header identification works', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('query parameter identification works', function () {
|
test('query parameter identification works', function () {
|
||||||
InitializeTenancyByRequestData::$header = null;
|
|
||||||
InitializeTenancyByRequestData::$queryParameter = 'tenant';
|
InitializeTenancyByRequestData::$queryParameter = 'tenant';
|
||||||
|
|
||||||
$tenant = Tenant::create();
|
$tenant = Tenant::create();
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ test('tenant can be identified by subdomain', function () {
|
||||||
|
|
||||||
test('onfail logic can be customized', function () {
|
test('onfail logic can be customized', function () {
|
||||||
InitializeTenancyBySubdomain::$onFail = function () {
|
InitializeTenancyBySubdomain::$onFail = function () {
|
||||||
return 'foo';
|
return response('foo');
|
||||||
};
|
};
|
||||||
|
|
||||||
pest()
|
pest()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue