1 <?php namespace BookStack\Api;
3 use Illuminate\Database\Eloquent\Builder;
4 use Illuminate\Database\Eloquent\Collection;
5 use Illuminate\Http\Request;
7 class ListingResponseBuilder
14 protected $filterOperators = [
25 * ListingResponseBuilder constructor.
27 public function __construct(Builder $query, Request $request, array $fields)
29 $this->query = $query;
30 $this->request = $request;
31 $this->fields = $fields;
35 * Get the response from this builder.
37 public function toResponse()
39 $data = $this->fetchData();
40 $total = $this->query->count();
42 return response()->json([
49 * Fetch the data to return in the response.
51 protected function fetchData(): Collection
53 $this->applyCountAndOffset($this->query);
54 $this->applySorting($this->query);
55 $this->applyFiltering($this->query);
57 return $this->query->get($this->fields);
61 * Apply any filtering operations found in the request.
63 protected function applyFiltering(Builder $query)
65 $requestFilters = $this->request->get('filter', []);
66 if (!is_array($requestFilters)) {
70 $queryFilters = collect($requestFilters)->map(function ($value, $key) {
71 return $this->requestFilterToQueryFilter($key, $value);
72 })->filter(function ($value) {
73 return !is_null($value);
74 })->values()->toArray();
76 $query->where($queryFilters);
80 * Convert a request filter query key/value pair into a [field, op, value] where condition.
82 protected function requestFilterToQueryFilter($fieldKey, $value): ?array
84 $splitKey = explode(':', $fieldKey);
85 $field = $splitKey[0];
86 $filterOperator = $splitKey[1] ?? 'eq';
88 if (!in_array($field, $this->fields)) {
92 if (!in_array($filterOperator, array_keys($this->filterOperators))) {
93 $filterOperator = 'eq';
96 $queryOperator = $this->filterOperators[$filterOperator];
97 return [$field, $queryOperator, $value];
101 * Apply sorting operations to the query from given parameters
102 * otherwise falling back to the first given field, ascending.
104 protected function applySorting(Builder $query)
106 $defaultSortName = $this->fields[0];
109 $sort = $this->request->get('sort', '');
110 if (strpos($sort, '-') === 0) {
114 $sortName = ltrim($sort, '+- ');
115 if (!in_array($sortName, $this->fields)) {
116 $sortName = $defaultSortName;
119 $query->orderBy($sortName, $direction);
123 * Apply count and offset for paging, based on params from the request while falling
124 * back to system defined default, taking the max limit into account.
126 protected function applyCountAndOffset(Builder $query)
128 $offset = max(0, $this->request->get('offset', 0));
129 $maxCount = config('api.max_item_count');
130 $count = $this->request->get('count', config('api.default_item_count'));
131 $count = max(min($maxCount, $count), 1);
133 $query->skip($offset)->take($count);