dnoegel/rules

使用php嵌套规则

dev-master 2015-02-23 17:09 UTC

This package is auto-updated.

Last update: 2024-09-04 15:25:22 UTC


README

'Rules' 是一个简单的PHP库,允许您检查嵌套逻辑规则。当您需要自动检查用户生成的规则集时,它们可能会很有用。

可用规则

"Rules" 知道两种不同的规则类型。容器(逻辑运算符/连接符)和规则(逻辑运算数)。

容器规则

  • AND
  • OR
  • XOR
  • NOT

规则

  • 比较

为了您自己的使用,您肯定会添加自己的规则,例如 "用户年龄 >= X" 或 "购物车金额 >= Y"。

使用规则

实例化

您可以直接实例化规则并像这样嵌套它们

$rule = new AndRule(
    new TrueRule(),
    new OrRule(
        new FalseRule(),
        new TrueRule()
    ),
    new NotRule(
        new FalseRule()
    )
);

$rule->validate();

这将返回 "true",因为逻辑表达式是真实的。

true AND (false OR true) AND NOT false

RuleBuilder

在许多情况下,您希望从现有的数据结构生成您的逻辑树。为此,您可以使用 RuleBuilder

$builder = new RuleBuilder(new RuleRegistry());

$result = $builder->fromArray(array(
    'and' => array(
        new TrueRule(),
        new TrueRule()
    ),
    'or' => array(
        'false',
        new TrueRule()
    )
));

通过 RuleBuilder 的 fromArray() 方法,您可以将规则作为嵌套数组传递。规则可以通过引用(例如 new TrueRule())或名称(例如 "false")传递。任何子数组都将导致创建一个新的容器规则,其类型为数组键的类型

array(
    'and' => array()
)

将创建一个 AND 容器。上面的调用将生成以下规则

(true AND true) AND (false OR true)

fromArray() 方法有一个可选的第二个参数 "containerType"。默认情况下,这是 AND。因此,第一层的逻辑元素将通过 AND 相连。

自定义规则

您可以非常容易地创建自己的规则。对于容器,您应该实现 "container" 接口,对于简单规则,实现 "rule" 接口。

class UserAgeRule implements Rule
{
    protected $user;
    public function __construct($user)
    {
        $this->user = $user;
    }

    public function validate()
    {
        return $this->user->getAge() >= 21;
    }
}

用法如下

$rule = new AndRule(
    new UserAgeRule($currentUser),
    new SomeOtherRule()
)
$rule->validate();

为了将当前上下文信息传递给您的规则,您应该使用该规则构造函数。

RuleRegistry

如果您希望您的规则由 RuleBuilder 支持,您应该将它们注册到 RuleRegistry 中

$registry = new RuleRegistry();
$registry->add('age', new UserAgeRule($currentUser));
$registry->add('someOtherRule', new Callback(function() { return new SomeOtherRule(); }));

$builder = new RuleBuilder($registry);
$rule = $builder->fromArray(array(
    'age',
    'someOtherRule'
));
$rule->validate();

通常有两种注册规则的方式:您可以为您的对象注册一个实例

$registry->add('age', new UserAgeRule($currentUser));

或者您可以注册一个可调用的函数,该函数返回您的规则的一个实例

$registry->add('someOtherRule', new Callback(function() { return new SomeOtherRule(); }));

注册可调用函数与注册实际实例相比有一些优点

  • 延迟实例化:您的规则仅在需要时创建。如果您需要为您的规则进行一些昂贵的计算,这特别有用。
  • 上下文:当与 RuleBuilder 一起使用时,您将在回调函数中接收到 "config" 信息
  • 无需克隆

规则配置

特别是如果规则是用户生成的,您可能需要一些额外的配置。因此,而不是有 "用户年龄大于18" 的规则,您想要一个 "用户年龄大于 X" 的规则。虽然手动实例化规则对象时没有问题,但您可能希望有一种方法,可以从 fromArray() 方法自动配置您的规则。

class MinimumAgeRule implements Rule
{
    protected $user;
    protected $minAge;

    public function __construct($user, $minAge)
    {
        $this->user = $user;
    }

    public function validate()
    {
        return $this->user->getAge() >= $this->minAge;
    }
}

现在您可以像这样配置您的规则

$registry = new RuleRegistry();
$registry->add('minimumAge', new Callback(function($minAge) use($currentUser) { return new MinimumAgeRule($currentUser, $minAge); } ));
$registry->add('someOtherRule', new SomeOtherRule());

$builder = new RuleBuilder($registry);
$rule = $builder->fromArray(array(
    'minimumAge' => 21,
    'maximumAge' => 44
));
$rule->validate();

在这种情况下,$currentUser 是我们业务逻辑中知道的对象 - 因此我们可以在可调用的函数中 just USE 它。另一方面,$minAge - 来自嵌套数组对象,并且仅在 fromArray() 方法期间已知。由于它传递给我们的可调用的函数,因此可以轻松访问