FilterQueryString: add hidden debug feature

Might help to track down potential problems in the future, should
not be enabled by default
This commit is contained in:
Thomas Gelf 2014-06-25 10:47:03 +02:00
parent 9359f527db
commit 7ebdb2d378
1 changed files with 26 additions and 0 deletions

View File

@ -8,12 +8,22 @@ class FilterQueryString
protected $pos; protected $pos;
protected $debug = array();
protected $reportDebug = false;
protected $length; protected $length;
protected function __construct() protected function __construct()
{ {
} }
protected function debug($msg, $level = 0, $op = null)
{
if ($op === null) $op = 'NULL';
$this->debug[] = sprintf('%s[%d=%s] (%s): %s', str_repeat('* ', $level), $this->pos, $this->string[$this->pos - 1], $op, $msg);
}
public static function parse($string) public static function parse($string)
{ {
$parser = new static(); $parser = new static();
@ -95,6 +105,9 @@ class FilterQueryString
if ($char === null) { if ($char === null) {
$char = $this->string[$this->pos]; $char = $this->string[$this->pos];
} }
if ($this->reportDebug) {
$extra .= "\n" . implode("\n", $this->debug);
}
throw new FilterParseException(sprintf( throw new FilterParseException(sprintf(
'Invalid filter "%s", unexpected %s at pos %d%s', 'Invalid filter "%s", unexpected %s at pos %d%s',
@ -119,12 +132,15 @@ class FilterQueryString
if ($filter === false) { if ($filter === false) {
$this->debug('Got no next expression, next is ' . $next, $nestingLevel, $op);
if ($next === '!') { if ($next === '!') {
$not = $this->readFilters($nestingLevel + 1, '!'); $not = $this->readFilters($nestingLevel + 1, '!');
$filters[] = $not; $filters[] = $not;
if (in_array($this->nextChar(), array('|', '&', ')'))) { if (in_array($this->nextChar(), array('|', '&', ')'))) {
$next = $this->readChar(); $next = $this->readChar();
$this->debug('Got NOT, next is now: ' . $next, $nestingLevel, $op);
} else { } else {
$this->debug('Breaking after NOT: ' . $not, $nestingLevel, $op);
break; break;
} }
} }
@ -141,6 +157,7 @@ class FilterQueryString
if ($next === ')') { if ($next === ')') {
if ($nestingLevel > 0) { if ($nestingLevel > 0) {
$this->debug('Closing without filter: ' . $next, $nestingLevel, $op);
break; break;
} }
$this->parseError($next); $this->parseError($next);
@ -155,9 +172,12 @@ class FilterQueryString
$this->parseError($next, "$op level $nestingLevel"); $this->parseError($next, "$op level $nestingLevel");
} else { } else {
$this->debug('Got new expression: ' . $filter, $nestingLevel, $op);
$filters[] = $filter; $filters[] = $filter;
if ($next === false) { if ($next === false) {
$this->debug('Next is false, nothing to read but got filter', $nestingLevel, $op);
// Got filter, nothing more to read // Got filter, nothing more to read
break; break;
} }
@ -167,16 +187,19 @@ class FilterQueryString
break; break;
} }
if ($next === $op) { if ($next === $op) {
$this->debug('Next matches operator', $nestingLevel, $op);
continue; // Break?? continue; // Break??
} }
if ($next === ')') { if ($next === ')') {
if ($nestingLevel > 0) { if ($nestingLevel > 0) {
$this->debug('Closing with filter: ' . $next, $nestingLevel, $op);
break; break;
} }
$this->parseError($next); $this->parseError($next);
} }
if ($op === null && in_array($next, array('&', '|'))) { if ($op === null && in_array($next, array('&', '|'))) {
$this->debug('Setting op to ' . $next, $nestingLevel, $op);
$op = $next; $op = $next;
continue; continue;
} }
@ -190,12 +213,15 @@ class FilterQueryString
if ($nestingLevel === 0 && count($filters) === 1 && $op !== '!') { if ($nestingLevel === 0 && count($filters) === 1 && $op !== '!') {
// There is only one filter expression, no chain // There is only one filter expression, no chain
$this->debug('Returning first filter only: ' . $filters[0], $nestingLevel, $op);
return $filters[0]; return $filters[0];
} }
if ($op === null && count($filters) === 1) { if ($op === null && count($filters) === 1) {
$this->debug('No op, single filter, setting AND', $nestingLevel, $op);
$op = '&'; $op = '&';
} }
$this->debug(sprintf('Got %d filters, returning', count($filters)), $nestingLevel, $op);
switch ($op) { switch ($op) {
case '&': return Filter::matchAll($filters); case '&': return Filter::matchAll($filters);