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/Models/SearchParsers/PostSearchParser.php

291 lines
9.6 KiB
PHP
Raw Normal View History

<?php
use \Chibi\Sql as Sql;
class PostSearchParser extends AbstractSearchParser
{
private $tags;
private $showHidden = false;
private $showDisliked = false;
protected function processSetup(&$tokens)
{
$config = \Chibi\Registry::getConfig();
$this->tags = [];
$this->statement->setCriterion(new Sql\ConjunctionFunctor());
$allowedSafety = PrivilegesHelper::getAllowedSafety();
$this->statement->getCriterion()->add(Sql\InFunctor::fromArray('safety', Sql\Binding::fromArray($allowedSafety)));
if (count($tokens) > $config->browsing->maxSearchTokens)
throw new SimpleException('Too many search tokens (maximum: ' . $config->browsing->maxSearchTokens . ')');
}
protected function processTeardown()
{
if (\Chibi\Registry::getContext()->user->hasEnabledHidingDislikedPosts() and !$this->showDisliked)
$this->processComplexToken('special', 'disliked', true);
if (!PrivilegesHelper::confirm(Privilege::ListPosts, 'hidden') or !$this->showHidden)
$this->processComplexToken('special', 'hidden', true);
foreach ($this->tags as $item)
{
list ($tagName, $neg) = $item;
$tag = TagModel::findByName($tagName);
$innerStmt = new Sql\SelectStatement();
$innerStmt->setTable('post_tag');
$innerStmt->setCriterion((new Sql\ConjunctionFunctor)
->add(new Sql\EqualsFunctor('post_tag.post_id', 'post.id'))
->add(new Sql\EqualsFunctor('post_tag.tag_id', new Sql\Binding($tag->id))));
$operator = new Sql\ExistsFunctor($innerStmt);
if ($neg)
$operator = new Sql\NegationFunctor($operator);
$this->statement->getCriterion()->add($operator);
}
2014-02-24 00:11:01 +01:00
$this->statement->addOrderBy('post.id',
empty($this->statement->getOrderBy())
? Sql\SelectStatement::ORDER_DESC
: $this->statement->getOrderBy()[0][1]);
}
protected function processSimpleToken($value, $neg)
{
$this->tags []= [$value, $neg];
return true;
}
protected function prepareCriterionForComplexToken($key, $value)
{
if (in_array($key, ['id', 'ids']))
{
$ids = preg_split('/[;,]/', $value);
$ids = array_map('intval', $ids);
return Sql\InFunctor::fromArray('post.id', Sql\Binding::fromArray($ids));
}
2014-03-03 21:05:44 +01:00
elseif (in_array($key, ['fav', 'favs', 'favd']))
{
$user = UserModel::findByNameOrEmail($value);
$innerStmt = (new Sql\SelectStatement)
->setTable('favoritee')
->setCriterion((new Sql\ConjunctionFunctor)
->add(new Sql\EqualsFunctor('favoritee.post_id', 'post.id'))
->add(new Sql\EqualsFunctor('favoritee.user_id', new Sql\Binding($user->id))));
return new Sql\ExistsFunctor($innerStmt);
}
2014-03-03 21:05:44 +01:00
elseif (in_array($key, ['comment', 'comments', 'commenter', 'commented']))
{
$user = UserModel::findByNameOrEmail($value);
$innerStmt = (new Sql\SelectStatement)
->setTable('comment')
->setCriterion((new Sql\ConjunctionFunctor)
->add(new Sql\EqualsFunctor('comment.post_id', 'post.id'))
->add(new Sql\EqualsFunctor('comment.commenter_id', new Sql\Binding($user->id))));
return new Sql\ExistsFunctor($innerStmt);
}
2014-03-03 21:05:44 +01:00
elseif (in_array($key, ['submit', 'upload', `uploads`, 'uploader', 'uploaded']))
{
$user = UserModel::findByNameOrEmail($value);
2014-03-03 21:27:10 +01:00
return new Sql\EqualsFunctor('post.uploader_id', new Sql\Binding($user->id));
}
elseif (in_array($key, ['idmin', 'id_min']))
return new Sql\EqualsOrGreaterFunctor('post.id', new Sql\Binding(intval($value)));
elseif (in_array($key, ['idmax', 'id_max']))
return new Sql\EqualsOrLesserFunctor('post.id', new Sql\Binding(intval($value)));
elseif (in_array($key, ['scoremin', 'score_min']))
2014-03-03 21:27:10 +01:00
return new Sql\EqualsOrGreaterFunctor('post.score', new Sql\Binding(intval($value)));
elseif (in_array($key, ['scoremax', 'score_max']))
2014-03-03 21:27:10 +01:00
return new Sql\EqualsOrLesserFunctor('post.score', new Sql\Binding(intval($value)));
elseif (in_array($key, ['tagmin', 'tag_min']))
2014-03-03 21:27:10 +01:00
return new Sql\EqualsOrGreaterFunctor('post.tag_count', new Sql\Binding(intval($value)));
elseif (in_array($key, ['tagmax', 'tag_max']))
2014-03-03 21:27:10 +01:00
return new Sql\EqualsOrLesserFunctor('post.tag_count', new Sql\Binding(intval($value)));
elseif (in_array($key, ['favmin', 'fav_min']))
2014-03-03 21:27:10 +01:00
return new Sql\EqualsOrGreaterFunctor('post.fav_count', new Sql\Binding(intval($value)));
elseif (in_array($key, ['favmax', 'fav_max']))
2014-03-03 21:27:10 +01:00
return new Sql\EqualsOrLesserFunctor('post.fav_count', new Sql\Binding(intval($value)));
elseif (in_array($key, ['commentmin', 'comment_min']))
2014-03-03 21:27:10 +01:00
return new Sql\EqualsOrGreaterFunctor('post.comment_count', new Sql\Binding(intval($value)));
elseif (in_array($key, ['commentmax', 'comment_max']))
2014-03-03 21:27:10 +01:00
return new Sql\EqualsOrLesserFunctor('post.comment_count', new Sql\Binding(intval($value)));
2014-02-24 15:52:13 +01:00
elseif (in_array($key, ['date']))
{
list ($dateMin, $dateMax) = self::parseDate($value);
return (new Sql\ConjunctionFunctor)
2014-03-03 21:27:10 +01:00
->add(new Sql\EqualsOrLesserFunctor('post.upload_date', new Sql\Binding($dateMax)))
->add(new Sql\EqualsOrGreaterFunctor('post.upload_date', new Sql\Binding($dateMin)));
2014-02-24 15:52:13 +01:00
}
elseif (in_array($key, ['datemin', 'date_min']))
{
list ($dateMin, $dateMax) = self::parseDate($value);
2014-03-03 21:27:10 +01:00
return new Sql\EqualsOrGreaterFunctor('post.upload_date', new Sql\Binding($dateMin));
}
2014-02-24 15:52:13 +01:00
elseif (in_array($key, ['datemax', 'date_max']))
{
list ($dateMin, $dateMax) = self::parseDate($value);
2014-03-03 21:27:10 +01:00
return new Sql\EqualsOrLesserFunctor('post.upload_date', new Sql\Binding($dateMax));
}
elseif ($key == 'special')
{
$context = \Chibi\Registry::getContext();
$value = strtolower($value);
2014-03-03 21:05:44 +01:00
if (in_array($value, ['fav', 'favs', 'favd']))
{
return $this->prepareCriterionForComplexToken('fav', $context->user->name);
}
elseif (in_array($value, ['like', 'liked', 'likes']))
{
if (!$this->statement->isTableJoined('post_score'))
{
$this->statement->addLeftOuterJoin('post_score', (new Sql\ConjunctionFunctor)
->add(new Sql\EqualsFunctor('post_score.post_id', 'post.id'))
->add(new Sql\EqualsFunctor('post_score.user_id', new Sql\Binding($context->user->id))));
}
return new Sql\EqualsFunctor(new Sql\IfNullFunctor('post_score.score', '0'), '1');
}
elseif (in_array($value, ['dislike', 'disliked', 'dislikes']))
{
$this->showDisliked = true;
if (!$this->statement->isTableJoined('post_score'))
{
$this->statement->addLeftOuterJoin('post_score', (new Sql\ConjunctionFunctor)
->add(new Sql\EqualsFunctor('post_score.post_id', 'post.id'))
->add(new Sql\EqualsFunctor('post_score.user_id', new Sql\Binding($context->user->id))));
}
return new Sql\EqualsFunctor(new Sql\IfNullFunctor('post_score.score', '0'), '-1');
}
elseif ($value == 'hidden')
{
$this->showHidden = true;
return new Sql\StringExpression('hidden');
}
else
throw new SimpleException('Invalid special token: ' . $value);
}
elseif ($key == 'type')
{
$value = strtolower($value);
if ($value == 'swf')
$type = PostType::Flash;
elseif ($value == 'img')
$type = PostType::Image;
elseif ($value == 'yt' or $value == 'youtube')
$type = PostType::Youtube;
else
throw new SimpleException('Invalid post type: ' . $value);
return new Sql\EqualsFunctor('type', new Sql\Binding($type));
}
return null;
}
protected function processComplexToken($key, $value, $neg)
{
$criterion = $this->prepareCriterionForComplexToken($key, $value);
if (!$criterion)
return false;
if ($neg)
$criterion = new Sql\NegationFunctor($criterion);
$this->statement->getCriterion()->add($criterion);
return true;
}
protected function processOrderToken($orderByString, $orderDir)
{
$randomReset = true;
if (in_array($orderByString, ['id']))
$orderColumn = 'post.id';
elseif (in_array($orderByString, ['date']))
2014-03-03 21:27:10 +01:00
$orderColumn = 'post.upload_date';
elseif (in_array($orderByString, ['score']))
2014-03-03 21:27:10 +01:00
$orderColumn = 'post.score';
elseif (in_array($orderByString, ['comment', 'comments', 'commentcount', 'comment_count']))
2014-03-03 21:27:10 +01:00
$orderColumn = 'post.comment_count';
elseif (in_array($orderByString, ['fav', 'favs', 'favcount', 'fav_count']))
2014-03-03 21:27:10 +01:00
$orderColumn = 'post.fav_count';
elseif (in_array($orderByString, ['tag', 'tags', 'tagcount', 'tag_count']))
2014-03-03 21:27:10 +01:00
$orderColumn = 'post.tag_count';
elseif (in_array($orderByString, ['commentdate', 'comment_date']))
2014-03-03 21:27:10 +01:00
$orderColumn = 'post.comment_date';
2014-03-03 19:27:43 +01:00
elseif (in_array($orderByString, ['favdate', 'fav_date']))
2014-03-03 21:27:10 +01:00
$orderColumn = 'post.fav_date';
2014-03-03 19:27:43 +01:00
elseif ($orderByString == 'random')
{
//seeding works like this: if you visit anything
//that triggers order other than random, the seed
//is going to reset. however, it stays the same as
//long as you keep visiting pages with order:random
//specified.
$randomReset = false;
if (!isset($_SESSION['browsing-seed']))
$_SESSION['browsing-seed'] = mt_rand();
$seed = $_SESSION['browsing-seed'];
$orderColumn = new Sql\SubstrFunctor(
new Sql\MultiplicationFunctor('post.id', $seed),
new Sql\AdditionFunctor(new Sql\LengthFunctor('post.id'), '2'));
}
else
return false;
if ($randomReset and isset($_SESSION['browsing-seed']))
unset($_SESSION['browsing-seed']);
$this->statement->setOrderBy($orderColumn, $orderDir);
return true;
}
protected static function parseDate($value)
{
list ($year, $month, $day) = explode('-', $value . '-0-0');
2014-03-03 21:10:09 +01:00
$year = intval($year);
$month = intval($month);
$day = intval($day);
$yearMin = $yearMax = $year;
$monthMin = $monthMax = $month;
$monthMin = $monthMin ?: 1;
$monthMax = $monthMax ?: 12;
2014-03-03 21:10:09 +01:00
$dayMin = $dayMax = $day;
$dayMin = $dayMin ?: 1;
$dayMax = $dayMax ?: intval(date('t', mktime(0, 0, 0, $monthMax, 1, $year)));
$timeMin = mktime(0, 0, 0, $monthMin, $dayMin, $yearMin);
$timeMax = mktime(0, 0, -1, $monthMax, $dayMax+1, $yearMax);
return [$timeMin, $timeMax];
}
}