mirror of
https://github.com/archtechx/tenancy.git
synced 2025-12-12 15:34:03 +00:00
path identification wip
This commit is contained in:
parent
7ad93adde5
commit
5e6d82be57
8 changed files with 215 additions and 3 deletions
27
src/Exceptions/TenantCouldNotBeIdentifiedByPathException.php
Normal file
27
src/Exceptions/TenantCouldNotBeIdentifiedByPathException.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?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;
|
||||
|
||||
class TenantCouldNotBeIdentifiedByPathException extends TenantCouldNotBeIdentifiedException implements ProvidesSolution
|
||||
{
|
||||
public function __construct($tenant_id)
|
||||
{
|
||||
parent::__construct("Tenant could not be identified on path with tenant_id: $tenant_id");
|
||||
}
|
||||
|
||||
public function getSolution(): Solution
|
||||
{
|
||||
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/v2/creating-tenants/', // todo update link for v3
|
||||
]);
|
||||
}
|
||||
}
|
||||
41
src/Middleware/InitializeTenancyByPath.php
Normal file
41
src/Middleware/InitializeTenancyByPath.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Stancl\Tenancy\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Route;
|
||||
use Stancl\Tenancy\Resolvers\PathTenantResolver;
|
||||
use Stancl\Tenancy\Tenancy;
|
||||
|
||||
class InitializeTenancyByPath
|
||||
{
|
||||
/** @var Tenancy */
|
||||
protected $tenancy;
|
||||
|
||||
/** @var PathTenantResolver */
|
||||
protected $resolver;
|
||||
|
||||
public function __construct(Tenancy $tenancy, PathTenantResolver $resolver)
|
||||
{
|
||||
$this->tenancy = $tenancy;
|
||||
$this->resolver = $resolver;
|
||||
}
|
||||
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
/** @var Route $route */
|
||||
$route = $request->route();
|
||||
|
||||
// Only initialize tenancy if tenant is the first parameter
|
||||
// We don't want to initialize tenancy if the tenant is
|
||||
// simply injected into some route controller action.
|
||||
if ($route->parameterNames()[0] === 'tenant') {
|
||||
$this->tenancy->initialize(
|
||||
$this->resolver->resolve($route)
|
||||
);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,14 +4,13 @@ namespace Stancl\Tenancy\Resolvers;
|
|||
|
||||
use Stancl\Tenancy\Contracts\Tenant;
|
||||
use Stancl\Tenancy\Contracts\TenantResolver;
|
||||
use Stancl\Tenancy\Database\Models\Domain;
|
||||
use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedOnDomainException;
|
||||
|
||||
class DomainTenantResolver implements TenantResolver
|
||||
{
|
||||
public function resolve(...$args): Tenant
|
||||
{
|
||||
$domain = app(config('tenancy.domain_model'))->where('domain', $args[0])->first();
|
||||
$domain = config('tenancy.domain_model')::where('domain', $args[0])->first();
|
||||
|
||||
if ($domain) {
|
||||
return $domain->tenant;
|
||||
|
|
|
|||
27
src/Resolvers/PathTenantResolver.php
Normal file
27
src/Resolvers/PathTenantResolver.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Stancl\Tenancy\Resolvers;
|
||||
|
||||
use Illuminate\Routing\Route;
|
||||
use Stancl\Tenancy\Contracts\Tenant;
|
||||
use Stancl\Tenancy\Contracts\TenantResolver;
|
||||
use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByPathException;
|
||||
|
||||
class PathTenantResolver implements TenantResolver
|
||||
{
|
||||
public function resolve(...$args): Tenant
|
||||
{
|
||||
/** @var Route $route */
|
||||
$route = $args[0];
|
||||
|
||||
if ($id = $route->parameter('tenant')) {
|
||||
$route->forgetParameter('tenant');
|
||||
|
||||
if ($tenant = config('tenancy.tenant_model')::find($id)) {
|
||||
return $tenant;
|
||||
}
|
||||
}
|
||||
|
||||
throw new TenantCouldNotBeIdentifiedByPathException($id);
|
||||
}
|
||||
}
|
||||
|
|
@ -13,15 +13,22 @@ class Tenancy
|
|||
/** @var callable|null */
|
||||
public static $getBootstrappers = null;
|
||||
|
||||
/** @var bool */
|
||||
public $initialized = false;
|
||||
|
||||
public function initialize(Tenant $tenant): void
|
||||
{
|
||||
$this->tenant = $tenant;
|
||||
|
||||
$this->initialized = true;
|
||||
|
||||
event(new Events\TenancyInitialized($tenant));
|
||||
}
|
||||
|
||||
public function end(): void
|
||||
{
|
||||
$this->initialized = false;
|
||||
|
||||
event(new Events\TenancyEnded($this->tenant));
|
||||
|
||||
$this->tenant = null;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ if (! function_exists('tenant')) {
|
|||
return app(Tenant::class);
|
||||
}
|
||||
|
||||
return optional(app(Tenant::class))->get($key) ?? null;
|
||||
return optional(app(Tenant::class))->getAttribute($key) ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
111
tests/v3/PathIdentificationTest.php
Normal file
111
tests/v3/PathIdentificationTest.php
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace Stancl\Tenancy\Tests\v3;
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Stancl\Tenancy\Database\Models\Tenant;
|
||||
use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByPathException;
|
||||
use Stancl\Tenancy\Middleware\InitializeTenancyByPath;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class PathIdentificationTest extends TestCase
|
||||
{
|
||||
public function getEnvironmentSetup($app)
|
||||
{
|
||||
parent::getEnvironmentSetUp($app);
|
||||
|
||||
config(['tenancy.global_middleware' => []]);
|
||||
}
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Route::group([
|
||||
'prefix' => '/{tenant}',
|
||||
'middleware' => InitializeTenancyByPath::class,
|
||||
], function () {
|
||||
Route::get('/foo/{a}/{b}', function ($a, $b) {
|
||||
return "$a + $b";
|
||||
});
|
||||
|
||||
Route::get('/bar', [TestController::class, 'index']);
|
||||
});
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenant_can_be_identified_by_path()
|
||||
{
|
||||
Tenant::create([
|
||||
'id' => 'acme',
|
||||
]);
|
||||
|
||||
$this->assertFalse(tenancy()->initialized);
|
||||
|
||||
$this
|
||||
->get('/acme/foo/abc/xyz');
|
||||
|
||||
$this->assertTrue(tenancy()->initialized);
|
||||
$this->assertSame('acme', tenant('id'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function route_actions_dont_get_the_tenant_id()
|
||||
{
|
||||
Tenant::create([
|
||||
'id' => 'acme',
|
||||
]);
|
||||
|
||||
$this->assertFalse(tenancy()->initialized);
|
||||
|
||||
$this
|
||||
->get('/acme/foo/abc/xyz')
|
||||
->assertSee('abc + xyz');
|
||||
|
||||
$this->assertTrue(tenancy()->initialized);
|
||||
$this->assertSame('acme', tenant('id'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function exception_is_thrown_when_tenant_cannot_be_identified_by_path()
|
||||
{
|
||||
// todo the exception assertion doesn't work
|
||||
$this->expectException(TenantCouldNotBeIdentifiedByPathException::class);
|
||||
|
||||
$this->assertFalse(tenancy()->initialized);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenancy_is_initialized_prior_to_controller_constructors()
|
||||
{
|
||||
// todo same test for domain resolver
|
||||
|
||||
Tenant::create([
|
||||
'id' => 'acme',
|
||||
]);
|
||||
|
||||
$this->assertFalse(tenancy()->initialized);
|
||||
|
||||
$this
|
||||
->get('/acme/bar')
|
||||
->assertSee('foo');
|
||||
|
||||
// todo make this pass
|
||||
$this->assertTrue(app('tenancy_was_initialized_in_constructor'));
|
||||
$this->assertTrue(tenancy()->initialized);
|
||||
$this->assertSame('acme', tenant('id'));
|
||||
}
|
||||
}
|
||||
|
||||
class TestController
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
app()->instance('tenancy_was_initialized_in_constructor', tenancy()->initialized);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
return 'foo';
|
||||
}
|
||||
}
|
||||
0
tests/v3/SubdomainIdentificationTest.php
Normal file
0
tests/v3/SubdomainIdentificationTest.php
Normal file
Loading…
Add table
Add a link
Reference in a new issue