Storage Service Override

The storage service override allows you to make Laravels filesystem disks tenant-aware, allowing each tenant to have their own storage location(s)

Introduction

The storage service override is an implementation of Sprouts service override functionality, that makes Laravel's built-in storage/filesystem service tenant-aware. The service override is deferrable until the filesystem (\Illuminate\Filesystem\FilesystemManager) service is resolved. It's also bootable.

How it works

The storage service override works by registering a custom filesystem driver called sprout. This driver uses Laravel's scoped filesystem functionality to automatically prefix a pre-configured disks path using a tenants' resource key.

This service override doesn't replace the original disk, it instead creates a "clone" with a prefixed path, allowing you to use both the tenanted and non-tenanted versions simultaneously, without worrying.

If the current request/process is one where the current tenant changes from one to another, any previously created/loaded tenant-aware disk will be removed from the filesystem manager, to avoid data-leaking between tenants.

Using

To use the storage service override, you must first make sure that it is registered in the services section of the sprout config.

1'services' => [
2 \Sprout\Overrides\StorageOverride::class,
3],

Once its registered, you need to create a disk within Laravel's filesystem.php config file, specifying sprout as the driver.

1'disks' => [
2 'local' => [
3 'driver' => 'local',
4 'root' => storage_path('app'),
5 'throw' => false,
6 ],
7 
8 'tenanted' => [
9 'driver' => 'sprout',
10 ],
11]

By default, Sprout will clone whichever disk is set as the default, but if you want to override this, you can provide the name of the disk using the disk config option.

1'disks' => [
2 'local' => [
3 'driver' => 'local',
4 'root' => storage_path('app'),
5 'throw' => false,
6 ],
7 
8 'tenanted' => [
9 'driver' => 'sprout',
10 'disk' => 'local',
11 ],
12]

Alternatively, instead of the name of a filesystem disk, you can provide a disk config which will be used in a similar fashion to Laravel's on-demand disks.

1'disks' => [
2 'local' => [
3 'driver' => 'local',
4 'root' => storage_path('app'),
5 'throw' => false,
6 ],
7 
8 'tenanted' => [
9 'driver' => 'sprout',
10 'disk' => [
11 'driver' => 'local',
12 'root' => storage_path('tenants'),
13 ],
14 ],
15]

You cannot nest sprout driver disks, attempting to do so will cause an exception to be thrown.

Once you have your disk configured, you can use it as you would any other, if the following criteria are met.

  • You are currently within multitenanted context
  • There is a current tenancy
  • The current tenancy has a current tenant
1Storage::disk('tenanted')->put('image.jpg', $content);
2 
3$contents = Storage::disk('tenanted')->get('image.jpg');
4 
5// Etc, etc

Considerations

This implementation of a storage service override works based on the idea of separating tenant files by subdirectory. If you require something more complex, like each tenant having their own disk configuration for external services like AWS S3, etc., then it may be worth considering Sprout Bud, a first party package for just such an occasion.