1
0
mirror of https://github.com/flarum/core.git synced 2025-10-14 00:15:51 +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

@@ -0,0 +1,86 @@
<?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\Filter;
use Flarum\Search\ApplySearchParametersTrait;
use Flarum\Search\SearchCriteria;
use Flarum\Search\SearchResults;
use Flarum\User\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use InvalidArgumentException;
abstract class AbstractFilterer
{
use ApplySearchParametersTrait;
protected $filters;
protected $filterMutators;
/**
* @param array $filters
* @param array $filterMutators
*/
public function __construct(array $filters, array $filterMutators)
{
$this->filters = $filters;
$this->filterMutators = $filterMutators;
}
abstract protected function getQuery(User $actor): Builder;
/**
* @param SearchCriteria $criteria
* @param mixed|null $limit
* @param int $offset
*
* @return SearchResults
* @throws InvalidArgumentException
*/
public function filter(SearchCriteria $criteria, int $limit = null, int $offset = 0): SearchResults
{
$actor = $criteria->actor;
$query = $this->getQuery($actor);
$filterState = new FilterState($query->getQuery(), $actor);
foreach ($criteria->query as $filterKey => $filterValue) {
$negate = false;
if (substr($filterKey, 0, 1) == '-') {
$negate = true;
$filterKey = substr($filterKey, 1);
}
foreach (Arr::get($this->filters, $filterKey, []) as $filter) {
$filter->filter($filterState, $filterValue, $negate);
}
}
$this->applySort($filterState, $criteria->sort);
$this->applyOffset($filterState, $offset);
$this->applyLimit($filterState, $limit + 1);
foreach ($this->filterMutators as $mutator) {
$mutator($query, $actor, $criteria->query, $criteria->sort);
}
// Execute the filter query and retrieve the results. We get one more
// results than the user asked for, so that we can say if there are more
// results. If there are, we will get rid of that extra result.
$results = $query->get();
if ($areMoreResults = $limit > 0 && $results->count() > $limit) {
$results->pop();
}
return new SearchResults($results, $areMoreResults);
}
}

View File

@@ -0,0 +1,26 @@
<?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\Filter;
interface FilterInterface
{
/**
* This filter will only be run when a query contains a filter param with this key.
*/
public function getFilterKey(): string;
/**
* Filters a query.
*
* @param FilterState $filter
* @param string $value The value of the requested filter
*/
public function filter(FilterState $filterState, string $filterValue, bool $negate);
}

View File

@@ -0,0 +1,85 @@
<?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\Filter;
use Flarum\Discussion\Filter\AuthorFilterGambit;
use Flarum\Discussion\Filter\CreatedFilterGambit;
use Flarum\Discussion\Filter\DiscussionFilterer;
use Flarum\Discussion\Filter\HiddenFilterGambit;
use Flarum\Discussion\Filter\UnreadFilterGambit;
use Flarum\Foundation\AbstractServiceProvider;
use Flarum\Foundation\ContainerUtil;
use Flarum\User\Filter\EmailFilterGambit;
use Flarum\User\Filter\GroupFilterGambit;
use Flarum\User\Filter\UserFilterer;
use Illuminate\Support\Arr;
class FilterServiceProvider extends AbstractServiceProvider
{
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->singleton('flarum.filter.filters', function () {
return [
DiscussionFilterer::class => [
AuthorFilterGambit::class,
CreatedFilterGambit::class,
HiddenFilterGambit::class,
UnreadFilterGambit::class,
],
UserFilterer::class => [
EmailFilterGambit::class,
GroupFilterGambit::class,
]
];
});
$this->app->singleton('flarum.filter.filter_mutators', function () {
return [];
});
}
public function boot()
{
// We can resolve the filter mutators in the when->needs->give callback,
// but we need to resolve at least one regardless so we know which
// filterers we need to register filters for.
$filters = $this->app->make('flarum.filter.filters');
foreach ($filters as $filterer => $filterClasses) {
$this->app
->when($filterer)
->needs('$filters')
->give(function () use ($filterClasses) {
$compiled = [];
foreach ($filterClasses as $filterClass) {
$filter = $this->app->make($filterClass);
$compiled[$filter->getFilterKey()][] = $filter;
}
return $compiled;
});
$this->app
->when($filterer)
->needs('$filterMutators')
->give(function () use ($filterer) {
return array_map(function ($filterMutatorClass) {
return ContainerUtil::wrapCallback($filterMutatorClass, $this->app);
}, Arr::get($this->app->make('flarum.filter.filter_mutators'), $filterer, []));
});
}
}
}

View File

@@ -0,0 +1,87 @@
<?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\Filter;
use Flarum\User\User;
use Illuminate\Database\Query\Builder;
class FilterState
{
/**
* @var Builder
*/
protected $query;
/**
* @var User
*/
protected $actor;
/**
* @var mixed
*/
protected $defaultSort = [];
/**
* @param Builder $query
* @param User $actor
*/
public function __construct(Builder $query, User $actor, $defaultSort = [])
{
$this->query = $query;
$this->actor = $actor;
$this->defaultSort = $defaultSort;
}
/**
* Get the query builder for the search results query.
*
* @return Builder
*/
public function getQuery()
{
return $this->query;
}
/**
* Get the user who is performing the search.
*
* @return User
*/
public function getActor()
{
return $this->actor;
}
/**
* Get the default sort order for the search.
*
* @return array
*/
public function getDefaultSort()
{
return $this->defaultSort;
}
/**
* Set the default sort order for the search. This will only be applied if
* a sort order has not been specified in the search criteria.
*
* @param mixed $defaultSort An array of sort-order pairs, where the column
* is the key, and the order is the value. The order may be 'asc',
* 'desc', or an array of IDs to order by.
* Alternatively, a callable may be used.
* @return mixed
*/
public function setDefaultSort($defaultSort)
{
$this->defaultSort = $defaultSort;
}
}