jose-chan/laravel-pipeline

A pipeline framework for laravel

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/jose-chan/laravel-pipeline

v1.0.0 2025-11-09 09:05 UTC

This package is auto-updated.

Last update: 2025-11-09 09:13:25 UTC


README

概述

PipeService 是一个基于 Laravel Pipeline 模式的可插拔管道服务框架。它提供了一套标准化的业务处理流程,支持参数映射、数据校验、异常处理等功能,特别适用于复杂业务流程的模块化处理。

核心架构

1. 架构组件图

PipeService
├── Facades/
│   └── PipeRoute.php              # Facade 门面类
├── Factories/
│   └── PipeHandlerFactory.php     # 管道处理器工厂
├── Pipes/
│   ├── PipeInterface.php          # 管道接口
│   └── AbstractPipe.php           # 抽象管道基类
├── Mappers/
│   ├── MapperInterface.php        # 映射器接口
│   └── AdvancedMapper.php         # 高级映射器
├── ExceptionHandlers/
│   └── ExceptionHandlerInterface.php # 异常处理器接口
├── Exceptions/
│   ├── MapException.php           # 映射异常
│   ├── EntityValidateException.php # 实体校验异常
│   └── MapValidateException.php   # 映射校验异常
├── PipeRouteManager.php           # 管道路由管理器
├── RequestManager.php             # 请求管理器
└── RequestManagerServiceProvider.php # 服务提供者

2. 核心概念

  • 管道线路 (Pipeline Line): 一系列按顺序执行的管道组合
  • 管道 (Pipe): 单个业务处理单元
  • 请求管理器 (RequestManager): 管理请求生命周期和依赖容器
  • 处理器工厂 (PipeHandlerFactory): 管理各种处理器的创建和调用

优化改进

版本更新记录

  • ✅ 修复了服务提供者继承错误(Carbon\Laravel\ServiceProvider → Illuminate\Support\ServiceProvider)
  • ✅ 增强了映射逻辑功能,支持高级映射语法
  • ✅ 兼容 PHP 7.3.3 语法要求

详细组件说明

安装

php artisan vendor:publish --provider=JoseChan\\Pipeline\\Framework\\RequestManagerServiceProvider

1. PipeRoute Facade (app/Services/PipeService/Facades/PipeRoute.php:15)

提供便捷的静态方法调用接口:

/**
 * @method static line(string $name, \Closure $group)
 * @method static pipe($pipe, $mapValidate = null, $mapper = null, $entityValidate = null, $mapExceptionHandler = null, $entityExceptionHandler = null)
 * @method static through(string $lineName, $requestManager)
 */
class PipeRoute extends Facade

2. PipeRouteManager 管道路由管理器

核心方法

line() - 定义管道线路 (app/Services/PipeService/PipeRouteManager.php:35)
public function line(string $name, \Closure $group)

功能: 定义一个命名的管道线路 参数:

  • $name: 线路名称,必须唯一
  • $group: 闭包函数,在其中定义管道

注意事项:

  • 不支持嵌套定义,如果已有活跃的线路定义会抛出 RuntimeException
  • 线路定义期间,$groupStack 会被设置为当前线路名
pipe() - 定义管道 (app/Services/PipeService/PipeRouteManager.php:57)
public function pipe($pipe, $mapValidate = null, $mapper = null, $entityValidate = null, $mapExceptionHandler = null, $entityExceptionHandler = null)

功能: 在当前线路中添加一个管道 参数详解:

  1. $pipe: 管道类名,必须实现 PipeInterface
  2. $mapValidate: 映射参数校验规则
  3. $mapper: 参数映射逻辑
  4. $entityValidate: 实体校验规则
  5. $mapExceptionHandler: 映射异常处理器
  6. $entityExceptionHandler: 实体异常处理器
through() - 执行管道线路 (app/Services/PipeService/PipeRouteManager.php:80)
public function through(string $lineName, $requestManager)

功能: 执行指定的管道线路 参数:

  • $lineName: 要执行的线路名称
  • $requestManager: RequestManager 实例

3. RequestManager 请求管理器

核心功能 (app/Services/PipeService/RequestManager.php:13)

  • 请求生命周期管理: 为每个请求生成唯一ID
  • 依赖注入容器: 管理请求范围内的对象实例
  • 实体工厂集成: 自动配置实体创建和验证

关键方法

public function __construct($request, Application $application)
public function getContainer()  // 获取依赖容器
public function getRequestId(): string  // 获取请求ID

容器初始化逻辑 (app/Services/PipeService/RequestManager.php:29)

// 生成唯一请求ID并创建专属容器
$this->container = $this->application->instance($this->makeRequestId(), new Container());
// 注入原始请求对象
$this->container->instance("input", $this->request);
// 绑定实体工厂
$this->container->bind(IEntityFactory::class, ContainerEntityFactory::class, true);

