uuf6429/rune

PHP 规则引擎。

3.0-RC1 2023-10-28 17:52 UTC

README

Build Status Latest Stable Version Latest Unstable Version PHP Version Require License Coverage Reliability Rating

Rune - PHP Rule Engine 工具包。

这个库是实现 业务规则引擎(一种业务流程自动化软件)的。

目录

安装

推荐且最简单的安装 Rune 的方式是通过 Composer

composer require uuf6429/rune

架构

该库由以下主要部分组成

  • 规则(实现 Rule\RuleInterface) - 表示业务规则的对象。对于大多数用例,可以使用 Rule\GenericRule。每个规则必须有一个唯一的 id、描述性名称、条件(作为一个返回 truefalse 的表达式)和当条件满足时触发的操作(见下文)。
  • 操作(实现 Action\ActionInterface) - 当相关规则被触发时执行某些操作的对象。一般来说,操作可以被多个规则重用。例如,如果您在产品销售中使用规则引擎,则操作可能会在满足某些条件时自动向账单添加费用(例如,针对特定配送国家的费用,或针对折扣的负费用)。
  • 上下文(实现 Context\ContextInterface) - 为规则引擎和操作提供数据以进行工作的对象。这可以被视为当前情况所有可用数据的一个集合。例如,当当前情况是关于用户购买产品时,您将拥有有关用户、产品、优惠的数据,也许还有时间、地区等高级信息。几乎总是需要实现自己的上下文,因为这总是取决于您的(业务)场景。
  • RuleEngine - 实质上,连接其他部分以使其工作的对象。

使用方法

可以在 uuf6429/rune-examples 找到各种示例。

实时示例

示例代码

以下代码是 Rune 可以如何使用的非常简单的示例。它定义了一个模型(Product)、上下文(ProductContext),并使用 CallbackAction 打印出已触发的规则。

namespace MyApplication;

use uuf6429\Rune\Action\CallbackAction;
use uuf6429\Rune\Context\ClassContext;
use uuf6429\Rune\Engine;
use uuf6429\Rune\Rule\GenericRule;
use uuf6429\Rune\Rule\RuleInterface;

// A class whose instances will be available inside the rule engine.
class Product
{
    public function __construct(
        public readonly string $name,
        public readonly string $colour,
    ) {
    }
}

// A class that represents the rule engine execution context.
// Note that public properties will be available in the rule expressions,
// in this case rules will have access to "product" as a variable (and all of product's public properties).
class ProductContext extends ClassContext
{
    public function __construct(
        public readonly Product $product
    ) {
    }
}

// Declare an action to be triggered when a rule matches against a product.
$action = new CallbackAction(
    static fn ($eval, ProductContext $context, RuleInterface $rule) => printf(
        "Rule %s triggered for %s %s\n",
        $rule->getId(),
        ucwords($context->product->colour),
        $context->product->name
    )
);

// Declare some sample rules.
$rules = [
    new GenericRule(1, 'Red Products', 'product.colour == "red"', $action),
    new GenericRule(2, 'Red Socks', 'product.colour == "red" and product.name matches "/socks/i"', $action),
    new GenericRule(3, 'Green Socks', 'product.colour == "green" and product.name matches "/socks/i"', $action),
    new GenericRule(4, 'Socks', 'product.name matches "/socks/" > 0', $action),
];

// Declare available products (to run rules against).
$products = [
    new Product('Bricks', 'red'),
    new Product('Soft Socks', 'green'),
    new Product('Sporty Socks', 'yellow'),
];

// Create rule engine.
$engine = new Engine();

// Run rules for each product. Note that each product should exist in a separate context.
foreach ($products as $product) {
    $engine->execute(new ProductContext($product), $rules);
}