Laravel 的强大之处不仅在于其丰富的内置功能,更在于其高度可扩展的架构。通过包(Package),你可以将通用功能封装成独立组件,并在多个项目间复用。服务提供者(Service Provider)是 Laravel 包的核心,负责绑定服务到容器、注册事件、路由、迁移等。本章将带你从零开始创建一个完整的 Laravel 包。
一个典型的 Laravel 包通常包含以下文件和目录:
my-package/
├── src/
│ ├── MyPackageServiceProvider.php # 服务提供者
│ ├── MyPackage.php # 主类
│ ├── Commands/ # Artisan 命令
│ ├── Http/ # 控制器、中间件等
│ ├── Models/ # 模型
│ └── config/
│ └── mypackage.php # 配置文件
├── database/
│ ├── migrations/ # 迁移文件
│ └── seeds/ # 种子文件
├── resources/
│ ├── views/ # 视图文件
│ └── lang/ # 语言文件
├── routes/
│ ├── web.php
│ └── api.php
├── composer.json
└── README.md
首先,在项目的 packages/ 目录下(或独立目录)创建包文件夹,例如 packages/my-vendor/my-package。然后初始化 composer.json:
cd packages/my-vendor/my-package
composer init
编辑 composer.json,添加 autoload 和 extra 字段:
{
"name": "my-vendor/my-package",
"description": "My awesome Laravel package",
"type": "library",
"license": "MIT",
"autoload": {
"psr-4": {
"MyVendor\\MyPackage\\": "src/"
}
},
"extra": {
"laravel": {
"providers": [
"MyVendor\\MyPackage\\MyPackageServiceProvider"
]
}
},
"require": {
"php": "^8.1",
"illuminate/support": "^11.0"
}
}
然后在项目的根 composer.json 中添加本地仓库:
"repositories": [
{
"type": "path",
"url": "packages/my-vendor/my-package"
}
]
最后运行 composer require my-vendor/my-package @dev 安装包。
服务提供者是包的入口,所有绑定、注册逻辑都放在这里。创建 src/MyPackageServiceProvider.php:
<?php
namespace MyVendor\MyPackage;
use Illuminate\Support\ServiceProvider;
class MyPackageServiceProvider extends ServiceProvider
{
/**
* 注册服务
*/
public function register()
{
// 绑定单例
$this->app->singleton(MyPackage::class, function ($app) {
return new MyPackage(config('mypackage'));
});
// 合并配置文件(允许用户发布并覆盖)
$this->mergeConfigFrom(
__DIR__.'/../config/mypackage.php', 'mypackage'
);
}
/**
* 启动服务
*/
public function boot()
{
// 加载路由
$this->loadRoutesFrom(__DIR__.'/../routes/web.php');
// 加载视图
$this->loadViewsFrom(__DIR__.'/../resources/views', 'mypackage');
// 加载迁移
$this->loadMigrationsFrom(__DIR__.'/../database/migrations');
// 发布配置文件(使开发者可以自定义)
$this->publishes([
__DIR__.'/../config/mypackage.php' => config_path('mypackage.php'),
], 'config');
// 发布视图文件
$this->publishes([
__DIR__.'/../resources/views' => resource_path('views/vendor/mypackage'),
], 'views');
// 发布迁移文件
$this->publishes([
__DIR__.'/../database/migrations' => database_path('migrations'),
], 'migrations');
}
}
创建 config/mypackage.php,定义包的可配置项:
<?php
return [
'api_key' => env('MYPACKAGE_API_KEY', 'default-key'),
'timeout' => 30,
];
在 routes/web.php 中添加示例路由:
Route::get('/mypackage', function () {
return view('mypackage::index');
});
创建 resources/views/index.blade.php:
<h1>欢迎使用 MyPackage!</h1>
<p>当前配置 API Key: </p>
在 database/migrations 中创建迁移文件,例如 2024_01_01_000000_create_package_tables.php:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePackageTables extends Migration
{
public function up()
{
Schema::create('package_data', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('package_data');
}
}
安装包后,用户可以通过 Artisan 命令发布资源:
php artisan vendor:publish --provider="MyVendor\MyPackage\MyPackageServiceProvider"
然后可以运行迁移:
php artisan migrate
在应用中可以通过依赖注入或 Facade 使用包提供的服务:
use MyVendor\MyPackage\MyPackage;
Route::get('/use-package', function (MyPackage $package) {
return $package->doSomething();
});
Vendor\Package 格式,避免与 Laravel 核心冲突。register() 只负责绑定,boot() 中做配置、路由等需要依赖已注册服务的操作。config、views、migrations)让用户选择性发布。phpunit 运行。通过服务提供者,Laravel 包可以无缝集成到任何 Laravel 应用中。掌握包开发技能,可以让你创建可复用的组件,提高开发效率,并为 Laravel 社区贡献力量。从简单的服务提供者到完整的包结构,本章为你奠定了坚实基础。