Laravel 13 服务提供者是应用引导的核心,本文深入探讨高级用法。
服务提供者基础
基础服务提供者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
abstract class BaseServiceProvider extends ServiceProvider { protected bool $defer = false; protected array $bindings = []; protected array $singletons = []; public function register(): void { foreach ($this->bindings as $abstract => $concrete) { $this->app->bind($abstract, $concrete); } foreach ($this->singletons as $abstract => $concrete) { $this->app->singleton($abstract, $concrete); } $this->registerServices(); } public function boot(): void { $this->bootServices(); } protected function registerServices(): void { } protected function bootServices(): void { } public function provides(): array { return array_keys(array_merge($this->bindings, $this->singletons)); } }
|
延迟加载
延迟服务提供者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| <?php
namespace App\Providers;
use App\Contracts\PaymentInterface; use App\Services\PaymentService; use Illuminate\Support\ServiceProvider;
class DeferredPaymentServiceProvider extends ServiceProvider { protected bool $defer = true; public function register(): void { $this->app->singleton(PaymentInterface::class, function ($app) { return new PaymentService( config('services.payment.key'), config('services.payment.secret') ); }); $this->app->singleton('payment', function ($app) { return $app->make(PaymentInterface::class); }); } public function provides(): array { return [ PaymentInterface::class, 'payment', ]; } }
class DeferredCacheServiceProvider extends ServiceProvider { protected bool $defer = true; public function register(): void { $this->app->singleton('cache', function ($app) { return new CacheManager($app); }); $this->app->singleton('cache.store', function ($app) { return $app['cache']->driver(); }); $this->app->singleton('cache.psr6', function ($app) { return new Psr16Adapter($app['cache.store']); }); } public function provides(): array { return ['cache', 'cache.store', 'cache.psr6']; } }
|
配置发布
发布配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| <?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class PackageServiceProvider extends ServiceProvider { public function boot(): void { $this->publishes([ __DIR__ . '/../config/package.php' => config_path('package.php'), ], 'config'); $this->publishes([ __DIR__ . '/../resources/views' => resource_path('views/vendor/package'), ], 'views'); $this->publishes([ __DIR__ . '/../database/migrations' => database_path('migrations'), ], 'migrations'); $this->publishes([ __DIR__ . '/../public' => public_path('vendor/package'), ], 'public'); $this->publishes([ __DIR__ . '/../config/package.php' => config_path('package.php'), __DIR__ . '/../resources/views' => resource_path('views/vendor/package'), ], 'package-all'); } public function register(): void { $this->mergeConfigFrom( __DIR__ . '/../config/package.php', 'package' ); $this->loadViewsFrom( __DIR__ . '/../resources/views', 'package' ); $this->loadTranslationsFrom( __DIR__ . '/../resources/lang', 'package' ); $this->loadMigrationsFrom( __DIR__ . '/../database/migrations' ); $this->loadRoutesFrom( __DIR__ . '/../routes/web.php' ); } }
|
命令注册
注册命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <?php
namespace App\Providers;
use App\Console\Commands\ProcessQueueCommand; use App\Console\Commands\CleanupCommand; use App\Console\Commands\ReportCommand; use Illuminate\Support\ServiceProvider;
class CommandServiceProvider extends ServiceProvider { protected array $commands = [ ProcessQueueCommand::class, CleanupCommand::class, ReportCommand::class, ]; public function boot(): void { if ($this->app->runningInConsole()) { $this->commands($this->commands); $this->publishes([ __DIR__ . '/../../stubs' => base_path('stubs'), ], 'stubs'); } } public function register(): void { $this->app->singleton('command.process-queue', function ($app) { return new ProcessQueueCommand( $app->make('queue'), $app->make('log') ); }); $this->app->singleton('command.cleanup', function ($app) { return new CleanupCommand( $app->make('filesystem') ); }); } public function provides(): array { return [ 'command.process-queue', 'command.cleanup', ]; } }
|
中间件注册
中间件服务提供者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| <?php
namespace App\Providers;
use App\Http\Middleware\Authenticate; use App\Http\Middleware\Authorize; use App\Http\Middleware\ThrottleRequests; use Illuminate\Support\ServiceProvider;
class MiddlewareServiceProvider extends ServiceProvider { protected array $middleware = [ Authenticate::class, Authorize::class, ThrottleRequests::class, ]; protected array $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, ], 'api' => [ \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, 'throttle:api', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], ]; protected array $routeMiddleware = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, ]; public function boot(): void { $router = $this->app['router']; foreach ($this->middleware as $middleware) { $router->middleware($middleware); } foreach ($this->middlewareGroups as $group => $middlewares) { $router->middlewareGroup($group, $middlewares); } foreach ($this->routeMiddleware as $alias => $middleware) { $router->aliasMiddleware($alias, $middleware); } } }
|
事件监听
事件服务提供者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <?php
namespace App\Providers;
use App\Events\OrderCreated; use App\Events\UserRegistered; use App\Listeners\SendOrderConfirmation; use App\Listeners\SendWelcomeEmail; use App\Listeners\UpdateStatistics; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider { protected $listen = [ UserRegistered::class => [ SendWelcomeEmail::class, UpdateStatistics::class, ], OrderCreated::class => [ SendOrderConfirmation::class, UpdateInventory::class, 'App\Listeners\NotifyAdmin@handle', ], ]; protected $subscribe = [ 'App\Listeners\UserEventSubscriber', 'App\Listeners\OrderEventSubscriber', ]; protected $observers = [ User::class => [UserObserver::class], Order::class => [OrderObserver::class], ]; public function boot(): void { parent::boot(); foreach ($this->observers as $model => $observers) { $model::observe($observers); } } }
|
路由注册
路由服务提供者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| <?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider { protected string $namespace = 'App\\Http\\Controllers'; protected array $apiRoutes = [ 'v1' => __DIR__ . '/../../routes/api/v1.php', 'v2' => __DIR__ . '/../../routes/api/v2.php', ]; public function boot(): void { parent::boot(); Route::pattern('id', '[0-9]+'); Route::pattern('slug', '[a-z0-9-]+'); Route::pattern('uuid', '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'); } public function map(): void { $this->mapApiRoutes(); $this->mapWebRoutes(); $this->mapAdminRoutes(); } protected function mapWebRoutes(): void { Route::middleware('web') ->namespace($this->namespace) ->group(base_path('routes/web.php')); } protected function mapApiRoutes(): void { foreach ($this->apiRoutes as $version => $path) { Route::prefix("api/{$version}") ->middleware(['api', "api.version:{$version}"]) ->namespace("{$this->namespace}\\Api\\{$version}") ->group($path); } } protected function mapAdminRoutes(): void { Route::prefix('admin') ->middleware(['web', 'auth', 'admin']) ->namespace("{$this->namespace}\\Admin") ->group(base_path('routes/admin.php')); } }
|
视图组件
视图服务提供者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <?php
namespace App\Providers;
use App\View\Components\Alert; use App\View\Components\Card; use App\View\Components\Modal; use App\View\Composers\NavigationComposer; use App\View\Composers\UserComposer; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\Blade;
class ViewServiceProvider extends ServiceProvider { protected array $components = [ 'alert' => Alert::class, 'card' => Card::class, 'modal' => Modal::class, ]; protected array $composers = [ 'layouts.*' => NavigationComposer::class, 'users.*' => UserComposer::class, ]; public function boot(): void { foreach ($this->components as $alias => $component) { Blade::component($alias, $component); } foreach ($this->composers as $views => $composer) { view()->composer($views, $composer); } Blade::directive('datetime', function ($expression) { return "<?php echo ($expression)->format('Y-m-d H:i:s'); ?>"; }); Blade::directive('money', function ($expression) { return "<?php echo number_format($expression, 2); ?>"; }); Blade::if('admin', function () { return auth()->check() && auth()->user()->isAdmin(); }); Blade::if('feature', function ($feature) { return app('features')->enabled($feature); }); } }
|
验证规则
验证服务提供者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| <?php
namespace App\Providers;
use App\Rules\PhoneNumber; use App\Rules\PostalCode; use App\Rules\StrongPassword; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\Validator;
class ValidationServiceProvider extends ServiceProvider { protected array $rules = [ 'phone' => PhoneNumber::class, 'postal_code' => PostalCode::class, 'strong_password' => StrongPassword::class, ]; public function boot(): void { foreach ($this->rules as $name => $rule) { Validator::extend($name, function ($attribute, $value, $parameters, $validator) use ($rule) { return (new $rule)->passes($attribute, $value); }); } Validator::extend('foo', function ($attribute, $value, $parameters, $validator) { return $value === 'foo'; }); Validator::replacer('foo', function ($message, $attribute, $rule, $parameters) { return str_replace(':attribute', $attribute, 'The :attribute must be foo'); }); Validator::extendImplicit('required_if_admin', function ($attribute, $value, $parameters, $validator) { if (auth()->check() && auth()->user()->isAdmin()) { return !empty($value); } return true; }); } }
|
总结
Laravel 13 服务提供者是应用引导的核心机制。通过延迟加载、配置发布、命令注册、中间件注册等功能,可以构建模块化、可维护的应用架构。