diff --git a/src/Controllers/PostController.php b/src/Controllers/PostController.php index 82c0ccc2..a6a48679 100644 --- a/src/Controllers/PostController.php +++ b/src/Controllers/PostController.php @@ -70,21 +70,6 @@ class PostController extends AbstractController $this->redirect($url); } - public function favoritesView($page = 1) - { - $this->listView('favmin:1', $page, 'favorites'); - } - - public function upvotedView($page = 1) - { - $this->listView('scoremin:1', $page, 'upvoted'); - } - - public function randomView($page = 1) - { - $this->listView('order:random', $page, 'random'); - } - public function toggleTagAction($identifier, $tag, $enable) { Access::assert(new Privilege( diff --git a/src/Models/SearchParsers/AbstractSearchParser.php b/src/Models/SearchParsers/AbstractSearchParser.php index da0daff7..316c9ec7 100644 --- a/src/Models/SearchParsers/AbstractSearchParser.php +++ b/src/Models/SearchParsers/AbstractSearchParser.php @@ -5,11 +5,41 @@ abstract class AbstractSearchParser { protected $statement; - public function decorate($statement, $filterString) + public function disassembleTokens($searchString) + { + return preg_split('/\s+/', $searchString); + } + + public function assembleTokens($tokens) + { + return implode(' ', $tokens); + } + + public function addTokenToSearchString($searchString, $token) + { + $tokensToInclude = is_array($token) + ? $token + : [$token]; + $tokens = $this->disassembleTokens($searchString); + $newTokens = array_filter(array_unique(array_merge($tokens, $tokensToInclude))); + return $this->assembleTokens($newTokens); + } + + public function removeTokenFromSearchString($searchString, $token) + { + $tokensToExclude = is_array($token) + ? $token + : [$token]; + $tokens = $this->disassembleTokens($searchString); + $newTokens = array_diff($tokens, $tokensToExclude); + return $this->assembleTokens($newTokens); + } + + public function decorate($statement, $searchString) { $this->statement = $statement; - $tokens = preg_split('/\s+/', $filterString); + $tokens = $this->disassembleTokens($searchString); $tokens = array_filter($tokens); $tokens = array_unique($tokens); $this->processSetup($tokens); diff --git a/src/Models/SearchServices/AbstractSearchService.php b/src/Models/SearchServices/AbstractSearchService.php index 9f0aeec3..fc417464 100644 --- a/src/Models/SearchServices/AbstractSearchService.php +++ b/src/Models/SearchServices/AbstractSearchService.php @@ -3,38 +3,7 @@ use \Chibi\Sql as Sql; abstract class AbstractSearchService { - protected static function getModelClassName() - { - $searchServiceClassName = get_called_class(); - $modelClassName = str_replace('SearchService', 'Model', $searchServiceClassName); - return $modelClassName; - } - - protected static function getParserClassName() - { - $searchServiceClassName = get_called_class(); - $parserClassName = str_replace('SearchService', 'SearchParser', $searchServiceClassName); - return $parserClassName; - } - - protected static function decorateParser($stmt, $searchQuery) - { - $parserClassName = self::getParserClassName(); - (new $parserClassName)->decorate($stmt, $searchQuery); - } - - protected static function decorateCustom($stmt) - { - } - - protected static function decoratePager($stmt, $perPage, $page) - { - if ($perPage === null) - return; - $stmt->setLimit( - new Sql\Binding($perPage), - new Sql\Binding(($page - 1) * $perPage)); - } + protected static $parser; public static function getEntities($searchQuery, $perPage = null, $page = 1) { @@ -44,7 +13,7 @@ abstract class AbstractSearchService $stmt = Sql\Statements::select(); $stmt->setColumn($table . '.*'); $stmt->setTable($table); - static::decorateParser($stmt, $searchQuery); + static::decorateFromParser($stmt, $searchQuery); static::decorateCustom($stmt); static::decoratePager($stmt, $perPage, $page); @@ -60,7 +29,7 @@ abstract class AbstractSearchService $innerStmt = Sql\Statements::select(); $innerStmt->setTable($table); - static::decorateParser($innerStmt, $searchQuery); + static::decorateFromParser($innerStmt, $searchQuery); static::decorateCustom($innerStmt); $innerStmt->resetOrderBy(); @@ -70,4 +39,45 @@ abstract class AbstractSearchService return Core::getDatabase()->fetchOne($stmt)['count']; } + + public static function getParser() + { + $parserClassName = self::getParserClassName(); + if (self::$parser == null) + self::$parser = new $parserClassName(); + return self::$parser; + } + + protected static function getModelClassName() + { + $searchServiceClassName = get_called_class(); + $modelClassName = str_replace('SearchService', 'Model', $searchServiceClassName); + return $modelClassName; + } + + protected static function decorateFromParser($stmt, $searchQuery) + { + self::getParser()->decorate($stmt, $searchQuery); + } + + protected static function decorateCustom($stmt) + { + } + + protected static function decoratePager($stmt, $perPage, $page) + { + if ($perPage === null) + return; + $stmt->setLimit( + new Sql\Binding($perPage), + new Sql\Binding(($page - 1) * $perPage)); + } + + private static function getParserClassName() + { + $searchServiceClassName = get_called_class(); + $parserClassName = str_replace('SearchService', 'SearchParser', $searchServiceClassName); + return $parserClassName; + } + } diff --git a/src/Models/SearchServices/PostSearchService.php b/src/Models/SearchServices/PostSearchService.php index cc891cab..fa7d27d4 100644 --- a/src/Models/SearchServices/PostSearchService.php +++ b/src/Models/SearchServices/PostSearchService.php @@ -20,7 +20,7 @@ class PostSearchService extends AbstractSearchService $innerStmt = Sql\Statements::select(); $innerStmt->setColumn('post.id'); $innerStmt->setTable('post'); - self::decorateParser($innerStmt, $searchQuery); + self::decorateFromParser($innerStmt, $searchQuery); $stmt = Sql\Statements::insert(); $stmt->setTable('post_search'); $stmt->setSource(['post_id'], $innerStmt); diff --git a/src/Router.php b/src/Router.php index 8ef719b8..3d3e37f2 100644 --- a/src/Router.php +++ b/src/Router.php @@ -63,13 +63,6 @@ class Router extends \Chibi\Routing\Router $this->register(['PostController', 'listView'], 'GET', '/{source}/{query}/{additionalInfo}/{page}', $postValidation); $this->register(['PostController', 'listRedirectAction'], 'POST', '/{source}-redirect', $postValidation); - $this->register(['PostController', 'randomView'], 'GET', '/random', $postValidation); - $this->register(['PostController', 'randomView'], 'GET', '/random/{page}', $postValidation); - $this->register(['PostController', 'favoritesView'], 'GET', '/favorites', $postValidation); - $this->register(['PostController', 'favoritesView'], 'GET', '/favorites/{page}', $postValidation); - $this->register(['PostController', 'upvotedView'], 'GET', '/upvoted', $postValidation); - $this->register(['PostController', 'upvotedView'], 'GET', '/upvoted/{page}', $postValidation); - $this->register(['PostController', 'genericView'], 'GET', '/post/{identifier}', $postValidation); $this->register(['PostController', 'fileView'], 'GET', '/post/{name}/retrieve', $postValidation); $this->register(['PostController', 'thumbnailView'], 'GET', '/post/{name}/thumb', $postValidation); diff --git a/src/Views/post/post-list-wrapper.phtml b/src/Views/post/post-list-wrapper.phtml index 61efa072..cfadbc52 100644 --- a/src/Views/post/post-list-wrapper.phtml +++ b/src/Views/post/post-list-wrapper.phtml @@ -1,59 +1,81 @@ assets->setSubTitle('posts'); +$searchQuery = isset($this->context->transport->searchQuery) + ? htmlspecialchars($this->context->transport->searchQuery) + : ''; + +$parser = PostSearchService::getParser(); +$newSearchQuery = PostSearchService::getParser()->removeTokenFromSearchString( + $searchQuery, + ['favmin:1', 'scoremin:1', 'order:random']); $tabs = []; $activeTab = 0; -if (Access::check(new Privilege(Privilege::ListPosts))) - $tabs []= ['All posts', Core::getRouter()->linkTo(['PostController', 'listView'])]; - if (Access::check(new Privilege(Privilege::ListPosts))) { - $tabs []= ['Random', Core::getRouter()->linkTo(['PostController', 'randomView'])]; - if ($this->context->source == 'random') - $activeTab = count($tabs) - 1; + $tabs []= [ + 'title' => 'All posts', + 'active' => function() { return true; }, + 'link' => Core::getRouter()->linkTo( + ['PostController', 'listView'], + !trim($newSearchQuery) ? [] : ['query' => $newSearchQuery])]; - $tabs []= ['Favorites', Core::getRouter()->linkTo(['PostController', 'favoritesView'])]; - if ($this->context->source == 'favorites') - $activeTab = count($tabs) - 1; + $tabs []= [ + 'title' => 'Random', + 'active' => function() use ($searchQuery) { return strpos($searchQuery, 'order:random') !== false; }, + 'link' => Core::getRouter()->linkTo( + ['PostController', 'listView'], + ['query' => $parser->addTokenToSearchString($newSearchQuery, 'order:random')])]; - $tabs []= ['Upvoted', Core::getRouter()->linkTo(['PostController', 'upvotedView'])]; - if ($this->context->source == 'upvoted') - $activeTab = count($tabs) - 1; + $tabs []= [ + 'title' => 'Favorites', + 'active' => function() use ($searchQuery) { return strpos($searchQuery, 'favmin:1') !== false; }, + 'link' => Core::getRouter()->linkTo( + ['PostController', 'listView'], + ['query' => $parser->addTokenToSearchString($newSearchQuery, 'favmin:1')])]; + + $tabs []= [ + 'title' => 'Upvoted', + 'active' => function() use ($searchQuery) { return strpos($searchQuery, 'scoremin:1') !== false; }, + 'link' => Core::getRouter()->linkTo( + ['PostController', 'listView'], + ['query' => $parser->addTokenToSearchString($newSearchQuery, 'scoremin:1')])]; } if (Access::check(new Privilege(Privilege::MassTag))) { - $tabs []= ['Mass tag', Core::getRouter()->linkTo(['PostController', 'listView'], [ - 'source' => 'mass-tag', - 'query' => isset($this->context->transport->searchQuery) - ? htmlspecialchars($this->context->transport->searchQuery) - : '', - 'page' => isset($this->context->transport->paginator) - ? $this->context->transport->paginator->page - : 1])]; - - if ($this->context->source == 'mass-tag') - $activeTab = count($tabs) - 1; + $tabs []= [ + 'title' => 'Mass tag', + 'active' => function() { return $this->context->source == 'mass-tag'; }, + 'link' => Core::getRouter()->linkTo(['PostController', 'listView'], [ + 'source' => 'mass-tag', + 'query' => $searchQuery, + 'page' => isset($this->context->transport->paginator) + ? $this->context->transport->paginator->page + : 1])]; } +$activeTab = null; +foreach ($tabs as $key => $tab) + if ($tab['active']()) + $activeTab = $key; ?>