Skip to content

Commit

Permalink
refactor: Tidy-up (#52)
Browse files Browse the repository at this point in the history
* refactor: Remove reliance on default sprout config

* feat: Add simple auth override

* chore: Add resolution helper method for parsing middleware options

* refactor: Remove resolver termination contract and update cookie resolver queueing

Remove the IdentityResolverTerminates middleware and all referencing code. Update the cookie identity resolver to queue up the cookie during the setup event.

Fixes #45

* feat: Allow for the disabling of tenant relation hydration

Fixes #37

* refactor: Move tenant-aware jobs functionality to job override

* chore: Move the context setting for the current tenant to be the first bootstrapper

* chore: Add the job override to the default config

* feat: Automatically add tenant header to response

Fixes #46

* chore: Relocate TenantChildScope class

* refactor: Collapse HasCustomCreators trait into BaseFactory class

* chore: Add docs for all classes and methods

Fixes #42

* refactor: Add better vendor-specific exceptions and replace uses

Fixes #43
  • Loading branch information
ollieread authored Oct 25, 2024
1 parent 0157640 commit 541fe49
Show file tree
Hide file tree
Showing 75 changed files with 1,682 additions and 343 deletions.
1 change: 0 additions & 1 deletion resources/config/multitenancy.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
'options' => [
TenancyOptions::hydrateTenantRelation(),
TenancyOptions::throwIfNotRelated(),
TenancyOptions::makeJobsTenantAware(),
],
],

Expand Down
10 changes: 8 additions & 2 deletions resources/config/sprout.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@
*/

'bootstrappers' => [
// Set the current tenant within the Laravel context
\Sprout\Listeners\SetCurrentTenantContext::class,
// Calls the setup method on the current identity resolver
\Sprout\Listeners\PerformIdentityResolverSetup::class,
// Performs any clean-up from the previous tenancy
\Sprout\Listeners\CleanupServiceOverrides::class,
// Sets up service overrides for the current tenancy
\Sprout\Listeners\SetupServiceOverrides::class,
// Set the current tenant within the Laravel context
\Sprout\Listeners\SetCurrentTenantContext::class,
],

