PluginProbe
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI / 6.0.2
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI v6.0.2
6.0.2 6.0.1 6.0.0 5.8.6 5.8.5 5.8.4 5.8.3 5.8.2 5.8.1 5.8.0 5.7.9.2 5.7.9.1 5.7.8 5.7.9 5.7.6 5.7.7 5.7.5 5.7.4 5.7.3 5.7.2 5.7.1 trunk 5.6.0 5.6.1 5.6.2 All 33 releases
automatorwp / libraries / ct / includes / class-ct-database-schema.php

class-ct-database-schema.php in AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI 6.0.2, at libraries/ct/includes/class-ct-database-schema.php

496 lines 17.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Database Table Schema class
4 *
5 * @author GamiPress <contact@gamipress.com>, Ruben Garcia <rubengcdev@gamil.com>
6 *
7 * @since 1.0.0
8 */
9 // Exit if accessed directly
10 defined( 'ABSPATH' ) || exit;
11
12 if ( ! class_exists( 'CT_DataBase_Schema' ) ) :
13
14 class CT_DataBase_Schema {
15
16 /**
17 * @var array Fields schema definition
18 */
19 public $fields = array();
20
21 /**
22 * @var array Keys schema definition
23 */
24 public $keys = array();
25
26 public $primary_key = '';
27
28 public function __construct( $schema ) {
29
30 $this->keys = array();
31
32 if( gettype( $schema ) === 'string' ) {
33 $schema = $this->string_schema_to_array( $schema );
34 }
35
36 if( is_array( $schema ) ) {
37
38 foreach( $schema as $field_id => $field_args ) {
39 $field_args = wp_parse_args( $field_args, array(
40 'type' => '',
41 'length' => 0,
42 'decimals' => 0, // numeric fields
43 'format' => '', // time fields
44 'options' => array(), // ENUM and SET types
45 'nullable' => false,
46 'unsigned' => null, // numeric field
47 'zerofill' => null, // numeric field
48 'binary' => null, // text fields
49 'charset' => false, // text fields
50 'collate' => false, // text fields
51 'default' => false,
52 'auto_increment' => false,
53 'unique' => false,
54 'primary_key' => false,
55 'key' => false,
56 ) );
57
58 $this->fields[$field_id] = $field_args;
59 }
60
61 }
62
63 }
64
65 public function __toString() {
66
67 $fields_def = array();
68
69 foreach( $this->fields as $field_id => $field_args ) {
70 // Turn field array to schema
71 $fields_def[] = $this->field_array_to_schema( $field_id, $field_args );
72 }
73
74 // Setup PRIMARY KEY definition
75 $sql = implode( ', ', $fields_def ) . ', '
76 . 'PRIMARY KEY (`' . $this->primary_key . '`)'; // Add two spaces to avoid issues
77
78 // Setup KEY definitions
79 if( ! empty( $this->keys ) ) {
80 $sql .= ', ' . implode( ', ', $this->keys );
81 }
82
83 return $sql;
84 }
85
86 /**
87 * Convert a field definition into a schema string
88 *
89 * @param string $field_id
90 * @param array $field_args
91 *
92 * @return string A schema string like: field type(length,decimals) UNSIGNED NOT NULL
93 */
94 public function field_array_to_schema( $field_id, $field_args ) {
95
96 $schema = '';
97
98 // Field name
99 $schema .= '`' . $field_id . '` ';
100
101 // Type definition
102 $schema .= $field_args['type'];
103
104 // Type definition args
105 switch( strtoupper( $field_args['type'] ) ) {
106 case 'ENUM':
107 case 'SET':
108 if( is_array( $field_args['options'] ) ) {
109 $schema .= '(' . implode( ',', $field_args['options'] ) . ')';
110 } else {
111 $schema .= '(' . $field_args['options'] . ')';
112 }
113 break;
114 case 'REAL':
115 case 'DOUBLE':
116 case 'FLOAT':
117 case 'DECIMAL':
118 case 'NUMERIC':
119 if( $field_args['length'] !== 0 ) {
120 $schema .= '(' . $field_args['length'] . ',' . $field_args['decimals'] . ')';
121 }
122 break;
123 case 'TIME':
124 case 'TIMESTAMP':
125 case 'DATETIME':
126 if( $field_args['format'] !== '' ) {
127 $schema .= '(' . $field_args['format'] . ')';
128 }
129 break;
130 default:
131 if( $field_args['length'] !== 0 ) {
132 $schema .= '(' . $field_args['length'] . ')';
133 }
134 break;
135 }
136
137 $schema .= ' ';
138
139 // Type specific definitions
140 switch( strtoupper( $field_args['type'] ) ) {
141 case 'TINYINT':
142 case 'SMALLINT':
143 case 'MEDIUMINT':
144 case 'INT':
145 case 'INTEGER':
146 case 'BIGINT':
147 case 'REAL':
148 case 'DOUBLE':
149 case 'FLOAT':
150 case 'DECIMAL':
151 case 'NUMERIC':
152 // UNSIGNED definition
153 if( $field_args['unsigned'] !== null ) {
154 if( $field_args['unsigned'] ) {
155 $schema .= 'UNSIGNED ';
156 } else {
157 $schema .= 'SIGNED ';
158 }
159 }
160
161 // ZEROFILL definition
162 if( $field_args['zerofill'] !== null && $field_args['zerofill'] ) {
163 $schema .= 'ZEROFILL ';
164 }
165 break;
166 case 'CHAR':
167 case 'VARCHAR':
168 case 'TINYTEXT':
169 case 'TEXT':
170 case 'MEDIUMTEXT':
171 case 'LONGTEXT':
172 case 'ENUM':
173 case 'SET':
174 // BINARY definition
175 if( $field_args['binary'] !== null && $field_args['binary']) {
176 $schema .= 'BINARY ';
177 }
178
179 // CHARACTER SET definition
180 if( $field_args['charset'] !== false ) {
181 $schema .= 'CHARACTER SET ' . $field_args['charset'] . ' ';
182 }
183
184 // COLLATE definition
185 if( $field_args['collate'] !== false ) {
186 $schema .= 'COLLATE ' . $field_args['collate'] . ' ';
187 }
188 break;
189 }
190
191
192 // NULL definition
193 if( $field_args['nullable'] ) {
194 $schema .= 'NULL ';
195 } else {
196 $schema .= 'NOT NULL ';
197 }
198
199 // DEFAULT definition
200 if( $field_args['default'] !== false ) {
201
202 if( gettype( $field_args['default'] ) === 'string' ) {
203 $field_args['default'] = "'" . $field_args['default'] . "'";
204 }
205
206 if( $field_args['default'] === null ) {
207 $field_args['default'] = 'NULL';
208 }
209
210 $schema .= 'DEFAULT ' . $field_args['default'] . ' ';
211 }
212
213 // UNIQUE definition
214 if( $field_args['unique'] ) {
215 $schema .= 'UNIQUE ';
216 }
217
218 // AUTO_INCREMENT definition
219 if( $field_args['auto_increment'] ) {
220 $schema .= 'AUTO_INCREMENT ';
221 }
222
223 // PRIMARY KEY definition
224 if( $field_args['primary_key'] ) {
225 $this->primary_key = $field_id;
226 }
227
228 // KEY definition
229 if( $field_args['key'] ) {
230
231 /*
232 * Indexes have a maximum size of 767 bytes. WordPress 4.2 was moved to utf8mb4, which uses 4 bytes per character.
233 * This means that an index which used to have room for floor(767/3) = 255 characters, now only has room for floor(767/4) = 191 characters.
234 */
235 $max_index_length = 191;
236 $length = min( $field_args['length'], $max_index_length );
237
238 // Ensure that length has a value
239 if( $length === 0 ) {
240 $length = $max_index_length;
241 }
242
243 if( $this->is_numeric( $field_args['type'] ) || strtoupper( $field_args['type'] ) === 'DATETIME' ) {
244 $this->keys[] = 'KEY `' . $field_id . '`(`' . $field_id . '`)';
245 } else {
246 $this->keys[] = 'KEY `' . $field_id . '`(`' . $field_id . '`(' . $length . '))';
247 }
248 }
249
250 return $schema;
251
252 }
253
254 /**
255 * Convert a schema string into an array of fields definitions
256 *
257 * @param string $schema
258 *
259 * @return array
260 */
261 public function string_schema_to_array( $schema ) {
262
263 $schema_array = explode( ',', trim( $schema ) );
264 $new_schema = array();
265
266 foreach( $schema_array as $field_def ) {
267
268 $field_id = '';
269 $field_args = array();
270
271 $field_def_parts = explode( ' ', trim( $field_def ) );
272
273 foreach( $field_def_parts as $index => $field_def_part ) {
274
275
276 if( $index === 0 ) {
277
278 // Field id at index 0
279 if( $field_def_part !== 'PRIMARY' && $field_def_part !== 'KEY' ) {
280 $field_id = $field_def_part;
281 continue;
282 }
283
284 // PRIMARY KEY at index 0
285 if( $field_def_part === 'PRIMARY' ) {
286 if( isset( $field_def_parts[$index+1] ) && strtoupper( $field_def_parts[$index+1] ) === 'KEY' && isset( $field_def_parts[$index+2] ) ) {
287 $primary_key_field = str_replace( array( '(', ')' ), '', $field_def_parts[$index+2] );
288
289 if( isset( $this->fields[$primary_key_field] ) ) {
290 $this->fields[$primary_key_field]['primary_key'] = true;
291 continue;
292 }
293 }
294 }
295 }
296
297 // NOT NULL definition
298 if( strtoupper( $field_def_part ) === 'NOT' ) {
299 if( isset( $field_def_parts[$index+1] ) && strtoupper( $field_def_parts[$index+1] ) === 'NULL' ) {
300 $field_args['nullable'] = false;
301 continue;
302 }
303 }
304
305 // NULL definition
306 if( strtoupper( $field_def_part ) === 'NULL' ) {
307 if( isset( $field_def_parts[$index-1] ) && strtoupper( $field_def_parts[$index-1] ) !== 'NOT' ) {
308 $field_args['nullable'] = true;
309 continue;
310 }
311 }
312
313 // UNSIGNED definition
314 if( strtoupper( $field_def_part ) === 'UNSIGNED' ) {
315 $field_args['unsigned'] = true;
316 continue;
317 }
318
319 // SIGNED definition
320 if( strtoupper( $field_def_part ) === 'SIGNED' ) {
321 $field_args['unsigned'] = false;
322 continue;
323 }
324
325 // ZEROFILL definition
326 if( strtoupper( $field_def_part ) === 'ZEROFILL' ) {
327 $field_args['zerofill'] = true;
328 continue;
329 }
330
331 // BINARY definition
332 if( strtoupper( $field_def_part ) === 'BINARY' ) {
333 $field_args['binary'] = true;
334 continue;
335 }
336
337 // CHARACTER SET definition
338 if( strtoupper( $field_def_part ) === 'CHARACTER' ) {
339 if( isset( $field_def_parts[$index+1] ) && strtoupper( $field_def_parts[$index+1] ) === 'SET' ) {
340 $field_args['charset'] = $field_def_parts[$index+2];
341 continue;
342 }
343 }
344
345 // COLLATE definition
346 if( strtoupper( $field_def_part ) === 'COLLATE' ) {
347 if( isset( $field_def_parts[$index+1] ) ) {
348 $field_args['collate'] = $field_def_parts[$index+1];
349 continue;
350 }
351 }
352
353 // DEFAULT definition
354 if( strtoupper( $field_def_part ) === 'DEFAULT' ) {
355 if( isset( $field_def_parts[$index+1] ) ) {
356 $field_args['default'] = $field_def_parts[$index+1];
357 continue;
358 }
359 }
360
361 // UNIQUE definition
362 if( strtoupper( $field_def_part ) === 'UNIQUE' ) {
363 $field_args['unique'] = true;
364 continue;
365 }
366
367 // AUTO_INCREMENT definition
368 if( strtoupper( $field_def_part ) === 'AUTO_INCREMENT' ) {
369 $field_args['auto_increment'] = true;
370 continue;
371 }
372
373 // PRIMARY KEY definition
374 if( strtoupper( $field_def_part ) === 'PRIMARY' ) {
375 if( isset( $field_def_parts[$index+1] ) && strtoupper( $field_def_parts[$index+1] ) === 'KEY' ) {
376 $field_args['primary_key'] = true;
377 continue;
378 }
379 }
380
381 $type_parts = explode( '(', $field_def_part );
382
383 // Possible field type
384 if( in_array( strtoupper( $field_def_part ), $this->allowed_field_types() ) ) {
385 $field_args['type'] = strtoupper( $field_def_part );
386 continue;
387 } else if( isset( $type_parts[0] ) && in_array( strtoupper( $type_parts[0] ), $this->allowed_field_types() ) ) {
388 $field_args['type'] = strtoupper( $type_parts[0] );
389
390 if( isset( $type_parts[1] ) ) {
391 $type_def = explode( ',', str_replace(')', '', $type_parts[1] ) );
392
393 switch( $field_args['type'] ) {
394 case 'ENUM':
395 case 'SET':
396 $field_args['options'] = $type_def;
397 break;
398 case 'REAL':
399 case 'DOUBLE':
400 case 'FLOAT':
401 case 'DECIMAL':
402 case 'NUMERIC':
403 $field_args['length'] = $type_def[0];
404
405 if( isset( $type_def[1] ) ) {
406 $field_args['decimals'] = $type_def[1];
407 }
408 break;
409 case 'TIME':
410 case 'TIMESTAMP':
411 case 'DATETIME':
412 $field_args['format'] = $type_def[0];
413 break;
414 default:
415 $field_args['length'] = $type_def[0];
416 break;
417 }
418 }
419 }
420 }
421
422 if( ! empty( $field_id ) && ! empty( $field_args ) ) {
423 $new_schema[$field_id] = $field_args;
424 }
425 }
426
427 return $new_schema;
428
429 }
430
431 /**
432 * Get the list of allowed types
433 *
434 * @return array
435 */
436 public function allowed_field_types() {
437 return array(
438 'BIT',
439 'TINYINT',
440 'SMALLINT',
441 'MEDIUMINT',
442 'INT',
443 'INTEGER',
444 'BIGINT',
445 'REAL',
446 'DOUBLE',
447 'FLOAT',
448 'DECIMAL',
449 'NUMERIC',
450 'DATE',
451 'TIME',
452 'TIMESTAMP',
453 'DATETIME',
454 'YEAR',
455 'CHAR',
456 'VARCHAR',
457 'BINARY',
458 'VARBINARY',
459 'TINYBLOB',
460 'BLOB',
461 'MEDIUMBLOB',
462 'LONGBLOB',
463 'TINYTEXT',
464 'TEXT',
465 'JSON'
466 );
467 }
468
469 /**
470 * Check if given type is numeric
471 *
472 * @param string $type
473 *
474 * @return bool
475 */
476 public function is_numeric( $type ) {
477
478 return in_array( strtoupper( $type ), array(
479 'TINYINT',
480 'SMALLINT',
481 'MEDIUMINT',
482 'INT',
483 'INTEGER',
484 'BIGINT',
485 'REAL',
486 'DOUBLE',
487 'FLOAT',
488 'DECIMAL',
489 'NUMERIC',
490 ) );
491
492 }
493
494 }
495
496 endif;