4. AbstractPipe 抽象管道基类

处理流程 (app/Services/PipeService/Pipes/AbstractPipe.php:32)

public function handle($requestManager, Closure $next)
{
    // 1. 校验是否需要处理
    if (!$this->verification($requestManager)) {
        return $next($requestManager);
    }

    try {
        // 2. 映射参数前处理钩子
        $this->beforeMap($requestManager);
        // 3. 映射参数校验
        $this->mapValidate($requestManager);
        // 4. 映射参数
        $params = $this->map($requestManager);
        // 5. 映射参数后处理钩子
        $this->afterMap($requestManager);
        // 6. 获取实体
        $entity = $this->getEntity($params);
        // 7. 实体校验
        $this->validateEntity($entity);
        // 8. 注册实体到容器
        $requestManager->getContainer()->instance($this->abstractName($entity), $entity);
        // 9. 成功回调
        $this->success($requestManager);
    } catch (Throwable $e) {
        // 10. 失败处理
        $this->fails($requestManager, $e);
    }

    // 11. 继续下一个管道
    return $next($requestManager);
}

必须实现的抽象方法

abstract protected function verification($requestManager): bool;  // 校验是否需要处理
abstract protected function getEntity($params);  // 获取实体对象

可选重写的方法

protected function beforeMap($requestManager) {}  // 映射前钩子
protected function afterMap($requestManager) {}   // 映射后钩子
protected function success($requestManager) {}    // 成功回调
protected function fails($requestManager, Throwable $throwable) {}  // 失败处理

参数映射逻辑 (app/Services/PipeService/Pipes/AbstractPipe.php:137)

protected function map($requestManager)
{
    $mapper = $this->mapper();  // 获取映射配置
    if (empty($mapper) || !is_array($mapper)) {
        return [];
    }
    
    return collect($mapper)->flatMap(function ($to, $from) use ($requestManager) {
        list($entry, $field) = explode(".", $from);
        /** @var Entity $entryObject */
        $entryObject = $requestManager->getContainer()->get($entry);
        return [$to => Arr::get($entryObject->toArray(), $field)];
    })->toArray();
}

映射格式: "source.field" => "target_field"

  • source: 容器中的对象名称
  • field: 对象中的字段名
  • target_field: 映射后的字段名

高级映射支持 (需要在管道中启用 useAdvancedMapping()):

  • "object.field[0]" - 数组索引访问
  • "object.field.nested.deep" - 深层嵌套访问
  • "object.field|default_value" - 默认值支持
  • "?object.field" - 可选字段(不存在时跳过)

5. AdvancedMapper 高级映射器

新增的高级映射器提供了更强大的映射功能:

核心功能

use App\Services\PipeService\Mappers\AdvancedMapper;

$mapper = new AdvancedMapper($requestManager);
支持的映射语法
  1. 基础映射:

    ['input.name' => 'customer_name']
  2. 数组索引:

    ['input.items[0].price' => 'first_item_price']
  3. 深层嵌套:

    ['user.profile.address.city' => 'city']
  4. 默认值:

    ['input.currency|USD' => 'currency_code']
  5. 可选字段:

    ['?input.optional_field' => 'optional_data']
  6. 嵌套目标:

    ['input.name' => 'customer.profile.name']
条件映射
$result = $mapper->conditionalMap(
    'input.type=premium',  // 条件
    ['input.amount' => 'premium_amount'],  // 真值映射
    ['input.amount' => 'regular_amount']   // 假值映射
);

支持的条件操作符:=, !=, >, <, >=, <=, ?(存在性检查)

数组批量映射
$result = $mapper->mapArray(
    'input.items',  // 源数组
    [               // 每个元素的映射规则
        '$item.name' => 'product_name',
        '$item.price' => 'amount'
    ],
    'products'      // 目标键名
);

在管道中使用高级映射

class MyPipe extends AbstractPipe
{
    protected function useAdvancedMapping(): bool
    {
        return true;  // 启用高级映射
    }
    
    // 其他方法...
}

6. PipeHandlerFactory 处理器工厂

处理器类型常量 (app/Services/PipeService/Factories/PipeHandlerFactory.php:13-17)

public const HANDLER_MAP_VALIDATE = 'mapValidate';        // 映射校验
public const HANDLER_MAPPER = 'mapper';                   // 参数映射
public const HANDLER_ENTITY_VALIDATE = 'entityValidate'; // 实体校验
public const HANDLER_MAP_EXCEPTION = 'mapExceptionHandler';     // 映射异常处理
public const HANDLER_ENTITY_EXCEPTION = 'entityExceptionHandler'; // 实体异常处理

