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

misc improvements - stronger types, exception refactor

This commit is contained in:
Samuel Štancl 2022-08-26 21:35:17 +02:00
parent ddc7cf49c3
commit 55d0a9ab87
34 changed files with 179 additions and 209 deletions

View file

@ -5,12 +5,6 @@ ARG PHP_VERSION=8.1
WORKDIR /var/www/html WORKDIR /var/www/html
LABEL org.opencontainers.image.source=https://github.com/stancl/tenancy \
org.opencontainers.image.vendor="Samuel Štancl" \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.title="PHP ${PHP_VERSION} with modules for laravel support" \
org.opencontainers.image.description="PHP ${PHP_VERSION} with a set of php/os packages suitable for running Laravel apps"
# our default timezone and langauge # our default timezone and langauge
ENV TZ=Europe/London ENV TZ=Europe/London
ENV LANG=en_GB.UTF-8 ENV LANG=en_GB.UTF-8

View file

@ -6,11 +6,16 @@ namespace Stancl\Tenancy\Contracts;
use Stancl\Tenancy\DatabaseConfig; use Stancl\Tenancy\DatabaseConfig;
// todo possibly move to Database namespace, along with other classes
interface ManagesDatabaseUsers extends TenantDatabaseManager interface ManagesDatabaseUsers extends TenantDatabaseManager
{ {
/** Create a database user. */
public function createUser(DatabaseConfig $databaseConfig): bool; public function createUser(DatabaseConfig $databaseConfig): bool;
/** Delete a database user. */
public function deleteUser(DatabaseConfig $databaseConfig): bool; public function deleteUser(DatabaseConfig $databaseConfig): bool;
/** Does a database user exist? */
public function userExists(string $username): bool; public function userExists(string $username): bool;
} }

View file

@ -7,6 +7,8 @@ namespace Stancl\Tenancy\Contracts;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
// todo move all resource syncing-related things to a separate namespace?
/** /**
* @property-read Tenant[]|Collection $tenants * @property-read Tenant[]|Collection $tenants
*/ */

View file

@ -4,11 +4,11 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Contracts; namespace Stancl\Tenancy\Contracts;
use Closure;
/** /**
* @see \Stancl\Tenancy\Database\Models\Tenant * @see \Stancl\Tenancy\Database\Models\Tenant
* *
* @method __call(string $method, array $parameters) IDE support. This will be a model.
* @method static __callStatic(string $method, array $parameters) IDE support. This will be a model.
* @mixin \Illuminate\Database\Eloquent\Model * @mixin \Illuminate\Database\Eloquent\Model
*/ */
interface Tenant interface Tenant
@ -17,14 +17,14 @@ interface Tenant
public function getTenantKeyName(): string; public function getTenantKeyName(): string;
/** Get the value of the key used for identifying the tenant. */ /** Get the value of the key used for identifying the tenant. */
public function getTenantKey(); public function getTenantKey(): int|string;
/** Get the value of an internal key. */ /** Get the value of an internal key. */
public function getInternal(string $key); public function getInternal(string $key): mixed;
/** Set the value of an internal key. */ /** Set the value of an internal key. */
public function setInternal(string $key, $value); public function setInternal(string $key, mixed $value): static;
/** Run a callback in this tenant's environment. */ /** Run a callback in this tenant's environment. */
public function run(callable $callback); public function run(Closure $callback): mixed;
} }

View file

