Для тих, хто не користувався постачальниками послуг у Laravel, це містичний «термін»: яку «послуги» вони насправді «надають», і як саме все це працює? Я поясню це в цій статті.
Постачальники послуг Laravel за умовчанням
Почнемо з постачальників послуг за замовчуванням, включених до Laravel, усі вони знаходяться в папці app/Providers
:
- AppServiceProvider
- AuthServiceProvider
- BroadcastServiceProvider
- EventServiceProvider
- RouteServiceProvider
Всі вони є класами PHP, кожен з яких пов’язаний зі своєю темою: загальні "програми", Auth, Broadcasting, Events і Routes. Але всі вони мають одну спільну рису: метод boot()
.
Усередині цього методу ви можете написати будь-який код, пов’язаний з одним із цих розділів: auth, події, маршрути тощо. Іншими словами, постачальники послуг – це просто класи для реєстрації певної глобальної функціональності.
Вони відокремлені як «постачальники», оскільки вони виконуються дуже на початку життєвого циклу програми, тому тут зручно щось глобальне, перш ніж сценарій виконання надходить до моделей або контролерів.
Найбільше функцій міститься в RouteServiceProvider, давайте подивимося на його код:
class RouteServiceProvider extends ServiceProvider
{
public const HOME = '/dashboard';
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
Route::prefix('api')
->middleware('api')
->group(base_path('routes/api.php'));
Route::middleware('web')
->group(base_path('routes/web.php'));
});
}
protected function configureRateLimiting()
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
});
}
}
Це клас, у якому налаштовуються файли маршрутів із routes/web.php
і routes/api.php
, включеними за замовчуванням.Зверніть увагу, що для API також існують різні конфігурації: префікс кінцевої точки /api
і проміжне програмне забезпечення api
для всіх маршрутів.
Ви можете редагувати цих постачальників послуг як завгодно, вони не знаходяться в папці /vendor
. Типове налаштування цього файлу відбувається, коли у вас є багато маршрутів, і ви хочете розділити їх у своєму файлі.Ви створюєте routes/auth.php
і розміщуєте туди маршрути, а потім "включаєте" цей файл у методі boot()
RouteServiceProvider
, просто додайте третє речення:
`Route::middleware('web') // or maybe you want another middleware?
->group(base_path('routes/auth.php'));
Інші постачальники послуг за замовчуванням мають інші функції, ви можете проаналізувати їх самостійно.За винятком AppServiceProvider
, він порожній, як заповнювач для додавання будь-якого коду, пов’язаного з деякими глобальними налаштуваннями програми.
Один популярний приклад додавання коду до AppServiceProvider
— це вимкнення ліниве завантаження в Eloquent.Для цього вам просто потрібно додати два рядки в метод boot()
:
// app/Providers/AppServiceProvider.php
use Illuminate\Database\Eloquent\Model;
public function boot()
{
Model::preventLazyLoading(! $this->app->isProduction());
}
Це створить виняток, якщо деяка модель відносин не буде завантажена, що спричинить так звану проблему запиту N+1 з продуктивністю.
Коли виконуються постачальники послуг?
Якщо ви подивитеся на офіційні документи про життєвий цикл запиту, то це те, що виконується на самому початку:
- public/index.php
- bootstrap/app.php
- app/Http/Kernel.php and its Middlewares
- Service Providers: exactly our topic of this article
Які постачальники завантажені? Він визначається в На додаток до існуючих файлів за замовчуванням, ви можете легко створити свого постачальника послуг, пов’язаних з деякими іншими темами, ніж стандартні, наприклад auth/event/routes. Досить типовим прикладом є конфігурація, пов’язана з переглядами Blade.Якщо ви хочете створити свою директиву Blade, ви можете додати цей код до методу Ви можете створити його за допомогою цієї команди: Це створить шаблон за замовчуванням: Ви можете видалити метод Інший приклад ViewServiceProvider стосується View Composers, ось фрагмент з офіційних документів Laravel: Для виконання цього нового постачальника слід додати до масиву постачальників у На завершення я хочу згадати кілька прикладів із вільно доступних проектів Laravel. Один із найпопулярніших проектів з відкритим кодом Laravel має окремий файл для реєстрації макросів колекції: Відома компанія Spatie опублікувала вихідний код для особистого блогу Freek Van der Herten з цим файлом. p>
Один із найпопулярніших проектів з відкритим кодом Laravel має окремий файл для реєстрації макросів колекції: Ви також можете знайти ще кілька прикладів постачальників послуг на моєму веб-сайті LaravelExamples.com.config/app.
return [
// ... other configuration values
'providers' => [
/*
* Laravel Framework Service Providers...
*/
Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class,
// ... other framework providers from /vendor
Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class,
/*
* PUBLIC Service Providers - the ones we mentioned above
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
],
];
Створіть свого постачальника послуг
boot()
будь-якого постачальника послуг, включаючи стандартний AppServiceProvider
, але досить часто розробники створюють окремий ViewServiceProvider .
register()
, а всередині boot()
додати код директиви Blade:config/app.php
, як зазначено вище:Приклади з проектів з відкритим кодом
php artisan make:provider ViewServiceProvider
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ViewServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
//
}
}
use Illuminate\Support\Facades\Blade;
public function boot()
{
Blade::directive('datetime', function ($expression) {
return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
});
}
use App\View\Composers\ProfileComposer;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
class ViewServiceProvider extends ServiceProvider
{
public function boot()
{
// Using class based composers...
View::composer('profile', ProfileComposer::class);
// Using closure based composers...
View::composer('dashboard', function ($view) {
//
});
}
}
return [
// ... other configuration values
'providers' => [
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
// Add your provider here
App\Providers\ViewServiceProvider::class,
],
];
namespace App\Providers;
use App\Http\Components\AdComponent;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class BladeComponentServiceProvider extends ServiceProvider
{
public function boot()
{
Blade::component('ad', AdComponent::class);
Blade::component('front.components.inputField', 'input-field');
Blade::component('front.components.submitButton', 'submit-button');
Blade::component('front.components.textarea', 'textarea');
Blade::component('front.components.textarea', 'textarea');
Blade::component('front.components.shareButton', 'share-button');
Blade::component('front.components.lazy', 'lazy');
Blade::component('front.components.postHeader', 'post-header');
Blade::component('front.layouts.app', 'app-layout');
}
}
namespace App\Providers;
use App\Helpers\CollectionHelper;
use Illuminate\Support\Collection;
use Illuminate\Support\ServiceProvider;
class MacroServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
if (! Collection::hasMacro('sortByCollator')) {
Collection::macro('sortByCollator', function ($callback, $options = \Collator::SORT_STRING, $descending = false) {
/** @var Collection */
$collect = $this;
return CollectionHelper::sortByCollator($collect, $callback, $options, $descending);
});
}
if (! Collection::hasMacro('groupByItemsProperty')) {
Collection::macro('groupByItemsProperty', function ($property) {
/** @var Collection */
$collect = $this;
return CollectionHelper::groupByItemsProperty($collect, $property);
});
}
if (! Collection::hasMacro('mapUuid')) {
Collection::macro('mapUuid', function () {
/** @var Collection */
$collect = $this;
return $collect->map(function ($item) {
return $item->uuid;
})->toArray();
});
}
}
}
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Blade;
use App\Helpers\FileUpload\UploadComponents;
class DashboardComponentsServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
Blade::directive('uploadForm', function () {
$component = UploadComponents::getUploadForm();
$html = '<?php echo \'' . $component . '\'; ?>';
return ('<?php echo "' . $component . '"; ?>');
});
}
}