1111
1212namespace BlitzPHP \Database \Builder ;
1313
14+ use BlitzPHP \Database \Query \Expression ;
15+ use InvalidArgumentException ;
1416use PDO ;
1517use PDOStatement ;
1618
1719class BindingCollection
1820{
19- protected array $ values = [];
21+ /**
22+ * Types de bindings supportés
23+ */
24+ public const TYPES = [
25+ 'select ' , 'from ' , 'join ' , 'where ' , 'having ' ,
26+ 'order ' , 'union ' , 'values ' , 'uniqueBy ' ,
27+ ];
28+
29+ /**
30+ * Bindings organisés par type
31+ *
32+ * @var array<string, list<mixed>>
33+ */
34+ protected array $ bindings = [];
35+
36+ /**
37+ * Types PDO pour chaque binding (optionnel)
38+ *
39+ * @var array<string, list<int>>
40+ */
2041 protected array $ types = [];
2142
43+ public function __construct ()
44+ {
45+ foreach (self ::TYPES as $ type ) {
46+ $ this ->bindings [$ type ] = [];
47+ $ this ->types [$ type ] = [];
48+ }
49+ }
50+
2251 /**
23- * Ajoute un binding
52+ * Ajoute un binding dans un contexte spécifique
53+ *
54+ * @param mixed $value Valeur à binder
55+ * @param string $type Contexte ('where', 'values', etc.)
56+ * @param int|null $pdoType Type PDO (optionnel)
57+ *
58+ * @throws InvalidArgumentException
2459 */
25- public function add (mixed $ value , ?int $ type = null ): self
60+ public function add (mixed $ value , string $ type = ' where ' , ?int $ pdoType = null ): self
2661 {
27- $ this ->values [] = $ value ;
28- $ this ->types [] = $ type ?? $ this ->guessType ($ value );
29-
62+ if (!in_array ($ type , self ::TYPES , true )) {
63+ throw new InvalidArgumentException ("Type de binding invalide: {$ type }" );
64+ }
65+
66+ $ this ->bindings [$ type ][] = $ value ;
67+ $ this ->types [$ type ][] = $ pdoType ?? $ this ->guessType ($ value );
68+
3069 return $ this ;
3170 }
3271
3372 /**
34- * Ajoute plusieurs bindings
73+ * Ajoute plusieurs bindings dans un contexte
3574 */
36- public function addMany (array $ values ): self
75+ public function addMany (array $ values, string $ type = ' where ' ): self
3776 {
3877 foreach ($ values as $ value ) {
39- $ this ->add ($ value );
78+ $ this ->add ($ value, $ type );
4079 }
4180
4281 return $ this ;
@@ -45,84 +84,156 @@ public function addMany(array $values): self
4584 /**
4685 * Ajoute un binding nommé
4786 */
48- public function addNamed (string $ name , mixed $ value , ?int $ type = null ): self
87+ public function addNamed (string $ name , mixed $ value , string $ type = ' where ' , ?int $ pdoType = null ): self
4988 {
50- $ this ->values [$ name ] = $ value ;
51- $ this ->types [$ name ] = $ type ?? $ this ->guessType ($ value );
89+ $ this ->bindings [ $ type ] [$ name ] = $ value ;
90+ $ this ->types [$ type ][ $ name ] = $ pdoType ?? $ this ->guessType ($ value );
5291
5392 return $ this ;
5493 }
5594
5695 /**
57- * Récupère toutes les valeurs
96+ * Récupère tous les bindings d'un contexte
97+ *
98+ * @return list<mixed>|mixed
5899 */
59- public function getValues (): array
100+ public function get ( string $ type , ? string $ name = null )
60101 {
61- return $ this ->values ;
102+ $ bindings = $ this ->bindings [$ type ] ?? [];
103+
104+ return $ name ? ($ bindings [$ name ] ?? null ) : $ bindings ;
105+ }
106+
107+ /**
108+ * Récupère tous les bindings dans l'ordre de compilation
109+ *
110+ * @param list<string> $types
111+ *
112+ * @return list<mixed>
113+ */
114+ public function getOrdered (array $ types = []): array
115+ {
116+ if ($ types === []) {
117+ $ types = self ::TYPES ;
118+ }
119+
120+ $ result = [];
121+ foreach ($ types as $ type ) {
122+ if (!empty ($ this ->bindings [$ type ])) {
123+ array_push ($ result , ...$ this ->bindings [$ type ]);
124+ }
125+ }
126+
127+ return $ result ;
62128 }
63129
64130 /**
65- * Récupère tous les types
131+ * Récupère tous les types dans l'ordre
132+ *
133+ * @param list<string> $types
134+ *
135+ * @return list<int>
66136 */
67- public function getTypes ( ): array
137+ public function getTypesOrdered ( array $ types = [] ): array
68138 {
69- return $ this ->types ;
139+ if ($ types === []) {
140+ $ types = self ::TYPES ;
141+ }
142+
143+ $ result = [];
144+ foreach ($ types as $ type ) {
145+ if (!empty ($ this ->types [$ type ])) {
146+ array_push ($ result , ...$ this ->types [$ type ]);
147+ }
148+ }
149+
150+ return $ result ;
70151 }
71152
72153 /**
73- * Récupère un binding
154+ * Vérifie si un contexte a des bindings
74155 */
75- public function get (string | int $ key ): mixed
156+ public function has (string $ type ): bool
76157 {
77- return $ this ->values [ $ key ] ?? null ;
158+ return ! empty ( $ this ->bindings [ $ type ]) ;
78159 }
79160
80161 /**
81- * Récupère le type d'un binding
162+ * Compte le nombre total de bindings
82163 */
83- public function getType ( string | int $ key ): ? int
164+ public function count (? string $ type = null ): int
84165 {
85- return $ this ->types [$ key ] ?? null ;
166+ if ($ type !== null ) {
167+ return count ($ this ->bindings [$ type ] ?? []);
168+ }
169+
170+ return array_sum (array_map ('count ' , $ this ->bindings ));
86171 }
87172
88173 /**
89- * Vérifie si des bindings existent
174+ * Vérifie si un contexte est vide
90175 */
91- public function isEmpty (): bool
176+ public function isEmpty (? string $ type = null ): bool
92177 {
93- return empty ( $ this ->values ) ;
178+ return $ this ->count ( $ type ) === 0 ;
94179 }
95180
96181 /**
97- * Vide la collection
182+ * Vide tous les bindings
98183 */
99- public function clear (): self
184+ public function clear (? string $ type = null ): self
100185 {
101- $ this ->values = [];
102- $ this ->types = [];
103-
186+ if ($ type !== null ) {
187+ $ this ->bindings [$ type ] = [];
188+ $ this ->types [$ type ] = [];
189+ } else {
190+ foreach (self ::TYPES as $ t ) {
191+ $ this ->bindings [$ t ] = [];
192+ $ this ->types [$ t ] = [];
193+ }
194+ }
195+
104196 return $ this ;
105197 }
106198
107199 /**
108- * Compte le nombre de bindings
200+ * Vide les bindings d'un contexte spécifique
109201 */
110- public function count ( ): int
202+ public function clearType ( string $ type ): self
111203 {
112- return count ($ this ->values );
204+ if (isset ($ this ->bindings [$ type ])) {
205+ $ this ->bindings [$ type ] = [];
206+ $ this ->types [$ type ] = [];
207+ }
208+
209+ return $ this ;
113210 }
114211
115212 /**
116213 * Fusionne une autre collection
117214 */
118- public function merge (self $ bindings ): self
215+ public function merge (self $ collection ): self
119216 {
120- $ this ->values = array_merge ($ this ->values , $ bindings ->values );
121- $ this ->types = array_merge ($ this ->types , $ bindings ->types );
122-
217+ foreach (self ::TYPES as $ type ) {
218+ array_push ($ this ->bindings [$ type ], ...$ collection ->bindings [$ type ]);
219+ array_push ($ this ->types [$ type ], ...$ collection ->types [$ type ]);
220+ }
221+
123222 return $ this ;
124223 }
125224
225+ /**
226+ * Retire les expressions des bindings (elles ne doivent pas être bindées)
227+ *
228+ * @param list<mixed> $bindings
229+ *
230+ * @return list<mixed>
231+ */
232+ public function clean (array $ bindings ): array
233+ {
234+ return array_filter ($ bindings , fn ($ binding ) => !$ binding instanceof Expression);
235+ }
236+
126237 /**
127238 * Devine le type PDO d'une valeur
128239 */
@@ -138,10 +249,21 @@ protected function guessType(mixed $value): int
138249 }
139250
140251 /**
141- * Clone la collection
252+ * Pour le débogage
142253 */
254+ public function toArray (): array
255+ {
256+ return $ this ->bindings ;
257+ }
258+
143259 public function __clone ()
144260 {
145- // Rien de spécial à faire, les tableaux sont copiés
261+ foreach ($ this ->bindings as $ type => $ bindings ) {
262+ $ this ->bindings [$ type ] = $ bindings ;
263+ }
264+
265+ foreach ($ this ->types as $ type => $ types ) {
266+ $ this ->types [$ type ] = $ types ;
267+ }
146268 }
147- }
269+ }
0 commit comments