Detailed explanation of the problems encountered when setting delayed loading in Laravel Service Provider development
- 2021-08-28 19:42:18
- OfStack
Preface
This paper mainly introduces some problems encountered when setting delayed loading for Laravel Service Provider. All this article is due to the actual project requirements. Recently, when developing laravel-database-logger package, it was found that setting ServiceProvider defer attribute to true will cause middleware registered in register method to be invalid.
class ServiceProvider extends \Illuminate\Support\ServiceProvider
{
protected $defer = true;
public function register()
{
$this->mergeConfigFrom(
__DIR__ . '/../config/config.php', 'ibrand.dblogger'
);
$this->app->singleton(DbLogger::class, function ($app) {
return new DbLogger();
});
// When $defer Set to true Reference in the route when databaselogger middleware Errors will be reported and prompted databaselogger class not found.
$this->app[\Illuminate\Routing\Router::class]->middleware('databaselogger', Middleware::class);
}
public function provides()
{
return [DbLogger::class];
}
}
When the problem occurs, it is suspected that it is caused by setting the defer attribute to true, and immediately modify the source code to
protected $defer = true;
Comment out the code, and the result is still a prompt
databaselogger class not found.
Laravel is not registered for this ServiceProvder
Next, I want to solve this problem and try the following methods:
1. Verify that there is something wrong with your code
Register your own ServiceProvider in the normally registered AppServiceProvider
public function register()
{
//
$this->app->register(\Ibrand\DatabaseLogger\ServiceProvider::class);
}
Result 1 is normal after registration.
2. Study the source code
providers registration is invalid in config/app. php, but valid in other ServiceProvider, indicating other problems.
Find the method of registerConfiguredProviders by studying the source code of Illuminate\ Foundation\ Application:
Laravel is to read providers contents in config/app. php and load into ProviderRepository in this method.
(new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath()))
->load($providers->collapse()->toArray());
The point is
$this->getCachedServicesPath()
Through the source found Laravel is based on bootstrap/cache/services. php file to determine how to register ServiceProvider.
At this time, I thought of why I commented before
//protected $defer = true;
The reason why it is still invalid after the code.
So in order to make the annotated
//protected $defer = true;
The code is valid and needs to be executed
php artisan clear-compiled
php artisan optimize
After that, the problem was solved, and the principle of ServiceProvider was further understood.
Therefore, remember: If you are going to use delayed loading of ServiceProvider, it is strictly forbidden to register middleware, route and other series of operations. At the same time, after changing the defer property value, you need to execute
php artisan clear-compiled
And
php artisan optimize
To update the ServiceProvider cache.
3. Why is the registration valid in AppServiceProvider?
The willingness is simple, because AppServiceProvider does not delay loading, so executing the register method in AppServiceProvider to register a new ServiceProvider does not delay loading.
Summarize
Careful use of delayed loading ServiceProvider
After you change the defer property value, you need to execute the
php artisan clear-compiled
And
php artisan optimize
To update the ServiceProvider cache.
It is strictly forbidden to register middleware and route with delayed loading ServiceProvider.