zaengle / pipeline
在 Laravel Pipelines 之上的便捷功能
Requires
- php: ^8.1|^8.2|^8.3
- illuminate/console: 8.*|9.*|10.*|11.*
- illuminate/support: 8.*|9.*|10.*|11.*
Requires (Dev)
- mockery/mockery: >=0.9.9
- orchestra/testbench: ~8.0
- phpunit/phpunit: >=4.1
README
Zaengle Pipeline
在项目中使用 Laravel Pipelines 来处理复杂的数据流后,我们注意到一些模式出现
- 数据库事务
- 管道接口
- 响应和异常处理
这个包在 Laravel Pipeline 上增加了便捷功能,并将它们整合到一个可重用的位置。
注意 - 更多详细示例请参阅 "示例" 目录。
安装
composer require zaengle/pipeline
测试
phpunit
基本类示例
管道是将数据、逻辑和响应/异常拆分为三个独立元素的一种常见模式。 Zaengle Pipeline 将这些部分抽象为有用的类,并为底层模式提供了一些结构。例如,让我们探索一下虚构的用户注册的管道可能是什么样子
<?php use App\RegisterTraveler; use App\Pipes\CreateUser; use App\Pipes\HandleMailingList; use Zaengle\Pipeline\Pipeline; class FicticiousRegisterController { public function __invoke() { $traveler = (new RegisterTraveler())->setRequest(request()->all()); $pipes = [ CreateUser::class, HandleMailingList::class, // any other items that need to happen during registration... ]; $response = app(Pipeline::class)->pipe($traveler, $pipes, $useTransactions = true); if ($response->passed()) { return response()->json('Welcome!'); } else { return response()->json('Your registration failed with the following error: ' . $response->getMessage()); } } }
分解
创建旅行者
使用 Zaengle Pipeline 的第一步是创建一个数据旅行者类。 注意:以下示例中使用的 setRequest()
方法是人为设计的。
$traveler = (new RegisterTraveler())->setRequest(request()->all());
Zaengle\Pipeline\Contracts\AbstractTraveler
为 Zaengle\Pipeline\Pipeline
类提供了额外的用于方法。
<?php use Zaengle\Pipeline\Contracts\AbstractTraveler; class RegisterTraveler extends AbstractTraveler { }
在 $traveler
中可以设置任何所需的数据,并且它将在任何管道中可用。
<?php use Zaengle\Pipeline\Contracts\AbstractTraveler; class RegisterTraveler extends AbstractTraveler { private $request; private $user; // custom methods public function setRequest($request) { $this->request = $request; return $this; } public function getRequest() { return $this->request; } public function setUser($user) { $this->user = $user; return $this; } public function getUser() { return $this->user; } }
管道
将业务逻辑分离到合适的 "管道" 中,每个管道都应该实现 Zaengle\Pipeline\Contracts\PipeInterface
。
<?php use App\User; use Zaengle\Pipeline\Contracts\PipeInterface; class CreateUser implements PipeInterface { public function handle(RegisterTraveler|AbstractTraveler $traveler, \Closure $next): RegisterTraveler { $traveler->setUser( User::create([ 'email' => $traveler->getRequest()->email, 'password' => $traveler()->getRequest()->password, ]) ); return $next($traveler); } }
<?php use App\MailingService; use Zaengle\Pipeline\Contracts\PipeInterface; class HandleMailingList implements PipeInterface { public function handle(RegisterTraveler|AbstractTraveler $traveler, \Closure $next): RegisterTraveler { if ($traveler->getRequest()->subscribe) { MailingService::subscribe($traveler->getUser()->email); $traveler->getUser()->update([ 'subscriber' => true, ]); } return $next($traveler); } }
主管道
一旦你有了数据和管道,就可以通过 Zaengle\Pipeline\Pipeline
的 ->pipe()
方法发送它们。
pipe()
接受三个参数,其中两个是必需的。第一个参数应该是你的 $traveler
,第二个是管道数组,第三个是可选参数,告诉 Pipeline
是否使用事务。
// use Zaengle\Pipeline\Pipeline; $response = app(Pipeline::class)->pipe($traveler, $pipes, $useTransactions = true);
结果
将 $traveler
通过数据管道发送后,你可以访问一个 ->passed()
方法,该方法指示管道是否成功完成。
$response = app(Pipeline::class)->pipe($traveler, $pipes, $useTransactions = true); if ($response->passed()) { // Handle pass dump($response->getMessage()); } else { // Handle fail // $response->getException(); // $response->getMessage(); // $response->getStatus(); }
AbstractTraveler
允许你访问以下便捷方法
$response->passed()
一个布尔值,指示旅行者是否成功通过所有管道而没有任何异常。
$response->getStatus()
你可以使用 ->setStatus()
设置的字符串,或者自动设置为 'ok' 或 'fail'。
$response->getException()
要终止过程,你可以抛出一个异常,管道将在响应中捕获它。它还将设置状态和信息,让你可以访问 $response->getMessage()
。
$response->setMessage()
在异常情况下,将自动设置 $message
属性。否则,你可以在管道执行的任何时刻设置它。
$response->getMessage()
管道完成后可用的字符串。
测试策略
测试管道时,应该测试整体管道,以确保给定的输入与预期输出相匹配。
<?php use TestCase; class FicticiousRegistrationTest extends TestCase { /** @test */ public function it_registers_a_user() { $userStub = factory(User::class)->make(); $response = $this->postJson('ficticious-endpoint', [ 'email' => $userStub->email, 'password' => 'password', 'subscribe' => true, ]); $response->assertJsonFragment('Welcome!'); $this->assertDatabaseHas('users', [ 'email' => $userStub->email, 'subscribed' => true, ]); } }
你还可以测试单个管道,例如这样
<?php use TestCase; use App\User; use App\RegisterTraveler; use App\Pipes\CreateUser; class CreateUserTest extends TestCase { /** @test */ public function it_creates_a_user() { $traveler = (new RegisterTraveler)->setRequest(['email' => 'test', 'password' => 'password']); (new CreateUser)->handle($traveler, function () {}); $this->assertInstanceOf(User::class, $traveler->getUser()); } }
许可
MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件。