1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2025-12-12 17:44:04 +00:00

get down to 21 phpstan errors

This commit is contained in:
Samuel Štancl 2022-09-29 23:39:35 +02:00
parent a94227a19c
commit f98a901aeb
16 changed files with 85 additions and 26 deletions

View file

@ -31,6 +31,18 @@ parameters:
message: '#PHPDoc tag \@param has invalid value \(dynamic#' message: '#PHPDoc tag \@param has invalid value \(dynamic#'
paths: paths:
- src/helpers.php - src/helpers.php
-
message: '#Illuminate\\Routing\\UrlGenerator#'
paths:
- src/Bootstrappers/FilesystemTenancyBootstrapper.php
-
message: '#select\(\) expects string, Illuminate\\Database\\Query\\Expression given#'
paths:
- src/Database/TenantDatabaseManagers/PermissionControlledMySQLDatabaseManager.php
-
message: '#Trying to invoke Closure\|null but it might not be a callable#'
paths:
- src/Database/DatabaseConfig.php
checkMissingIterableValueType: false checkMissingIterableValueType: false
treatPhpDocTypesAsCertain: false treatPhpDocTypesAsCertain: false

View file

@ -120,7 +120,7 @@ class QueueTenancyBootstrapper implements TenancyBootstrapper
tenancy()->initialize($tenant); tenancy()->initialize($tenant);
} }
protected static function revertToPreviousState($event, ?Tenant &$previousTenant): void protected static function revertToPreviousState(JobProcessed|JobFailed $event, ?Tenant &$previousTenant): void
{ {
$tenantId = $event->job->payload()['tenant_id'] ?? null; $tenantId = $event->job->payload()['tenant_id'] ?? null;

View file

@ -20,7 +20,7 @@ class Down extends DownCommand
protected $description = 'Put tenants into maintenance mode.'; protected $description = 'Put tenants into maintenance mode.';
public function handle(): void public function handle(): int
{ {
// The base down command is heavily used. Instead of saving the data inside a file, // The base down command is heavily used. Instead of saving the data inside a file,
// the data is stored the tenant database, which means some Laravel features // the data is stored the tenant database, which means some Laravel features
@ -29,16 +29,18 @@ class Down extends DownCommand
$payload = $this->getDownDatabasePayload(); $payload = $this->getDownDatabasePayload();
// This runs for all tenants if no --tenants are specified // This runs for all tenants if no --tenants are specified
tenancy()->runForMultiple($this->option('tenants'), function ($tenant) use ($payload) { tenancy()->runForMultiple($this->getTenants(), function ($tenant) use ($payload) {
$this->line("Tenant: {$tenant['id']}"); $this->line("Tenant: {$tenant['id']}");
$tenant->putDownForMaintenance($payload); $tenant->putDownForMaintenance($payload);
}); });
$this->comment('Tenants are now in maintenance mode.'); $this->comment('Tenants are now in maintenance mode.');
return 0;
} }
/** Get the payload to be placed in the "down" file. */ /** Get the payload to be placed in the "down" file. */
protected function getDownDatabasePayload() protected function getDownDatabasePayload(): array
{ {
return [ return [
'except' => $this->excludedPaths(), 'except' => $this->excludedPaths(),
@ -46,7 +48,7 @@ class Down extends DownCommand
'retry' => $this->getRetryTime(), 'retry' => $this->getRetryTime(),
'refresh' => $this->option('refresh'), 'refresh' => $this->option('refresh'),
'secret' => $this->option('secret'), 'secret' => $this->option('secret'),
'status' => (int) $this->option('status', 503), 'status' => (int) ($this->option('status') ?? 503),
]; ];
} }
} }

View file

