mirror of
https://github.com/flarum/framework.git
synced 2024-11-25 01:36:53 +08:00
Refactor ListPostsController, make filtering extensible
It became apparent in https://github.com/flarum/core/issues/319#issuecomment-170558573 that there was no way for extensions to add filter parameters to the /api/posts endpoint (e.g. /api/posts?filter[mentioned]=1). Simply adding an event to modify the `$where` array severely limits how much can be done with the query. This commit refactors the controller so that filters are applied directly to the query Builder, and exposes the Builder in a new `ConfigurePostsQuery` event.
This commit is contained in:
parent
36ad4a8554
commit
2018e424ec
|
@ -11,6 +11,8 @@
|
||||||
namespace Flarum\Api\Controller;
|
namespace Flarum\Api\Controller;
|
||||||
|
|
||||||
use Flarum\Core\Repository\PostRepository;
|
use Flarum\Core\Repository\PostRepository;
|
||||||
|
use Flarum\Event\ConfigurePostsQuery;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Tobscure\JsonApi\Document;
|
use Tobscure\JsonApi\Document;
|
||||||
use Tobscure\JsonApi\Exception\InvalidParameterException;
|
use Tobscure\JsonApi\Exception\InvalidParameterException;
|
||||||
|
@ -41,7 +43,7 @@ class ListPostsController extends AbstractCollectionController
|
||||||
/**
|
/**
|
||||||
* @var \Flarum\Core\Repository\PostRepository
|
* @var \Flarum\Core\Repository\PostRepository
|
||||||
*/
|
*/
|
||||||
private $posts;
|
protected $posts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \Flarum\Core\Repository\PostRepository $posts
|
* @param \Flarum\Core\Repository\PostRepository $posts
|
||||||
|
@ -59,55 +61,90 @@ class ListPostsController extends AbstractCollectionController
|
||||||
$actor = $request->getAttribute('actor');
|
$actor = $request->getAttribute('actor');
|
||||||
$filter = $this->extractFilter($request);
|
$filter = $this->extractFilter($request);
|
||||||
$include = $this->extractInclude($request);
|
$include = $this->extractInclude($request);
|
||||||
$where = [];
|
|
||||||
|
|
||||||
if ($postIds = array_get($filter, 'id')) {
|
if ($postIds = array_get($filter, 'id')) {
|
||||||
$posts = $this->posts->findByIds(explode(',', $postIds), $actor);
|
$postIds = explode(',', $postIds);
|
||||||
} else {
|
} else {
|
||||||
if ($discussionId = array_get($filter, 'discussion')) {
|
$postIds = $this->getPostIds($request);
|
||||||
$where['discussion_id'] = $discussionId;
|
|
||||||
}
|
|
||||||
if ($number = array_get($filter, 'number')) {
|
|
||||||
$where['number'] = $number;
|
|
||||||
}
|
|
||||||
if ($userId = array_get($filter, 'user')) {
|
|
||||||
$where['user_id'] = $userId;
|
|
||||||
}
|
|
||||||
if ($type = array_get($filter, 'type')) {
|
|
||||||
$where['type'] = $type;
|
|
||||||
}
|
|
||||||
|
|
||||||
$posts = $this->getPosts($request, $where);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$posts = $this->posts->findByIds($postIds, $actor);
|
||||||
|
|
||||||
return $posts->load($include);
|
return $posts->load($include);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ServerRequestInterface $request
|
* {@inheritdoc}
|
||||||
* @param array $where
|
|
||||||
* @return \Illuminate\Database\Eloquent\Collection
|
|
||||||
* @throws InvalidParameterException
|
|
||||||
*/
|
*/
|
||||||
private function getPosts(ServerRequestInterface $request, array $where)
|
protected function extractOffset(ServerRequestInterface $request)
|
||||||
{
|
{
|
||||||
$queryParams = $request->getQueryParams();
|
|
||||||
$actor = $request->getAttribute('actor');
|
$actor = $request->getAttribute('actor');
|
||||||
|
$queryParams = $request->getQueryParams();
|
||||||
$sort = $this->extractSort($request);
|
$sort = $this->extractSort($request);
|
||||||
$limit = $this->extractLimit($request);
|
$limit = $this->extractLimit($request);
|
||||||
|
$filter = $this->extractFilter($request);
|
||||||
|
|
||||||
if (($near = array_get($queryParams, 'page.near')) > 1) {
|
if (($near = array_get($queryParams, 'page.near')) > 1) {
|
||||||
if (count($where) > 1 || ! isset($where['discussion_id']) || $sort) {
|
if (count($filter) > 1 || ! isset($filter['discussion']) || $sort) {
|
||||||
throw new InvalidParameterException('You can only use page[near] with '
|
throw new InvalidParameterException('You can only use page[near] with '
|
||||||
. 'filter[discussion] and the default sort order');
|
. 'filter[discussion] and the default sort order');
|
||||||
}
|
}
|
||||||
|
|
||||||
$offset = $this->posts->getIndexForNumber($where['discussion_id'], $near, $actor);
|
$offset = $this->posts->getIndexForNumber($filter['discussion'], $near, $actor);
|
||||||
$offset = max(0, $offset - $limit / 2);
|
|
||||||
} else {
|
return max(0, $offset - $limit / 2);
|
||||||
$offset = $this->extractOffset($request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->posts->findWhere($where, $actor, $sort, $limit, $offset);
|
return parent::extractOffset($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ServerRequestInterface $request
|
||||||
|
* @return array
|
||||||
|
* @throws InvalidParameterException
|
||||||
|
*/
|
||||||
|
private function getPostIds(ServerRequestInterface $request)
|
||||||
|
{
|
||||||
|
$filter = $this->extractFilter($request);
|
||||||
|
$sort = $this->extractSort($request);
|
||||||
|
$limit = $this->extractLimit($request);
|
||||||
|
$offset = $this->extractOffset($request);
|
||||||
|
|
||||||
|
$query = $this->posts->query();
|
||||||
|
|
||||||
|
$this->applyFilters($query, $filter);
|
||||||
|
|
||||||
|
$query->skip($offset)->take($limit);
|
||||||
|
|
||||||
|
foreach ((array) $sort as $field => $order) {
|
||||||
|
$query->orderBy($field, $order);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->lists('id')->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Builder $query
|
||||||
|
* @param array $filter
|
||||||
|
*/
|
||||||
|
private function applyFilters(Builder $query, array $filter)
|
||||||
|
{
|
||||||
|
if ($discussionId = array_get($filter, 'discussion')) {
|
||||||
|
$query->where('discussion_id', $discussionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($number = array_get($filter, 'number')) {
|
||||||
|
$query->where('number', $number);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($userId = array_get($filter, 'user')) {
|
||||||
|
$query->where('user_id', $userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type = array_get($filter, 'type')) {
|
||||||
|
$query->where('type', $type);
|
||||||
|
}
|
||||||
|
|
||||||
|
event(new ConfigurePostsQuery($query, $filter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,16 @@ use Flarum\Core\Discussion;
|
||||||
|
|
||||||
class PostRepository
|
class PostRepository
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Get a new query builder for the posts table.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Builder
|
||||||
|
*/
|
||||||
|
public function query()
|
||||||
|
{
|
||||||
|
return Post::query();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a post by ID, optionally making sure it is visible to a certain
|
* Find a post by ID, optionally making sure it is visible to a certain
|
||||||
* user, or throw an exception.
|
* user, or throw an exception.
|
||||||
|
|
36
src/Event/ConfigurePostsQuery.php
Normal file
36
src/Event/ConfigurePostsQuery.php
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of Flarum.
|
||||||
|
*
|
||||||
|
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Flarum\Event;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
|
||||||
|
class ConfigurePostsQuery
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Builder
|
||||||
|
*/
|
||||||
|
public $query;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $filter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Builder $query
|
||||||
|
* @param array $filter
|
||||||
|
*/
|
||||||
|
public function __construct(Builder $query, array $filter)
|
||||||
|
{
|
||||||
|
$this->query = $query;
|
||||||
|
$this->filter = $filter;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user