matchory / data-pipe
数据处理管道框架
Requires
- php: >8
- dusank/knapsack: ^10.0
- marcj/topsort: ^2.0
- phpunit/phpunit: ^9.5
- psr/event-dispatcher: ^1.0
- symfony/event-dispatcher: ^5.3
Requires (Dev)
- illuminate/contracts: ^8.48
- illuminate/support: ^8.48
- jetbrains/phpstorm-attributes: ^1.0
- symfony/framework-bundle: ^5.3
- vimeo/psalm: ^4.7
README
一个用于在PHP中构建数据丰富管道的具有观点的框架
Data Pipe是一个用于在PHP中创建数据丰富管道的框架。此类应用程序通过获取一些信息,用附加数据丰富它,并通过对其应用转换来增强这些数据来工作。
作为一个更具体的例子,考虑一个客户管道:它获取客户的姓名,检索他们的购物历史和年龄,然后通过从购物历史中删除旧项目并为客户分配目标组来增强记录。
当然,这仅仅描述了一些任意的业务逻辑,Data Pipe可以帮助你用一组可重用、可组合和封装的步骤来描述这个过程!
前言
请注意,此软件包仍在积极开发中,并且尚未准备好在生产环境中使用。我们仍在data-pipe之上构建自己的工作流程,因此一切都将根据1.0版本进行更改。如果您有兴趣塑造这个库的未来,我们非常欢迎您加入!
安装
使用composer将库作为依赖项安装
php composer require matchory/data-pipe
Symfony使用
此软件包包含一个Symfony集成。请阅读说明以开始使用。
集成将为您应用程序添加完全自动的管道配置。
Laravel使用
此软件包包含一个不完整的Laravel集成。请阅读说明以开始使用。
注意:我们尚未实现Laravel支持,因为我们目前不需要它。如果您有兴趣在Laravel应用程序中使用
data-pipe,并且希望像使用Symfony一样自动配置管道,请打开一个问题。
使用
注意:在开始使用Data Pipe之前,您应该熟悉其核心概念。
Data Pipe通过设置具有预先配置的相互依赖节点的管道来工作。目前有两种类型的节点:收集器节点和转换器节点(它们都是通用管道节点的变体)。
节点接收一个有效负载对象,修改并返回它。丰富节点添加新数据,后处理节点转换现有值。这种区别可能看起来无关紧要,但它允许大量的运行时优化。
创建节点
在其最简单的形式中,一个丰富节点可能看起来像这样
use Matchory\DataPipe\Nodes\AbstractCollector as Node; use Matchory\DataPipe\PipelineContext; class MyNode extends Node { public function __construct(protected $yourInternalAgeApi) {} public function pipe(PipelineContext $context): PipelineContext { // Work with the data payload $email = $context->getPayload()->getAttribute('email'); // Perform domain-specific work $age = $this->yourInternalAgeApi->query($email); // Update the payload if ($age) { $context->proposeChange($this, 'age', $age); } return $context; } }
提出更改
请注意,您不能直接更新有效负载:每个节点都只接收实际有效负载的一个副本。相反,您可以提出对有效负载的更改。Data Pipe提供了一个简单的算法来应用最佳拟合更改。这允许为单个属性保留和比较多个值。
创建管道
现在我们有一个节点,让我们创建一个管道来将其添加进去
use Matchory\DataPipe\Payload\Payload; use Matchory\DataPipe\Pipeline; use Symfony\Component\EventDispatcher\EventDispatcher; $nodes = [ new MyNode(), ]; $eventDispatcher = new EventDispatcher(); $pipeline = new Pipeline($nodes, $eventDispatcher); function(): Generator { yield new Payload([ 'email' => 'foo@bar.com' ]); } $pipeline->process(fetchNextPayload());
DI使用
这当然是一个虚构的例子;在现实中,依赖注入容器几乎会为你处理所有事情
use Matchory\DataPipe\Pipeline; class EntryPoint { public function main(Pipeline $pipeline, Generator $recordFetcher): void { foreach ($recordFetcher as $record) { $pipeline->process($recordFetcher); } } }
核心概念
Data Pipe使用几个构建块来构建你的管道。
管道节点
节点是构成管道的阶段。它们可以依赖于之前已执行的其他节点;这些依赖关系将在管道运行之前解决,因此您不需要手动定义顺序。管道处理的每个有效载荷都将被发送到管道中的所有节点,每个节点都有权对数据进行修改。
目前有两种类型的节点
收集器节点
增强记录以添加额外信息的节点称为收集器节点。这些节点可以可选地定义一个成本:它用于按成本对节点进行排序,并确定是否执行额外的节点是否必要。
想象你有两个数据源——你自己的内部数据库和一个按API调用收费的外部系统。数据库节点将比外部API的成本低。现在,如果我们正在寻找一些信息,我们将首先执行“较便宜”的节点(内部数据库),然后,只有在它不能满足我们的要求时,我们也会执行更昂贵的节点。
你拥有的节点越多,细粒度成本的优势就越明显:信息将始终以可能的最便宜方式获取。
转换器节点
转换器节点允许您细化、修改或比较之前收集的信息。这与数据丰富节点不同,因为它们通常在那些节点之后执行。
最佳匹配更改应用
你拥有的数据源越多,你将收集到的信息变体就越多。问题是确定这些变体中的最佳选项——例如,考虑一个电子邮件地址
- dxdtnfa1n5@privaterelay.appleid.com
- foobar@trashmail.to
- john.doe@company.com
- john.doe+yourdomain.tld@gmail.com
- john.doe@gmail.com
根据一些规则,你可能会推断出与你要寻找的内容最接近的变体。现在,为了防止一系列节点相互覆盖结果,它们不是在有效载荷上设置属性,而是可以建议更改。
$context->proposeChange($this, 'attribute_name', 42);
所有节点都可以提出对现有数据的修改,以及一个可选的置信度分数:例如,在电子邮件的例子中,我们可能会有一个垃圾邮件域的灰名单,并分配给该地址一个较低的置信度分数。这里的想法是,如果之后找不到更好的选择,就采用该电子邮件。