1
0
mirror of https://github.com/flarum/core.git synced 2025-10-19 02:36:08 +02:00

Search Filter Split, Use Same Controller (#2454)

This commit is contained in:
Alexander Skvortsov
2021-02-24 11:17:40 -05:00
committed by GitHub
parent 1c578a83e4
commit 023871ef86
42 changed files with 1663 additions and 535 deletions

View File

@@ -9,8 +9,8 @@
namespace Flarum\Discussion\Event;
use Flarum\Discussion\Search\DiscussionSearch;
use Flarum\Search\SearchCriteria;
use Flarum\Search\SearchState;
/**
* @deprecated beta 16, remove beta 17
@@ -18,7 +18,7 @@ use Flarum\Search\SearchCriteria;
class Searching
{
/**
* @var DiscussionSearch
* @var SearchState
*/
public $search;
@@ -28,10 +28,10 @@ class Searching
public $criteria;
/**
* @param DiscussionSearch $search
* @param SearchState $search
* @param \Flarum\Search\SearchCriteria $criteria
*/
public function __construct(DiscussionSearch $search, SearchCriteria $criteria)
public function __construct(SearchState $search, SearchCriteria $criteria)
{
$this->search = $search;
$this->criteria = $criteria;

View File

@@ -0,0 +1,72 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Filter;
use Flarum\Filter\FilterInterface;
use Flarum\Filter\FilterState;
use Flarum\Search\AbstractRegexGambit;
use Flarum\Search\SearchState;
use Flarum\User\UserRepository;
use Illuminate\Database\Query\Builder;
class AuthorFilterGambit extends AbstractRegexGambit implements FilterInterface
{
/**
* @var \Flarum\User\UserRepository
*/
protected $users;
/**
* @param \Flarum\User\UserRepository $users
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}
/**
* {@inheritdoc}
*/
public function getGambitPattern()
{
return 'author:(.+)';
}
/**
* {@inheritdoc}
*/
protected function conditions(SearchState $search, array $matches, $negate)
{
$this->constrain($search->getQuery(), $matches[1], $negate);
}
public function getFilterKey(): string
{
return 'author';
}
public function filter(FilterState $filterState, string $filterValue, bool $negate)
{
$this->constrain($filterState->getQuery(), $filterValue, $negate);
}
protected function constrain(Builder $query, $rawUsernames, $negate)
{
$usernames = trim($rawUsernames, '"');
$usernames = explode(',', $usernames);
$ids = [];
foreach ($usernames as $username) {
$ids[] = $this->users->getIdForUsername($username);
}
$query->whereIn('discussions.user_id', $ids, 'and', $negate);
}
}

View File

@@ -0,0 +1,61 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Filter;
use Flarum\Filter\FilterInterface;
use Flarum\Filter\FilterState;
use Flarum\Search\AbstractRegexGambit;
use Flarum\Search\SearchState;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Arr;
class CreatedFilterGambit extends AbstractRegexGambit implements FilterInterface
{
/**
* {@inheritdoc}
*/
public function getGambitPattern()
{
return 'created:(\d{4}\-\d\d\-\d\d)(\.\.(\d{4}\-\d\d\-\d\d))?';
}
/**
* {@inheritdoc}
*/
protected function conditions(SearchState $search, array $matches, $negate)
{
$this->constrain($search->getQuery(), Arr::get($matches, 1), Arr::get($matches, 3), $negate);
}
public function getFilterKey(): string
{
return 'created';
}
public function filter(FilterState $filterState, string $filterValue, bool $negate)
{
preg_match('/^'.$this->getGambitPattern().'$/i', 'created:'.$filterValue, $matches);
$this->constrain($filterState->getQuery(), Arr::get($matches, 1), Arr::get($matches, 3), $negate);
}
public function constrain(Builder $query, ?string $firstDate, ?string $secondDate, $negate)
{
// If we've just been provided with a single YYYY-MM-DD date, then find
// discussions that were started on that exact date. But if we've been
// provided with a YYYY-MM-DD..YYYY-MM-DD range, then find discussions
// that were started during that period.
if (empty($secondDate)) {
$query->whereDate('created_at', $negate ? '!=' : '=', $firstDate);
} else {
$query->whereBetween('created_at', [$firstDate, $secondDate], 'and', $negate);
}
}
}

View File

@@ -0,0 +1,40 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Filter;
use Flarum\Discussion\DiscussionRepository;
use Flarum\Filter\AbstractFilterer;
use Flarum\User\User;
use Illuminate\Database\Eloquent\Builder;
class DiscussionFilterer extends AbstractFilterer
{
/**
* @var DiscussionRepository
*/
protected $discussions;
/**
* @param DiscussionRepository $discussions
* @param array $filters
* @param array $filterMutators
*/
public function __construct(DiscussionRepository $discussions, array $filters, array $filterMutators)
{
parent::__construct($filters, $filterMutators);
$this->discussions = $discussions;
}
protected function getQuery(User $actor): Builder
{
return $this->discussions->query()->select('discussions.*')->whereVisibleTo($actor);
}
}

View File

@@ -0,0 +1,56 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Filter;
use Flarum\Filter\FilterInterface;
use Flarum\Filter\FilterState;
use Flarum\Search\AbstractRegexGambit;
use Flarum\Search\SearchState;
use Illuminate\Database\Query\Builder;
class HiddenFilterGambit extends AbstractRegexGambit implements FilterInterface
{
/**
* {@inheritdoc}
*/
public function getGambitPattern()
{
return 'is:hidden';
}
/**
* {@inheritdoc}
*/
protected function conditions(SearchState $search, array $matches, $negate)
{
$this->constrain($search->getQuery(), $negate);
}
public function getFilterKey(): string
{
return 'hidden';
}
public function filter(FilterState $filterState, string $filterValue, bool $negate)
{
$this->constrain($filterState->getQuery(), $negate);
}
protected function constrain(Builder $query, bool $negate)
{
$query->where(function ($query) use ($negate) {
if ($negate) {
$query->whereNull('hidden_at')->where('comment_count', '>', 0);
} else {
$query->whereNotNull('hidden_at')->orWhere('comment_count', 0);
}
});
}
}

View File

@@ -7,21 +7,18 @@
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Search\Gambit;
namespace Flarum\Discussion\Filter;
use Flarum\Discussion\DiscussionRepository;
use Flarum\Discussion\Search\DiscussionSearch;
use Flarum\Filter\FilterInterface;
use Flarum\Filter\FilterState;
use Flarum\Search\AbstractRegexGambit;
use Flarum\Search\AbstractSearch;
use LogicException;
use Flarum\Search\SearchState;
use Flarum\User\User;
use Illuminate\Database\Query\Builder;
class UnreadGambit extends AbstractRegexGambit
class UnreadFilterGambit extends AbstractRegexGambit implements FilterInterface
{
/**
* {@inheritdoc}
*/
protected $pattern = 'is:unread';
/**
* @var \Flarum\Discussion\DiscussionRepository
*/
@@ -38,18 +35,35 @@ class UnreadGambit extends AbstractRegexGambit
/**
* {@inheritdoc}
*/
protected function conditions(AbstractSearch $search, array $matches, $negate)
public function getGambitPattern()
{
if (! $search instanceof DiscussionSearch) {
throw new LogicException('This gambit can only be applied on a DiscussionSearch');
}
return 'is:unread';
}
$actor = $search->getActor();
/**
* {@inheritdoc}
*/
protected function conditions(SearchState $search, array $matches, $negate)
{
$this->constrain($search->getQuery(), $search->getActor(), $negate);
}
public function getFilterKey(): string
{
return 'unread';
}
public function filter(FilterState $filterState, string $filterValue, bool $negate)
{
$this->constrain($filterState->getQuery(), $filterState->getActor(), $negate);
}
protected function constrain(Builder $query, User $actor, bool $negate)
{
if ($actor->exists) {
$readIds = $this->discussions->getReadIds($actor);
$search->getQuery()->where(function ($query) use ($readIds, $negate, $actor) {
$query->where(function ($query) use ($readIds, $negate, $actor) {
if (! $negate) {
$query->whereNotIn('id', $readIds)->where('last_posted_at', '>', $actor->marked_all_as_read_at ?: 0);
} else {

View File

@@ -1,51 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Search;
use Flarum\Search\AbstractSearch;
/**
* An object which represents the internal state of a search for discussions:
* the search query, the user performing the search, the fallback sort order,
* relevant post information, and a log of which gambits have been used.
*/
class DiscussionSearch extends AbstractSearch
{
/**
* {@inheritdoc}
*/
protected $defaultSort = ['lastPostedAt' => 'desc'];
/**
* @var array
*/
protected $relevantPostIds = [];
/**
* Get the related IDs for each result.
*
* @return int[]
*/
public function getRelevantPostIds()
{
return $this->relevantPostIds;
}
/**
* Set the relevant post IDs for the results.
*
* @param array $relevantPostIds
* @return void
*/
public function setRelevantPostIds(array $relevantPostIds)
{
$this->relevantPostIds = $relevantPostIds;
}
}

View File

@@ -11,10 +11,10 @@ namespace Flarum\Discussion\Search;
use Flarum\Discussion\DiscussionRepository;
use Flarum\Discussion\Event\Searching;
use Flarum\Search\AbstractSearch;
use Flarum\Search\AbstractSearcher;
use Flarum\Search\GambitManager;
use Flarum\Search\SearchCriteria;
use Flarum\Search\SearchState;
use Flarum\User\User;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Database\Eloquent\Builder;
@@ -50,15 +50,10 @@ class DiscussionSearcher extends AbstractSearcher
return $this->discussions->query()->select('discussions.*')->whereVisibleTo($actor);
}
protected function getSearch(Builder $query, User $actor): AbstractSearch
{
return new DiscussionSearch($query->getQuery(), $actor);
}
/**
* @deprecated along with the Searching event, remove in Beta 17.
*/
protected function mutateSearch(AbstractSearch $search, SearchCriteria $criteria)
protected function mutateSearch(SearchState $search, SearchCriteria $criteria)
{
parent::mutateSearch($search, $criteria);

View File

@@ -1,57 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Search\Gambit;
use Flarum\Discussion\Search\DiscussionSearch;
use Flarum\Search\AbstractRegexGambit;
use Flarum\Search\AbstractSearch;
use Flarum\User\UserRepository;
use LogicException;
class AuthorGambit extends AbstractRegexGambit
{
/**
* {@inheritdoc}
*/
protected $pattern = 'author:(.+)';
/**
* @var \Flarum\User\UserRepository
*/
protected $users;
/**
* @param \Flarum\User\UserRepository $users
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}
/**
* {@inheritdoc}
*/
protected function conditions(AbstractSearch $search, array $matches, $negate)
{
if (! $search instanceof DiscussionSearch) {
throw new LogicException('This gambit can only be applied on a DiscussionSearch');
}
$usernames = trim($matches[1], '"');
$usernames = explode(',', $usernames);
$ids = [];
foreach ($usernames as $username) {
$ids[] = $this->users->getIdForUsername($username);
}
$search->getQuery()->whereIn('discussions.user_id', $ids, 'and', $negate);
}
}

View File

@@ -1,43 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Search\Gambit;
use Flarum\Discussion\Search\DiscussionSearch;
use Flarum\Search\AbstractRegexGambit;
use Flarum\Search\AbstractSearch;
use LogicException;
class CreatedGambit extends AbstractRegexGambit
{
/**
* {@inheritdoc}
*/
protected $pattern = 'created:(\d{4}\-\d\d\-\d\d)(\.\.(\d{4}\-\d\d\-\d\d))?';
/**
* {@inheritdoc}
*/
protected function conditions(AbstractSearch $search, array $matches, $negate)
{
if (! $search instanceof DiscussionSearch) {
throw new LogicException('This gambit can only be applied on a DiscussionSearch');
}
// If we've just been provided with a single YYYY-MM-DD date, then find
// discussions that were started on that exact date. But if we've been
// provided with a YYYY-MM-DD..YYYY-MM-DD range, then find discussions
// that were started during that period.
if (empty($matches[3])) {
$search->getQuery()->whereDate('created_at', $negate ? '!=' : '=', $matches[1]);
} else {
$search->getQuery()->whereBetween('created_at', [$matches[1], $matches[3]], 'and', $negate);
}
}
}

View File

@@ -9,24 +9,18 @@
namespace Flarum\Discussion\Search\Gambit;
use Flarum\Discussion\Search\DiscussionSearch;
use Flarum\Post\Post;
use Flarum\Search\AbstractSearch;
use Flarum\Search\GambitInterface;
use Flarum\Search\SearchState;
use Illuminate\Database\Query\Expression;
use LogicException;
class FulltextGambit implements GambitInterface
{
/**
* {@inheritdoc}
*/
public function apply(AbstractSearch $search, $bit)
public function apply(SearchState $search, $bit)
{
if (! $search instanceof DiscussionSearch) {
throw new LogicException('This gambit can only be applied on a DiscussionSearch');
}
// Replace all non-word characters with spaces.
// We do this to prevent MySQL fulltext search boolean mode from taking
// effect: https://dev.mysql.com/doc/refman/5.7/en/fulltext-boolean.html

View File

@@ -1,41 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Discussion\Search\Gambit;
use Flarum\Discussion\Search\DiscussionSearch;
use Flarum\Search\AbstractRegexGambit;
use Flarum\Search\AbstractSearch;
use LogicException;
class HiddenGambit extends AbstractRegexGambit
{
/**
* {@inheritdoc}
*/
protected $pattern = 'is:hidden';
/**
* {@inheritdoc}
*/
protected function conditions(AbstractSearch $search, array $matches, $negate)
{
if (! $search instanceof DiscussionSearch) {
throw new LogicException('This gambit can only be applied on a DiscussionSearch');
}
$search->getQuery()->where(function ($query) use ($negate) {
if ($negate) {
$query->whereNull('hidden_at')->where('comment_count', '>', 0);
} else {
$query->whereNotNull('hidden_at')->orWhere('comment_count', 0);
}
});
}
}