@ -49,8 +49,8 @@ class Link extends Command
{ {
CreateStorageSymlinksAction::handle( CreateStorageSymlinksAction::handle(
$tenants, $tenants,
$this->option('relative') ?? false, (bool) ($this->option('relative') ?? false),
$this->option('force') ?? false, (bool) ($this->option('force') ?? false),
); );
$this->info('The links have been created.'); $this->info('The links have been created.');

View file

@ -36,7 +36,7 @@ class Rollback extends RollbackCommand
return 1; 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 RollingBackDatabase($tenant)); event(new RollingBackDatabase($tenant));

View file

@ -6,11 +6,14 @@ namespace Stancl\Tenancy\Commands;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Kernel; use Illuminate\Contracts\Console\Kernel;
use Stancl\Tenancy\Concerns\HasATenantsOption;
use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\ConsoleOutput;
class Run extends Command class Run extends Command
{ {
use HasATenantsOption;
protected $description = 'Run a command for tenant(s)'; protected $description = 'Run a command for tenant(s)';
protected $signature = 'tenants:run {commandname : The artisan command.} protected $signature = 'tenants:run {commandname : The artisan command.}
@ -19,7 +22,8 @@ class Run extends Command
public function handle(): void public function handle(): void
{ {
$argvInput = $this->argvInput(); $argvInput = $this->argvInput();
tenancy()->runForMultiple($this->option('tenants'), function ($tenant) use ($argvInput) {
tenancy()->runForMultiple($this->getTenants(), function ($tenant) use ($argvInput) {
$this->line("Tenant: {$tenant->getTenantKey()}"); $this->line("Tenant: {$tenant->getTenantKey()}");
$this->getLaravel() $this->getLaravel()
@ -30,12 +34,15 @@ class Run extends Command
protected function argvInput(): ArgvInput protected function argvInput(): ArgvInput
{ {
/** @var string $commandname */
$commandname = $this->argument('commandname');
// Convert string command to array // Convert string command to array
$subCommand = explode(' ', $this->argument('commandname')); $subcommand = explode(' ', $commandname);
// Add "artisan" as first parameter because ArgvInput expects "artisan" as first parameter and later removes it // Add "artisan" as first parameter because ArgvInput expects "artisan" as first parameter and later removes it
array_unshift($subCommand, 'artisan'); array_unshift($subcommand, 'artisan');
return new ArgvInput($subCommand); return new ArgvInput($subcommand);
} }
} }

View file

@ -35,7 +35,7 @@ class Seed extends SeedCommand
return 1; 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 SeedingDatabase($tenant)); event(new SeedingDatabase($tenant));

View file

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Contracts; namespace Stancl\Tenancy\Contracts;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/** /**
* @property-read Tenant $tenant * @property-read Tenant $tenant
* *
@ -15,5 +17,5 @@ namespace Stancl\Tenancy\Contracts;
*/ */
interface Domain interface Domain
{ {
public function tenant(); public function tenant(): BelongsTo;
} }

View file

@ -8,6 +8,7 @@ abstract class TenantCannotBeCreatedException extends \Exception
{ {
abstract public function reason(): string; abstract public function reason(): string;
/** @var string */
protected $message; protected $message;
public function __construct() public function __construct()

View file

@ -6,6 +6,7 @@ namespace Stancl\Tenancy\Controllers;
use Closure; use Closure;
use Illuminate\Routing\Controller; use Illuminate\Routing\Controller;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Throwable; use Throwable;
class TenantAssetsController extends Controller // todo rename this to TenantAssetController & update references in docs class TenantAssetsController extends Controller // todo rename this to TenantAssetController & update references in docs
@ -17,7 +18,10 @@ class TenantAssetsController extends Controller // todo rename this to TenantAss
$this->middleware(static::$tenancyMiddleware); $this->middleware(static::$tenancyMiddleware);
} }
public function asset(string $path = null) /**
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*/
public function asset(string $path = null): BinaryFileResponse
{ {
abort_if($path === null, 404); abort_if($path === null, 404);

View file

@ -9,5 +9,15 @@ use Stancl\Tenancy\Database\DatabaseConfig;
interface TenantWithDatabase extends Tenant interface TenantWithDatabase extends Tenant
{ {
/** Get the tenant's database config. */
public function database(): DatabaseConfig; public function database(): DatabaseConfig;
/** Get the internal prefix. */
public static function internalPrefix(): string;
/** Get an internal key. */
public function getInternal(string $key): mixed;
/** Set internal key. */
public function setInternal(string $key, mixed $value): static;
} }

View file

@ -81,7 +81,7 @@ class DatabaseConfig
*/ */
public function makeCredentials(): void public function makeCredentials(): void
{ {
$this->tenant->setInternal('db_name', $this->getName() ?? (static::$databaseNameGenerator)($this->tenant)); $this->tenant->setInternal('db_name', $this->getName());
if ($this->manager() instanceof Contracts\ManagesDatabaseUsers) { if ($this->manager() instanceof Contracts\ManagesDatabaseUsers) {
$this->tenant->setInternal('db_username', $this->getUsername() ?? (static::$usernameGenerator)($this->tenant)); $this->tenant->setInternal('db_username', $this->getUsername() ?? (static::$usernameGenerator)($this->tenant));

View file

@ -18,7 +18,7 @@ class TenantConfig implements Feature
{ {
public array $originalConfig = []; public array $originalConfig = [];
/** @var array<string, string> */ /** @var array<string, string|array> */
public static array $storageToConfigMap = [ public static array $storageToConfigMap = [
// 'paypal_api_key' => 'services.paypal.api_key', // 'paypal_api_key' => 'services.paypal.api_key',
]; ];
@ -30,7 +30,10 @@ class TenantConfig implements Feature
public function bootstrap(Tenancy $tenancy): void public function bootstrap(Tenancy $tenancy): void
{ {
Event::listen(TenancyBootstrapped::class, function (TenancyBootstrapped $event) { Event::listen(TenancyBootstrapped::class, function (TenancyBootstrapped $event) {
$this->setTenantConfig($event->tenancy->tenant); /** @var Tenant $tenant */
$tenant = $event->tenancy->tenant;
$this->setTenantConfig($tenant);
}); });
Event::listen(RevertedToCentralContext::class, function () { Event::listen(RevertedToCentralContext::class, function () {
@ -40,8 +43,8 @@ class TenantConfig implements Feature
public function setTenantConfig(Tenant $tenant): void public function setTenantConfig(Tenant $tenant): void
{ {
/** @var Tenant|Model $tenant */
foreach (static::$storageToConfigMap as $storageKey => $configKey) { foreach (static::$storageToConfigMap as $storageKey => $configKey) {
/** @var Tenant&Model $tenant */
$override = Arr::get($tenant, $storageKey); $override = Arr::get($tenant, $storageKey);
if (! is_null($override)) { if (! is_null($override)) {

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Listeners; namespace Stancl\Tenancy\Listeners;
use Stancl\Tenancy\Contracts\Tenant;
use Stancl\Tenancy\Events\BootstrappingTenancy; use Stancl\Tenancy\Events\BootstrappingTenancy;
use Stancl\Tenancy\Events\TenancyBootstrapped; use Stancl\Tenancy\Events\TenancyBootstrapped;
use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Events\TenancyInitialized;
@ -15,7 +16,10 @@ class BootstrapTenancy
event(new BootstrappingTenancy($event->tenancy)); event(new BootstrappingTenancy($event->tenancy));
foreach ($event->tenancy->getBootstrappers() as $bootstrapper) { foreach ($event->tenancy->getBootstrappers() as $bootstrapper) {
$bootstrapper->bootstrap($event->tenancy->tenant); /** @var Tenant $tenant */
$tenant = $event->tenancy->tenant;
$bootstrapper->bootstrap($tenant);
} }
event(new TenancyBootstrapped($event->tenancy)); event(new TenancyBootstrapped($event->tenancy));

View file

@ -99,19 +99,30 @@ class Tenancy
{ {
$class = config('tenancy.tenant_model'); $class = config('tenancy.tenant_model');
return new $class; /** @var Tenant&Model $model */
$model = new $class;
return $model;
} }
/**
* Try to find a tenant using an ID.
*
* @return (Tenant&Model)|null
*/
public static function find(int|string $id): Tenant|null public static function find(int|string $id): Tenant|null
{ {
return static::model()->where(static::model()->getTenantKeyName(), $id)->first(); /** @var (Tenant&Model)|null */
$tenant = static::model()->where(static::model()->getTenantKeyName(), $id)->first();
return $tenant;
} }
/** /**
* Run a callback in the central context. * Run a callback in the central context.
* Atomic, safely reverts to previous context. * Atomic, safely reverts to previous context.
*/ */
public function central(Closure $callback) public function central(Closure $callback): mixed
{ {
$previousTenant = $this->tenant; $previousTenant = $this->tenant;
@ -132,7 +143,7 @@ class Tenancy
* Run a callback for multiple tenants. * Run a callback for multiple tenants.
* More performant than running $tenant->run() one by one. * More performant than running $tenant->run() one by one.
* *
* @param array<Tenant>|array<string>|\Traversable|null $tenants * @param array<Tenant>|array<string|int>|\Traversable|string|int|null $tenants
*/ */
public function runForMultiple($tenants, Closure $callback): void public function runForMultiple($tenants, Closure $callback): void
{ {
@ -155,6 +166,7 @@ class Tenancy
$tenant = $this->find($tenant); $tenant = $this->find($tenant);
} }
/** @var Tenant $tenant */
$this->initialize($tenant); $this->initialize($tenant);
$callback($tenant); $callback($tenant);
} }

View file

@ -3,6 +3,7 @@
declare(strict_types=1); declare(strict_types=1);
use Illuminate\Database\DatabaseManager; use Illuminate\Database\DatabaseManager;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Event;
@ -201,8 +202,9 @@ test('run command with array of tenants works', function () {
Artisan::call('tenants:migrate-fresh'); Artisan::call('tenants:migrate-fresh');
pest()->artisan("tenants:run --tenants=$tenantId1 --tenants=$tenantId2 'foo foo --b=bar --c=xyz'") pest()->artisan("tenants:run --tenants=$tenantId1 --tenants=$tenantId2 'foo foo --b=bar --c=xyz'")
->expectsOutput('Tenant: ' . $tenantId1) ->expectsOutputToContain('Tenant: ' . $tenantId1)
->expectsOutput('Tenant: ' . $tenantId2); ->expectsOutputToContain('Tenant: ' . $tenantId2)
->assertExitCode(0);
}); });
test('link command works', function() { test('link command works', function() {