@ -5,7 +5,50 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Contracts; namespace Stancl\Tenancy\Contracts;
use Exception; use Exception;
use Facade\IgnitionContracts\BaseSolution;
use Facade\IgnitionContracts\ProvidesSolution;
use Facade\IgnitionContracts\Solution;
abstract class TenantCouldNotBeIdentifiedException extends Exception abstract class TenantCouldNotBeIdentifiedException extends Exception implements ProvidesSolution
{ {
/** Default solution title. */
protected string $solutionTitle = 'Tenant could not be identified';
/** Default solution description. */
protected string $solutionDescription = 'Are you sure this tenant exists?';
/** Set the message. */
protected function tenantCouldNotBeIdentified(string $how): static
{
$this->message = "Tenant could not be identified " . $how;
return $this;
}
/** Set the solution title. */
protected function title(string $solutionTitle): static
{
$this->solutionTitle = $solutionTitle;
return $this;
}
/** Set the solution description. */
protected function description(string $solutionDescription): static
{
$this->solutionDescription = $solutionDescription;
return $this;
}
/** Get the Ignition description. */
public function getSolution(): Solution
{
return BaseSolution::create($this->solutionTitle)
->setSolutionDescription($this->solutionDescription)
->setDocumentationLinks([
'Tenants' => 'https://tenancyforlaravel.com/docs/v3/tenants',
'Tenant Identification' => 'https://tenancyforlaravel.com/docs/v3/tenant-identification',
]);
}
} }

View file

@ -8,24 +8,16 @@ use Stancl\Tenancy\Exceptions\NoConnectionSetException;
interface TenantDatabaseManager interface TenantDatabaseManager
{ {
/** /** Create a database. */
* Create a database.
*/
public function createDatabase(TenantWithDatabase $tenant): bool; public function createDatabase(TenantWithDatabase $tenant): bool;
/** /** Delete a database. */
* Delete a database.
*/
public function deleteDatabase(TenantWithDatabase $tenant): bool; public function deleteDatabase(TenantWithDatabase $tenant): bool;
/** /** Does a database exist? */
* Does a database exist.
*/
public function databaseExists(string $name): bool; public function databaseExists(string $name): bool;
/** /** Construct a DB connection config array. */
* Make a DB connection config array.
*/
public function makeConnectionConfig(array $baseConfig, string $databaseName): array; public function makeConnectionConfig(array $baseConfig, string $databaseName): array;
/** /**

View file

@ -11,5 +11,5 @@ interface TenantWithDatabase extends Tenant
public function database(): DatabaseConfig; public function database(): DatabaseConfig;
/** Get an internal key. */ /** Get an internal key. */
public function getInternal(string $key); public function getInternal(string $key): mixed;
} }

View file

