Skip to content

Commit

Permalink
chore: A bit of tidying up and refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
ollieread committed Jan 27, 2025
1 parent b8d668a commit 23ba6e2
Show file tree
Hide file tree
Showing 19 changed files with 1,032 additions and 606 deletions.
3 changes: 1 addition & 2 deletions infection.json5
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,5 @@
"Sprout\\Support\\BaseFactory::callCustomCreator"
]
}
},
"testFrameworkOptions": "--testsuite=Unit,Feature"
}
}
6 changes: 3 additions & 3 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
testdox="true"
>
<testsuites>
<testsuite name="Feature">
<directory>./tests/Feature</directory>
</testsuite>
<testsuite name="Unit">
<directory>./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory>./tests/Feature</directory>
</testsuite>
</testsuites>
<source>
<include>
Expand Down
63 changes: 38 additions & 25 deletions src/Http/Resolvers/CookieIdentityResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
namespace Sprout\Http\Resolvers;

use Closure;
use Illuminate\Contracts\Encryption\Encrypter;
use Illuminate\Cookie\CookieJar;
use Illuminate\Cookie\CookieValuePrefix;
use Illuminate\Http\Request;
use Illuminate\Routing\Router;
use Illuminate\Routing\RouteRegistrar;
Expand All @@ -13,10 +15,10 @@
use Sprout\Contracts\Tenant;
use Sprout\Exceptions\CompatibilityException;
use Sprout\Http\Middleware\TenantRoutes;
use Sprout\Overrides\CookieOverride;
use Sprout\Support\BaseIdentityResolver;
use Sprout\Support\PlaceholderHelper;
use function Sprout\sprout;
use Sprout\Support\ResolutionHook;
use Sprout\TenancyOptions;

/**
* Cookie Identity Resolver
Expand Down Expand Up @@ -73,7 +75,7 @@ public function getCookieName(): string
*
* @return array<string, mixed>
*/
public function getOptions(): array
public function getCookieOptions(): array
{
return $this->options;
}
Expand Down Expand Up @@ -120,7 +122,7 @@ public function getRequestCookieName(Tenancy $tenancy): string
*/
public function resolveFromRequest(Request $request, Tenancy $tenancy): ?string
{
if (sprout()->overrides()->hasOverride('cookie')) {
if (TenancyOptions::shouldEnableOverride($tenancy, 'cookie')) {
throw CompatibilityException::make('resolver', $this->getName(), 'service override', 'cookie');
}

Expand All @@ -131,6 +133,12 @@ public function resolveFromRequest(Request $request, Tenancy $tenancy): ?string
*/
$cookie = $request->cookie($this->getRequestCookieName($tenancy));

if ($cookie !== null && $this->getSprout()->isCurrentHook(ResolutionHook::Routing)) {
// If we're processing during the routing hook, the cookies aren't
// decrypted yet, so we have to manually decrypt them
$cookie = $this->decryptCookie($this->getRequestCookieName($tenancy), $cookie);
}

return $cookie;
}

Expand Down Expand Up @@ -184,7 +192,9 @@ public function setup(Tenancy $tenancy, ?Tenant $tenant): void
]
);

app(CookieJar::class)->queue(Cookie::make(...$details));
$this->getApp()
->make(CookieJar::class)
->queue(Cookie::make(...$details));
}
}

Expand Down Expand Up @@ -227,30 +237,33 @@ private function getCookieDetails(array $details): array
}

