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:
committed by
GitHub
parent
1c578a83e4
commit
023871ef86
@@ -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;
|
||||
|
72
src/Discussion/Filter/AuthorFilterGambit.php
Normal file
72
src/Discussion/Filter/AuthorFilterGambit.php
Normal 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);
|
||||
}
|
||||
}
|
61
src/Discussion/Filter/CreatedFilterGambit.php
Normal file
61
src/Discussion/Filter/CreatedFilterGambit.php
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
40
src/Discussion/Filter/DiscussionFilterer.php
Normal file
40
src/Discussion/Filter/DiscussionFilterer.php
Normal 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);
|
||||
}
|
||||
}
|
56
src/Discussion/Filter/HiddenFilterGambit.php
Normal file
56
src/Discussion/Filter/HiddenFilterGambit.php
Normal 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -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 {
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user