3
3
4
4
Ruler is a simple stateless production rules engine for PHP 5.3+.
5
5
6
- [ ![ Build Status] ( https://secure.travis-ci.org/bobthecow/Ruler.png?branch=master )] ( http://travis-ci.org/bobthecow/Ruler )
6
+ [ ![ Package version] ( http://img.shields.io/packagist/v/ruler/ruler.svg )] ( https://packagist.org/packages/ruler/ruler )
7
+ [ ![ Build status] ( http://img.shields.io/travis/bobthecow/Ruler/develop.svg )] ( http://travis-ci.org/bobthecow/Ruler )
7
8
8
9
9
10
Ruler has an easy, straightforward DSL
@@ -12,8 +13,6 @@ Ruler has an easy, straightforward DSL
12
13
... provided by the RuleBuilder:
13
14
14
15
``` php
15
- <?php
16
-
17
16
$rb = new RuleBuilder;
18
17
$rule = $rb->create(
19
18
$rb->logicalAnd(
@@ -42,8 +41,6 @@ $rule->execute($context); // "Yay!"
42
41
... you can use it without a RuleBuilder:
43
42
44
43
``` php
45
- <?php
46
-
47
44
$actualNumPeople = new Variable('actualNumPeople');
48
45
$rule = new Rule(
49
46
new Operator\LogicalAnd(array(
@@ -75,8 +72,6 @@ Things you can do with your Ruler
75
72
### Compare things
76
73
77
74
``` php
78
- <?php
79
-
80
75
// These are Variables. They'll be replaced by terminal values during Rule evaluation.
81
76
82
77
$a = $rb['a'];
@@ -85,23 +80,80 @@ $b = $rb['b'];
85
80
// Here are bunch of Propositions. They're not too useful by themselves, but they
86
81
// are the building blocks of Rules, so you'll need 'em in a bit.
87
82
88
- $a->greaterThan($b); // true if $a > $b
89
- $a->greaterThanOrEqualTo($b); // true if $a >= $b
90
- $a->lessThan($b); // true if $a < $b
91
- $a->lessThanOrEqualTo($b); // true if $a <= $b
92
- $a->equalTo($b); // true if $a == $b
93
- $a->notEqualTo($b); // true if $a != $b
94
- $a->contains($b); // true if in_array($b, $a) || strpos($b, $a) !== false
95
- $a->doesNotContain($b); // true if !in_array($b, $a) || strpos($b, $a) === false
96
- $a->sameAs($b); // true if $a === $b
97
- $a->notSameAs($b); // true if $a !== $b
83
+ $a->greaterThan($b); // true if $a > $b
84
+ $a->greaterThanOrEqualTo($b); // true if $a >= $b
85
+ $a->lessThan($b); // true if $a < $b
86
+ $a->lessThanOrEqualTo($b); // true if $a <= $b
87
+ $a->equalTo($b); // true if $a == $b
88
+ $a->notEqualTo($b); // true if $a != $b
89
+ $a->stringContains($b); // true if strpos($b, $a) !== false
90
+ $a->stringDoesNotContain($b); // true if strpos($b, $a) === false
91
+ $a->stringContainsInsensitive($b); // true if stripos($b, $a) !== false
92
+ $a->stringDoesNotContainInsensitive($b); // true if stripos($b, $a) === false
93
+ $a->startsWith($b); // true if strpos($b, $a) === 0
94
+ $a->startsWithInsensitive($b); // true if stripos($b, $a) === 0
95
+ $a->endsWith($b); // true if strpos($b, $a) === len($a) - len($b)
96
+ $a->endsWithInsensitive($b); // true if stripos($b, $a) === len($a) - len($b)
97
+ $a->sameAs($b); // true if $a === $b
98
+ $a->notSameAs($b); // true if $a !== $b
98
99
```
99
100
100
- ### Combine things
101
+
102
+ ### Math even more things
101
103
102
104
``` php
103
- <?php
105
+ $c = $rb['c'];
106
+ $d = $rb['d'];
107
+
108
+ // Mathematical operators are a bit different. They're not Propositions, so
109
+ // they don't belong in rules all by themselves, but they can be combined
110
+ // with Propositions for great justice.
111
+
112
+ $rb['price']
113
+ ->add($rb['shipping'])
114
+ ->greaterThanOrEqualTo(50)
115
+
116
+ // Of course, there are more.
117
+
118
+ $c->add($d); // $c + $d
119
+ $c->subtract($d); // $c - $d
120
+ $c->multiply($d); // $c * $d
121
+ $c->divide($d); // $c / $d
122
+ $c->modulo($d); // $c % $d
123
+ $c->exponentiate($d); // $c ** $d
124
+ $c->negate(); // -$c
125
+ $c->ceil(); // ceil($c)
126
+ $c->floor(); // floor($c)
127
+ ```
128
+
129
+
130
+ ### Reason about sets
131
+
132
+ ``` php
133
+ $e = $rb['e']; // These should both be arrays
134
+ $f = $rb['f'];
135
+
136
+ // Manipulate sets with set operators
137
+
138
+ $e->union($f);
139
+ $e->intersect($f);
140
+ $e->complement($f);
141
+ $e->symmetricDifference($f);
142
+ $e->min();
143
+ $e->max();
144
+
145
+ // And use set Propositions to include them in Rules.
146
+
147
+ $e->containsSubset($f);
148
+ $e->doesNotContainSubset($f);
149
+ $e->setContains($a);
150
+ $e->setDoesNotContain($a);
151
+ ```
152
+
104
153
154
+ ### Combine Rules
155
+
156
+ ``` php
105
157
// Create a Rule with an $a == $b condition
106
158
$aEqualsB = $rb->create($a->equalTo($b));
107
159
@@ -123,27 +175,27 @@ $context = new Context(array(
123
175
$eitherOne->evaluate($context);
124
176
```
125
177
126
- ### Combine more things
127
178
128
- ``` php
129
- <?php
179
+ ### Combine more Rules
130
180
181
+ ``` php
131
182
$rb->logicalNot($aEqualsB); // The same as $aDoesNotEqualB :)
132
183
$rb->logicalAnd($aEqualsB, $aDoesNotEqualB); // True if both conditions are true
133
184
$rb->logicalOr($aEqualsB, $aDoesNotEqualB); // True if either condition is true
134
185
$rb->logicalXor($aEqualsB, $aDoesNotEqualB); // True if only one condition is true
135
186
```
136
187
188
+
137
189
### ` evaluate ` and ` execute ` Rules
138
190
139
191
` evaluate() ` a Rule with Context to figure out whether it is true.
140
192
141
193
``` php
142
- <?php
143
-
144
- $context = new Context(array( 'userName', function() {
145
- return isset($_SESSION['userName']) ? $_SESSION['userName'] : null;
146
- } ));
194
+ $context = new Context(array(
195
+ 'userName' => function() {
196
+ return isset($_SESSION[ 'userName']) ? $_SESSION['userName'] : null;
197
+ }
198
+ ));
147
199
148
200
$userIsLoggedIn = $rb->create($rb['userName']->notEqualTo(null));
149
201
@@ -155,10 +207,7 @@ if ($userIsLoggedIn->evaluate($context)) {
155
207
If a Rule has an action, you can ` execute() ` it directly and save yourself a
156
208
couple of lines of code.
157
209
158
-
159
210
``` php
160
- <?php
161
-
162
211
$hiJustin = $rb->create(
163
212
$rb['userName']->equalTo('bobthecow'),
164
213
function() {
@@ -169,6 +218,7 @@ $hiJustin = $rb->create(
169
218
$hiJustin->execute($context); // "Hi, Justin!"
170
219
```
171
220
221
+
172
222
### Even ` execute ` a whole grip of Rules at once
173
223
174
224
``` php
@@ -219,8 +269,6 @@ static values, or even code for lazily evaluating the Variables needed by your
219
269
Rules.
220
270
221
271
``` php
222
- <?php
223
-
224
272
$context = new Context;
225
273
226
274
// Some static values...
@@ -254,6 +302,18 @@ for a shipping price calculator?
254
302
> If the current User has placed 5 or more orders, but isn't "really annoying",
255
303
> give 'em free shipping.
256
304
305
+ ``` php
306
+ $rb->create(
307
+ $rb->logicalAnd(
308
+ $rb['orderCount']->greaterThanOrEqualTo(5),
309
+ $rb['reallyAnnoyingUsers']->doesNotContain($rb['userName'])
310
+ ),
311
+ function() use ($shipManager, $context) {
312
+ $shipManager->giveFreeShippingTo($context['user']);
313
+ }
314
+ );
315
+ ```
316
+
257
317
258
318
Access variable properties
259
319
--------------------------
@@ -264,7 +324,6 @@ Context Variable values. This can come in really handy.
264
324
Say we wanted to log the current user's name if they are an administrator:
265
325
266
326
``` php
267
-
268
327
// Reusing our $context from the last example...
269
328
270
329
// We'll define a few context variables for determining what roles a user has,
@@ -304,7 +363,7 @@ everything we might need to access in a rule, we can use VariableProperties, and
304
363
their convenient RuleBuilder interface:
305
364
306
365
``` php
307
- // We can skip over the Context Variable building above. We'll simply set our,
366
+ // We can skip over the Context Variable building above. We'll simply set our,
308
367
// default roles on the VariableProperty itself, then go right to writing rules:
309
368
310
369
$rb['user']['roles'] = array('anonymous');
@@ -335,6 +394,48 @@ If none of the above are true, it will return the default value for this
335
394
VariableProperty.
336
395
337
396
397
+ Add your own Operators
398
+ ----------------------
399
+
400
+ If none of the default Ruler Operators fit your needs, you can write your own! Just define
401
+ additional operators like this:
402
+
403
+ ``` php
404
+
405
+ namespace My\Ruler\Operators;
406
+
407
+ use Ruler\Context;
408
+ use Ruler\Operator\VariableOperator;
409
+ use Ruler\Proposition;
410
+ use Ruler\Value;
411
+
412
+ class ALotGreaterThan extends VariableOperator implements Proposition
413
+ {
414
+ public function evaluate(Context $context)
415
+ {
416
+ list($left, $right) = $this->getOperands();
417
+ $value = $right->prepareValue($context)->getValue() * 10;
418
+
419
+ return $left->prepareValue($context)->greaterThan(new Value($value));
420
+ }
421
+
422
+ protected function getOperandCardinality()
423
+ {
424
+ return static::BINARY;
425
+ }
426
+ }
427
+ ```
428
+
429
+ Then you can use them with RuleBuilder like this:
430
+
431
+ ``` php
432
+ $rb->registerOperatorNamespace('My\Ruler\Operators');
433
+ $rb->create(
434
+ $rb['a']->aLotGreaterThan(10);
435
+ );
436
+ ```
437
+
438
+
338
439
But that's not all...
339
440
---------------------
340
441
0 commit comments