mirror of
https://github.com/archtechx/tenancy.git
synced 2026-02-06 13:34:05 +00:00
Merge branch 'master' into bugfix/batch-bootstrapper
This commit is contained in:
commit
d1a8b741d1
16 changed files with 268 additions and 31 deletions
42
src/Bootstrappers/Integrations/ScoutTenancyBootstrapper.php
Normal file
42
src/Bootstrappers/Integrations/ScoutTenancyBootstrapper.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Bootstrappers\Integrations;
|
||||
|
||||
use Illuminate\Contracts\Config\Repository;
|
||||
use Stancl\Tenancy\Contracts\TenancyBootstrapper;
|
||||
use Stancl\Tenancy\Contracts\Tenant;
|
||||
|
||||
class ScoutTenancyBootstrapper implements TenancyBootstrapper
|
||||
{
|
||||
/** @var Repository */
|
||||
protected $config;
|
||||
|
||||
/** @var string */
|
||||
protected $originalScoutPrefix;
|
||||
|
||||
public function __construct(Repository $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function bootstrap(Tenant $tenant)
|
||||
{
|
||||
if (! isset($this->originalScoutPrefix)) {
|
||||
$this->originalScoutPrefix = $this->config->get('scout.prefix');
|
||||
}
|
||||
|
||||
$this->config->set('scout.prefix', $this->getTenantPrefix($tenant));
|
||||
}
|
||||
|
||||
public function revert()
|
||||
{
|
||||
$this->config->set('scout.prefix', $this->originalScoutPrefix);
|
||||
}
|
||||
|
||||
protected function getTenantPrefix(Tenant $tenant): string
|
||||
{
|
||||
return (string) $tenant->getTenantKey();
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,9 @@ declare(strict_types=1);
|
|||
namespace Stancl\Tenancy\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
class Run extends Command
|
||||
{
|
||||
|
|
@ -29,12 +31,27 @@ class Run extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
tenancy()->runForMultiple($this->option('tenants'), function ($tenant) {
|
||||
$argvInput = $this->ArgvInput();
|
||||
tenancy()->runForMultiple($this->option('tenants'), function ($tenant) use ($argvInput) {
|
||||
$this->line("Tenant: {$tenant->getTenantKey()}");
|
||||
|
||||
Artisan::call($this->argument('commandname'));
|
||||
$this->comment('Command output:');
|
||||
$this->info(Artisan::output());
|
||||
$this->getLaravel()
|
||||
->make(Kernel::class)
|
||||
->handle($argvInput, new ConsoleOutput);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get command as ArgvInput instance.
|
||||
*/
|
||||
protected function ArgvInput(): ArgvInput
|
||||
{
|
||||
// Convert string command to array
|
||||
$subCommand = explode(' ', $this->argument('commandname'));
|
||||
|
||||
// Add "artisan" as first parameter because ArgvInput expects "artisan" as first parameter and later removes it
|
||||
array_unshift($subCommand, 'artisan');
|
||||
|
||||
return new ArgvInput($subCommand);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,12 @@ declare(strict_types=1);
|
|||
namespace Stancl\Tenancy\Database\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\Auth\StatefulGuard;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
use Stancl\Tenancy\Database\Concerns\CentralConnection;
|
||||
use Stancl\Tenancy\Exceptions\StatefulGuardRequiredException;
|
||||
|
||||
/**
|
||||
* @property string $token
|
||||
|
|
@ -38,9 +41,15 @@ class ImpersonationToken extends Model
|
|||
public static function booted(): void
|
||||
{
|
||||
static::creating(function ($model) {
|
||||
$authGuard = $model->auth_guard ?? config('auth.defaults.guard');
|
||||
|
||||
if (! Auth::guard($authGuard) instanceof StatefulGuard) {
|
||||
throw new StatefulGuardRequiredException($authGuard);
|
||||
}
|
||||
|
||||
$model->created_at = $model->created_at ?? $model->freshTimestamp();
|
||||
$model->token = $model->token ?? Str::random(128);
|
||||
$model->auth_guard = $model->auth_guard ?? config('auth.defaults.guard');
|
||||
$model->auth_guard = $authGuard;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
15
src/Exceptions/StatefulGuardRequiredException.php
Normal file
15
src/Exceptions/StatefulGuardRequiredException.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class StatefulGuardRequiredException extends Exception
|
||||
{
|
||||
public function __construct(string $guardName)
|
||||
{
|
||||
parent::__construct("Cannot use a non-stateful guard ('$guardName'). A guard implementing the Illuminate\\Contracts\\Auth\\StatefulGuard interface is required.");
|
||||
}
|
||||
}
|
||||
|
|
@ -14,12 +14,16 @@ class CrossDomainRedirect implements Feature
|
|||
{
|
||||
RedirectResponse::macro('domain', function (string $domain) {
|
||||
/** @var RedirectResponse $this */
|
||||
|
||||
// Replace first occurrence of the hostname fragment with $domain
|
||||
$url = $this->getTargetUrl();
|
||||
|
||||
/**
|
||||
* The original hostname in the redirect response.
|
||||
*
|
||||
* @var string $hostname
|
||||
*/
|
||||
$hostname = parse_url($url, PHP_URL_HOST);
|
||||
$position = strpos($url, $hostname);
|
||||
$this->setTargetUrl(substr_replace($url, $domain, $position, strlen($hostname)));
|
||||
|
||||
$this->setTargetUrl((string) str($url)->replace($hostname, $domain));
|
||||
|
||||
return $this;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ namespace Stancl\Tenancy\Middleware;
|
|||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Route;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Stancl\Tenancy\Events\InitializingTenancy;
|
||||
use Stancl\Tenancy\Exceptions\RouteIsMissingTenantParameterException;
|
||||
use Stancl\Tenancy\Resolvers\PathTenantResolver;
|
||||
use Stancl\Tenancy\Tenancy;
|
||||
|
|
@ -37,6 +40,11 @@ class InitializeTenancyByPath extends IdentificationMiddleware
|
|||
// We don't want to initialize tenancy if the tenant is
|
||||
// simply injected into some route controller action.
|
||||
if ($route->parameterNames()[0] === PathTenantResolver::$tenantParameterName) {
|
||||
// Set tenant as a default parameter for the URLs in the current request
|
||||
Event::listen(InitializingTenancy::class, function (InitializingTenancy $event) {
|
||||
URL::defaults([PathTenantResolver::$tenantParameterName => $event->tenancy->tenant->getTenantKey()]);
|
||||
});
|
||||
|
||||
return $this->initializeTenancy(
|
||||
$request,
|
||||
$next,
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ class Tenancy
|
|||
$tenants = is_string($tenants) ? [$tenants] : $tenants;
|
||||
|
||||
// Use all tenants if $tenants is falsey
|
||||
$tenants = $tenants ?: $this->model()->cursor();
|
||||
$tenants = $tenants ?: $this->model()->cursor(); // todo0 phpstan thinks this isn't needed, but tests fail without it
|
||||
|
||||
$originalTenant = $this->tenant;
|
||||
|
||||
|
|
|
|||
|
|
@ -58,11 +58,15 @@ if (! function_exists('global_cache')) {
|
|||
if (! function_exists('tenant_route')) {
|
||||
function tenant_route(string $domain, string $route, array $parameters = [], bool $absolute = true): string
|
||||
{
|
||||
// replace the first occurrence of the hostname fragment with $domain
|
||||
$url = route($route, $parameters, $absolute);
|
||||
$hostname = parse_url($url, PHP_URL_HOST);
|
||||
$position = strpos($url, $hostname);
|
||||
|
||||
return substr_replace($url, $domain, $position, strlen($hostname));
|
||||
/**
|
||||
* The original hostname in the generated route.
|
||||
*
|
||||
* @var string $hostname
|
||||
*/
|
||||
$hostname = parse_url($url, PHP_URL_HOST);
|
||||
|
||||
return (string) str($url)->replace($hostname, $domain);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue