PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.84
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.84
5.5.84 5.5.83 5.5.82 5.5.81 5.5.80 5.5.79 5.5.77 5.5.76 5.5.75 5.5.73 5.5.72 5.5.22 5.5.23 5.5.29 5.5.3 5.5.31 5.5.32 5.5.34 5.5.35 5.5.36 5.5.37 5.5.4 5.5.40 5.5.41 5.5.42 All 160 releases
wp-data-access / WPDataAccess / Plugin_Table_Models / WPDA_Design_Table_Model.php

WPDA_Design_Table_Model.php in WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards 5.5.84, at WPDataAccess/Plugin_Table_Models/WPDA_Design_Table_Model.php

536 lines 16.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Suppress "error - 0 - No summary was found for this file" on phpdoc generation
5 *
6 * @package WPDataAccess\Plugin_Table_Models
7 */
8
9 namespace WPDataAccess\Plugin_Table_Models {
10
11 use WPDataAccess\WPDA;
12
13 /**
14 * Class WPDA_Design_Table_Model
15 *
16 * @author Peter Schulz
17 * @since 1.1.0
18 */
19 class WPDA_Design_Table_Model extends WPDA_Plugin_Table_Base_Model {
20
21 const BASE_TABLE_NAME = 'wpda_table_design';
22
23 /**
24 * Name of table where design is stored
25 *
26 * @var string|null
27 */
28 protected $table_name = null;
29
30 /**
31 * Design table name
32 *
33 * @var string|null
34 */
35 protected $wpda_table_name = null;
36
37 /**
38 * Original design table name
39 *
40 * Used to detect a table name update.
41 *
42 * @var string|null
43 */
44 protected $wpda_table_name_original = null;
45
46 /**
47 * Design database name
48 *
49 * @var string|null
50 */
51 protected $wpda_schema_name = null;
52
53 /**
54 * Original design database name
55 *
56 * Used to detect a database name update.
57 *
58 * @var string|null
59 */
60 protected $wpda_schema_name_original = null;
61
62 /**
63 * The actual table design
64 *
65 * @var string|null
66 */
67 protected $wpda_table_design = null;
68
69 /**
70 * WPDA_Design_Table_Model constructor
71 *
72 * @since 1.1.0
73 */
74 public function __construct() {
75 $this->table_name = self::get_base_table_name();
76
77 // Watch out for arrays! (array = starting export)
78 if ( isset( $_REQUEST['wpda_table_name'] ) && ! is_array( $_REQUEST['wpda_table_name'] ) ) { // phpcs:ignore
79 $this->wpda_table_name = sanitize_text_field( wp_unslash( $_REQUEST['wpda_table_name'] ) ); // phpcs:ignore
80 }
81
82 if ( isset( $_REQUEST['wpda_table_name_original'] ) ) { // phpcs:ignore
83 $this->wpda_table_name_original = sanitize_text_field( wp_unslash( $_REQUEST['wpda_table_name_original'] ) ); // phpcs:ignore
84 }
85
86 if ( isset( $_REQUEST['wpda_schema_name'] ) && ! is_array( $_REQUEST['wpda_schema_name'] ) ) { // phpcs:ignore
87 $this->wpda_schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpda_schema_name'] ) ); // phpcs:ignore
88 }
89
90 if ( isset( $_REQUEST['wpda_schema_name_original'] ) ) { // phpcs:ignore
91 $this->wpda_schema_name_original = sanitize_text_field( wp_unslash( $_REQUEST['wpda_schema_name_original'] ) ); // phpcs:ignore
92 }
93 }
94
95 /**
96 * Get design for a specific table name
97 *
98 * @param string|null $wpda_table_name_original Table name to be queried. If null query 'wpda_table_name'.
99 * @param string|null $wpda_schema_name_original Schema name to be queried. If null query 'wpda_schema_name'.
100 *
101 * @return int Number of rows.
102 */
103 public function query( $wpda_table_name_original = null, $wpda_schema_name_original = null ) {
104 if ( null === $this->wpda_table_name || null === $this->wpda_schema_name ) {
105 return false;
106 }
107
108 global $wpdb;
109 $wpda_table_design_raw = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- plugin table
110 $wpdb->prepare(
111 'SELECT wpda_table_design FROM `%1s` WHERE wpda_table_name = %s AND wpda_schema_name = %s', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
112 array(
113 WPDA::remove_backticks( $this->table_name ),
114 $wpda_table_name_original === null ? $this->wpda_table_name : $wpda_table_name_original,
115 $wpda_schema_name_original === null ? $this->wpda_schema_name : $wpda_schema_name_original,
116 )
117 ),
118 'ARRAY_A'
119 );
120
121 if ( 1 === $wpdb->num_rows ) {
122 $this->wpda_table_design = json_decode( $wpda_table_design_raw[0]['wpda_table_design'] );
123 }
124
125 return $wpdb->num_rows;
126 }
127
128 /**
129 * Return table design
130 *
131 * @return null|array
132 */
133 public function get_table_design() {
134
135 return $this->wpda_table_design;
136
137 }
138
139 /**
140 * Perform validations and return array containing errors
141 *
142 * @return array List of errors found.
143 */
144 public function validate() {
145 $structure_messages = array();
146
147 if ( ! isset( $this->wpda_table_design->design_mode ) ) {
148 $structure_messages[] = array( 'ERR', 'Invalid structure [missing element design_mode]' );
149 }
150 if ( ! isset( $this->wpda_table_design->engine )
151 && (
152 ! isset( $this->wpda_table_design->table_type )
153 ||
154 ( isset( $this->wpda_table_design->table_type ) && 'TABLE' === $this->wpda_table_design->table_type )
155 )
156 ) {
157 $structure_messages[] = array( 'ERR', 'Invalid structure [missing element engine]' );
158 }
159 if ( ! isset( $this->wpda_table_design->collation )
160 && (
161 ! isset( $this->wpda_table_design->table_type )
162 ||
163 ( isset( $this->wpda_table_design->table_type ) && 'TABLE' === $this->wpda_table_design->table_type )
164 )
165 ) {
166 $structure_messages[] = array( 'ERR', 'Invalid structure [missing element collation]' );
167 }
168 if ( ! isset( $this->wpda_table_design->table ) ) {
169 $structure_messages[] = array( 'ERR', 'Invalid structure [missing element table]' );
170 } else {
171 $unique_column_names = array();
172 foreach ( $this->wpda_table_design->table as $column ) {
173 $unique_column_names[ $column->column_name ] = true;
174 }
175 if ( count( $unique_column_names ) !== count( $this->wpda_table_design->table ) ) { // phpcs:ignore -- 8.1 proof
176 $structure_messages[] = array( 'ERR', 'Column name must be unique within a table' );
177 }
178 }
179 if ( ! isset( $this->wpda_table_design->indexes ) ) {
180 $structure_messages[] = array( 'ERR', 'Invalid structure [missing element indexes]' );
181 } else {
182 $unique_index_names = array();
183 foreach ( $this->wpda_table_design->indexes as $index ) {
184 $unique_index_names[ $index->index_name ] = true;
185 }
186 if ( count( $unique_index_names ) !== count( $this->wpda_table_design->indexes ) ) { // phpcs:ignore -- 8.1 proof
187 $structure_messages[] = array( 'ERR', 'Index name must be unique within a table' );
188 }
189 }
190 return $structure_messages;
191
192 }
193
194 /**
195 * Prepare insert statement (process arguments)
196 *
197 * @since 1.1.0
198 */
199 public function prepare_insert() {
200 $this->wpda_table_design = (object) null;
201
202 if ( isset( $_REQUEST['design_mode'] ) ) { // phpcs:ignore
203 $this->wpda_table_design->design_mode = sanitize_text_field( wp_unslash( $_REQUEST['design_mode'] ) ); // phpcs:ignore
204 } else {
205 $this->wpda_table_design->design_mode = WPDA::get_option( WPDA::OPTION_BE_DESIGN_MODE );
206 }
207
208 if ( isset( $_REQUEST['engine'] ) ) { // phpcs:ignore
209 $this->wpda_table_design->engine = sanitize_text_field( wp_unslash( $_REQUEST['engine'] ) ); // phpcs:ignore
210 } else {
211 $this->wpda_table_design->engine = '';
212 }
213
214 if ( isset( $_REQUEST['collation'] ) ) { // phpcs:ignore
215 $this->wpda_table_design->collation = sanitize_text_field( wp_unslash( $_REQUEST['collation'] ) ); // phpcs:ignore
216 } else {
217 $this->wpda_table_design->collation = '';
218 }
219
220 $this->wpda_table_design->table = $this->get_table_structure();
221
222 $this->wpda_table_design->indexes = array();
223 }
224
225 /**
226 * Add a new table design
227 *
228 * @return bool TRUE = insert successful, FALSE ; insert failed.
229 * @since 1.1.0
230 */
231 public function insert() {
232 if ( null === $this->wpda_table_name || null === $this->wpda_schema_name ) {
233 return false;
234 }
235
236 $this->prepare_insert();
237
238 $this->wpda_table_design->table_type = self::get_table_type( $this->table_name, $this->wpda_schema_name );
239
240 global $wpdb;
241
242 return $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- plugin table
243 $this->table_name,
244 array(
245 'wpda_table_name' => $this->wpda_table_name,
246 'wpda_schema_name' => $this->wpda_schema_name,
247 'wpda_table_design' => json_encode( $this->wpda_table_design ),
248 )
249 );
250
251 }
252
253 /**
254 * Get structure of table design from post variables
255 *
256 * @return array Table design.
257 * @since 1.1.0
258 */
259 protected function get_table_structure() {
260 $table_structure = array();
261
262 if ( isset( $_REQUEST['column_name'] ) && // phpcs:ignore
263 is_array( $_REQUEST['column_name'] )) { // phpcs:ignore
264 $no_columns = count( $_REQUEST['column_name'] ); // phpcs:ignore
265 for ( $i = 0; $i < $no_columns; $i ++ ) {
266 if ( isset( $_REQUEST['row_action'][ $i ] ) && 'd' === $_REQUEST['row_action'][ $i ] ) { // phpcs:ignore
267 // Do not process deleted rows.
268 continue;
269 }
270
271 $column_name = sanitize_text_field( wp_unslash( $_REQUEST['column_name'][ $i ] ) ); // phpcs:ignore
272 $data_type = sanitize_text_field( wp_unslash( $_REQUEST['data_type'][ $i ] ) ); // phpcs:ignore
273 $type_attribute = sanitize_text_field( wp_unslash( $_REQUEST['type_attribute'][ $i ] ) ); // phpcs:ignore
274 $key = sanitize_text_field( wp_unslash( $_REQUEST['key'][ $i ] ) ); // phpcs:ignore
275 $mandatory = sanitize_text_field( wp_unslash( $_REQUEST['mandatory'][ $i ] ) ); // phpcs:ignore
276 $max_length = sanitize_text_field( wp_unslash( $_REQUEST['max_length'][ $i ] ) ); // phpcs:ignore
277 $extra = sanitize_text_field( wp_unslash( $_REQUEST['extra'][ $i ] ) ); // phpcs:ignore
278 $default = sanitize_text_field( wp_unslash( $_REQUEST['default'][ $i ] ) ); // phpcs:ignore
279 $list = sanitize_text_field( wp_unslash( $_REQUEST['list'][ $i ] ) ); // phpcs:ignore
280
281 $table_structure[ $i ]['column_name'] = $column_name;
282 $table_structure[ $i ]['data_type'] = $data_type;
283 $table_structure[ $i ]['type_attribute'] = $type_attribute;
284 $table_structure[ $i ]['key'] = $key;
285 $table_structure[ $i ]['mandatory'] = $mandatory;
286 $table_structure[ $i ]['max_length'] = $max_length;
287 $table_structure[ $i ]['extra'] = $extra;
288 $table_structure[ $i ]['default'] = $default;
289 $table_structure[ $i ]['list'] = $list;
290 }
291 }
292
293 return $table_structure;
294 }
295
296 /**
297 * Get table indexes from post variables
298 *
299 * @return array Index design.
300 * @since 1.1.0
301 */
302 protected function get_indexes() {
303 $indexes = array();
304
305 if ( isset( $_REQUEST['column_names'] ) && is_array( $_REQUEST['column_names']) ) { // phpcs:ignore
306 $no_columns = count( $_REQUEST['column_names'] ); // phpcs:ignore -- 8.1 proof
307 for ( $i = 0; $i < $no_columns; $i ++ ) {
308 if ( isset( $_REQUEST['row_action'][ $i ] ) && 'd' === $_REQUEST['row_action'][ $i ] ) { // phpcs:ignore
309 // Do not process deleted rows.
310 continue;
311 }
312
313 $index_name = sanitize_text_field( wp_unslash( $_REQUEST['index_name'][ $i ] ) ); // phpcs:ignore
314 $unique = sanitize_text_field( wp_unslash( $_REQUEST['unique'][ $i ] ) ); // phpcs:ignore
315 $column_names = sanitize_text_field( wp_unslash( $_REQUEST['column_names'][ $i ] ) ); // phpcs:ignore
316
317 $indexes[ $i ]['index_name'] = $index_name;
318 $indexes[ $i ]['unique'] = $unique;
319 $indexes[ $i ]['column_names'] = $column_names;
320 }
321 }
322
323 return $indexes;
324 }
325
326 /**
327 * Prepare update statement
328 *
329 * @since 1.1.0
330 *
331 * Get table structure from database and update it using the arguments in the request.
332 */
333 public function prepare_update() {
334 $this->query(
335 $this->wpda_table_name_original === $this->wpda_table_name ? null : $this->wpda_table_name_original,
336 $this->wpda_schema_name_original === $this->wpda_schema_name ? null : $this->wpda_schema_name_original
337 );
338
339 if ( isset( $_REQUEST['design_mode'] ) ) { // phpcs:ignore
340 $this->wpda_table_design->design_mode = sanitize_text_field( wp_unslash( $_REQUEST['design_mode'] ) ); // phpcs:ignore
341 }
342
343 if ( isset( $_REQUEST['engine'] ) ) { // phpcs:ignore
344 $this->wpda_table_design->engine = sanitize_text_field( wp_unslash( $_REQUEST['engine'] ) ); // phpcs:ignore
345 }
346
347 if ( isset( $_REQUEST['collation'] ) ) { // phpcs:ignore
348 $this->wpda_table_design->collation = sanitize_text_field( wp_unslash( $_REQUEST['collation'] ) ); // phpcs:ignore
349 }
350
351 if ( isset( $_REQUEST['column_name'] ) ) { // phpcs:ignore
352 $this->wpda_table_design->table = $this->get_table_structure();
353 } else {
354 if ( isset( $_REQUEST['submitted_changes'] ) && 'table' === $_REQUEST['submitted_changes'] ) { // phpcs:ignore
355 $this->wpda_table_design->table = array();
356 }
357 }
358
359 if ( isset( $_REQUEST['column_names'] ) ) { // phpcs:ignore
360 $this->wpda_table_design->indexes = $this->get_indexes();
361 } else {
362 if ( isset( $_REQUEST['submitted_changes'] ) && 'indexes' === $_REQUEST['submitted_changes'] ) { // phpcs:ignore
363 $this->wpda_table_design->indexes = array();
364 }
365 }
366 }
367
368 /**
369 * Update table design
370 *
371 * @return bool TRUE = update successful, FALSE ; update failed.
372 * @since 1.1.0
373 */
374 public function update() {
375 if ( null === $this->wpda_table_name || null === $this->wpda_schema_name ) {
376 return false;
377 }
378
379 $this->prepare_update();
380
381 global $wpdb;
382
383 return $wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- plugin table
384 $this->table_name,
385 array(
386 'wpda_table_name' => $this->wpda_table_name,
387 'wpda_schema_name' => $this->wpda_schema_name,
388 'wpda_table_design' => json_encode( $this->wpda_table_design ),
389 ),
390 array(
391 'wpda_table_name' => $this->wpda_table_name_original === $this->wpda_table_name ? $this->wpda_table_name : $this->wpda_table_name_original,
392 'wpda_schema_name' => $this->wpda_schema_name_original === $this->wpda_schema_name ? $this->wpda_schema_name : $this->wpda_schema_name_original,
393 )
394 );
395
396 }
397
398 /**
399 * Simple list containing all table names in data designer table
400 *
401 * @return array
402 */
403 public static function get_designer_table_list() {
404 global $wpdb;
405 return $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- plugin table
406 $wpdb->prepare(
407 'SELECT `wpda_table_name` FROM `%1s`', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
408 array(
409 WPDA::remove_backticks( self::get_base_table_name() ),
410 )
411 ),
412 'ARRAY_A'
413 );
414 }
415
416 /**
417 * Reverse engineer table and store result in data designer table
418 *
419 * @param $wpda_table_name
420 * @param $wpda_schema_name
421 * @param $wpda_table_design
422 *
423 * @return bool
424 */
425 public static function insert_reverse_engineered( $wpda_table_name, $wpda_schema_name, $wpda_table_design ) {
426 global $wpdb;
427
428 $table_name = self::get_base_table_name();
429
430 $wpda_table_design['table_type'] = self::get_table_type( $wpda_table_name, $wpda_schema_name );
431
432 return (
433 1 === $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- plugin table
434 $table_name,
435 array(
436 'wpda_table_name' => $wpda_table_name,
437 'wpda_schema_name' => $wpda_schema_name,
438 'wpda_table_design' => json_encode( $wpda_table_design ),
439 )
440 )
441 );
442 }
443
444 /**
445 * Get table type from MySQL dictionary
446 *
447 * @param string $schema_name Schema name
448 * @param string $table_name Table name
449 *
450 * @return bool
451 */
452 public static function get_table_type( $table_name, $schema_name ) {
453 global $wpdb;
454 $result = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- plugin table
455 $wpdb->prepare(
456 '
457 SELECT table_type AS table_type
458 FROM information_schema.tables
459 WHERE table_schema = %s
460 AND table_name = %s
461 ',
462 array(
463 $schema_name,
464 $table_name,
465 )
466 ), // db call ok; no-cache ok.
467 'ARRAY_A'
468 );
469
470 if ( 1 !== $wpdb->num_rows ) {
471 return false;
472 } else {
473 if ( stripos( $result[0]['table_type'], 'view' ) === false ) {
474 return 'TABLE';
475 } else {
476 return 'VIEW';
477 }
478 }
479 }
480
481 /**
482 * Convert MySQL data type to basic data type (used in basic mode)
483 *
484 * @param string $arg MySQL data type.
485 *
486 * @return string Basic data type.
487 * @since 1.6.0
488 */
489 public static function datatype2basic( $arg ) {
490 switch ( $arg ) {
491 case 'tinyint':
492 case 'smallint':
493 case 'mediumint':
494 case 'int':
495 case 'integer':
496 case 'bigint':
497 case 'year':
498 return 'Integer';
499
500 case 'decimal':
501 case 'float':
502 case 'double':
503 case 'real':
504 return 'Real';
505
506 case 'bool':
507 case 'boolean':
508 return 'Boolean';
509
510 case 'date':
511 case 'time':
512 case 'datetime':
513 case 'timestamp':
514 return 'Datetime';
515
516 case 'enum':
517 case 'set':
518 return 'List';
519
520 case 'binary':
521 case 'varbinary':
522 case 'tinyblob':
523 case 'blob':
524 case 'mediumblob':
525 case 'longblob':
526 return 'Binary';
527
528 default:
529 return 'Text';
530 }
531 }
532
533 }
534
535 }
536