2014-09-23 20:45:59 +02:00
|
|
|
<?php
|
|
|
|
namespace Szurubooru\SearchServices\Parsers;
|
|
|
|
|
|
|
|
abstract class AbstractSearchParser
|
|
|
|
{
|
2014-09-27 10:59:37 +02:00
|
|
|
const ALLOW_COMPOSITE = 1;
|
|
|
|
const ALLOW_RANGES = 2;
|
|
|
|
|
2014-09-26 19:14:34 +02:00
|
|
|
public function createFilterFromInputReader(\Szurubooru\Helpers\InputReader $inputReader)
|
2014-09-23 20:45:59 +02:00
|
|
|
{
|
|
|
|
$filter = $this->createFilter();
|
2014-09-26 19:14:34 +02:00
|
|
|
$filter->setOrder(array_merge($this->getOrder($inputReader->order), $filter->getOrder()));
|
2014-09-23 20:45:59 +02:00
|
|
|
|
2014-09-26 19:14:34 +02:00
|
|
|
if ($inputReader->page)
|
|
|
|
{
|
|
|
|
$filter->setPageNumber($inputReader->page);
|
|
|
|
$filter->setPageSize(25);
|
|
|
|
}
|
|
|
|
|
|
|
|
$tokens = $this->tokenize($inputReader->query);
|
2014-09-23 20:45:59 +02:00
|
|
|
|
|
|
|
foreach ($tokens as $token)
|
|
|
|
{
|
2014-09-27 10:59:37 +02:00
|
|
|
if ($token instanceof \Szurubooru\SearchServices\Tokens\NamedSearchToken)
|
2014-09-23 20:45:59 +02:00
|
|
|
$this->decorateFilterFromNamedToken($filter, $token);
|
2014-09-27 10:59:37 +02:00
|
|
|
elseif ($token instanceof \Szurubooru\SearchServices\Tokens\SearchToken)
|
2014-09-23 20:45:59 +02:00
|
|
|
$this->decorateFilterFromToken($filter, $token);
|
|
|
|
else
|
2014-09-26 19:14:34 +02:00
|
|
|
throw new \RuntimeException('Invalid search token type: ' . get_class($token));
|
2014-09-23 20:45:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected abstract function createFilter();
|
|
|
|
|
|
|
|
protected abstract function decorateFilterFromToken($filter, $token);
|
|
|
|
|
|
|
|
protected abstract function decorateFilterFromNamedToken($filter, $namedToken);
|
|
|
|
|
|
|
|
protected abstract function getOrderColumn($token);
|
|
|
|
|
2014-09-27 10:59:37 +02:00
|
|
|
protected function createRequirementValue($text, $flags = 0)
|
|
|
|
{
|
|
|
|
if ((($flags & self::ALLOW_RANGES) === self::ALLOW_RANGES) and substr_count($text, '..') === 1)
|
|
|
|
{
|
|
|
|
list ($minValue, $maxValue) = explode('..', $text);
|
|
|
|
$tokenValue = new \Szurubooru\SearchServices\Requirements\RequirementRangedValue();
|
|
|
|
$tokenValue->setMinValue($minValue);
|
|
|
|
$tokenValue->setMaxValue($maxValue);
|
|
|
|
return $tokenValue;
|
|
|
|
}
|
|
|
|
else if ((($flags & self::ALLOW_COMPOSITE) === self::ALLOW_COMPOSITE) and strpos($text, ',') !== false)
|
|
|
|
{
|
|
|
|
$values = explode(',', $text);
|
|
|
|
$tokenValue = new \Szurubooru\SearchServices\Requirements\RequirementCompositeValue();
|
|
|
|
$tokenValue->setValues($values);
|
|
|
|
return $tokenValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return new \Szurubooru\SearchServices\Requirements\RequirementSingleValue($text);
|
|
|
|
}
|
|
|
|
|
2014-09-23 20:45:59 +02:00
|
|
|
private function getOrder($query)
|
|
|
|
{
|
|
|
|
$order = [];
|
2014-09-26 19:14:34 +02:00
|
|
|
$tokens = array_filter(preg_split('/\s+/', trim($query)));
|
2014-09-23 20:45:59 +02:00
|
|
|
|
|
|
|
foreach ($tokens as $token)
|
|
|
|
{
|
|
|
|
$token = preg_split('/,|\s+/', $token);
|
|
|
|
$orderToken = $token[0];
|
|
|
|
$orderDir = (count($token) === 2 and $token[1] === 'desc')
|
2014-09-26 19:14:34 +02:00
|
|
|
? \Szurubooru\SearchServices\Filters\IFilter::ORDER_DESC
|
|
|
|
: \Szurubooru\SearchServices\Filters\IFilter::ORDER_ASC;
|
2014-09-23 20:45:59 +02:00
|
|
|
|
|
|
|
$orderColumn = $this->getOrderColumn($orderToken);
|
|
|
|
if ($orderColumn === null)
|
|
|
|
throw new \InvalidArgumentException('Invalid search order token: ' . $orderToken);
|
|
|
|
|
|
|
|
$order[$orderColumn] = $orderDir;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $order;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function tokenize($query)
|
|
|
|
{
|
|
|
|
$searchTokens = [];
|
|
|
|
|
2014-09-26 19:14:34 +02:00
|
|
|
foreach (array_filter(preg_split('/\s+/', trim($query))) as $tokenText)
|
2014-09-23 20:45:59 +02:00
|
|
|
{
|
|
|
|
$negated = false;
|
|
|
|
if (substr($tokenText, 0, 1) === '-')
|
|
|
|
{
|
|
|
|
$negated = true;
|
|
|
|
$tokenText = substr($tokenText, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strpos($tokenText, ':') !== false)
|
|
|
|
{
|
2014-09-27 10:59:37 +02:00
|
|
|
$searchToken = new \Szurubooru\SearchServices\Tokens\NamedSearchToken();
|
|
|
|
list ($tokenKey, $tokenValue) = explode(':', $tokenText, 2);
|
2014-09-24 20:13:16 +02:00
|
|
|
$searchToken->setKey($tokenKey);
|
|
|
|
$searchToken->setValue($tokenValue);
|
2014-09-23 20:45:59 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-09-27 10:59:37 +02:00
|
|
|
$searchToken = new \Szurubooru\SearchServices\Tokens\SearchToken();
|
2014-09-24 20:13:16 +02:00
|
|
|
$searchToken->setValue($tokenText);
|
2014-09-23 20:45:59 +02:00
|
|
|
}
|
|
|
|
|
2014-09-24 20:13:16 +02:00
|
|
|
$searchToken->setNegated($negated);
|
2014-09-23 20:45:59 +02:00
|
|
|
$searchTokens[] = $searchToken;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $searchTokens;
|
|
|
|
}
|
|
|
|
}
|