PHPackages                             vertilia/recif - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. vertilia/recif

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

vertilia/recif
==============

Code generator for rule engines

v2.5.1(3y ago)013BSD-2-ClausePHPPHP &gt;=7.4

Since Aug 24Pushed 3y ago1 watchersCompare

[ Source](https://github.com/vertilia/recif)[ Packagist](https://packagist.org/packages/vertilia/recif)[ RSS](/packages/vertilia-recif/feed)WikiDiscussions master Synced today

READMEChangelogDependencies (1)Versions (19)Used By (0)

recif: rule engine comme il faut
================================

[](#recif-rule-engine-comme-il-faut)

Rule engine parser that translates conditions from rule file in json or yaml format to native code.

Description
-----------

[](#description)

When businesses express new or updated rulesets, they may be either coded by programmers into the existing information system, or they may be declared in a special dialect that the system may parse and evaluate. In this case programmer's intervention is not needed, but the parsing and evaluation time may be significant. Each time the system needs to evaluate conditions from a ruleset for specific context (for example, define product segment) the system needs to parse the rule file, process conditions starting at the top level until the matching rule found, all this recursively calling methods for each operation mentioned in a ruleset.

With recif, when rulesets are updated in a rule file we call the converter that translates the rules into a native code. That code represents the ruleset conditions from the file. All operations are already translated to native constructs like OR, AND etc, so the execution of the full ruleset is optimal. To use that class inside your project instantiate the object and call its `evaluate()` method passing the context as its parameter. `evaluate()` will return `true` (or corresponding value) if match found, or `false` if passed context does not match any condition (yes, you may provide your own return value).

Example 1
---------

[](#example-1)

Single condition. Input context is a literal numeric value that is evaluated and returns `true` if it is greater than `10`:

```
{
  "gt": [{"cx":""}, 10]
}
```

Example 2
---------

[](#example-2)

Multiple conditions combined with `AND` operator. Input context is a literal numeric value. Returns `true` if context value is in the range `0..100`:

```
{
  "and": [
    {"ge": [{"cx":""}, 0]},
    {"le": [{"cx":""}, 100]}
  ]
}
```

Example 3
---------

[](#example-3)

Complex conditions: context is an associative array with `country` and `currency` entries which must match the following matrix:

countrycurrency`DE``EUR``ES``EUR``FR``EUR``IT``EUR``US``USD`If condition matches it will return continent name for the context (`North America` or `Europe`) instead of simple `true` value.

```
{
  "or": [
    {
      "and": [
        {"in": [{"cx":"country"}, {"_": ["DE", "ES", "FR", "IT"]}]},
        {"eq": [{"cx":"currency"}, "EUR"]}
      ],
      "return": "Europe"
    },
    {
      "and": [
        {"eq": [{"cx":"country"}, "US"]},
        {"eq": [{"cx":"currency"}, "USD"]}
      ],
      "return": "North America"
    }
  ]
}
```

Note: to represent an array you need to use a special `{"_": ...}` inline operator.

Installation
------------

[](#installation)

Require with `composer`:

```
$ composer require vertilia/recif

```

Command line usage
------------------

[](#command-line-usage)

After installation with `composer`, `recif` binary is available as `vendor/bin/recif`.

```
$ vendor/bin/recif
Usage: recif [options] Ruleset.php
Options:
  -C  COMMENT add comments text, should not contain open / close comment sequences (default: not set)
  -n  NAMESPACE use namespace (default: not set)
  -s  generate static evaluate() method (default: not set)
  -c  CLASS use class name (default: Ruleset)
  -e  CLASS extends class (default: not set)
  -i  INTERFACE implements interfaces, comma separated list (default: not set)
  -x  TYPE define context parameter type (default: not set)
  -r  TYPE define method return type (default: not set)
  -S  VALUE return on success default value (default: true)
  -F  VALUE return on fail default value (default: false)
  -d  declare static_types (default: not set)
  -5  generate php5-compatible code
  -y  input stream in YAML format (needs yaml PECL extension)

```

Simplest ruleset: evaluate the `true` statement:

```
echo 'true' | recif

```

Same level: evaluate that `1 > 0`:

```
echo '{"gt":[1,0]}' | recif

```

Do something meaningful: check context, add namespace to generated class and specify return type of its `evaluate()` method:

```
echo '{"gt":[{"cx":""},0]}' | recif -n MyNamespace\\Level2 -r bool

```

Syntax of rule files
--------------------

[](#syntax-of-rule-files)

Rule file contains a tree of conditions starting with a root condition.

Each condition is an object with a single required entry containing operation name as key and arguments as value. An optional `return` entry may contain returned value for the case if operation matches, otherwise the default `true` will be returned.

Operators like `or` must contain an array of arguments. Unary operators like `not` operate on a single value, not an array. See Operations reference for the full list of available operations.

Each argument may have one of the following forms:

- literal value or array (normally used to compare the value with context field), like `true` or `"US"`;
- object (representing context or another operation), like `{"cx":"currency"}` or `{"eq": [{"cx":"country"}, "US"]}` or `{"_": ["DE", "ES", "FR", "IT"]}`.

Returned value represents the value that is returned to the outer operation when the corresponding condition evaluates to `true`. It may be declared as any type. If value is an object, it may represent context or one of its properties, like `{"cx":""}` or `{"cx":"currency.iso_name"}`. In this case the value of this element or property will be returned.

Operations reference
--------------------

[](#operations-reference)

Examples below are given in json notation, meanings are given as php code.

### Context operator

[](#context-operator)

`cx` - context value (argument: empty string if context is literal, dot-separated list of keys if array)

Example: `{"cx":""}`, `{"cx":"url.path"}`

Meaning: `$context`, `$context['url']['path']`

### Comparison operators

[](#comparison-operators)

`eq` - equal

Example: `{"eq": [{"cx":""}, 0]}`

Meaning: `$context == 0`

`===` - identical (equal and same type)

Example: `{"===": [{"cx":""}, '15h']}`

Meaning: `$context === '15h'`

`ne` - not equal

Example: `{"ne": [{"cx":""}, 0]}`

Meaning: `$context != 0`

`!==` - not identical (not equal or different type)

Example: `{"!==": [{"cx":""}, '15h']}`

Meaning: `$context !== '15h'`

`lt` - less than

Example: `{"lt": [{"cx":""}, 0]}`

Meaning: `$context < 0`

`le` - less or equal

Example: `{"le": [{"cx":""}, 0]}`

Meaning: `$context  0`

`ge` - greater or equal

Example: `{"ge": [{"cx":""}, 0]}`

Meaning: `$context >= 0`

### Logical operators

[](#logical-operators)

`or` - or (two or more arguments)

Example: `{"or": [{"eq": [{"cx":""}, 0]}, {"eq": [{"cx":""}, 10]}]}`

Meaning: `($context == 0) or ($context == 10)`

`and` - and (two or more arguments)

Example: `{"and": [{"gt": [{"cx":""}, 0]}, {"lt": [{"cx":""}, 10]}]}`

Meaning: `($context > 0) and ($context < 10)`

`not` - not (unary operator, single argument)

Example: `{"not": {"lt": [{"cx":""}, 0]}}`

Meaning: `! ($context < 0)`

### Math operations

[](#math-operations)

`mod` - modulo (arguments: value, modulo)

Example: `{"mod": [{"cx":""}, 10]}`

Meaning: `$context % 10`

`rnd` - random integer number within range (arguments: min, max)

Example: `{"rnd": [1, 10]}`

Meaning: `rand(1, 10)`

### Array operations

[](#array-operations)

`in` - element exists in array (arguments: element, array)

Example: `{"in": [{"cx":""}, {"_": [1, 2, 3, 5, 8, 13]}]}`

Meaning: `in_array($context, [1, 2, 3, 5, 8, 13])`

`inx` - get element from hash map by index (arguments: index, hash map)

Example: `{"inx": [{"cx":""}, {"_": ["FR": "Europe", "US": "North America"]}]}`, `{"inx": [{"cx":""}, {"_": ["US": "North America", "default": "Europe"]}]}`

Meaning: `(["FR" => "Europe", "US" => "North America"])[$context]`, `(["US" => "North America"])[$context] ?? "Europe"`

### String operations

[](#string-operations)

`sub` - needle substring exists in haystack string (arguments: needle, haystack). Search in Unicode case-insensitive mode.

Example: `{"sub": ["word", {"cx":""}]}`

Meaning: `mb_stripos($context, "word") !== false`

`re` - string matches regular expression (arguments: regex, text).

Example: `{"re": ["/^\w+$/u", {"cx":""}]}`

Meaning: `preg_match('/^\w+$/u', $context)`

`spf` - formatted string a.k.a. sprintf (arguments: format string, zero or more values).

Example: `{"spf": ["%.2f", {"cx":""}]}`

Meaning: `sprintf('%.2f', $context)`

### Inline operator

[](#inline-operator)

`_` (underscore) - uses argument value as is (argument of any type).

Example: `{"_": true}`, `{"_": ["a": "b"]}`, `{"_": [1, {"_": []}, 3]}`

Meaning: `true`, `['a' => 'b']`, `[1, [], 3]`

### Native function call

[](#native-function-call)

`fn` - calls native function with provided params (arguments: function name, param1, ...).

Example: `{"fn": ["Currencies::getRateForCountry", {"cx":"country"}]}`

Meaning: `Currencies::getRateForCountry($context['country'])`

Code examples
-------------

[](#code-examples)

### Example 1

[](#example-1-1)

Rule file:

```
{
  "gt": [{"cx":""}, 10]
}
```

Generated code:

```
