Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce operation scoped service providers #938

Draft
wants to merge 4 commits into
base: 2.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions config/octane.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,20 @@
],
],

/*
|--------------------------------------------------------------------------
| Operation Scoped ServiceProviders
|--------------------------------------------------------------------------
|
| Here you can list service providers which should be registered
| on start of each operation, rather than during boot process.
|
*/

'op_service_providers' => [
//
],

/*
|--------------------------------------------------------------------------
| Warm / Flush Bindings
Expand Down
18 changes: 15 additions & 3 deletions src/ApplicationFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,14 @@ public function bootstrap(Application $app, array $initialInstances = []): Appli

$app->bootstrapWith($this->getBootstrappers($app));

$app->loadDeferredProviders();
// We will register all but operation scoped deferred providers right away so
// they are resolved once, during boot. Remaining operation providers will
// be registered with classical approach, during the occasions of need.
foreach ($app->getDeferredServices() as $service => $provider) {
if (!in_array($provider, $app->make('config')->get('octane.op_service_providers', []))) {
$app->loadDeferredProvider($service);
}
}

return $app;
}
Expand All @@ -61,10 +68,15 @@ protected function getBootstrappers(Application $app): array

$method->setAccessible(true);

$bootstrappers = $method->invoke($kernel);

$replaceIndex = array_search(RegisterProviders::class, $bootstrappers, true);
$bootstrappers = array_replace($bootstrappers, [$replaceIndex => OctaneRegisterProviders::class]);

return $this->injectBootstrapperBefore(
RegisterProviders::class,
OctaneRegisterProviders::class,
SetRequestForConsole::class,
$method->invoke($kernel)
$bootstrappers
);
}

Expand Down
1 change: 1 addition & 0 deletions src/Concerns/ProvidesDefaultConfigurationOptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public static function prepareApplicationForNextOperation(): array
\Laravel\Octane\Listeners\FlushMonologState::class,
\Laravel\Octane\Listeners\FlushStrCache::class,
\Laravel\Octane\Listeners\FlushTranslatorCache::class,
\Laravel\Octane\Listeners\RegisterOperationServiceProviders::class,

// First-Party Packages...
\Laravel\Octane\Listeners\PrepareInertiaForNextOperation::class,
Expand Down
27 changes: 27 additions & 0 deletions src/Listeners/RegisterOperationServiceProviders.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Laravel\Octane\Listeners;

class RegisterOperationServiceProviders
{
/**
* Handle the event.
*
* @param mixed $event
*/
public function handle($event): void
{
$resolved_providers = [];

foreach ($event->sandbox->make('config')->get('octane.op_service_providers', []) as $provider) {
$provider = $event->sandbox->resolveProvider($provider);
if ($provider->isDeferred()) continue;
$resolved_providers[] = $event->sandbox->register($provider, boot: false);
}

// After all service providers have been registered, we will boot them.
foreach ($resolved_providers as $provider) {
$event->sandbox->bootProvider($provider);
}
}
}
43 changes: 43 additions & 0 deletions src/OctaneProviderRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace Laravel\Octane;

use Illuminate\Foundation\ProviderRepository;

class OctaneProviderRepository extends ProviderRepository
{
/**
* Register the application service providers.
*
* @param array $providers
* @return void
*/
public function load(array $providers)
{
$manifest = $this->loadManifest();

// First we will load the service manifest, which contains information on all
// service providers registered with the application and which services it
// provides. This is used to know which services are "deferred" loaders.
if ($this->shouldRecompile($manifest, $providers)) {
$manifest = $this->compileManifest($providers);
}

// Next, we will register events to load the providers for each of the events
// that it has requested. This allows the service provider to defer itself
// while still getting automatically loaded when a certain event occurs.
foreach ($manifest['when'] as $provider => $events) {
$this->registerLoadEvents($provider, $events);
}

// We will register eagerly loaded providers, just like base ProviderRepository,
// except we will leave out the ones specified in op_service_providers array.
foreach ($manifest['eager'] as $provider) {
if (!in_array($provider, $this->app->make('config')->get('octane.op_service_providers', []))) {
$this->app->register($provider);
}
}

$this->app->addDeferredServices($manifest['deferred']);
}
}
31 changes: 31 additions & 0 deletions src/OctaneRegisterProviders.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Laravel\Octane;

use Illuminate\Contracts\Foundation\Application;
use Laravel\Octane\OctaneProviderRepository;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Foundation\Bootstrap\RegisterProviders;

class OctaneRegisterProviders extends RegisterProviders
{
/**
* Bootstrap the given application.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function bootstrap(Application $app)
{
if (
!$app->bound('config_loaded_from_cache') ||
$app->make('config_loaded_from_cache') === false
) {
$this->mergeAdditionalProviders($app);
}

$providerRepository = new OctaneProviderRepository($app, new Filesystem, $app->getCachedServicesPath());

$app->registerConfiguredProviders($providerRepository);
}
}
Loading