Skip to content

Commit

Permalink
feat: Add Laravel filesystem storage custom driver to tenantise stora…
Browse files Browse the repository at this point in the history
…ge disks
  • Loading branch information
ollieread committed Sep 28, 2024
1 parent 0e91fda commit 282c205
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 0 deletions.
4 changes: 4 additions & 0 deletions resources/config/sprout.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@

'listen_for_routing' => true,

'services' => [
'storage' => true,
],

];
51 changes: 51 additions & 0 deletions src/Listeners/CleanupLaravelServices.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);

namespace Sprout\Listeners;

use Illuminate\Filesystem\FilesystemManager;
use Sprout\Events\CurrentTenantChanged;

final class CleanupLaravelServices
{
/**
* @var \Illuminate\Filesystem\FilesystemManager
*/
private FilesystemManager $filesystemManager;

public function __construct(FilesystemManager $filesystemManager)
{
$this->filesystemManager = $filesystemManager;
}

/**
* @template TenantClass of \Sprout\Contracts\Tenant
*
* @param \Sprout\Events\CurrentTenantChanged<TenantClass> $event
*
* @return void
*/
public function handle(CurrentTenantChanged $event): void
{
$this->purgeFilesystemDisks();
}

private function purgeFilesystemDisks(): void
{
// If we're not overriding the storage service we can exit early
if (config('sprout.services.storage', false) === false) {
return;

Check warning on line 37 in src/Listeners/CleanupLaravelServices.php

View check run for this annotation

Codecov / codecov/patch

src/Listeners/CleanupLaravelServices.php#L37

Added line #L37 was not covered by tests
}

/** @var array<string, array<string, mixed>> $diskConfig */
$diskConfig = config('filesystems.disks', []);

// If any of the disks have the 'sprout' driver we need to purge them,
// if they exist, so we don't end up leaking tenant information
foreach ($diskConfig as $disk => $config) {
if (($config['driver'] ?? null) === 'sprout') {
$this->filesystemManager->forgetDisk($disk);

Check warning on line 47 in src/Listeners/CleanupLaravelServices.php

View check run for this annotation

Codecov / codecov/patch

src/Listeners/CleanupLaravelServices.php#L47

Added line #L47 was not covered by tests
}
}
}
}
42 changes: 42 additions & 0 deletions src/SproutServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@
namespace Sprout;

use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Filesystem\FilesystemManager;
use Illuminate\Foundation\Application;
use Illuminate\Queue\Events\JobProcessing;
use Illuminate\Routing\Events\RouteMatched;
use Illuminate\Routing\Router;
use Illuminate\Support\ServiceProvider;
use RuntimeException;
use Sprout\Contracts\TenantHasResources;
use Sprout\Events\CurrentTenantChanged;
use Sprout\Http\Middleware\TenantRoutes;
use Sprout\Http\RouterMethods;
use Sprout\Listeners\CleanupLaravelServices;
use Sprout\Listeners\IdentifyTenantOnRouting;
use Sprout\Listeners\PerformIdentityResolverSetup;
use Sprout\Listeners\SetCurrentTenantContext;
Expand Down Expand Up @@ -86,6 +91,7 @@ public function boot(): void
{
$this->publishConfig();
$this->registerEventListeners();
$this->registerServiceOverrides();
}

private function publishConfig(): void
Expand All @@ -105,6 +111,42 @@ private function registerEventListeners(): void

$events->listen(CurrentTenantChanged::class, SetCurrentTenantContext::class);
$events->listen(CurrentTenantChanged::class, PerformIdentityResolverSetup::class);
$events->listen(CurrentTenantChanged::class, CleanupLaravelServices::class);
$events->listen(JobProcessing::class, SetCurrentTenantForJob::class);
}

private function registerServiceOverrides(): void
{
// If we're providing a tenanted override for Laravels filesystem/storage
// service, we'll do that here
if ($this->sprout->config('services.storage', false)) {
$filesystemManager = $this->app->make(FilesystemManager::class);
$filesystemManager->extend('sprout', function (Application $app, array $config) use ($filesystemManager) {
$tenancy = $this->sprout->tenancies()->get($config['tenancy'] ?? null);

Check warning on line 125 in src/SproutServiceProvider.php

View check run for this annotation

Codecov / codecov/patch

src/SproutServiceProvider.php#L125

Added line #L125 was not covered by tests

// If there's no tenant, error out
if (! $tenancy->check()) {

Check warning on line 128 in src/SproutServiceProvider.php

View check run for this annotation

Codecov / codecov/patch

src/SproutServiceProvider.php#L128

Added line #L128 was not covered by tests
// TODO: Better exception
throw new RuntimeException('There isn\'t a current a tenant');

Check warning on line 130 in src/SproutServiceProvider.php

View check run for this annotation

Codecov / codecov/patch

src/SproutServiceProvider.php#L130

Added line #L130 was not covered by tests
}

$tenant = $tenancy->tenant();

Check warning on line 133 in src/SproutServiceProvider.php

View check run for this annotation

Codecov / codecov/patch

src/SproutServiceProvider.php#L133

Added line #L133 was not covered by tests

// If the tenant isn't configured for resources, also error out
if (! ($tenant instanceof TenantHasResources)) {

Check warning on line 136 in src/SproutServiceProvider.php

View check run for this annotation

Codecov / codecov/patch

src/SproutServiceProvider.php#L136

Added line #L136 was not covered by tests
// TODO: Better exception
throw new RuntimeException('Current tenant isn\t configured for resources');

Check warning on line 138 in src/SproutServiceProvider.php

View check run for this annotation

Codecov / codecov/patch

src/SproutServiceProvider.php#L138

Added line #L138 was not covered by tests
}

/** @var string $pathPrefix */
$pathPrefix = $this->config['path'] ?? '{tenant}';

Check warning on line 142 in src/SproutServiceProvider.php

View check run for this annotation

Codecov / codecov/patch

src/SproutServiceProvider.php#L142

Added line #L142 was not covered by tests

// Build up the path prefix with the tenant resource key
$config['prefix'] = str_replace('{tenant}', $tenant->getTenantResourceKey(), $pathPrefix);

Check warning on line 145 in src/SproutServiceProvider.php

View check run for this annotation

Codecov / codecov/patch

src/SproutServiceProvider.php#L145

Added line #L145 was not covered by tests

// Create a scoped driver for the new path
return $filesystemManager->createScopedDriver($config);

Check warning on line 148 in src/SproutServiceProvider.php

View check run for this annotation

Codecov / codecov/patch

src/SproutServiceProvider.php#L148

Added line #L148 was not covered by tests
});
}
}
}

0 comments on commit 282c205

Please sign in to comment.