-
Notifications
You must be signed in to change notification settings - Fork 11k
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
[5.8] Application::registerConfiguredProviders - Load Order Change #28223
Conversation
- Previous load order: --- Config file Illuminate\\, Autoload Vendor, Config file Vendor and App\\ - New load order: --- Config file Illuminate\\, Config file Vendor, Autoload Vendor, Config file App\\
$providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]); | ||
$appProviders = $providers->get(1) | ||
->partition(function ($provider) { | ||
return Str::startsWith($provider, 'App\\'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here u could use getNamespace
😃
return Str::startsWith($provider, 'App\\'); | |
return Str::startsWith($provider, $this->getNamespace()); |
I check both packages and failed to where where exactly did you replace |
Seems like there's been a lot of discussion about this and several PRs, however I've not yet understood the need. This shouldn't be necessary. |
<?php
namespace Wpb\String_Blade_Compiler;
use Illuminate\Support\ServiceProvider;
use Wpb\String_Blade_Compiler\Compilers\StringBladeCompiler;
use Wpb\String_Blade_Compiler\Engines\CompilerEngine;
class StringBladeServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
// include the package config
$this->mergeConfigFrom(
__DIR__.'/../config/blade.php', 'blade'
);
$this->app->afterResolving('view.engine.resolver', function ($resolver) {
$this->registerStringBladeEngine($resolver);
});
}
/**
* Register the StringBlade engine implementation.
*
* @param \Illuminate\View\Engines\EngineResolver $resolver
* @return void
*/
public function registerStringBladeEngine($resolver)
{
$app = $this->app;
// The Compiler engine requires an instance of the CompilerInterface, which in
// this case will be the Blade compiler, so we'll first create the compiler
// instance to pass into the engine so it can compile the views properly.
$app->singleton('stringblade.compiler', function ($app) {
$cache = $app['config']['view.compiled'];
return new StringBladeCompiler($app['files'], $cache);
});
$resolver->register('stringblade', function () use ($app) {
return new CompilerEngine($app['stringblade.compiler']);
});
}
/**
* Get the events that trigger this service provider to register.
*
* @return array
*/
public function when()
{
return ['Illuminate\View\ViewServiceProvider'];
}
} This would simply be enough to handle what the @TerrePorter wanted to do in his package. There no reason to completely override the default |
Both packages? I am assuming you mean the voyager ones. The voyager packages to not replace View. My package is a replacement for View, the replacement would happen when the person installing the StringBladeCompiler package added my package service provider in config/app.php. In my install instructions I had them commend out the original View service provider. Regarding the code change using @devcircus |
Disregard above comment. Didn't realise that Laravel have removed the functionality in 5.5 but keep the the registration of the event in Illuminate\Foundation\ProviderRepository <?php
namespace Wpb\String_Blade_Compiler;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
use Wpb\String_Blade_Compiler\Compilers\StringBladeCompiler;
use Wpb\String_Blade_Compiler\Engines\CompilerEngine;
class StringBladeServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
// include the package config
$this->mergeConfigFrom(
__DIR__.'/../config/blade.php', 'blade'
);
View::resolved(function ($view) {
$this->registerStringBladeEngine($view->getEngineResolver());
});
}
/**
* Register the StringBlade engine implementation.
*
* @param \Illuminate\View\Engines\EngineResolver $resolver
* @return void
*/
public function registerStringBladeEngine($resolver)
{
$app = $this->app;
// The Compiler engine requires an instance of the CompilerInterface, which in
// this case will be the Blade compiler, so we'll first create the compiler
// instance to pass into the engine so it can compile the views properly.
$app->singleton('stringblade.compiler', function ($app) {
$cache = $app['config']['view.compiled'];
return new StringBladeCompiler($app['files'], $cache);
});
$resolver->register('stringblade', function () use ($app) {
return new CompilerEngine($app['stringblade.compiler']);
});
}
}
|
@crynobone what removed functionality are you referring to? the when function is in the service provider code,
|
Laravel still register event using Laravel 5.3 - https://github.com/laravel/framework/blob/5.3/src/Illuminate/Foundation/Application.php#L619-L626 Best approach now is to use |
But, this is just reverses the scenario and possibly puts the problem on someone else. It's very much not recommended to depend on the registration order of service providers in any way. I think @crynobone is on the right track in offering alternative solutions. |
@crynobone I discovered another function alternative. But the only place I found where I could precede the service provider registration process was in the $app->resolving(Illuminate\Foundation\Bootstrap\RegisterProviders::class, function () use ($app) {
// need? necessary? to be the first service provider - hell no, its just because I want to
dump('I want to be first before any service provider listed in config/app.php');
$app->register(\MyClass::class);
});
$app->resolving('view', function () use ($app) {
dump('I want to be next in line after the view service provider');
$app->register(\MyClass::class);
}); So technically, my proposed code change is not “needed”, as I can easily circumvent the service provider loading process now. |
@taylorotwell
Perhaps, not sure how though. Maybe making a package that extends another package and the parent package is not registered yet, I guess...
Sure, says the guy who has the service providers loading in a preset hard-coded order. (Illuminate\, Autoload, Config vendor and Config App\). I don’t see a ‘array random’ in there, so view is always going to be the last of the Illuminate providers loaded and before any of the autoloads – that is “dependable” to me.
Yes, he was very helpful. I have a working alternative. Wrap my solution in to a "install" command with my package and the service load order means nothing. |
Why I am making this pull request:
History/Reasons
I wrote StringBladeCompiler which adds to the functionality of the View class. The original way I replaced the View component was to remove the ServiceProvider reference in the config/app.php file and register the package ServiceProvider, which set up my extended view classes as the base View class.
This worked fine until the ServiceProvider auto load feature was implemented. Vendor packages that are registered with autoload are loaded before vendor packages referenced in the config/app.php file.
A example of the issue, I was messing around with https://github.com/the-control-group/voyager, a admin package. That package requires this package, https://github.com/larapack/voyager-hooks, which registers a view namespace in the register function, #L40
Using my original method of replacing the View class, and the example above, this process will now cause an error as other package service providers load before mine. This results in the View class not existing, when the voyager-hooks register function tries to add a view namespace location. However, before the autoloading of service providers my process worked fine.
I have since updated my code to not need the removal of the original View registration in config/app.php. So this is not a "issue" for me anymore.
The However
The pull request is to allow that ability.
The Existing Code
The existing code in
Application::registerConfiguredProviders
, does the following.$this->config['app.providers']
, splits them in to two groups. Those packages that start withIlluminate\\
and everything else.This results in the following registration order for Service Providers:
As you can see my directly registered package is not loaded until after all other vendor packages are loaded.
The code change
$this->config['app.providers']
, splits them in to two groups. Those packages that start withIlluminate\\
and everything else.App\\
service providers.Illuminate\\
,config/app.php vendor
, andApp\\
App\\
group.This results in the following registration order for Service Providers:
As you can see the new registration order now give the vendor packages registered in config/app.php priority over the auto registered packages.
Thanks for reading.