Laravel 扩展包开发模板

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

发布流程

  1. 版本标记
git tag -a v1.0.0 -m "Initial release"
git push origin --tags
  1. Packagist 发布

    1. 将代码推送到 GitHub/GitLab
    2. 在 Packagist 提交仓库 URL
    3. 启用自动更新
  2. 文档更新
    在 README.md 中包含:

    • 安装说明
    • 配置指南
    • 使用示例
    • 进阶功能
    • 常见问题

此模板为 Laravel 扩展包开发提供了完整的起点,包含了现代化扩展包所需的所有组件和实践。您可以根据具体需求调整各个部分,快速构建高质量的 Laravel 扩展包。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值