@@ -13,6 +13,11 @@ class QueryExpression implements Countable {
13
13
14
14
protected $ _identifier ;
15
15
16
+ protected $ _bindingsCount = 0 ;
17
+
18
+ protected $ _replaceArrayParams = false ;
19
+
20
+
16
21
public function __construct ($ conditions = [], $ types = [], $ conjunction = 'AND ' ) {
17
22
$ this ->_conjunction = strtoupper ($ conjunction );
18
23
$ this ->_identifier = substr (spl_object_hash ($ this ), 7 , 9 );
@@ -89,6 +94,10 @@ public function in($field, $values, $type = null) {
89
94
return $ this ->add ([$ field . ' IN ' => $ values ], $ type ? [$ field => $ type ] : []);
90
95
}
91
96
97
+ public function notIn ($ field , $ values , $ type = null ) {
98
+ return $ this ->add ([$ field . ' NOT IN ' => $ values ], $ type ? [$ field => $ type ] : []);
99
+ }
100
+
92
101
/**
93
102
* Associates a query placeholder to a value and a type for next execution
94
103
*
@@ -101,15 +110,20 @@ public function in($field, $values, $type = null) {
101
110
*/
102
111
public function bind ($ token , $ value , $ type ) {
103
112
$ param = $ token ;
104
- $ number = count ( $ this ->_bindings ) ;
113
+ $ number = $ this ->_bindingsCount ++ ;
105
114
106
115
if (is_numeric ($ token )) {
107
116
$ param = '? ' ;
108
117
} else if ($ param [0 ] !== ': ' ) {
109
118
$ param = sprintf (':c%s%s ' , $ this ->_identifier , $ number );
110
119
}
111
120
112
- $ this ->_bindings [$ number ] = compact ('value ' , 'type ' ) + [
121
+ if (strpos ($ type , '[] ' ) !== false ) {
122
+ $ param = sprintf (':array%d ' , $ number );
123
+ $ type = str_replace ('[] ' , '' , $ type );
124
+ }
125
+
126
+ $ this ->_bindings [$ number ] = compact ('value ' , 'type ' , 'token ' ) + [
113
127
'placeholder ' => substr ($ param , 1 )
114
128
];
115
129
return $ param ;
@@ -134,6 +148,9 @@ public function __toString() {
134
148
}
135
149
136
150
public function sql () {
151
+ if ($ this ->_replaceArrayParams ) {
152
+ $ this ->_replaceArrays ();
153
+ }
137
154
$ conjunction = $ this ->_conjunction ;
138
155
return '( ' . implode (" $ conjunction " , $ this ->_conditions ) . ') ' ;
139
156
}
@@ -188,7 +205,34 @@ protected function _parseCondition($field, $value, $types) {
188
205
}
189
206
190
207
$ type = isset ($ types [$ expression ]) ? $ types [$ expression ] : null ;
191
- return sprintf ('%s %s %s ' , $ expression , $ operator , $ this ->bind ($ field , $ value , $ type ));
208
+ $ template = '%s %s %s ' ;
209
+
210
+ if (in_array (strtolower (trim ($ operator )), ['in ' , 'not in ' ])) {
211
+ $ type = $ type ?: 'string ' ;
212
+ $ type .= strpos ($ type , '[] ' ) === false ? '[] ' : null ;
213
+ $ template = '%s %s (%s) ' ;
214
+ $ this ->_replaceArrayParams = true ;
215
+ }
216
+
217
+ return sprintf ($ template , $ expression , $ operator , $ this ->bind ($ field , $ value , $ type ));
218
+ }
219
+
220
+ protected function _replaceArrays () {
221
+ foreach ($ this ->_conditions as $ k => $ condition ) {
222
+ if (!is_string ($ condition )) {
223
+ continue ;
224
+ }
225
+ $ condition = preg_replace_callback ('/(:array(\d+))/ ' , function ($ match ) {
226
+ $ params = [];
227
+ $ binding = $ this ->_bindings [$ match [2 ]];
228
+ foreach ($ this ->_bindings [$ match [2 ]]['value ' ] as $ value ) {
229
+ $ params [] = $ this ->bind ($ binding ['token ' ], $ value , $ binding ['type ' ]);
230
+ }
231
+ unset($ this ->_bindings [$ match [2 ]]);
232
+ return implode (', ' , $ params );
233
+ }, $ condition );
234
+ $ this ->_conditions [$ k ] = $ condition ;
235
+ }
192
236
}
193
237
194
238
}
0 commit comments