/**
* Generate a URL for a tenanted route
*
* This method wraps Laravel's {@see \route()} helper to allow for
* identity resolvers that use route parameters.
* Route parameter names are dynamic and configurable, so hard-coding them
* is less than ideal.
*
* This method is only really useful for identity resolvers that use route
* parameters, but, it's here for backwards compatibility.
* Decrypt a cookie value
*
* @template TenantClass of \Sprout\Contracts\Tenant
*
* @param string $name
* @param \Sprout\Contracts\Tenancy<TenantClass> $tenancy
* @param \Sprout\Contracts\Tenant $tenant
* @param array<string, mixed> $parameters
* @param bool $absolute
* @param string $key
* @param string $cookie
*
* @phpstan-param TenantClass $tenant
* @return string|null
*
* @return string
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function route(string $name, Tenancy $tenancy, Tenant $tenant, array $parameters = [], bool $absolute = true): string
private function decryptCookie(string $key, string $cookie): ?string
{
return route($name, $parameters, $absolute);
// The cookie is passed as a base64 encoded JSON string
$cookieJson = base64_decode($cookie);

if (json_validate($cookieJson) === false) {
// This isn't JSON, so we can assume the original value is correct
return $cookie;
}

// Get the encrypter
$encrypter = $this->getApp()->make(Encrypter::class);

// Decrypt the actual cookie value
$value = $encrypter->decrypt($cookie, false);

// And then "validate it"? This actually strips the value, so I'm not
// sure validate is the correct name, but I didn't name it..
return CookieValuePrefix::validate($key, $value, $encrypter->getAllKeys());
}
}
28 changes: 0 additions & 28 deletions src/Http/Resolvers/HeaderIdentityResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,32 +119,4 @@ public function routes(Router $router, Closure $groupRoutes, Tenancy $tenancy):
AddTenantHeaderToResponse::class . ':' . $this->getName() . ',' . $tenancy->getName(),
])->group($groupRoutes);
}

/**
* Generate a URL for a tenanted route
*
* This method wraps Laravel's {@see \route()} helper to allow for
* identity resolvers that use route parameters.
* Route parameter names are dynamic and configurable, so hard-coding them
* is less than ideal.
*
* This method is only really useful for identity resolvers that use route
* parameters, but, it's here for backwards compatibility.
*
* @template TenantClass of \Sprout\Contracts\Tenant
*
* @param string $name
* @param \Sprout\Contracts\Tenancy<TenantClass> $tenancy
* @param \Sprout\Contracts\Tenant $tenant
* @param array<string, mixed> $parameters
* @param bool $absolute
*
* @phpstan-param TenantClass $tenant
*
* @return string
*/
public function route(string $name, Tenancy $tenancy, Tenant $tenant, array $parameters = [], bool $absolute = true): string
{
return route($name, $parameters, $absolute);
}
}
5 changes: 1 addition & 4 deletions src/Http/Resolvers/PathIdentityResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@
use Sprout\Contracts\Tenant;
use Sprout\Exceptions\TenantMissingException;
use Sprout\Http\Middleware\TenantRoutes;
use Sprout\Overrides\CookieOverride;
use Sprout\Overrides\SessionOverride;
use Sprout\Support\BaseIdentityResolver;
use Sprout\Support\Settings;
use function Sprout\settings;

/**
Expand Down Expand Up @@ -179,7 +176,7 @@ public function setup(Tenancy $tenancy, ?Tenant $tenant): void
$this->parameterSetup($tenancy, $tenant);

if ($tenant !== null) {
settings()->setUrlPath($this->getTenantRoutePrefix($tenancy));
$this->getSprout()->settings()->setUrlPath($this->getTenantRoutePrefix($tenancy));
}
}
}
33 changes: 3 additions & 30 deletions src/Http/Resolvers/SessionIdentityResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Sprout\Support\BaseIdentityResolver;
use Sprout\Support\PlaceholderHelper;
use Sprout\Support\ResolutionHook;
use Sprout\TenancyOptions;
use function Sprout\sprout;

/**
Expand Down Expand Up @@ -99,7 +100,7 @@ public function getRequestSessionName(Tenancy $tenancy): string
*/
public function resolveFromRequest(Request $request, Tenancy $tenancy): ?string
{
if (sprout()->overrides()->hasOverride('session')) {
if (TenancyOptions::shouldEnableOverride($tenancy, 'session')) {
throw CompatibilityException::make('resolver', $this->getName(), 'service override', 'session');
}

Expand Down Expand Up @@ -149,34 +150,6 @@ public function routes(Router $router, Closure $groupRoutes, Tenancy $tenancy):
*/
public function canResolve(Request $request, Tenancy $tenancy, ResolutionHook $hook): bool
{
return $request->hasSession() && $hook === ResolutionHook::Middleware;
}

/**
* Generate a URL for a tenanted route
*
* This method wraps Laravel's {@see \route()} helper to allow for
* identity resolvers that use route parameters.
* Route parameter names are dynamic and configurable, so hard-coding them
* is less than ideal.
*
* This method is only really useful for identity resolvers that use route
* parameters, but, it's here for backwards compatibility.
*
* @template TenantClass of \Sprout\Contracts\Tenant
*
* @param string $name
* @param \Sprout\Contracts\Tenancy<TenantClass> $tenancy
* @param \Sprout\Contracts\Tenant $tenant
* @param array<string, mixed> $parameters
* @param bool $absolute
*
* @phpstan-param TenantClass $tenant
*
* @return string
*/
public function route(string $name, Tenancy $tenancy, Tenant $tenant, array $parameters = [], bool $absolute = true): string
{
return route($name, $parameters, $absolute);
return ! $tenancy->wasResolved() && $request->hasSession() && $hook === ResolutionHook::Middleware;
}
}
2 changes: 1 addition & 1 deletion src/Http/Resolvers/SubdomainIdentityResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ public function setup(Tenancy $tenancy, ?Tenant $tenant): void
$this->parameterSetup($tenancy, $tenant);

if ($tenant !== null) {
settings()->setUrlDomain($this->getTenantRouteDomain($tenancy));
$this->getSprout()->settings()->setUrlDomain($this->getTenantRouteDomain($tenancy));
}
}
}
4 changes: 1 addition & 3 deletions src/Listeners/RefreshTenantAwareDependencies.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
namespace Sprout\Listeners;

