Hoa central
Asserter.php
Go to the documentation of this file.
1 <?php
2 
38 
39 use Hoa\Core;
40 use Hoa\Ruler;
41 use Hoa\Visitor;
42 
51 class Asserter implements Visitor\Visit
52 {
58  protected $_context = null;
59 
65  protected $_operators = [];
66 
67 
68 
75  public function __construct(Ruler\Context $context = null)
76  {
77  if (null !== $context) {
78  $this->setContext($context);
79  }
80 
81  $this->setOperator('and', function ($a = false, $b = false) { return $a && $b; });
82  $this->setOperator('or', function ($a = false, $b = false) { return $a || $b; });
83  $this->setOperator('xor', function ($a, $b) { return (bool) ($a ^ $b); });
84  $this->setOperator('not', function ($a) { return !$a; });
85  $this->setOperator('=', function ($a, $b) { return $a == $b; });
86  $this->setOperator('is', $this->getOperator('='));
87  $this->setOperator('!=', function ($a, $b) { return $a != $b; });
88  $this->setOperator('>', function ($a, $b) { return $a > $b; });
89  $this->setOperator('>=', function ($a, $b) { return $a >= $b; });
90  $this->setOperator('<', function ($a, $b) { return $a < $b; });
91  $this->setOperator('<=', function ($a, $b) { return $a <= $b; });
92  $this->setOperator('in', function ($a, Array $b) { return in_array($a, $b); });
93  $this->setOperator('sum', function () { return array_sum(func_get_args()); });
94 
95  return;
96  }
97 
107  public function visit(Visitor\Element $element, &$handle = null, $eldnah = null)
108  {
109  if ($element instanceof Ruler\Model) {
110  return $this->visitModel($element, $handle, $eldnah);
111  }
112 
113  if ($element instanceof Ruler\Model\Operator) {
114  return $this->visitOperator($element, $handle, $eldnah);
115  }
116 
117  if ($element instanceof Ruler\Model\Bag\Scalar) {
118  return $this->visitScalar($element, $handle, $eldnah);
119  }
120 
121  if ($element instanceof Ruler\Model\Bag\RulerArray) {
122  return $this->visitArray($element, $handle, $eldnah);
123  }
124 
125  if ($element instanceof Ruler\Model\Bag\Context) {
126  return $this->visitContext($element, $handle, $eldnah);
127  }
128  }
129 
138  public function visitModel(Ruler\Model $element, &$handle = null, $eldnah = null)
139  {
140  return (bool) $element->getExpression()->accept($this, $handle, $eldnah);
141  }
142 
151  protected function visitOperator(Ruler\Model\Operator $element, &$handle = null, $eldnah = null)
152  {
153  $name = $element->getName();
154  $arguments = [];
155 
156  foreach ($element->getArguments() as $argument) {
157  $value = $argument->accept($this, $handle, $eldnah);
158  $arguments[] = $value;
159 
160  if ($element::LAZY_BREAK === $element->shouldBreakLazyEvaluation($value)) {
161  break;
162  }
163  }
164 
165  if (false === $this->operatorExists($name)) {
166  throw new Ruler\Exception\Asserter(
167  'Operator %s does not exist.',
168  0,
169  $name
170  );
171  }
172 
173  return $this->getOperator($name)->distributeArguments($arguments);
174  }
175 
184  protected function visitScalar(Ruler\Model\Bag\Scalar $element, &$handle = null, $eldnah = null)
185  {
186  return $element->getValue();
187  }
188 
197  protected function visitArray(Ruler\Model\Bag\RulerArray $element, &$handle = null, $eldnah = null)
198  {
199  $out = [];
200 
201  foreach ($element->getArray() as $key => $data) {
202  $out[$key] = $data->accept($this, $handle, $eldnah);
203  }
204 
205  return $out;
206  }
207 
216  protected function visitContext(Ruler\Model\Bag\Context $element, &$handle = null, $eldnah = null)
217  {
218  $context = $this->getContext();
219 
220  if (null === $context) {
221  throw new Ruler\Exeption\Asserter(
222  'Assert needs a context to work properly.',
223  1
224  );
225  }
226 
227  $id = $element->getId();
228 
229  if (!isset($context[$id])) {
230  throw new Ruler\Exception\Asserter(
231  'Context reference %s does not exists.',
232  2,
233  $id
234  );
235  }
236 
237  $contextPointer = $context[$id];
238 
239  foreach ($element->getDimensions() as $dimensionNumber => $dimension) {
240  ++$dimensionNumber;
241 
242  switch ($dimension[Ruler\Model\Bag\Context::ACCESS_TYPE]) {
243  case Ruler\Model\Bag\Context::ARRAY_ACCESS:
244  $this->visitContextArray(
245  $contextPointer,
246  $dimension,
247  $dimensionNumber,
248  $id,
249  $handle,
250  $eldnah
251  );
252 
253  break;
254 
255  case Ruler\Model\Bag\Context::ATTRIBUTE_ACCESS:
256  $this->visitContextAttribute(
257  $contextPointer,
258  $dimension,
259  $dimensionNumber,
260  $id,
261  $handle,
262  $eldnah
263  );
264 
265  break;
266 
267  case Ruler\Model\Bag\Context::METHOD_ACCESS:
268  $this->visitContextMethod(
269  $contextPointer,
270  $dimension,
271  $dimensionNumber,
272  $id,
273  $handle,
274  $eldnah
275  );
276 
277  break;
278  }
279  }
280 
281  return $contextPointer;
282  }
283 
295  protected function visitContextArray(
296  &$contextPointer,
297  Array $dimension,
298  $dimensionNumber,
299  $elementId,
300  &$handle = null,
301  $eldnah = null
302  ) {
303  $value = $dimension[Ruler\Model\Bag\Context::ACCESS_VALUE];
304  $key = $value->accept($this, $handle, $eldnah);
305 
306  if (!is_array($contextPointer)) {
307  throw new Ruler\Exception\Asserter(
308  'Try to access to an undefined index: %s ' .
309  '(dimension number %d of %s), because it is ' .
310  'not an array.',
311  3,
312  [$key, $dimensionNumber, $elementId]
313  );
314  }
315 
316  if (!isset($contextPointer[$key])) {
317  throw new Ruler\Exception\Asserter(
318  'Try to access to an undefined index: %s ' .
319  '(dimension number %d of %s).',
320  4,
321  [$key, $dimensionNumber, $elementId]
322  );
323  }
324 
325  $contextPointer = $contextPointer[$key];
326 
327  return;
328  }
329 
330 
342  protected function visitContextAttribute(
343  &$contextPointer,
344  Array $dimension,
345  $dimensionNumber,
346  $elementId,
347  &$handle = null,
348  $eldnah = null)
349  {
350  $attribute = $dimension[Ruler\Model\Bag\Context::ACCESS_VALUE];
351 
352  if (!is_object($contextPointer)) {
353  throw new Ruler\Exception\Asserter(
354  'Try to read an undefined attribute: %s ' .
355  '(dimension number %d of %s), because it is ' .
356  'not an object.',
357  5,
358  [$attribute, $dimensionNumber, $elementId]
359  );
360  }
361 
362  if (!property_exists($contextPointer, $attribute)) {
363  throw new Ruler\Exception\Asserter(
364  'Try to read an undefined attribute: %s ' .
365  '(dimension number %d of %s).',
366  6,
367  [$attribute, $dimensionNumber, $elementId]
368  );
369  }
370 
371  $contextPointer = $contextPointer->$attribute;
372 
373  return;
374  }
375 
387  protected function visitContextMethod(
388  &$contextPointer,
389  Array $dimension,
390  $dimensionNumber,
391  $elementId,
392  &$handle = null,
393  $eldnah = null
394  ) {
395  $value = $dimension[Ruler\Model\Bag\Context::ACCESS_VALUE];
396  $method = $value->getName();
397 
398  if (!is_object($contextPointer)) {
399  throw new Ruler\Exception\Asserter(
400  'Try to call an undefined method: %s ' .
401  '(dimension number %d of %s), because it is ' .
402  'not an object.',
403  7,
404  [$method, $dimensionNumber, $elementId]
405  );
406  }
407 
408  if (!method_exists($contextPointer, $method)) {
409  throw new Ruler\Exception\Asserter(
410  'Try to call an undefined method: %s ' .
411  '(dimension number %d of %s).',
412  8,
413  [$method, $dimensionNumber, $elementId]
414  );
415  }
416 
417  $arguments = [];
418 
419  foreach ($value->getArguments() as $argument) {
420  $arguments[] = $argument->accept($this, $handle, $eldnah);
421  }
422 
423  $contextPointer = call_user_func_array(
424  [$contextPointer, $method],
425  $arguments
426  );
427 
428  return;
429  }
430 
437  public function setContext(Ruler\Context $context)
438  {
439  $old = $this->_context;
440  $this->_context = $context;
441 
442  return $old;
443  }
444 
450  public function getContext()
451  {
452  return $this->_context;
453  }
454 
462  public function setOperator($operator, $callable)
463  {
464  $this->_operators[$operator] = $callable;
465 
466  return $this;
467  }
468 
475  public function operatorExists($operator)
476  {
477  return true === array_key_exists($operator, $this->_operators);
478  }
479 
486  public function getOperator($operator)
487  {
488  if (false === $this->operatorExists($operator)) {
489  return null;
490  }
491 
492  $handle = &$this->_operators[$operator];
493 
494  if (!($handle instanceof Core\Consistency\Xcallable)) {
495  $handle = xcallable($handle);
496  }
497 
498  return $this->_operators[$operator];
499  }
500 
506  public function getOperators()
507  {
508  foreach ($this->_operators as &$operator) {
509  if (!($operator instanceof Core\Consistency\Xcallable)) {
510  $operator = xcallable($operator);
511  }
512  }
513 
514  return $this->_operators;
515  }
516 }
visitContext(Ruler\Model\Bag\Context $element, &$handle=null, $eldnah=null)
Definition: Asserter.php:216
visitOperator(Ruler\Model\Operator $element, &$handle=null, $eldnah=null)
Definition: Asserter.php:151
visitModel(Ruler\Model $element, &$handle=null, $eldnah=null)
Definition: Asserter.php:138
visitContextArray(&$contextPointer, Array $dimension, $dimensionNumber, $elementId, &$handle=null, $eldnah=null)
Definition: Asserter.php:295
visit(Visitor\Element $element, &$handle=null, $eldnah=null)
Definition: Asserter.php:107
setOperator($operator, $callable)
Definition: Asserter.php:462
visitScalar(Ruler\Model\Bag\Scalar $element, &$handle=null, $eldnah=null)
Definition: Asserter.php:184
visitContextMethod(&$contextPointer, Array $dimension, $dimensionNumber, $elementId, &$handle=null, $eldnah=null)
Definition: Asserter.php:387
visitArray(Ruler\Model\Bag\RulerArray $element, &$handle=null, $eldnah=null)
Definition: Asserter.php:197
__construct(Ruler\Context $context=null)
Definition: Asserter.php:75
visitContextAttribute(&$contextPointer, Array $dimension, $dimensionNumber, $elementId, &$handle=null, $eldnah=null)
Definition: Asserter.php:342
setContext(Ruler\Context $context)
Definition: Asserter.php:437