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

Finish path identification - configurability & exception handling

This commit is contained in:
Samuel Štancl 2020-05-10 20:16:08 +02:00
parent cb2bd018aa
commit 494d274798
4 changed files with 83 additions and 5 deletions

View file

@ -0,0 +1,16 @@
<?php
namespace Stancl\Tenancy\Exceptions;
use Exception;
use Stancl\Tenancy\Resolvers\PathTenantResolver;
class RouteIsMissingTenantParameterException extends Exception
{
public function __construct()
{
$parameter = PathTenantResolver::$tenantParameterName;
parent::__construct("The route's first argument is not the tenant id (configured paramter name: $parameter).");
}
}

View file

@ -5,6 +5,7 @@ namespace Stancl\Tenancy\Middleware;
use Closure; use Closure;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Routing\Route; use Illuminate\Routing\Route;
use Stancl\Tenancy\Exceptions\RouteIsMissingTenantParameterException;
use Stancl\Tenancy\Resolvers\PathTenantResolver; use Stancl\Tenancy\Resolvers\PathTenantResolver;
use Stancl\Tenancy\Tenancy; use Stancl\Tenancy\Tenancy;
@ -27,15 +28,16 @@ class InitializeTenancyByPath extends IdentificationMiddleware
/** @var Route $route */ /** @var Route $route */
$route = $request->route(); $route = $request->route();
// todo test the behavior described by the comment
// Only initialize tenancy if tenant is the first parameter // Only initialize tenancy if tenant is the first parameter
// We don't want to initialize tenancy if the tenant is // We don't want to initialize tenancy if the tenant is
// simply injected into some route controller action. // simply injected into some route controller action.
if ($route->parameterNames()[0] === 'tenant') { if ($route->parameterNames()[0] === PathTenantResolver::$tenantParameterName) {
return $this->initializeTenancy( return $this->initializeTenancy(
$request, $next, $route $request, $next, $route
); );
} // todo else case should probably throw exception about malformed route? or do we just leave that as the developer's responsibility? } else {
throw new RouteIsMissingTenantParameterException;
}
return $next($request); return $next($request);
} }

View file

@ -9,13 +9,15 @@ use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByPathException;
class PathTenantResolver implements TenantResolver class PathTenantResolver implements TenantResolver
{ {
public static $tenantParameterName = 'tenant';
public function resolve(...$args): Tenant public function resolve(...$args): Tenant
{ {
/** @var Route $route */ /** @var Route $route */
$route = $args[0]; $route = $args[0];
if ($id = $route->parameter('tenant')) { if ($id = $route->parameter(static::$tenantParameterName)) {
$route->forgetParameter('tenant'); $route->forgetParameter(static::$tenantParameterName);
if ($tenant = config('tenancy.tenant_model')::find($id)) { if ($tenant = config('tenancy.tenant_model')::find($id)) {
return $tenant; return $tenant;

View file

@ -4,8 +4,10 @@ namespace Stancl\Tenancy\Tests\v3;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use Stancl\Tenancy\Database\Models\Tenant; use Stancl\Tenancy\Database\Models\Tenant;
use Stancl\Tenancy\Exceptions\RouteIsMissingTenantParameterException;
use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByPathException; use Stancl\Tenancy\Exceptions\TenantCouldNotBeIdentifiedByPathException;
use Stancl\Tenancy\Middleware\InitializeTenancyByPath; use Stancl\Tenancy\Middleware\InitializeTenancyByPath;
use Stancl\Tenancy\Resolvers\PathTenantResolver;
use Stancl\Tenancy\Tests\TestCase; use Stancl\Tenancy\Tests\TestCase;
class PathIdentificationTest extends TestCase class PathIdentificationTest extends TestCase
@ -14,6 +16,8 @@ class PathIdentificationTest extends TestCase
{ {
parent::setUp(); parent::setUp();
PathTenantResolver::$tenantParameterName = 'tenant';
Route::group([ Route::group([
'prefix' => '/{tenant}', 'prefix' => '/{tenant}',
'middleware' => InitializeTenancyByPath::class, 'middleware' => InitializeTenancyByPath::class,
@ -79,4 +83,58 @@ class PathIdentificationTest extends TestCase
->get('/acme/foo/abc/xyz') ->get('/acme/foo/abc/xyz')
->assertContent('foo'); ->assertContent('foo');
} }
/** @test */
public function an_exception_is_thrown_when_the_routes_first_parameter_is_not_tenant()
{
Route::group([
// 'prefix' => '/{tenant}', -- intentionally commented
'middleware' => InitializeTenancyByPath::class,
], function () {
Route::get('/bar/{a}/{b}', function ($a, $b) {
return "$a + $b";
});
});
Tenant::create([
'id' => 'acme',
]);
$this->expectException(RouteIsMissingTenantParameterException::class);
$this
->withoutExceptionHandling()
->get('/bar/foo/bar');
}
/** @test */
public function tenant_parameter_name_can_be_customized()
{
PathTenantResolver::$tenantParameterName = 'team';
Route::group([
'prefix' => '/{team}',
'middleware' => InitializeTenancyByPath::class,
], function () {
Route::get('/bar/{a}/{b}', function ($a, $b) {
return "$a + $b";
});
});
Tenant::create([
'id' => 'acme',
]);
$this
->get('/acme/bar/abc/xyz')
->assertContent('abc + xyz');
// Parameter for resolver is changed, so the /{tenant}/foo route will no longer work.
$this->expectException(RouteIsMissingTenantParameterException::class);
$this
->withoutExceptionHandling()
->get('/acme/foo/abc/xyz');
}
} }