diff --git a/Exception/NoResult.php b/Exception/NoResult.php new file mode 100644 index 0000000..6d411f3 --- /dev/null +++ b/Exception/NoResult.php @@ -0,0 +1,6 @@ +name = $name; + $this->rule = $rule; + $this->result = $result; + } + + /** + * @param string $name + * + * @throws \Error + * + * @return mixed + */ + public function __get($name) + { + switch (strtolower($name)) { + case 'name': + return $name; + + case 'result': + if (is_object($this->result)) { + if ($this->result instanceof \Closure) { + return $this->result; + } + + return clone $this->result; + } + + return $this->result; + + case 'rule': + return clone $this->rule; + + default: + throw new Exception\Exception('Unable to get property ' . $name); + } + } +} diff --git a/Rule.php b/Rule.php new file mode 100644 index 0000000..611b897 --- /dev/null +++ b/Rule.php @@ -0,0 +1,62 @@ +queue = new Max(); + } + + /** + * @param string $name + * @param Rule $rule + * @param int $priority + * + * @return Rules + */ + public function add($name, Rule $rule, $priority = -1) + { + $this->queue->insert([$name, $rule], $priority); + + return $this; + } + + /** + * @param Ruler $ruler + * @param Context $context + * + * @throws NoResult + * + * @return Result + */ + public function getBestResult(Ruler $ruler, Context $context) + { + $ruler = self::initializeRuler($ruler, $context); + + foreach ($this->queue as $nameAndRule) { + /** + * @var string $name + * @var Rule $rule + */ + list($name, $rule) = $nameAndRule; + + try { + $context['.' . $name] = $rule->execute($ruler, $context); + } catch (RuleDoesNotValidate $exception) { + $context['.' . $name] = null; + } + + if ($rule->valid($ruler, $context)) { + return new Result($name, $rule, $context['.' . $name]); + } + } + + throw new NoResult(); + } + + /** + * @param Ruler $ruler + * @param Context $context + * + * @return Result[] + */ + public function getAllResults(Ruler $ruler, Context $context) + { + $ruler = self::initializeRuler($ruler, $context); + $results = []; + + foreach ($this->queue as $nameAndRule) { + /** + * @var string $name + * @var Rule $rule + */ + list($name, $rule) = $nameAndRule; + + try { + $context['.' . $name] = $rule->execute($ruler, $context); + } catch (RuleDoesNotValidate $exception) { + $context['.' . $name] = null; + } + + $results[] = new Result($name, $rule, $context['.' . $name]); + } + + return $results; + } + + /** + * @param Ruler $ruler + * @param array $context + * + * @return Ruler + */ + private static function initializeRuler(Ruler $ruler, Context $context) + { + if ($ruler->getDefaultAsserter()->operatorExists('rule')) { + return $ruler; + } + + $ruler = clone $ruler; + + $ruler->getDefaultAsserter()->setOperator('rule', function($id) use ($context) { + return $context['.' . $id]; + }); + + return $ruler; + } +} diff --git a/Rules/Then.php b/Rules/Then.php new file mode 100644 index 0000000..2dd2b11 --- /dev/null +++ b/Rules/Then.php @@ -0,0 +1,100 @@ +rule = $rule; + $this->result = $result; + } + + /** + * @param Ruler $ruler + * @param Context $context + * + * @return bool + */ + public function valid(Ruler $ruler, Context $context) + { + return $ruler->assert($this->rule, $context); + } + + /** + * @param Ruler $ruler + * @param Context $context + * + * @return mixed + */ + public function execute(Ruler $ruler, Context $context) + { + if ($this->valid($ruler, $context)) { + return $this->result; + } + + throw new RuleDoesNotValidate('Rule ' . $this->rule . ' does not validate'); + } +} diff --git a/Rules/ThenElse.php b/Rules/ThenElse.php new file mode 100644 index 0000000..159347e --- /dev/null +++ b/Rules/ThenElse.php @@ -0,0 +1,101 @@ +rule = new Then($rule, $result); + $this->otherwise = $otherwise; + } + + /** + * @param Ruler $ruler + * @param Context $context + * + * @return bool + */ + public function valid(Ruler $ruler, Context $context) + { + return $this->rule->valid($ruler, $context); + } + + /** + * @param Ruler $ruler + * @param Context $context + * + * @return mixed + */ + public function execute(Ruler $ruler, Context $context) + { + try { + return $this->rule->execute($ruler, $context); + } catch (RuleDoesNotValidate $e) { + return $this->otherwise; + } + } +} diff --git a/composer.json b/composer.json index 2a393fc..ec155ec 100644 --- a/composer.json +++ b/composer.json @@ -28,6 +28,7 @@ "hoa/consistency": "~1.0", "hoa/exception" : "~1.0", "hoa/file" : "~1.0", + "hoa/heap" : "~0.0@dev", "hoa/protocol" : "~1.0", "hoa/visitor" : "~2.0" },