Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
44 / 44 |
|
100.00% |
8 / 8 |
CRAP | |
100.00% |
1 / 1 |
ConditionBuilder | |
100.00% |
44 / 44 |
|
100.00% |
8 / 8 |
14 | |
100.00% |
1 / 1 |
andWith | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
orWith | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
addCondition | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
3 | |||
conditions | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
buildConditionSQL | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
buildPartsSQL | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
5 | |||
getConditionParameters | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
hasConditions | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | namespace BO\Zmsdb\Query\Builder; |
4 | |
5 | /** |
6 | * ConditionBuilder |
7 | * |
8 | * Builds up a set of conditions for a query, either used in a WHERE or |
9 | * HAVING block of SQL. |
10 | * |
11 | * @package BO\Zmsdb\Query\Builder |
12 | * @author Alex Gisby<alex@solution10.com> |
13 | * @license MIT |
14 | */ |
15 | class ConditionBuilder |
16 | { |
17 | /** |
18 | * @var array "Parts" as in field, op, value |
19 | */ |
20 | protected $parts = []; |
21 | |
22 | /** |
23 | * @var array Params (used as a shortcut for feeding into PDO) |
24 | */ |
25 | protected $params = []; |
26 | |
27 | /** |
28 | * Adds an AND condition into the builder |
29 | * |
30 | * @param string|\Closure $field Fieldname|callback for group |
31 | * @param string $operator Operator (=, !=, <>, <= etc) |
32 | * @param mixed $value Value to test against |
33 | * @return $this |
34 | */ |
35 | public function andWith($field, $operator = null, $value = null) |
36 | { |
37 | $this->addCondition('AND', $field, $operator, $value); |
38 | return $this; |
39 | } |
40 | |
41 | /** |
42 | * Adds an OR condition into the builder |
43 | * |
44 | * @param string|\Closure $field Fieldname|callback for group |
45 | * @param string $operator Operator (=, !=, <>, <= etc) |
46 | * @param mixed $value Value to test against |
47 | * @return $this |
48 | */ |
49 | public function orWith($field, $operator = null, $value = null) |
50 | { |
51 | $this->addCondition('OR', $field, $operator, $value); |
52 | return $this; |
53 | } |
54 | |
55 | /** |
56 | * Adds the condition into the family we're building. |
57 | * |
58 | * @param string $join AND or OR |
59 | * @param string|\Closure $field Fieldname|callback for group |
60 | * @param string $operator Operator (=, !=, <>, <= etc) |
61 | * @param mixed $value Value to test against |
62 | * @return $this $this on set, array on get |
63 | */ |
64 | protected function addCondition($join, $field, $operator, $value) |
65 | { |
66 | $newParams = []; |
67 | if ($field instanceof \Closure) { |
68 | // Return and merge the result of these queries |
69 | $subQuery = new ConditionBuilder(); |
70 | $field($subQuery); |
71 | $this->parts[] = [ |
72 | 'join' => $join, |
73 | 'sub' => $subQuery->conditions() |
74 | ]; |
75 | $newParams = $subQuery->getConditionParameters(); |
76 | // $this->params = array_merge($this->params, $subQuery->getConditionParameters()); |
77 | } else { |
78 | $this->parts[] = [ |
79 | 'join' => $join, |
80 | 'field' => $field, |
81 | 'operator' => $operator, |
82 | 'value' => $value |
83 | ]; |
84 | $newParams = $value; |
85 | } |
86 | |
87 | if (!is_array($newParams)) { |
88 | $newParams = [$newParams]; |
89 | } |
90 | |
91 | $this->params = array_merge($this->params, $newParams); |
92 | |
93 | return $this; |
94 | } |
95 | |
96 | /** |
97 | * Returns the conditions that have been set on this builder. |
98 | * |
99 | * @return array |
100 | */ |
101 | public function conditions() |
102 | { |
103 | return $this->parts; |
104 | } |
105 | |
106 | /** |
107 | * Builds up the SQL for this condition. |
108 | * |
109 | * @param DialectInterface $dialect |
110 | * @return string |
111 | */ |
112 | public function buildConditionSQL(DialectInterface $dialect) |
113 | { |
114 | return $this->buildPartsSQL($this->parts, $dialect); |
115 | } |
116 | |
117 | /** |
118 | * Builds up an array of parts into a SQL string. To be used recursively. |
119 | * |
120 | * @param DialectInterface $dialect |
121 | * @param array $parts |
122 | * @return string |
123 | */ |
124 | protected function buildPartsSQL(array $parts, DialectInterface $dialect) |
125 | { |
126 | $where = ''; |
127 | foreach ($parts as $c) { |
128 | $where .= ' ' . $c['join'] . ' '; |
129 | if (array_key_exists('sub', $c)) { |
130 | $where .= '('; |
131 | $where .= $this->buildPartsSQL($c['sub'], $dialect); |
132 | $where .= ')'; |
133 | } else { |
134 | $where .= $dialect->quoteField($c['field']) . ' ' . $c['operator'] . ' '; |
135 | if (is_array($c['value'])) { |
136 | $inParts = []; |
137 | for ($i = 0; $i < count($c['value']); $i++) { |
138 | $inParts[] = '?'; |
139 | } |
140 | $where .= '(' . implode(', ', $inParts) . ')'; |
141 | } else { |
142 | $where .= '?'; |
143 | } |
144 | } |
145 | } |
146 | $where = trim(preg_replace('/^(AND|OR) /', '', trim($where))); |
147 | return $where; |
148 | } |
149 | |
150 | /** |
151 | * Returns the parameters from this set of conditions ready to throw at a PDO statement |
152 | * |
153 | * @return array |
154 | */ |
155 | public function getConditionParameters() |
156 | { |
157 | return $this->params; |
158 | } |
159 | |
160 | /** |
161 | * Returns whether any conditions have been added to this builder |
162 | * |
163 | * @return bool |
164 | */ |
165 | public function hasConditions() |
166 | { |
167 | return !empty($this->parts); |
168 | } |
169 | } |