1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2025-12-12 09:54:03 +00:00

phpstan, global_cache, resolver improvements, InitializationHelpers trait

This commit is contained in:
Samuel Štancl 2022-09-29 02:47:13 +02:00
parent fd65cf1754
commit 87212e5390
35 changed files with 170 additions and 231 deletions

View file

@ -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

View file

@ -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', [

View file

@ -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();

View file

@ -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;
} }
} }

View file

@ -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',

View file

@ -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';
} }
} }

View file

@ -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'));

View file

@ -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;
} }
} }

View file

@ -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()

View file

@ -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')];
} }
} }

View file

@ -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;
} }

View file

@ -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
{ {

View 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();
}
}

View file

@ -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';

View file

@ -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;
}
} }

View file

@ -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)
{ {

View file

@ -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,

View file

@ -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);

View file

@ -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();

View file

@ -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));

View file

@ -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());

View file

@ -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 () {

View file

@ -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');

View file

@ -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
{ {
} }

View file

@ -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]);
} }

View file

@ -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()],
]; ];
} }
} }

View file

@ -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()],
]; ];
} }
} }

View file

@ -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();
} }

View file

@ -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')) {

View file

@ -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()

View file

@ -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;

View file

@ -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
});

View file

@ -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()

View file

@ -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();

View file

@ -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()