mirror of
https://github.com/flarum/framework.git
synced 2024-11-24 15:37:36 +08:00
Add extender and tests for filter
This commit is contained in:
parent
0b2d01b75f
commit
baa5fdad95
65
src/Extend/Filter.php
Normal file
65
src/Extend/Filter.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?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\Extend;
|
||||
|
||||
use Flarum\Extension\Extension;
|
||||
use Flarum\Filter\Filterer;
|
||||
use Flarum\Filter\FilterInterface;
|
||||
use Flarum\Foundation\ContainerUtil;
|
||||
use Illuminate\Contracts\Container\Container;
|
||||
|
||||
class Filter implements ExtenderInterface
|
||||
{
|
||||
private $resource;
|
||||
private $filters = [];
|
||||
private $filterMutators = [];
|
||||
|
||||
/**
|
||||
* @param string $resource: The ::class attribute of the resource this applies to, which is typically an Eloquent model.
|
||||
*/
|
||||
public function __construct($resource)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a filter to run when the resource is filtered
|
||||
*
|
||||
* @param string $filterClass: The ::class attribute of the filter you are adding.
|
||||
*/
|
||||
public function addFilter(string $filterClass)
|
||||
{
|
||||
$this->filters[] = $filterClass;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a callback through which to run all filter queries after filters have been applied.
|
||||
*/
|
||||
public function addFilterMutator($callback)
|
||||
{
|
||||
$this->filterMutators[] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function extend(Container $container, Extension $extension = null)
|
||||
{
|
||||
|
||||
foreach ($this->filters as $filter) {
|
||||
Filterer::addFilter($this->resource, $container->make($filter));
|
||||
}
|
||||
|
||||
foreach ($this->filterMutators as $mutator) {
|
||||
Filterer::addFilterMutator($this->resource, ContainerUtil::wrapCallback($mutator, $container));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,13 +21,17 @@ class Filterer
|
|||
|
||||
protected static $filterMutators = [];
|
||||
|
||||
public static function addFilter($resource, $filterKey, $filter)
|
||||
public static function addFilter($resource, FilterInterface $filter)
|
||||
{
|
||||
if (!array_key_exists($resource, static::$filters)) {
|
||||
static::$filters[$resource] = [];
|
||||
}
|
||||
|
||||
static::$filters[$resource][$filterKey] = $filter;
|
||||
if (!array_key_exists($filter->getKey(), static::$filters[$resource])) {
|
||||
static::$filters[$resource][$filter->getKey()] = [];
|
||||
}
|
||||
|
||||
static::$filters[$resource][$filter->getKey()][] = $filter;
|
||||
}
|
||||
|
||||
public static function addFilterMutator($resource, $mutator)
|
||||
|
@ -52,20 +56,20 @@ class Filterer
|
|||
|
||||
$query->whereVisibleTo($actor);
|
||||
|
||||
foreach (Arr::get(static::$filters, $resource, []) as $filterKey => $filterCallback) {
|
||||
if (array_key_exists($filterKey, $filters)) {
|
||||
$filterCallback($query, $filters[$filterKey]);
|
||||
$wrappedFilter = new WrappedFilter($query->getQuery(), $actor);
|
||||
|
||||
foreach ($filters as $filterKey => $filterValue) {
|
||||
foreach (Arr::get(static::$filters, "$resource.$filterKey", []) as $filter) {
|
||||
$filter->apply($wrappedFilter, $filterValue);
|
||||
}
|
||||
}
|
||||
|
||||
$wrappedFilter = new WrappedFilter($query->getQuery(), $actor);
|
||||
|
||||
$this->applySort($wrappedFilter, $sort);
|
||||
$this->applyOffset($wrappedFilter, $offset);
|
||||
$this->applyLimit($wrappedFilter, $limit + 1);
|
||||
|
||||
foreach (Arr::get(static::$filterMutators, $resource, []) as $mutator) {
|
||||
$mutator($wrappedFilter, $filters, $sort);
|
||||
$mutator($query, $actor, $filters, $sort);
|
||||
}
|
||||
|
||||
// Execute the filter query and retrieve the results. We get one more
|
||||
|
|
138
tests/integration/extenders/FilterTest.php
Normal file
138
tests/integration/extenders/FilterTest.php
Normal file
|
@ -0,0 +1,138 @@
|
|||
<?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\Tests\integration\extenders;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Flarum\Discussion\Discussion;
|
||||
use Flarum\Discussion\Search\DiscussionSearcher;
|
||||
use Flarum\Extend;
|
||||
use Flarum\Filter\FilterInterface;
|
||||
use Flarum\Filter\WrappedFilter;
|
||||
use Flarum\Search\AbstractSearch;
|
||||
use Flarum\Tests\integration\RetrievesAuthorizedUsers;
|
||||
use Flarum\Tests\integration\TestCase;
|
||||
use Flarum\User\User;
|
||||
|
||||
class FilterTest extends TestCase
|
||||
{
|
||||
use RetrievesAuthorizedUsers;
|
||||
|
||||
public function prepDb()
|
||||
{
|
||||
$this->prepareDatabase([
|
||||
'discussions' => [
|
||||
['id' => 1, 'title' => 'DISCUSSION 1', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'first_post_id' => 1, 'comment_count' => 1],
|
||||
['id' => 2, 'title' => 'DISCUSSION 2', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'first_post_id' => 2, 'comment_count' => 1],
|
||||
],
|
||||
'posts' => [
|
||||
['id' => 1, 'discussion_id' => 1, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'type' => 'comment', 'content' => '<t><p>foo bar</p></t>'],
|
||||
['id' => 2, 'discussion_id' => 2, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'type' => 'comment', 'content' => '<t><p>foo bar not the same</p></t>'],
|
||||
],
|
||||
'users' => [
|
||||
$this->adminUser(),
|
||||
$this->normalUser(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function filterDiscussions($filters, $limit = null)
|
||||
{
|
||||
$response = $this->send(
|
||||
$this->request('GET', '/api/discussions', [
|
||||
'authenticatedAs' => 1,
|
||||
])->withQueryParams([
|
||||
'filter' => $filters,
|
||||
'include' => 'mostRelevantPost',
|
||||
])
|
||||
);
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true)['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function works_as_expected_with_no_modifications()
|
||||
{
|
||||
$this->prepDb();
|
||||
|
||||
$searchForAll = json_encode($this->filterDiscussions([], 5));
|
||||
$this->assertContains('DISCUSSION 1', $searchForAll);
|
||||
$this->assertContains('DISCUSSION 2', $searchForAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function custom_filter_gambit_has_effect_if_added()
|
||||
{
|
||||
$this->extend((new Extend\Filter(Discussion::class))->addFilter(NoResultFilter::class));
|
||||
|
||||
$this->prepDb();
|
||||
|
||||
$withResultSearch = json_encode($this->filterDiscussions(['noResult' => 0], 5));
|
||||
$this->assertContains('DISCUSSION 1', $withResultSearch);
|
||||
$this->assertContains('DISCUSSION 2', $withResultSearch);
|
||||
$this->assertEquals([], $this->filterDiscussions(['noResult' => 1], 5));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function filter_mutator_has_effect_if_added()
|
||||
{
|
||||
$this->extend((new Extend\Filter(Discussion::class))->addFilterMutator(function ($query, $actor, $filters, $sort) {
|
||||
$query->getQuery()->whereRaw('1=0');
|
||||
}));
|
||||
|
||||
$this->prepDb();
|
||||
|
||||
$this->assertEquals([], $this->filterDiscussions([], 5));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function filter_mutator_has_effect_if_added_with_invokable_class()
|
||||
{
|
||||
$this->extend((new Extend\Filter(Discussion::class))->addFilterMutator(CustomFilterMutator::class));
|
||||
|
||||
$this->prepDb();
|
||||
|
||||
$this->assertEquals([], $this->filterDiscussions([], 5));
|
||||
}
|
||||
}
|
||||
|
||||
class NoResultFilter implements FilterInterface
|
||||
{
|
||||
public function getKey(): string
|
||||
{
|
||||
return 'noResult';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(WrappedFilter $wrappedFilter, $filterValue)
|
||||
{
|
||||
if ($filterValue) {
|
||||
$wrappedFilter->getQuery()
|
||||
->whereRaw('0=1');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CustomFilterMutator
|
||||
{
|
||||
public function __invoke($query, $actor, $filters, $sort)
|
||||
{
|
||||
$query->getQuery()->whereRaw('1=0');
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user