hoaproject / Ruler

The Hoa\Ruler library.
https://hoa-project.net
627 stars 66 forks source link

Produce results in response of rule evaluations #94

Open jubianchi opened 8 years ago

jubianchi commented 8 years ago

Ruler is well designed for writing rules and making assertions on them (i.e checking if some input validates the rule).

An nice feature would to be able to produce any result in response of these assertions (i.e if some input validates a rule then the engine should provide us a value).

Let's take a simple example:

With only ruler, I would have to write two rules:

And some PHP code:

<?php

$ruler = new Hoa\Ruler\Ruler();
$context = new Hoa\Ruler\Context();
$context['person'] = new Person();
$context['person']->age = 19;

$beverages = [];

if ($ruler->assert($r1, $context)) {
    $beverages[] = 'beer';
}

if ($ruler->assert($r2, $context)) {
    $beverages[] = 'whiskey';
    $beverages[] = 'gin';
    $beverages[] = 'vodka';
}

var_dump($beverages); 

/*
array(4) {
  [0] => string(3) "beer",
  [1] => string(3) "whiskey",
  [2] => string(3) "gin",
  [3] => string(3) "vodka"
}
*/

This is not really efficient: the more rules I have, the more code I need to write. If the results change, I'll have to change my PHP code, ...

What I propose here is something more flexible:

$ruler = new Hoa\Ruler\Ruler();
$rules = new Hoa\Ruler\Rules();
$context = new Hoa\Ruler\Context();
$context['person'] = new Person();
$context['person']->age = 19;

$rules->add('16yo', new Hoa\Ruler\Rules\ThenElse('person.age >= 16', ['beer'], ['water']), 1);
$rules->add('18yo', new Hoa\Ruler\Rules\Then('person.age >= 18', ['whiskey', 'gin', 'vodka']), 2);

var_dump($rules->getBestResult($ruler, $context));
/*
array(3) {
  [0] => string(3) "whiskey",
  [1] => string(3) "gin",
  [2] => string(3) "vodka"
}
*/

var_dump($rules->getAllResults($ruler, $context));
/*
array(2) {
  '18yo' => array(3) {
    [0] => string(3) "whiskey",
    [1] => string(3) "gin",
    [2] => string(3) "vodka"
  },
  '16yo' => array(1) {
    [0] => string(3) "beer"
  }
}
*/

Let me explain:

This kind of feature will allow for more generic code when it comes to work with rules and produce results depending on them.

The Rules collection can easily be built with results coming from a database.

What has to be done:

Let me know if I forgot something. I have a working POC which needs some cleanup.

Hywan commented 8 years ago

That's an excellent idea. I would change the API though. Why not having:

Rules::add(string $id, $ruleKind, int $priority)

where $ruleKind is a Then or other rule. Thus, behind add, we will have a graph.

Thoughts?

jubianchi commented 8 years ago

@Hywan you are totally right. I made some mistake while writing the issue. They are now fixed.

Hywan commented 8 years ago

@jubianchi What do you think of my API proposal?

Grummfy commented 8 years ago

yeah! far better!

jubianchi commented 8 years ago

@Hywan I'm totally ok with your API proposal, I edited the issue's description:

  • [the Hoa\Ruler\Rules class] has a add(string $id, Rule $rule, int $priority) method, [...]
  • the $rule is a standard ruler rule (a string or a compiled rule) wrapped in a Then or ThenElse class,