Service Overrides
The documentation is still in progress, and this page is not yet complete. Please check back again in the future.
Introduction
Your application is made up of many "services", whether they're things like file storage, sessions, authentication, or one of the many others provided by Laravel. Sometimes these services aren't part of the core Laravel installation, things like Fortify, Livewire, Inertia or Filament. Whatever they are, they aren't going to understand your application out of the box, and they're definitely not going to support your multitenancy functionality.
This is where the service override comes in. Service overrides are similar to service providers, except they're specific to the lifecycle of Sprout, as well as that of a tenant. They are called when the current tenant changes, allowing them to set up for the new tenant, as well as clean up after the previous. They can also optionally be bootable, which means they have actions to perform once Laravel has booted.
Configuring Overrides
Service overrides are configured in the sprout.overrides
config again the
"service" they override, with their class as the driver
, and any extra configuration options required or allowed by
the driver itself.
The order that the overrides appear in the sprout.overrides
config is the order that they'll be registered in, and
the order they'll be called in.
There are no specific rules surrounding the name that a service override is registered under, but it is recommended that you avoid changing them.
Stacking Overrides
There are times when you'll need more than one service override for a service, and rather than having to register each
under a different name, Sprout supports stacking.
If you need to stack, you can set the driver to
\Sprout\Overrides\StackedOverride
,
then provide the drivers you want to stack under the overrides
config key.
If either driver requires config options, you can provide them normally.
1'filesystem' => [2 'driver' => \Sprout\Overrides\StackedOverride::class,3 'overrides' => [4 \Sprout\Overrides\FilesystemManagerOverride::class,5 \Sprout\Overrides\FilesystemOverride::class,6 ],7],
There are two menu uses for stacking.
- The override for a particular service has been broken into smaller separate parts, and can be used independently of the others.
- You have multiple overrides from different sources, and want to use all of them.
Per Tenancy
Once a service override is registered with Sprout, it is available for use. By default, no service override is used unless the tenancy is configured to use it. You can do this using tenancy options, by either enabling all overrides for the tenancy, which is what the default config does.
1'tenants' => [2 'provider' => 'tenants',3 'options' => [4 TenancyOptions::allOverrides(),5 ],6],
Or by listing only the ones you want.
1'tenants' => [2 'provider' => 'tenants',3 'options' => [4 TenancyOptions::overrides([5 'job', 'filesystem', 'cache'6 ]),7 ],8],
While you can enable or disable service overrides on a per tenancy basic, any that are bootable will be booted regardless, as that happens before the tenancy is identified.
Setting and Cleaning Up
Service overrides are built around the concept of setting the override up for the tenant when it becomes the current one, and cleaning up once it no longer is. While this is a core part of this feature, both the setting and cleaning up are controlled by tenancy bootstrappers.
The \Sprout\Listeners\CleanupServiceOverrides
bootstrapper is responsible for making the service overrides clean-up after themselves,
and the \Sprout\Listeners\SetupServiceOverrides
bootstrapper is responsible for the setup.
Both the order that these bootstrappers appear in the config, and their presence in it is important for the service override functionality. Removing either, or changing their order relative to each other, will have unknown side effects and may cause your application to not function properly.
Available Service Overrides
Sprout ships with several overrides for core parts of Laravel, all of which are enabled by default.
Filesystem
The filesystem override comes in two parts.
The first replace Laravel's filesystem manager with Sprouts, which only exists to simplify the second, which adds a
sprout
driver that allows you to create
tenant scoped filesystem disks.
1'filesystem' => [2 'driver' => \Sprout\Overrides\StackedOverride::class,3 'overrides' => [4 \Sprout\Overrides\FilesystemManagerOverride::class,5 \Sprout\Overrides\FilesystemOverride::class,6 ],7],
This service override requires that the tenant is configured for resources, and will throw an exception if it isn't.
Filesystem Manager
The filesystem manager service override does only a single thing, and that is adding the name of the disk to the
disk config as name
, when calling a custom driver.
This is primarily of use to the other override, as it keeps track of the tenant disks that were accessed, and uses that
to perform the clean-up.
Filesystem
This service override is the one responsible for adding the sprout
driver to the filesystem service.
The new driver allows you to create a filesystem disk scoped to the current tenant, either based on an existing disk,
or using new settings.
To use this override, create a filesystem disk in config/filesystems.php
under disks
, whose driver is sprout
.
Then under the disk
option, add either the name of an existing disk.
1'tenant-disk' => [2 'driver' => 'sprout',3 'disk' => 'local',4],
This override uses the config from the other disk, and then scopes it, so you can use both the sprout one, and the base one simultaneously. Just be aware that the base one will have access to all data for all tenants.
Or the config for a new disk.
1'tenant-disk' => [2 'driver' => 'sprout',3 'disk' => [4 'driver' => 'local',5 'root' => storage_path('tenants'),6 'throw' => false,7 ],8],
When the disk is created, its root will be set to {tenancy}/{tenant}
, where tenancy
is the name of the tenancy
from the multitenancy.tenancies
config, and tenant
is replaced with its
resource key.
If you want to change this, you can provide the path
config option for the disk, which uses the same
placeholders as the identity resolver parameter names, except that tenant
uses the resource key, and not identifier.
1'tenant-disk' => [2 'driver' => 'sprout',3 'disk' => 'local',4 'path' => '/{tenancy}/files/{tenant}'5],
Sprout will not take steps to ensure that the disk path exists. This is something that you will need to do as part of your applications lifecycle whenever a new tenant is created.
Job
The job service override is arguably the simplest of the defaults. All it does is register an event listener for a job event that makes sure that whenever a job is run, it has the same tenancies and tenants available as it did when it was first queued.
1'job' => [2 'driver' => \Sprout\Overrides\JobOverride::class,3],
This is registered as job
because it technically does do anything with the queue, and naming it something like
that may get in the way or cause confusion.