支持的处理器定义格式

  1. 类名字符串:

    'App\Services\SomeService\Mapper::class'
  2. 类@方法格式:

    'SomeMapper@customMethod'
  3. 闭包函数:

    function ($requestManager) { return ['field' => 'required']; }
  4. 带参数的类数组:

    [App\Services\SomeService\Mapper::class => ["param1" => "value1"]]

核心方法

public function addHandler($pipe, $handler)  // 添加处理器
public function getHandler($pipe, $handlerType)  // 获取处理器
public function call($pipe, $handlerType, ...$args)  // 调用处理器

6. 异常处理

MapException (app/Services/PipeService/Exceptions/MapException.php:5)

  • 继承自 Exception
  • 用于参数映射过程中的异常

EntityValidateException (app/Services/PipeService/Exceptions/EntityValidateException.php:5)

  • 继承自 Exception
  • 包含验证失败的详细信息
  • 提供 getFailed() 方法获取失败详情
public function __construct($message = "", $code = 0, array $failed, \Throwable $previous = null)
public function getFailed(): array  // 获取验证失败的字段信息

完整使用示例

1. 服务提供者注册

config/app.php 中注册服务提供者:

'providers' => [
    // ...
    App\Services\PipeService\RequestManagerServiceProvider::class,
],

2. 定义管道线路

piperoute/piperoute.php 中定义:

use App\Services\PipeService\Facades\PipeRoute;

PipeRoute::line("order.process", function () {
    
    // 基础管道 - 只有管道类
    PipeRoute::pipe(ValidateOrderPipe::class);
    
    // 完整配置管道
    PipeRoute::pipe(
        GetCurrencyPipe::class,
        null,                                    // 映射校验(不校验)
        GetCurrencyMapper::class,                // 参数映射器
        CurrencyEntity::class,                   // 实体校验
        CurrencyMapExceptionHandler::class,      // 映射异常处理
        CurrencyEntityExceptionHandler::class    // 实体异常处理
    );
    
    // 使用闭包的管道
    PipeRoute::pipe(
        CalculatePricePipe::class,
        function($requestManager) {              // 映射校验闭包
            return ['amount' => 'required|numeric|min:0'];
        },
        function($requestManager) {              // 映射闭包
            $input = $requestManager->getContainer()->get('input');
            return ['amount' => $input->get('total_amount')];
        }
    );
});

3. 创建自定义管道

use App\Services\PipeService\Pipes\AbstractPipe;
use App\Services\PipeService\RequestManager;

class GetCurrencyPipe extends AbstractPipe
{
    /**
     * 校验是否需要处理此管道
     */
    protected function verification($requestManager): bool
    {
        $input = $requestManager->getContainer()->get('input');
        return $input->has('currency_code');
    }

    /**
     * 获取实体对象
     */
    protected function getEntity($params)
    {
        return new CurrencyEntity($params);
    }

    /**
     * 映射前处理
     */
    protected function beforeMap($requestManager)
    {
        // 可以进行一些预处理
        Log::info('开始处理货币信息');
    }

    /**
     * 成功回调
     */
    protected function success($requestManager)
    {
        Log::info('货币处理成功');
    }

    /**
     * 实体校验规则(如果不使用外部校验器)
     */
    protected function entityRule()
    {
        return [
            'code' => 'required|string|size:3',
            'rate' => 'required|numeric|min:0'
        ];
    }

    /**
     * 校验错误消息
     */
    protected function entityMessage()
    {
        return [
            'code.required' => '货币代码不能为空',
            'rate.numeric' => '汇率必须为数字'
        ];
    }
}

4. 创建映射器

use App\Services\PipeService\Mappers\MapperInterface;

class GetCurrencyMapper implements MapperInterface
{
    public function map()
    {
        return [
            'input.currency_code' => 'code',  // input对象的currency_code字段映射到code
            'input.exchange_rate' => 'rate',  // input对象的exchange_rate字段映射到rate
        ];
    }
}

5. 创建异常处理器

use App\Services\PipeService\ExceptionHandlers\ExceptionHandlerInterface;
use App\Services\PipeService\RequestManager;

class CurrencyExceptionHandler implements ExceptionHandlerInterface
{
    public function handle(RequestManager $requestManager, \Throwable $e)
    {
        Log::error('货币处理异常', [
            'request_id' => $requestManager->getRequestId(),
            'error' => $e->getMessage()
        ]);
        
        // 可以设置默认值或者重新抛出异常
        // throw new CustomException('货币处理失败');
    }
}

6. 控制器中使用

use App\Services\PipeService\Facades\PipeRoute;
use App\Services\PipeService\RequestManager;
use Illuminate\Http\Request;

class OrderController extends Controller
{
    public function store(Request $request)
    {
        // 创建请求管理器
        $requestManager = new RequestManager($request, app());
        
        try {
            // 执行管道线路
            PipeRoute::through('order.process', $requestManager);
            
            // 从容器中获取处理结果
            $currency = $requestManager->getContainer()->get(CurrencyEntity::class);
            $orderData = $requestManager->getContainer()->get(OrderEntity::class);
            
            // 业务逻辑处理
            $order = Order::create($orderData->toArray());
            
            return response()->json(['success' => true, 'order_id' => $order->id]);
            
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 400);
        }
    }
}