use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Context;
use Sprout\Contracts\Tenancy;
use Sprout\Contracts\Tenant;
use Sprout\Events\CurrentTenantChanged;

Expand Down Expand Up @@ -41,7 +39,7 @@ public function handle(CurrentTenantChanged $event): void
{
if ($event->current !== null) {
$this->app->forgetExtenders(Tenant::class);
$this->app->extend(Tenant::class, fn(?Tenant $tenant) => $tenant);
$this->app->extend(Tenant::class, fn (?Tenant $tenant) => $tenant);
}
}
}
19 changes: 4 additions & 15 deletions src/Overrides/SessionOverride.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use Sprout\Overrides\Session\SproutFileSessionHandlerCreator;
use Sprout\Sprout;
use Sprout\Support\Settings;
use function Sprout\settings;

/**
* Session Override
Expand Down Expand Up @@ -174,26 +173,16 @@ private function refreshSessionStore(?Tenancy $tenancy = null, ?Tenant $tenant =
// We only want to touch this if the session manager has actually been
// loaded, and is therefore most likely being used
if ($this->app->resolved('session')) {
$manager = app('session');
$manager = $this->getApp()->make('session');

// If there are no loaded drivers, we can exit early
if (empty($manager->getDrivers())) {
return;
}

/** @var \Illuminate\Session\Store $driver */
$driver = $manager->driver();
$handler = $driver->getHandler();

if ($handler instanceof TenantAware) {
// If the handler is one of our tenant-aware boyos, we'll set
// the tenancy and tenant
$handler->setTenancy($tenancy)->setTenant($tenant);

// Unfortunately, we can't call 'loadSession', so we have to settle
// for start
$driver->start();
}
// We need to forget the driver, so that they can be reloaded
// with new session data
$manager->forgetDrivers();
}
}
}
18 changes: 18 additions & 0 deletions src/Sprout.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,24 @@ public function getAllCurrentTenancies(): array
return $this->tenancies;
}

/**
* Reset all the current tenancies
*
* @return static
*/
public function resetTenancies(): self
{
foreach (array_reverse($this->getAllCurrentTenancies()) as $tenancy) {
if ($tenancy->check()) {
$tenancy->setTenant(null);
}
}

$this->tenancies = [];

return $this;
}

/**
* Get the identity resolver manager
*
Expand Down
28 changes: 28 additions & 0 deletions src/Support/BaseIdentityResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,32 @@ public function canResolve(Request $request, Tenancy $tenancy, ResolutionHook $h
{
return ! $tenancy->wasResolved() && in_array($hook, $this->hooks, true);
}

/**
* Generate a URL for a tenanted route
*
* This method wraps Laravel's {@see \route()} helper to allow for
* identity resolvers that use route parameters.
* Route parameter names are dynamic and configurable, so hard-coding them
* is less than ideal.
*
* This method is only really useful for identity resolvers that use route
* parameters, but, it's here for backwards compatibility.
*
* @template TenantClass of \Sprout\Contracts\Tenant
*
* @param string $name
* @param \Sprout\Contracts\Tenancy<TenantClass> $tenancy
* @param \Sprout\Contracts\Tenant $tenant
* @param array<string, mixed> $parameters
* @param bool $absolute
*
* @phpstan-param TenantClass $tenant
*
* @return string
*/
public function route(string $name, Tenancy $tenancy, Tenant $tenant, array $parameters = [], bool $absolute = true): string
{
return route($name, $parameters, $absolute);
}
}
12 changes: 12 additions & 0 deletions src/TenancyOptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,16 @@ public static function shouldEnableAllOverrides(Tenancy $tenancy): bool
{
return $tenancy->hasOption(static::allOverrides());
}

/**
* @param \Sprout\Contracts\Tenancy<*> $tenancy
* @param string $service
*
* @return bool
*/
public static function shouldEnableOverride(Tenancy $tenancy, string $service): bool
{
return self::shouldEnableAllOverrides($tenancy)
|| in_array($service, self::enabledOverrides($tenancy) ?? [], true);
}
}
Loading

0 comments on commit 23ba6e2

Please sign in to comment.