@@ -11,7 +11,8 @@ highly coupled with the application's logic and choice of data storage.
1111This package therefore provides the following capabilities:
1212
1313- Validation of the ` filter ` parameter.
14- - An easy hook in the Eloquent adapter to convert validated filter parameters to database queries.
14+ - An easy hook in the Eloquent adapter to convert validated filter parameters to database queries.
15+ - An opt-in implementation to map JSON API filters to model scopes and/or Eloquent's magic ` where* ` method.
1516
1617## Example Requests
1718
@@ -72,37 +73,15 @@ class Validators extends AbstractValidators
7273
7374## Validation
7475
75- Filter parameters should always be validated to ensure that their use in database queries is valid. You can
76- validate them in your [ Validators] ( ../basics/validators.md ) query rules. For example:
76+ Filter parameters should always be validated to ensure that their use in database queries is valid.
77+ You can validate them in your [ Validators] ( ../basics/validators.md ) query rules. For example:
7778
7879``` php
7980class Validators extends AbstractValidators
8081{
8182 // ...
8283
83- protected function queryRules(): array
84- {
85- return [
86- 'filter.title' => 'filled|string',
87- 'filter.slug' => 'filled|string',
88- 'filter.authors' => 'array|min:1',
89- 'filter.authors.*' => 'integer',
90- ];
91- }
92-
93- }
94- ```
95-
96- By default we allow a client to submit any filter parameters as we assume that you will validate the values
97- of expected filters as in the example above. However, you can whitelist expected filter parameters by listing
98- them on the ` $allowedFilteringParameters ` of your validators class. For example:
99-
100- ``` php
101- class Validators extends AbstractValidators
102- {
103- // ...
104-
105- protected $allowedFilteringParameters = ['title', 'authors'];
84+ protected $allowedFilteringParameters = ['title', 'slug', 'authors'];
10685
10786 protected function queryRules(): array
10887 {
@@ -117,6 +96,9 @@ class Validators extends AbstractValidators
11796}
11897```
11998
99+ The above whitelists the allowed filter parameters, and then also validates the values that can be
100+ submitted for each.
101+
120102Any requests that contain filter keys that are not in your allowed filtering parameters list will be rejected
121103with a ` 400 Bad Request ` response, for example:
122104
@@ -143,7 +125,75 @@ Content-Type: application/vnd.api+json
143125The Eloquent adapter provides a ` filter ` method that allows you to implement your filtering logic.
144126This method is provided with an Eloquent query builder and the filters provided by the client.
145127
146- For example, our ` posts ` adapter filtering implementation could be:
128+ ### Filter Scopes
129+
130+ A newly generated Eloquent adapter will use our ` filterWithScopes() ` implementation. For example:
131+
132+ ``` php
133+ class Adapter extends AbstractAdapter
134+ {
135+
136+ // ...
137+
138+ /**
139+ * Mapping of JSON API filter names to model scopes.
140+ *
141+ * @var array
142+ */
143+ protected $filterScopes = [];
144+
145+ /**
146+ * @param Builder $query
147+ * @param Collection $filters
148+ * @return void
149+ */
150+ protected function filter($query, Collection $filters)
151+ {
152+ $this->filterWithScopes($query, $filters);
153+ }
154+ }
155+ ```
156+
157+ The ` filterWithScopes ` method will map JSON API filters to model scopes, and pass the filter value to that scope.
158+ For example, if the client has sent a ` filter[slug] ` query parameter, we expect either there to be a
159+ ` scopeSlug ` method on the model, or we will use Eloquent's magic ` whereSlug ` method.
160+
161+ If you need to map a filter parameter to a different scope name, then you can define it here.
162+ For example if ` filter[slug] ` needed to be passed to the ` onlySlug ` scope, it can be defined
163+ as follows:
164+
165+ ``` php
166+ protected $filterScopes = [
167+ 'slug' => 'onlySlug'
168+ ];
169+ ```
170+
171+ If you want a filter parameter to not be mapped, define the mapping as ` null ` , for example:
172+
173+ ``` php
174+ protected $filterScopes = [
175+ 'slug' => null
176+ ];
177+ ```
178+
179+ Alternatively you could let some filters be applied using scopes, and then implement your own logic
180+ for others. For example:
181+
182+ ``` php
183+ protected function filter($query, Collection $filters)
184+ {
185+ $this->filterWithScopes($query, $filters->only('foo', 'bar', 'bat'));
186+
187+ if ($baz = $filters->get('baz')) {
188+ // filter logic for baz.
189+ }
190+ }
191+ ```
192+
193+ ### Custom Filter Logic
194+
195+ If you do not want to use our filter by scope implementation, then it is easy to implement your
196+ own logic. Remove the call to ` filterWithScopes() ` and insert your own logic. For example:
147197
148198``` php
149199class Adapter extends AbstractAdapter
@@ -166,5 +216,7 @@ class Adapter extends AbstractAdapter
166216}
167217```
168218
169- > As filters are also applied when filtering the resource through a relationship, it is good practice
219+ ### Relationships
220+
221+ Filters are also applied when filtering the resource through a relationship. It is good practice
170222to qualify any column names.
0 commit comments