/*
Expand All @@ -53,9 +53,15 @@
// This will override the storage by introducing a 'sprout' driver
// that wraps any other storage drive in a tenant resource subdirectory.
\Sprout\Overrides\StorageOverride::class,
// This will hydrate tenants when running jobs, based on the current
// context.
\Sprout\Overrides\JobOverride::class,
// This will override the cache by introducing a 'sprout' driver
// that adds a prefix to cache stores for the current tenant.
\Sprout\Overrides\CacheOverride::class,
// This is a simple override that removes all currently resolved
// guards to prevent user auth leaking.
\Sprout\Overrides\AuthOverride::class,
// This will override the cookie settings so that all created cookies
// are specific to the tenant.
\Sprout\Overrides\CookieOverride::class,
Expand Down
29 changes: 29 additions & 0 deletions src/Attributes/CurrentTenant.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,45 @@
use Sprout\Contracts\Tenant;
use Sprout\Managers\TenancyManager;

/**
* Current Tenant Attribute
*
* This is a contextual attribute that allows for the auto-injection of the
* current tenant for the default, or a given tenancy.
*
* @see https://laravel.com/docs/11.x/container#contextual-attributes
*
* @package Core
*/
#[Attribute(Attribute::TARGET_PARAMETER)]
final readonly class CurrentTenant implements ContextualAttribute
{
/**
* The tenancy to use
*
* @var string|null
*/
public ?string $tenancy;

/**
* Create a new instance
*
* @param string|null $tenancy
*/
public function __construct(?string $tenancy = null)
{
$this->tenancy = $tenancy;
}

/**
* Resolve the tenant using this attribute
*
* @param \Sprout\Attributes\CurrentTenant $tenant
* @param \Illuminate\Container\Container $container
*
* @return \Sprout\Contracts\Tenant|null
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function resolve(CurrentTenant $tenant, Container $container): ?Tenant
{
/**
Expand Down
11 changes: 11 additions & 0 deletions src/Attributes/TenantRelation.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@

use Attribute;

/**
* Tenant Relation Attribute
*
* This attribute marks a relation method within an Eloquent model as
* relating to the tenant.
*
* This is primarily used in the tenant child/descendant functionality that
* comes with Sprout.
*
* @package Database\Eloquent
*/
#[Attribute(Attribute::TARGET_METHOD)]
final class TenantRelation
{
Expand Down
81 changes: 76 additions & 5 deletions src/Concerns/FindsIdentityInRouteParameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,43 @@
use Sprout\Contracts\Tenant;

/**
* Find Identity in Route Parameter
*
* This trait provides both helper methods and default implementations for
* methods required by the {@see \Sprout\Contracts\IdentityResolverUsesParameters}
* interface.
*
* @package Resolvers
*
* @phpstan-require-implements \Sprout\Contracts\IdentityResolverUsesParameters
*/
trait FindsIdentityInRouteParameter
{

/**
* The route parameter pattern
*
* @var string|null
*/
private ?string $pattern = null;

/**
* The route parameter name
*
* @var string
*/
private string $parameter = '{tenancy}_{resolver}';

/**
* Initialise the pattern and parameter name values
*
* This method sets the value for {@see self::$pattern}, and optionally
* {@see self::$parameter} if the value isn't null.
*
* @param string|null $pattern
* @param string|null $parameter
*
* @return void
*/
protected function initialiseRouteParameter(?string $pattern = null, ?string $parameter = null): void
{
$this->setPattern($pattern);
Expand All @@ -31,11 +57,25 @@ protected function initialiseRouteParameter(?string $pattern = null, ?string $pa
}
}

/**
* Set the route parameter pattern
*
* @param string|null $pattern
*
* @return void
*/
public function setPattern(?string $pattern): void
{
$this->pattern = $pattern;
}

/**
* Set the route parameter name
*
* @param string $parameter
*
* @return void
*/
public function setParameter(string $parameter): void
{
$this->parameter = $parameter;
Expand All @@ -44,6 +84,10 @@ public function setParameter(string $parameter): void
/**
* Get the name of the route parameter
*
* This method uses the route parameter name stored in {@see self::$parameter},
* replacing occurrences of <code>{tenancy}</code> with the name of the
* tenancy, and <code>{resolver}</code> with the name of the resolver.
*
* @template TenantClass of \Sprout\Contracts\Tenant
*
* @param \Sprout\Contracts\Tenancy<TenantClass> $tenancy
Expand All @@ -60,7 +104,11 @@ public function getRouteParameterName(Tenancy $tenancy): string
}

/**
* Get the route parameter with braces
* Get the route parameter placeholder
*
* This method returns the route parameter provided by
* {@see self::getRouteParameterName()}, but wrapped with curly braces for
* use in route definitions.
*
* @param \Sprout\Contracts\Tenancy<\Sprout\Contracts\Tenant> $tenancy
*
Expand All @@ -71,12 +119,19 @@ public function getRouteParameter(Tenancy $tenancy): string
return '{' . $this->getRouteParameterName($tenancy) . '}';
}

/**
* Get the route parameter pattern
*
* @return string|null
*/
public function getPattern(): ?string
{
return $this->pattern;
}

/**
* Check if there is a route parameter pattern set
*
* @return bool
*
* @phpstan-assert-if-true string $this->getPattern()
Expand All @@ -87,19 +142,29 @@ public function hasPattern(): bool
return $this->pattern !== null;
}

/**
* Get the route parameter pattern
*
* @return string
*/
public function getParameter(): string
{
return $this->parameter;
}

/**
* Get the route parameter pattern mapping
*
* This method returns an array mappings the route parameter name to its
* pattern, for use in route definitions.
*
* @template TenantClass of \Sprout\Contracts\Tenant
*
* @param \Sprout\Contracts\Tenancy<TenantClass> $tenancy
*
* @return array<string, string>
*/
protected function getParameterPattern(Tenancy $tenancy): array
protected function getParameterPatternMapping(Tenancy $tenancy): array
{
if (! $this->hasPattern()) {
return [];
Expand All @@ -111,20 +176,26 @@ protected function getParameterPattern(Tenancy $tenancy): array
}

/**
* Apply the route parameter pattern mapping to a route
*
* This method applies the route parameter pattern mapping provided by
* {@see self::getParameterPatternMapping()} to a supplied route registrar,
* for a supplied tenancy.
*
* @template TenantClass of \Sprout\Contracts\Tenant
*
* @param \Illuminate\Routing\RouteRegistrar $registrar
* @param \Sprout\Contracts\Tenancy<TenantClass> $tenancy
*
* @return \Illuminate\Routing\RouteRegistrar
*/
protected function applyParameterPattern(RouteRegistrar $registrar, Tenancy $tenancy): RouteRegistrar
protected function applyParameterPatternMapping(RouteRegistrar $registrar, Tenancy $tenancy): RouteRegistrar
{
if ($this->hasPattern()) {
return $registrar;
}

return $registrar->where($this->getParameterPattern($tenancy));
return $registrar->where($this->getParameterPatternMapping($tenancy));
}

/**
Expand Down
34 changes: 0 additions & 34 deletions src/Concerns/HasCustomCreators.php

This file was deleted.

Loading

0 comments on commit 541fe49

Please sign in to comment.