高级用法

1. 条件处理器

PipeRoute::pipe(
    ConditionalPipe::class,
    function($requestManager) {
        // 动态校验规则
        $input = $requestManager->getContainer()->get('input');
        if ($input->get('type') === 'premium') {
            return ['amount' => 'required|numeric|min:100'];
        }
        return ['amount' => 'required|numeric|min:1'];
    }
);

2. 带参数的处理器

PipeRoute::pipe(
    NotificationPipe::class,
    null,
    [NotificationMapper::class => ['channel' => 'email', 'template' => 'order']]
);

3. 复杂映射逻辑

class ComplexMapper implements MapperInterface
{
    public function map()
    {
        return [
            'user.profile.email' => 'customer_email',
            'user.profile.name' => 'customer_name', 
            'order.items.0.price' => 'first_item_price',
        ];
    }
}

4. 异常恢复机制

class RecoveryExceptionHandler implements ExceptionHandlerInterface
{
    public function handle(RequestManager $requestManager, \Throwable $e)
    {
        if ($e instanceof CurrencyNotFoundException) {
            // 设置默认货币
            $defaultCurrency = new CurrencyEntity(['code' => 'USD', 'rate' => 1.0]);
            $requestManager->getContainer()->instance(CurrencyEntity::class, $defaultCurrency);
            return; // 不重新抛出异常,使用默认值继续处理
        }
        
        throw $e; // 其他异常继续抛出
    }
}

最佳实践

1. 管道设计原则

  • 单一职责: 每个管道只负责一个具体的业务逻辑
  • 无副作用: 管道处理应该是幂等的,多次执行结果一致
  • 容错性: 合理处理异常情况,避免整个流程崩溃

2. 性能优化

  • 延迟加载: 在 verification() 中进行轻量级检查
  • 缓存策略: 对重复计算的结果进行缓存
  • 异步处理: 对非关键路径使用队列异步处理

3. 调试技巧

// 在管道中添加调试信息
protected function beforeMap($requestManager)
{
    Log::debug('Pipeline Debug', [
        'pipe' => static::class,
        'request_id' => $requestManager->getRequestId(),
        'container_bindings' => array_keys($requestManager->getContainer()->getBindings())
    ]);
}

4. 错误处理策略

  • 分层异常: 区分业务异常和系统异常
  • 异常恢复: 对可恢复的异常提供默认值或备选方案
  • 日志记录: 详细记录异常上下文信息

故障排除

常见问题

  1. 管道线路未定义错误

    • 检查 piperoute/piperoute.php 中是否正确定义
    • 确认线路名称拼写正确
  2. 处理器类不存在

    • 检查类的命名空间是否正确
    • 确认类已被正确加载
  3. 映射字段不存在

    • 检查映射配置中的字段路径
    • 确认容器中的对象已正确注册
  4. 验证失败

    • 检查验证规则是否合理
    • 确认输入数据格式正确

调试工具

// 查看请求管理器状态
dd($requestManager->getContainer()->getBindings());

// 查看管道执行流程
PipeRoute::line("debug.test", function() {
    PipeRoute::pipe(DebugPipe::class);
});

扩展开发

自定义处理器工厂

class CustomPipeHandlerFactory extends PipeHandlerFactory
{
    public function getHandlerCaller($pipe, $handlerType)
    {
        // 添加自定义处理器解析逻辑
        if ($handlerType === 'custom_handler') {
            // 自定义逻辑
        }
        
        return parent::getHandlerCaller($pipe, $handlerType);
    }
}

自定义异常类型

class BusinessLogicException extends Exception
{
    protected $context;
    
    public function __construct($message, array $context = [])
    {
        $this->context = $context;
        parent::__construct($message);
    }
    
    public function getContext(): array
    {
        return $this->context;
    }
}

版本: 1.1.0
最后更新: 2024年10月
维护者: 开发团队

更新日志

v1.1.0 (2024-10-10)

  • ✅ 修复服务提供者继承错误
  • ✅ 新增 AdvancedMapper 高级映射器
  • ✅ 支持数组索引、嵌套字段、默认值、可选字段等高级映射语法
  • ✅ 支持条件映射和数组批量映射
  • ✅ 兼容 PHP 7.3.3+ 版本
  • ✅ 保持向后兼容性

v1.0.0 (初始版本)

  • 基础管道服务功能
  • 参数映射和验证
  • 异常处理机制

此文档涵盖了 PipeService 包的完整使用方法,从基础概念到高级用法,以及最佳实践和故障排除。如有疑问或建议,请联系开发团队。