@ -6,26 +6,20 @@ namespace Stancl\Tenancy\Database\Concerns;
trait HasInternalKeys trait HasInternalKeys
{ {
/** /** Get the internal prefix. */
* Get the internal prefix.
*/
public static function internalPrefix(): string public static function internalPrefix(): string
{ {
return 'tenancy_'; return 'tenancy_';
} }
/** /** Get an internal key. */
* Get an internal key. public function getInternal(string $key): mixed
*/
public function getInternal(string $key)
{ {
return $this->getAttribute(static::internalPrefix() . $key); return $this->getAttribute(static::internalPrefix() . $key);
} }
/** /** Set internal key. */
* Set internal key. public function setInternal(string $key, mixed $value): static
*/
public function setInternal(string $key, $value)
{ {
$this->setAttribute(static::internalPrefix() . $key, $value); $this->setAttribute(static::internalPrefix() . $key, $value);

View file

@ -4,15 +4,17 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Database\Concerns; namespace Stancl\Tenancy\Database\Concerns;
use Closure;
use Stancl\Tenancy\Contracts\Tenant; use Stancl\Tenancy\Contracts\Tenant;
trait TenantRun trait TenantRun
{ {
/** /**
* Run a callback in this tenant's context. * Run a callback in this tenant's context.
* Atomic, safely reverts to previous context. *
* This method is atomic and safely reverts to the previous context.
*/ */
public function run(callable $callback) public function run(Closure $callback): mixed
{ {
/** @var Tenant $this */ /** @var Tenant $this */
$originalTenant = tenant(); $originalTenant = tenant();

View file

@ -14,6 +14,8 @@ use Stancl\Tenancy\Exceptions\DatabaseManagerNotRegisteredException;
use Stancl\Tenancy\Exceptions\TenantDatabaseAlreadyExistsException; use Stancl\Tenancy\Exceptions\TenantDatabaseAlreadyExistsException;
use Stancl\Tenancy\Exceptions\TenantDatabaseUserAlreadyExistsException; use Stancl\Tenancy\Exceptions\TenantDatabaseUserAlreadyExistsException;
// todo move to Database namespace
/** /**
* @internal Class is subject to breaking changes in minor and patch versions. * @internal Class is subject to breaking changes in minor and patch versions.
*/ */

View file

@ -35,10 +35,8 @@ class ImpersonationToken extends Model
'created_at', 'created_at',
]; ];
public static function boot() public static function booted()
{ {
parent::boot();
static::creating(function ($model) { static::creating(function ($model) {
$model->created_at = $model->created_at ?? $model->freshTimestamp(); $model->created_at = $model->created_at ?? $model->freshTimestamp();
$model->token = $model->token ?? Str::random(128); $model->token = $model->token ?? Str::random(128);

View file

@ -39,7 +39,7 @@ class Tenant extends Model implements Contracts\Tenant
return 'id'; return 'id';
} }
public function getTenantKey() public function getTenantKey(): int|string
{ {
return $this->getAttribute($this->getTenantKeyName()); return $this->getAttribute($this->getTenantKeyName());
} }

View file

@ -9,10 +9,8 @@ use Stancl\Tenancy\Contracts\Syncable;
class TenantPivot extends Pivot class TenantPivot extends Pivot
{ {
public static function boot() public static function booted()
{ {
parent::boot();
static::saved(function (self $pivot) { static::saved(function (self $pivot) {
$parent = $pivot->pivotParent; $parent = $pivot->pivotParent;

View file

@ -10,7 +10,7 @@ use Illuminate\Database\Eloquent\Scope;
class ParentModelScope implements Scope class ParentModelScope implements Scope
{ {
public function apply(Builder $builder, Model $model) public function apply(Builder $builder, Model $model): void
{ {
if (! tenancy()->initialized) { if (! tenancy()->initialized) {
return; return;

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Database; namespace Stancl\Tenancy\Database;
use Closure;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
use Stancl\Tenancy\Contracts\Tenant; use Stancl\Tenancy\Contracts\Tenant;
@ -16,7 +17,7 @@ use Stancl\Tenancy\Contracts\Tenant;
*/ */
class TenantCollection extends Collection class TenantCollection extends Collection
{ {
public function runForEach(callable $callable): self public function runForEach(Closure $callable): self
{ {
tenancy()->runForMultiple($this->items, $callable); tenancy()->runForMultiple($this->items, $callable);

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Stancl\Tenancy; namespace Stancl\Tenancy;
use Closure;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str; use Illuminate\Support\Str;
@ -48,17 +49,17 @@ class DatabaseConfig
$this->tenant = $tenant; $this->tenant = $tenant;
} }
public static function generateDatabaseNamesUsing(callable $databaseNameGenerator): void public static function generateDatabaseNamesUsing(Closure $databaseNameGenerator): void
{ {
static::$databaseNameGenerator = $databaseNameGenerator; static::$databaseNameGenerator = $databaseNameGenerator;
} }
public static function generateUsernamesUsing(callable $usernameGenerator): void public static function generateUsernamesUsing(Closure $usernameGenerator): void
{ {
static::$usernameGenerator = $usernameGenerator; static::$usernameGenerator = $usernameGenerator;
} }
public static function generatePasswordsUsing(callable $passwordGenerator): void public static function generatePasswordsUsing(Closure $passwordGenerator): void
{ {
static::$passwordGenerator = $passwordGenerator; static::$passwordGenerator = $passwordGenerator;
} }

View file

@ -1,28 +0,0 @@
<?php
declare(strict_types=1);
namespace Stancl\Tenancy\Exceptions;
use Facade\IgnitionContracts\BaseSolution;
use Facade\IgnitionContracts\ProvidesSolution;
use Facade\IgnitionContracts\Solution;
use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException;
// todo: in v4 this should be suffixed with Exception
class TenantCouldNotBeIdentifiedById extends TenantCouldNotBeIdentifiedException implements ProvidesSolution
{
public function __construct($tenant_id)
{
parent::__construct("Tenant could not be identified with tenant_id: $tenant_id");
}
public function getSolution(): Solution
{
return BaseSolution::create('Tenant could not be identified with that ID')
->setSolutionDescription('Are you sure the ID is correct and the tenant exists?')
->setDocumentationLinks([
'Initializing Tenants' => 'https://tenancyforlaravel.com/docs/v3/tenants',
]);
}
}

View file

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Stancl\Tenancy\Exceptions;
use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException;
class TenantCouldNotBeIdentifiedByIdException extends TenantCouldNotBeIdentifiedException
{
public function __construct(int|string $tenant_id)
{
$this
->tenantCouldNotBeIdentified("by tenant id: $tenant_id")
->title('Tenant could not be identified with that ID')
->description('Are you sure the ID is correct and the tenant exists?');
}
}

View file

@ -4,24 +4,15 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Exceptions; namespace Stancl\Tenancy\Exceptions;
use Facade\IgnitionContracts\BaseSolution;
use Facade\IgnitionContracts\ProvidesSolution;
use Facade\IgnitionContracts\Solution;
use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException; use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException;
class TenantCouldNotBeIdentifiedByPathException extends TenantCouldNotBeIdentifiedException implements ProvidesSolution class TenantCouldNotBeIdentifiedByPathException extends TenantCouldNotBeIdentifiedException
{ {
public function __construct($tenant_id) public function __construct(int|string $tenant_id)
{ {
parent::__construct("Tenant could not be identified on path with tenant_id: $tenant_id"); $this
} ->tenantCouldNotBeIdentified("on path with tenant id: $tenant_id")
->title('Tenant could not be identified on this path')
public function getSolution(): Solution ->description('Did you forget to create a tenant for this path?');
{
return BaseSolution::create('Tenant could not be identified on this path')
->setSolutionDescription('Did you forget to create a tenant for this path?')
->setDocumentationLinks([
'Creating Tenants' => 'https://tenancyforlaravel.com/docs/v3/tenants/',
]);
} }
} }

View file

@ -4,24 +4,15 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Exceptions; namespace Stancl\Tenancy\Exceptions;
use Facade\IgnitionContracts\BaseSolution;
use Facade\IgnitionContracts\ProvidesSolution;
use Facade\IgnitionContracts\Solution;
use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException; use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException;
class TenantCouldNotBeIdentifiedByRequestDataException extends TenantCouldNotBeIdentifiedException implements ProvidesSolution class TenantCouldNotBeIdentifiedByRequestDataException extends TenantCouldNotBeIdentifiedException
{ {
public function __construct($tenant_id) public function __construct(mixed $payload)
{ {
parent::__construct("Tenant could not be identified by request data with payload: $tenant_id"); $this
} ->tenantCouldNotBeIdentified("by request data with payload: $payload")
->title('Tenant could not be identified using this request data')
public function getSolution(): Solution ->description('Did you forget to create a tenant with this id?');
{
return BaseSolution::create('Tenant could not be identified with this request data')
->setSolutionDescription('Did you forget to create a tenant with this id?')
->setDocumentationLinks([
'Creating Tenants' => 'https://tenancyforlaravel.com/docs/v3/tenants/',
]);
} }
} }

View file

@ -4,24 +4,15 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Exceptions; namespace Stancl\Tenancy\Exceptions;
use Facade\IgnitionContracts\BaseSolution;
use Facade\IgnitionContracts\ProvidesSolution;
use Facade\IgnitionContracts\Solution;
use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException; use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException;
class TenantCouldNotBeIdentifiedOnDomainException extends TenantCouldNotBeIdentifiedException implements ProvidesSolution class TenantCouldNotBeIdentifiedOnDomainException extends TenantCouldNotBeIdentifiedException
{ {
public function __construct($domain) public function __construct(string $domain)
{ {
parent::__construct("Tenant could not be identified on domain $domain"); $this
} ->tenantCouldNotBeIdentified("on domain $domain")
->title('Tenant could not be identified on this domain')
public function getSolution(): Solution ->description('Did you forget to create a tenant for this domain?');
{
return BaseSolution::create('Tenant could not be identified on this domain')
->setSolutionDescription('Did you forget to create a tenant for this domain?')
->setDocumentationLinks([
'Creating Tenants' => 'https://tenancyforlaravel.com/docs/v3/tenants/',
]);
} }
} }

View file

@ -8,18 +8,14 @@ use Stancl\Tenancy\Contracts\TenantCannotBeCreatedException;
class TenantDatabaseAlreadyExistsException extends TenantCannotBeCreatedException class TenantDatabaseAlreadyExistsException extends TenantCannotBeCreatedException
{ {
/** @var string */ public function __construct(
protected $database; protected string $database,
) {
parent::__construct();
}
public function reason(): string public function reason(): string
{ {
return "Database {$this->database} already exists."; return "Database {$this->database} already exists.";
} }
public function __construct(string $database)
{
$this->database = $database;
parent::__construct();
}
} }

View file

@ -8,7 +8,7 @@ use Exception;
class TenantDatabaseDoesNotExistException extends Exception class TenantDatabaseDoesNotExistException extends Exception
{ {
public function __construct($database) public function __construct(string $database)
{ {
parent::__construct("Database $database does not exist."); parent::__construct("Database $database does not exist.");
} }

View file

@ -8,18 +8,14 @@ use Stancl\Tenancy\Contracts\TenantCannotBeCreatedException;
class TenantDatabaseUserAlreadyExistsException extends TenantCannotBeCreatedException class TenantDatabaseUserAlreadyExistsException extends TenantCannotBeCreatedException
{ {
/** @var string */ public function __construct(
protected $user; protected string $user,
) {
parent::__construct();
}
public function reason(): string public function reason(): string
{ {
return "Database user {$this->user} already exists."; return "Database user {$this->user} already exists.";
} }
public function __construct(string $user)
{
parent::__construct();
$this->user = $user;
}
} }

View file

@ -15,7 +15,7 @@ class CrossDomainRedirect implements Feature
RedirectResponse::macro('domain', function (string $domain) { RedirectResponse::macro('domain', function (string $domain) {
/** @var RedirectResponse $this */ /** @var RedirectResponse $this */
// replace first occurance of hostname fragment with $domain // Replace first occurrence of the hostname fragment with $domain
$url = $this->getTargetUrl(); $url = $this->getTargetUrl();
$hostname = parse_url($url, PHP_URL_HOST); $hostname = parse_url($url, PHP_URL_HOST);
$position = strpos($url, $hostname); $position = strpos($url, $hostname);

View file

@ -13,9 +13,10 @@ use Stancl\Tenancy\Tenancy;
class UniversalRoutes implements Feature class UniversalRoutes implements Feature
{ {
public static $middlewareGroup = 'universal'; public static string $middlewareGroup = 'universal';
public static $identificationMiddlewares = [ // todo docblock
public static array $identificationMiddlewares = [
Middleware\InitializeTenancyByDomain::class, Middleware\InitializeTenancyByDomain::class,
Middleware\InitializeTenancyBySubdomain::class, Middleware\InitializeTenancyBySubdomain::class,
]; ];
@ -39,7 +40,7 @@ class UniversalRoutes implements Feature
} }
} }
public static function routeHasMiddleware(Route $route, $middleware): bool public static function routeHasMiddleware(Route $route, string $middleware): bool
{ {
if (in_array($middleware, $route->middleware(), true)) { if (in_array($middleware, $route->middleware(), true)) {
return true; return true;

View file

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Features; namespace Stancl\Tenancy\Features;
use Carbon\Carbon;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Stancl\Tenancy\Contracts\Feature; use Stancl\Tenancy\Contracts\Feature;
@ -14,7 +13,8 @@ use Stancl\Tenancy\Tenancy;
class UserImpersonation implements Feature class UserImpersonation implements Feature
{ {
public static $ttl = 60; // seconds /** The lifespan of impersonation tokens (in seconds). */
public static int $ttl = 60;
public function bootstrap(Tenancy $tenancy): void public function bootstrap(Tenancy $tenancy): void
{ {
@ -28,25 +28,20 @@ class UserImpersonation implements Feature
}); });
} }
/** /** Impersonate a user and get an HTTP redirect response. */
* Impersonate a user and get an HTTP redirect response. public static function makeResponse(string|ImpersonationToken $token, int $ttl = null): RedirectResponse
*
* @param string|ImpersonationToken $token
* @param int $ttl
*/
public static function makeResponse($token, int $ttl = null): RedirectResponse
{ {
$token = $token instanceof ImpersonationToken ? $token : ImpersonationToken::findOrFail($token); $token = $token instanceof ImpersonationToken ? $token : ImpersonationToken::findOrFail($token);
$ttl ??= static::$ttl;
if (((string) $token->tenant_id) !== ((string) tenant()->getTenantKey())) { $tokenExpired = $token->created_at->diffInSeconds(now()) > $ttl;
abort(403);
}
$ttl = $ttl ?? static::$ttl; abort_if($tokenExpired, 403);
if ($token->created_at->diffInSeconds(Carbon::now()) > $ttl) { $tokenTenantId = (string) $token->tenant_id;
abort(403); $currentTenantId = (string) tenant()->getTenantKey();
}
abort_unless($tokenTenantId === $currentTenantId, 403);
Auth::guard($token->auth_guard)->loginUsingId($token->user_id); Auth::guard($token->auth_guard)->loginUsingId($token->user_id);

View file

@ -11,14 +11,11 @@ use Stancl\Tenancy\Contracts\TenantResolver;
abstract class CachedTenantResolver implements TenantResolver abstract class CachedTenantResolver implements TenantResolver
{ {
/** @var bool */ public static bool $shouldCache = false; // todo docblocks for these
public static $shouldCache = false;
/** @var int */ public static int $cacheTTL = 3600; // seconds
public static $cacheTTL = 3600; // seconds
/** @var string|null */ public static string|null $cacheStore = null; // default
public static $cacheStore = null; // default
/** @var Repository */ /** @var Repository */
protected $cache; protected $cache;

View file

@ -11,21 +11,14 @@ use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedOnDomainException;
class DomainTenantResolver extends Contracts\CachedTenantResolver class DomainTenantResolver extends Contracts\CachedTenantResolver
{ {
/** /** The model representing the domain that the tenant was identified on. */
* The model representing the domain that the tenant was identified on. public static Domain $currentDomain; // todo |null?
*
* @var Domain
*/
public static $currentDomain;
/** @var bool */ public static bool $shouldCache = false;
public static $shouldCache = false;
/** @var int */ public static int $cacheTTL = 3600; // seconds
public static $cacheTTL = 3600; // seconds
/** @var string|null */ public static string|null $cacheStore = null; // default
public static $cacheStore = null; // default
public function resolveWithoutCache(...$args): Tenant public function resolveWithoutCache(...$args): Tenant
{ {

View file

@ -10,16 +10,13 @@ use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByPathException;
class PathTenantResolver extends Contracts\CachedTenantResolver class PathTenantResolver extends Contracts\CachedTenantResolver
{ {
public static $tenantParameterName = 'tenant'; public static string $tenantParameterName = 'tenant';
/** @var bool */ public static bool $shouldCache = false;
public static $shouldCache = false;
/** @var int */ public static int $cacheTTL = 3600; // seconds
public static $cacheTTL = 3600; // seconds
/** @var string|null */ public static string|null $cacheStore = null; // default
public static $cacheStore = null; // default
public function resolveWithoutCache(...$args): Tenant public function resolveWithoutCache(...$args): Tenant
{ {

View file

@ -9,14 +9,11 @@ use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByRequestDataException;
class RequestDataTenantResolver extends Contracts\CachedTenantResolver class RequestDataTenantResolver extends Contracts\CachedTenantResolver
{ {
/** @var bool */ public static bool $shouldCache = false;
public static $shouldCache = false;
/** @var int */ public static int $cacheTTL = 3600; // seconds
public static $cacheTTL = 3600; // seconds
/** @var string|null */ public static string|null $cacheStore = null; // default
public static $cacheStore = null; // default
public function resolveWithoutCache(...$args): Tenant public function resolveWithoutCache(...$args): Tenant
{ {

View file

@ -11,7 +11,7 @@ use Illuminate\Support\Traits\Macroable;
use Stancl\Tenancy\Concerns\Debuggable; use Stancl\Tenancy\Concerns\Debuggable;
use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\Contracts\TenancyBootstrapper;
use Stancl\Tenancy\Contracts\Tenant; use Stancl\Tenancy\Contracts\Tenant;
use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedById; use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByIdException;
class Tenancy class Tenancy
{ {
@ -38,7 +38,7 @@ class Tenancy
$tenant = $this->find($tenantId); $tenant = $this->find($tenantId);
if (! $tenant) { if (! $tenant) {
throw new TenantCouldNotBeIdentifiedById($tenantId); throw new TenantCouldNotBeIdentifiedByIdException($tenantId);
} }
} }
@ -62,17 +62,17 @@ class Tenancy
public function end(): void public function end(): void
{ {
event(new Events\EndingTenancy($this));
if (! $this->initialized) { if (! $this->initialized) {
return; return;
} }
event(new Events\TenancyEnded($this)); event(new Events\EndingTenancy($this));
$this->tenant = null;
$this->initialized = false; $this->initialized = false;
$this->tenant = null; event(new Events\TenancyEnded($this));
} }
/** @return TenancyBootstrapper[] */ /** @return TenancyBootstrapper[] */
@ -131,7 +131,7 @@ class Tenancy
* *
* @param Tenant[]|\Traversable|string[]|null $tenants * @param Tenant[]|\Traversable|string[]|null $tenants
*/ */
public function runForMultiple($tenants, callable $callback): void public function runForMultiple($tenants, Closure $callback): void
{ {
// Convert null to all tenants // Convert null to all tenants
$tenants = is_null($tenants) ? $this->model()->cursor() : $tenants; $tenants = is_null($tenants) ? $this->model()->cursor() : $tenants;

View file

@ -2,6 +2,8 @@
declare(strict_types=1); declare(strict_types=1);
// todo likely move all of these classes to Database\
namespace Stancl\Tenancy\TenantDatabaseManagers; namespace Stancl\Tenancy\TenantDatabaseManagers;
use Illuminate\Database\Connection; use Illuminate\Database\Connection;
@ -12,10 +14,9 @@ use Stancl\Tenancy\Exceptions\NoConnectionSetException;
class MicrosoftSQLDatabaseManager implements TenantDatabaseManager class MicrosoftSQLDatabaseManager implements TenantDatabaseManager
{ {
/** @var string */ protected string $connection; // todo docblock, in all of these classes
protected $connection;
protected function database(): Connection protected function database(): Connection // todo consider abstracting this method & setConnection() into a base class
{ {
if ($this->connection === null) { if ($this->connection === null) {
throw new NoConnectionSetException(static::class); throw new NoConnectionSetException(static::class);
@ -33,7 +34,7 @@ class MicrosoftSQLDatabaseManager implements TenantDatabaseManager
{ {
$database = $tenant->database()->getName(); $database = $tenant->database()->getName();
$charset = $this->database()->getConfig('charset'); $charset = $this->database()->getConfig('charset');
$collation = $this->database()->getConfig('collation'); $collation = $this->database()->getConfig('collation'); // todo check why these are not used
return $this->database()->statement("CREATE DATABASE [{$database}]"); return $this->database()->statement("CREATE DATABASE [{$database}]");
} }

View file

@ -157,23 +157,25 @@ class AnotherTenant extends Model implements Contracts\Tenant
return 'id'; return 'id';
} }
public function getTenantKey() public function getTenantKey(): int|string
{ {
return $this->getAttribute('id'); return $this->getAttribute('id');
} }
public function run(callable $callback) public function run(Closure $callback): mixed
{ {
$callback(); $callback();
} }
public function getInternal(string $key) public function getInternal(string $key): mixed
{ {
return $this->$key; return $this->$key;
} }
public function setInternal(string $key, $value) public function setInternal(string $key, mixed $value): static
{ {
$this->$key = $value; $this->$key = $value;
return $this;
} }
} }