Laravel 扩展包开发模板
下面是一个完整的 Laravel 扩展包开发模板,包含最佳实践和企业级功能实现:
<?php
/*
* Laravel 扩展包开发模板
* 版本:1.0.0
* 最后更新:2023年7月15日
*/
namespace VendorName\PackageName;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
use VendorName\PackageName\Console\InstallCommand;
use VendorName\PackageName\Console\PublishCommand;
use VendorName\PackageName\Services\PackageService;
use VendorName\PackageName\Contracts\PackageInterface;
use VendorName\PackageName\Exceptions\PackageException;
use VendorName\PackageName\Http\Middleware\PackageMiddleware;
use VendorName\PackageName\View\Components\AlertComponent;
class PackageNameServiceProvider extends ServiceProvider
{
/**
* 包名常量
*/
const PACKAGE_NAME = 'package-name';
/**
* 注册服务提供者
*
* @return void
*/
public function register()
{
// 合并默认配置
$this->mergeConfigFrom(
__DIR__.'/../config/'.self::PACKAGE_NAME.'.php', self::PACKAGE_NAME
);
// 绑定主服务到容器
$this->app->singleton(PackageInterface::class, function (Container $app) {
$config = $app['config']->get(self::PACKAGE_NAME);
return new PackageService(
$config['api_key'],
$config['options']['cache_ttl'] ?? 3600,
$config['options']['log_errors'] ?? true
);
});
// 绑定Facade访问器
$this->app->bind(self::PACKAGE_NAME, function ($app) {
return $app->make(PackageInterface::class);
});
}
/**
* 引导包服务
*
* @return void
*/
public function boot()
{
// 注册配置文件发布
$this->publishes([
__DIR__.'/../config/'.self::PACKAGE_NAME.'.php' => config_path(self::PACKAGE_NAME.'.php'),
], self::PACKAGE_NAME.'-config');
// 注册迁移文件发布
$this->publishes([
__DIR__.'/../database/migrations' => database_path('migrations'),
], self::PACKAGE_NAME.'-migrations');
// 注册前端资源发布
$this->publishes([
__DIR__.'/../resources/assets' => public_path('vendor/'.self::PACKAGE_NAME),
], self::PACKAGE_NAME.'-assets');
// 注册视图文件发布
$this->publishes([
__DIR__.'/../resources/views' => resource_path('views/vendor/'.self::PACKAGE_NAME),
], self::PACKAGE_NAME.'-views');
// 加载路由
$this->loadRoutesFrom(__DIR__.'/../routes/web.php');
// 加载视图
$this->loadViewsFrom(__DIR__.'/../resources/views', self::PACKAGE_NAME);
// 加载数据库迁移
$this->loadMigrationsFrom(__DIR__.'/../database/migrations');
// 加载语言文件
$this->loadTranslationsFrom(__DIR__.'/../resources/lang', self::PACKAGE_NAME);
// 加载Blade组件
$this->loadViewComponentsAs(self::PACKAGE_NAME, [
AlertComponent::class,
]);
// 注册中间件
$this->app['router']->aliasMiddleware('package', PackageMiddleware::class);
// 注册Blade指令
Blade::directive('package', function ($expression) {
return "<?php echo app('".self::PACKAGE_NAME."')->render($expression); ?>";
});
// 注册控制台命令
if ($this->app->runningInConsole()) {
$this->commands([
InstallCommand::class,
PublishCommand::class,
]);
}
}
}
完整文件结构模板
package-name/
├── config/ # 配置文件
│ └── package-name.php # 主配置文件
├── database/ # 数据库相关
│ ├── factories/ # 模型工厂
│ ├── migrations/ # 迁移文件
│ └── seeders/ # 数据填充
├── resources/ # 前端资源
│ ├── assets/ # 原始资源 (JS/CSS)
│ ├── lang/ # 多语言文件
│ │ └── en/ # 英语翻译
│ │ └── messages.php
│ └── views/ # 视图模板
│ ├── components/ # Blade组件
│ │ └── alert.blade.php
│ └── layouts/ # 布局文件
│ └── master.blade.php
├── routes/ # 路由定义
│ └── web.php # Web路由
├── src/ # 核心代码
│ ├── Console/ # 命令行
│ │ ├── InstallCommand.php # 安装命令
│ │ └── PublishCommand.php # 发布命令
│ ├── Contracts/ # 接口契约
│ │ └── PackageInterface.php # 包接口
│ ├── Exceptions/ # 异常处理
│ │ └── PackageException.php # 自定义异常
│ ├── Facades/ # 门面类
│ │ └── PackageFacade.php
│ ├── Http/ # HTTP相关
│ │ ├── Controllers/ # 控制器
│ │ │ └── PackageController.php
│ │ └── Middleware/ # 中间件
│ │ └── PackageMiddleware.php
│ ├── Models/ # 数据模型
│ │ └── PackageModel.php
│ ├── Providers/ # 服务提供者
│ │ └── PackageServiceProvider.php
│ ├── Services/ # 业务服务
│ │ └── PackageService.php # 核心逻辑
│ └── View/ # 视图组件
│ └── Components/ # Blade组件类
│ └── AlertComponent.php
├── tests/ # 测试代码
│ ├── Feature/ # 功能测试
│ │ ├── CommandsTest.php # 命令测试
│ │ └── ServiceTest.php # 服务测试
│ ├── Unit/ # 单元测试
│ │ └── PackageTest.php # 包测试
│ ├── TestCase.php # 测试基类
│ └── CreatesApplication.php # 应用创建
├── .gitignore # Git忽略规则
├── composer.json # Composer配置
├── CHANGELOG.md # 变更日志
└── README.md # 项目文档
核心配置文件模板 (config/package-name.php
)
<?php
return [
// API密钥配置(从.env获取)
'api_key' => env('PACKAGE_API_KEY', 'your-default-key'),
// 调试模式
'debug' => env('PACKAGE_DEBUG', false),
// 包选项
'options' => [
// 缓存时间(秒)
'cache_ttl' => 3600,
// 错误日志记录
'log_errors' => true,
// 最大重试次数
'max_retries' => 3,
],
// 路由配置
'routes' => [
// 路由前缀
'prefix' => 'package',
// 中间件
'middleware' => ['web'],
],
// 视图配置
'views' => [
// 默认布局
'layout' => 'package-name::layouts.master',
// 主题
'theme' => 'light',
],
];
模型示例 (src/Models/PackageModel.php
)
<?php
namespace VendorName\PackageName\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use VendorName\PackageName\Database\Factories\PackageModelFactory;
class PackageModel extends Model
{
use HasFactory;
protected $table = 'package_items';
protected $fillable = [
'name',
'status',
'meta',
];
protected $casts = [
'meta' => 'array',
'status' => 'boolean',
];
/**
* 模型工厂
*/
protected static function newFactory()
{
return PackageModelFactory::new();
}
/**
* 作用域:激活状态
*/
public function scopeActive($query)
{
return $query->where('status', true);
}
/**
* 加密敏感数据
*/
public function setApiKeyAttribute($value)
{
$this->attributes['api_key'] = encrypt($value);
}
/**
* 解密敏感数据
*/
public function getApiKeyAttribute($value)
{
try {
return decrypt($value);
} catch (\Exception $e) {
return null;
}
}
}
控制台命令示例 (src/Console/InstallCommand.php
)
<?php
namespace VendorName\PackageName\Console;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
class InstallCommand extends Command
{
protected $signature = 'package-name:install';
protected $description = 'Install the package and publish necessary resources';
public function handle()
{
$this->info('Installing Package Name...');
// 发布配置文件
$this->call('vendor:publish', [
'--provider' => 'VendorName\PackageName\PackageServiceProvider',
'--tag' => 'package-name-config',
'--force' => true
]);
// 发布前端资源
$this->call('vendor:publish', [
'--provider' => 'VendorName\PackageName\PackageServiceProvider',
'--tag' => 'package-name-assets',
'--force' => true
]);
// 运行数据库迁移
if ($this->confirm('Run database migrations?', true)) {
$this->call('migrate');
}
// 添加路由
$this->addRoutes();
$this->info('Package installed successfully!');
}
protected function addRoutes()
{
$routeContent = File::get(base_path('routes/web.php'));
if (!str_contains($routeContent, 'PackageName')) {
File::append(base_path('routes/web.php'), "\n\n// PackageName Routes\nRoute::package('package-name');\n");
$this->info('Routes added successfully.');
} else {
$this->line('Routes already exist.');
}
}
}
最佳实践建议
1. 版本兼容策略
在 composer.json
中明确定义兼容性:
{
"require": {
"php": "^8.1",
"laravel/framework": "^9.0|^10.0"
},
"require-dev": {
"orchestra/testbench": "^7.0|^8.0",
"phpunit/phpunit": "^9.5|^10.0"
}
}
2. 测试覆盖率策略
创建 PHPUnit 配置文件:
<!-- phpunit.xml.dist -->
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true">
<coverage>
<include>
<directory suffix=".php">src</directory>
</include>
<report>
<html outputDirectory="build/coverage"/>
<text outputFile="build/coverage.txt"/>
</report>
</coverage>
<testsuites>
<testsuite name="Package Tests">
<directory>tests</directory>
</testsuite>
</testsuites>
<php>
<env name="APP_ENV" value="testing"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
</php>
</phpunit>
3. 持续集成配置 (.github/workflows/ci.yml)
name: CI
on: [push, pull_request]
jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
php: [8.1, 8.2]
laravel: [9.*, 10.*]
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mbstring, dom, fileinfo, curl
coverage: xdebug
- name: Install dependencies
run: |
composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update
composer install --prefer-dist --no-interaction
- name: Run tests with coverage
run: vendor/bin/phpunit --coverage-clover build/logs/clover.xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: build/logs/clover.xml
flags: unittests
发布流程
- 版本标记
git tag -a v1.0.0 -m "Initial release"
git push origin --tags
-
Packagist 发布
- 将代码推送到 GitHub/GitLab
- 在 Packagist 提交仓库 URL
- 启用自动更新
-
文档更新
在 README.md 中包含:- 安装说明
- 配置指南
- 使用示例
- 进阶功能
- 常见问题
此模板为 Laravel 扩展包开发提供了完整的起点,包含了现代化扩展包所需的所有组件和实践。您可以根据具体需求调整各个部分,快速构建高质量的 Laravel 扩展包。