5
5
use \Carbon \Carbon ;
6
6
use \stdClass ;
7
7
use \Illuminate \Database \Query \Builder ;
8
+ use \Illuminate \Database \Eloquent \Builder as EloquentBuilder ;
8
9
use \timgws \QBParseException ;
9
10
10
11
class QueryBuilderParser
11
12
{
12
13
use QBPFunctions;
13
14
15
+ /**
16
+ * The fields (if any) that we allow to filter on using QBP
17
+ * @var array|null
18
+ */
14
19
protected $ fields ;
15
20
21
+ /**
22
+ * A list of all the callbacks that can be called to cleanse provided values from QBP
23
+ * @var array
24
+ */
25
+ private $ cleanFieldCallbacks = [];
26
+
16
27
/**
17
28
* @param array $fields a list of all the fields that are allowed to be filtered by the QueryBuilder
18
29
*/
@@ -27,13 +38,13 @@ public function __construct(array $fields = null)
27
38
* Build a query based on JSON that has been passed into the function, onto the builder passed into the function.
28
39
*
29
40
* @param $json
30
- * @param Builder $querybuilder
41
+ * @param EloquentBuilder| Builder $querybuilder
31
42
*
32
43
* @throws QBParseException
33
44
*
34
45
* @return Builder
35
46
*/
36
- public function parse ($ json , Builder $ querybuilder )
47
+ public function parse ($ json , EloquentBuilder | Builder $ querybuilder )
37
48
{
38
49
// do a JSON decode (throws exceptions if there is a JSON error...)
39
50
$ query = $ this ->decodeJSON ($ json );
@@ -55,14 +66,14 @@ public function parse($json, Builder $querybuilder)
55
66
* Called by parse, loops through all the rules to find out if nested or not.
56
67
*
57
68
* @param array $rules
58
- * @param Builder $querybuilder
69
+ * @param EloquentBuilder| Builder $querybuilder
59
70
* @param string $queryCondition
60
71
*
61
72
* @throws QBParseException
62
73
*
63
74
* @return Builder
64
75
*/
65
- protected function loopThroughRules (array $ rules , Builder $ querybuilder , $ queryCondition = 'AND ' )
76
+ protected function loopThroughRules (array $ rules , EloquentBuilder | Builder $ querybuilder , $ queryCondition = 'AND ' )
66
77
{
67
78
foreach ($ rules as $ rule ) {
68
79
/*
@@ -99,12 +110,12 @@ protected function isNested($rule)
99
110
*
100
111
* When a rule is actually a group of rules, we want to build a nested query with the specified condition (AND/OR)
101
112
*
102
- * @param Builder $querybuilder
113
+ * @param EloquentBuilder| Builder $querybuilder
103
114
* @param stdClass $rule
104
115
* @param string|null $condition
105
116
* @return Builder
106
117
*/
107
- protected function createNestedQuery (Builder $ querybuilder , stdClass $ rule , $ condition = null )
118
+ protected function createNestedQuery (EloquentBuilder | Builder $ querybuilder , stdClass $ rule , $ condition = null )
108
119
{
109
120
if ($ condition === null ) {
110
121
$ condition = $ rule ->condition ;
@@ -203,15 +214,15 @@ protected function getCorrectValue($operator, stdClass $rule, $value)
203
214
* Make sure that all the correct fields are in the rule object then add the expression to
204
215
* the query that was given by the user to the QueryBuilder.
205
216
*
206
- * @param Builder $query
217
+ * @param EloquentBuilder| Builder $query
207
218
* @param stdClass $rule
208
219
* @param string $queryCondition and/or...
209
220
*
210
221
* @throws QBParseException
211
222
*
212
223
* @return Builder
213
224
*/
214
- protected function makeQuery (Builder $ query , stdClass $ rule , $ queryCondition = 'AND ' )
225
+ protected function makeQuery (EloquentBuilder | Builder $ query , stdClass $ rule , $ queryCondition = 'AND ' )
215
226
{
216
227
/*
217
228
* Ensure that the value is correct for the rule, return query on exception
@@ -227,7 +238,7 @@ protected function makeQuery(Builder $query, stdClass $rule, $queryCondition = '
227
238
}
228
239
229
240
/**
230
- * Convert an incomming rule from jQuery QueryBuilder to the Eloquent Querybuilder
241
+ * Convert an incoming rule from jQuery QueryBuilder to the Eloquent Querybuilder
231
242
*
232
243
* (This used to be part of makeQuery, where the name made sense, but I pulled it
233
244
* out to reduce some duplicated code inside JoinSupportingQueryBuilder)
@@ -238,7 +249,7 @@ protected function makeQuery(Builder $query, stdClass $rule, $queryCondition = '
238
249
* @param string $queryCondition and/or...
239
250
* @return Builder
240
251
*/
241
- protected function convertIncomingQBtoQuery (Builder $ query , stdClass $ rule , $ value , $ queryCondition = 'AND ' )
252
+ protected function convertIncomingQBtoQuery (EloquentBuilder | Builder $ query , stdClass $ rule , $ value , $ queryCondition = 'AND ' )
242
253
{
243
254
/*
244
255
* Convert the Operator (LIKE/NOT LIKE/GREATER THAN) given to us by QueryBuilder
@@ -257,6 +268,28 @@ protected function convertIncomingQBtoQuery(Builder $query, stdClass $rule, $val
257
268
return $ query ->where ($ rule ->field , $ sqlOperator ['operator ' ], $ value , $ condition );
258
269
}
259
270
271
+ /**
272
+ * Add a filter for cleaning values that are inputted from a QueryBuilder (eg, for ACL)
273
+ * @param $field
274
+ * @param callable|null $callback
275
+ * @return $this
276
+ * @throws \timgws\QBParseException
277
+ */
278
+ public function clean ($ field , Callable $ callback = null )
279
+ {
280
+ if (isset ($ this ->cleanFieldCallbacks [$ field ])) {
281
+ throw new QBParseException ("Field $ field already has a clean callback set. " );
282
+ }
283
+
284
+ if ($ callback == null ) {
285
+ return $ this ;
286
+ }
287
+
288
+ $ this ->cleanFieldCallbacks [$ field ] = $ callback ;
289
+
290
+ return $ this ;
291
+ }
292
+
260
293
/**
261
294
* Ensure that the value is correct for the rule, try and set it if it's not.
262
295
*
@@ -272,6 +305,10 @@ protected function getValueForQueryFromRule(stdClass $rule)
272
305
/*
273
306
* Make sure most of the common fields from the QueryBuilder have been added.
274
307
*/
308
+ if (isset ($ this ->cleanFieldCallbacks [$ rule ->field ])) {
309
+ $ rule ->value = call_user_func ($ this ->cleanFieldCallbacks [$ rule ->field ], $ rule ->value );
310
+ }
311
+
275
312
$ value = $ this ->getRuleValue ($ rule );
276
313
277
314
/*
0 commit comments