mpoiriert/business-rule-engine

dev-master 2014-03-27 12:31 UTC

This package is auto-updated.

Last update: 2024-09-09 13:16:49 UTC


README

Build Status

实现规范模式的引擎

要使用业务引擎,您需要实例化一个IBusinessRuleEngine类并将其分配给一个IRuleProvider。IRuleProvider负责根据名称提供规则。规则只是一个附加名称的可调用对象。

$businessRuleEngine = new \Nucleus\BusinessRuleEngine\BusinessRuleEngine();

$ruleProvider = new \Nucleus\BusinessRuleEngine\InMemoryRuleProvider();

$businessRuleEngine->setRuleProvider($ruleProvider);

$ruleProvider->setRule('ruleTrue',function(){ return true; });
$ruleProvider->setRule('ruleFalse',function(){ return false; });

将规则实现为一个只关注此的类的一个简单方法就是使用__invoke魔术方法。

从那里,您可以使用规则规范调用业务规则引擎的方法

$businessRuleEngine->check("ruleTrue");//true
$businessRuleEngine->check("ruleFalse");//false

$result = $businessRuleEngine->getFirstMatch(
  array(
    "check1" => "ruleFalse",
    "check2" => "ruleTrue",
  )
);

echo $result;//check2

$result = $businessRuleEngine->getFirstMatch(
  array(
    "check1" => "ruleFalse",
    "check2" => "ruleTrue",
    "check3" => "ruleTrue",
  )
);

var_export($result);// array('check2','check3')

规则规范

规则规范是规则名称和Yaml中默认参数的字符串连接。如果您想调用规则toto,默认参数param1 = 1,param2 = array(1,2),它将看起来像这样

"toto{param1:1,param2[1,2]}"

如果您想在规则前添加一个!,使其变为false,那么您不需要向规则传递参数来表示不匹配

"!toto{param1:1,param2[1,2]}"

如果您想检查2个或更多规则必须验证,您可以传递一个规则数组

array("toto{param1:1,param2[1,2]}","!toto{param1:1,param2[1,2]}")

显然,前面的示例将不会通过,因为我们使用了相同的规则,在第二个测试中有一个not (!)。这将导致(true && !true)或(false && !false)评估。

如果您想进行OR检查,可以将此放入第二个数组中

array(array("toto{param1:1,param2[1,2]}","!toto{param1:1,param2[1,2]}"))

在这种情况下,最终结果总是返回true,因为评估将是((true || !true)或((false || !false)))

您可以混合这些

array(rule1{},array(rule2{},rule3{}))

这将导致($rule1Result && ($rule2Result || $rule3Result))

该系统灵感来源于Symfony 1凭证检查https://symfony.com.cn/legacy/doc/reference/1_4/en/08-Security和规范模式http://en.wikipedia.org/wiki/Specification_pattern

查看单元测试以获取更多使用示例。

实际应用

以下是一些实际应用中的示例。此库中不提供规则的类实现,该库只是引擎本身。

安全性

检查基于可以提供权限列表的对象的一些复杂权限规则

$businessRuleEngine->check(array("permission{name:user}","!permission{name:newUser}"),array($user));//user && !newUser

$businessRuleEngine->check(array(array("permission{name:admin}","permission{name:moderator}")),array($user));// admin || moderator

支付方式

根据某些订单属性检查要提供的支付方式

$paymentMethodName = $businessRuleEngine->getFirstMatch(
    array(
        "cheapCharge" => array("orderCountry{countries:[CA,US]}","maxOrderPrice{max:9.99}"),
        "digitalProduct" => array("!orderContainPhysical"),
        "fallback" => array()
    ),
    $order
)

扑克牌游戏

基于具有最大价值的牌手。这不是完整的,但展示了其可能的用途

$rules = array(
    array("cardsValues{values:[10,11,12,13,A]}","cardsSameColor"),
    array("cardsStraight","cardsSameColor"),
    array("cardsSameValue{amountOfCards:[4]}"),
    array("cardsSameValue{amountOfCards:[3,2]"),
    array("cardsSameColor"),
    array("cardsStraight"),
    array("cardsSameValue{amountOfCards:[3]"),
    array("cardsSameValue{amountOfCards:[2,2]"),
    array("cardsSameValue{amountOfCards:[2]"),
    array(),
);

$positionHand1 = $businessRuleEngine->getFirstMatch($rules,$hand1);
$positionHand2 = $businessRuleEngine->getFirstMatch($rules,$hand2);

if($positionHand1 == $positionHand2) {
    if($businessRuleEngine->check('firstHandHighestCardValue',array('hand1'=>$hand1,'hand2'=>$hand2))) {
        $winner = 'hand1';
    } else {
        $winner = 'hand2';
    }
} else {
    $winner = $positionHand1 < $positionHand2 ? 'hand1' : 'hand2';
}

促销显示

如果您根据用户显示促销。完全是虚构的规则...

$businessRuleEngine->check(
   array('lastTransaction{delay: - 1 months}','lastVisit{delay: -5 days}',array('totalPurchaseLessThan{amount:20.95}','fromCountry{countries[CA,US]}')),
   $user
);

这意味着如果

用户的最后交易在1个月前完成

AND

用户的最后访问在5天前完成

AND

(用户的总购买少于20.95美元)

OR

来自国家列表中的CA和US)