This repository has been archived on 2025-02-26. You can view files and clone it, but cannot push or open issues or pull requests.
szurubooru/src/SearchServices/Parsers/AbstractSearchParser.php
2014-10-18 18:48:32 +02:00

158 lines
4.5 KiB
PHP

<?php
namespace Szurubooru\SearchServices\Parsers;
abstract class AbstractSearchParser
{
const ALLOW_COMPOSITE = 1;
const ALLOW_RANGES = 2;
public function createFilterFromInputReader(\Szurubooru\Helpers\InputReader $inputReader)
{
$filter = $this->createFilter();
$filter->setOrder(array_merge($filter->getOrder(), $this->getOrder($inputReader->order)));
if ($inputReader->page)
{
$filter->setPageNumber($inputReader->page);
$filter->setPageSize(25);
}
$tokens = $this->tokenize($inputReader->query);
foreach ($tokens as $token)
{
if ($token instanceof \Szurubooru\SearchServices\Tokens\NamedSearchToken)
{
if ($token->getKey() === 'order')
$filter->setOrder(array_merge($filter->getOrder(), $this->getOrder($token->getValue())));
else
$this->decorateFilterFromNamedToken($filter, $token);
}
elseif ($token instanceof \Szurubooru\SearchServices\Tokens\SearchToken)
$this->decorateFilterFromToken($filter, $token);
else
throw new \RuntimeException('Invalid search token type: ' . get_class($token));
}
return $filter;
}
protected abstract function createFilter();
protected abstract function decorateFilterFromToken($filter, $token);
protected abstract function decorateFilterFromNamedToken($filter, $namedToken);
protected abstract function getOrderColumn($token);
protected function createRequirementValue($text, $flags = 0, $valueDecorator = null)
{
if ($valueDecorator === null)
{
$valueDecorator = function($value)
{
return $value;
};
}
if ((($flags & self::ALLOW_RANGES) === self::ALLOW_RANGES) and substr_count($text, '..') === 1)
{
list ($minValue, $maxValue) = explode('..', $text);
$minValue = $valueDecorator($minValue);
$maxValue = $valueDecorator($maxValue);
$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);
$values = array_map($valueDecorator, $values);
$tokenValue = new \Szurubooru\SearchServices\Requirements\RequirementCompositeValue();
$tokenValue->setValues($values);
return $tokenValue;
}
$value = $valueDecorator($text);
return new \Szurubooru\SearchServices\Requirements\RequirementSingleValue($value);
}
protected function addRequirementFromToken($filter, $token, $type, $flags, $valueDecorator = null)
{
$requirement = new \Szurubooru\SearchServices\Requirements\Requirement();
$requirement->setType($type, $flags);
$requirement->setValue($this->createRequirementValue($token->getValue(), $flags, $valueDecorator));
$requirement->setNegated($token->isNegated());
$filter->addRequirement($requirement);
}
private function getOrder($query)
{
$order = [];
$tokens = array_filter(preg_split('/\s+/', trim($query)));
foreach ($tokens as $token)
{
$token = preg_split('/,|\s+/', $token);
$orderToken = $token[0];
if (count($token) === 1)
{
$orderDir = \Szurubooru\SearchServices\Filters\IFilter::ORDER_DESC;
}
elseif (count($token) === 2)
{
if ($token[1] === 'desc')
$orderDir = \Szurubooru\SearchServices\Filters\IFilter::ORDER_DESC;
elseif ($token[1] === 'asc')
$orderDir = \Szurubooru\SearchServices\Filters\IFilter::ORDER_ASC;
else
throw new \Exception('Wrong search order direction');
}
else
throw new \Exception('Wrong search order token');
$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 = [];
foreach (array_filter(preg_split('/\s+/', trim($query))) as $tokenText)
{
$negated = false;
if (substr($tokenText, 0, 1) === '-')
{
$negated = true;
$tokenText = substr($tokenText, 1);
}
if (strpos($tokenText, ':') !== false)
{
$searchToken = new \Szurubooru\SearchServices\Tokens\NamedSearchToken();
list ($tokenKey, $tokenValue) = explode(':', $tokenText, 2);
$searchToken->setKey($tokenKey);
$searchToken->setValue($tokenValue);
}
else
{
$searchToken = new \Szurubooru\SearchServices\Tokens\SearchToken();
$searchToken->setValue($tokenText);
}
$searchToken->setNegated($negated);
$searchTokens[] = $searchToken;
}
return $searchTokens;
}
}