PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.3
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.3
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 5.5.43 All 159 releases
wp-data-access / WPDataAccess / Design_Table / WPDA_Design_Table_Form.php

WPDA_Design_Table_Form.php in WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards 5.5.3, at WPDataAccess/Design_Table/WPDA_Design_Table_Form.php

2,719 lines 102.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\Design_Table
7 */
8
9 namespace WPDataAccess\Design_Table {
10
11 use WPDataAccess\Connection\WPDADB;
12 use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Exist;
13 use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Lists;
14 use WPDataAccess\Data_Dictionary\WPDA_List_Columns_Cache;
15 use WPDataAccess\Utilities\WPDA_Message_Box;
16 use WPDataAccess\Utilities\WPDA_Reverse_Engineering;
17 use WPDataAccess\Plugin_Table_Models\WPDA_Design_Table_Model;
18 use WPDataAccess\WPDA;
19 use WPDataAccess\Dashboard\WPDA_Dashboard;
20
21 /**
22 * Class WPDA_Design_Table_Form
23 *
24 * This class provides the user interface of the Data Designer tool. The form can be used to create or alter table
25 * and index designs. Tables and indexes can be created from their design by using the appropriate buttons.
26 *
27 * Tables and their indexes can be reverse engineered from the database. This process can be started from scratch
28 * or applied to an existing table design. For the last situation users can use the reconcile button. This will
29 * bring the table and index design in the same state as their physical database counterpart.
30 *
31 * @author Peter Schulz
32 * @since 1.1.0
33 */
34 class WPDA_Design_Table_Form {
35
36 const NEW_LINE = '<br/>';
37
38 /**
39 * Page name (wpda_designer)
40 *
41 * @var string|null
42 */
43 protected $page = null;
44
45 /**
46 * Action argument
47 *
48 * @var string|null
49 */
50 protected $action = null;
51
52 /**
53 * Saved value of action2 argument used for later equations
54 *
55 * @var string|null
56 */
57 protected $action2 = null;
58
59 /**
60 * Action2 argument
61 *
62 * @var string|null
63 */
64 protected $action2_posted = null;
65
66 /**
67 * Object of type WPDA_Design_Table_Model used for data manipulation
68 *
69 * @var object|null
70 */
71 protected $model = null;
72
73 /**
74 * Table name
75 *
76 * @var string|null
77 */
78 protected $wpda_table_name = null;
79
80 /**
81 * Schema name
82 *
83 * @var string|null
84 */
85 protected $wpda_schema_name = null;
86
87 /**
88 * Table design (taken from WPDA_Design_Table_Model)
89 *
90 * @var array|null
91 */
92 protected $wpda_table_design = null;
93
94 /**
95 * Indicates whether the table was found in the database
96 *
97 * @var boolean|null
98 */
99 protected $table_exists = null;
100
101 /**
102 * Indicates whether the structure of the database table equals the table design
103 *
104 * @var boolean|null
105 */
106 protected $table_altered = false;
107
108 /**
109 * Indicates whether the table is a WordPress table
110 *
111 * @var boolean|null
112 */
113 protected $is_wp_table = false;
114
115 /**
116 * Create table statement for the designed table at startup. Updates in the user interface are not immediately
117 * reflected. User needs to reload/save the page.
118 *
119 * @var string
120 */
121 protected $create_table_statement = '';
122
123 /**
124 * Alter table statement for the designed table at startup. Updates in the user interface are not immediately
125 * reflected. User needs to reload/save the page.
126 *
127 * @var array
128 */
129 protected $alter_table_statement = array();
130
131 /**
132 * Create index statement(s) for the designed index(es) at startup. Updates in the user interface are not
133 * immediately reflected. User needs to reload/save the page.
134 *
135 * @var string
136 */
137 protected $create_index_statement = '';
138
139 /**
140 * Indicates where a create table statement succeeded
141 *
142 * @var boolean|null
143 */
144 protected $create_table_succeeded = null;
145
146 /**
147 * Indicates where a alter table statement succeeded
148 *
149 * @var boolean|null
150 */
151 protected $alter_table_succeeded = null;
152
153 /**
154 * Indicates where a create index statement failed
155 *
156 * @var boolean|null
157 */
158 protected $create_index_failed = null;
159
160 /**
161 * Named array holding table columns
162 *
163 * @see WPDA_List_Columns_Cache::get_list_columns()
164 *
165 * @var array|null
166 */
167 protected $table_columns = null;
168
169 /**
170 * Allowed values are: Basic or Advanced. Can be supplied as an argument. Taken from WPDA class f no argument
171 * is provided.
172 *
173 * @see WPDA::OPTION_BE_DESIGN_MODE
174 *
175 * @var string|null
176 */
177 protected $design_mode = null;
178
179 /**
180 * Last error from wpdb
181 *
182 * @var string|null
183 */
184 protected $wpdb_error = null;
185
186 /**
187 * Indicates whether columns or indexes were deleted in the actual design. If true checkbox "Show deleted
188 * columns and indexes" will be accessible.
189 *
190 * @var bool
191 */
192 protected $deleted_columns_and_indexes = false;
193
194 /**
195 * Indicates whether indexes were updated in the actual design.
196 *
197 * @var bool
198 */
199 protected $updated_indexes = false;
200
201 /**
202 * Holds the structure of the real physical database table
203 *
204 * @var array|null
205 */
206 protected $real_table = null;
207
208 /**
209 * Holds the structure of the real physical database indexes
210 *
211 * @var array|null
212 */
213 protected $real_indexes = null;
214
215 /**
216 * Indicates whether the design has indexes.
217 *
218 * @var bool
219 */
220 protected $indexes_found = false;
221
222 /**
223 * Argument which can be used to jump back to another page than the default table list for table designs.
224 *
225 * @var string
226 */
227 protected $caller = '';
228
229 /**
230 * Holds all available databases
231 *
232 * @var array
233 */
234 protected $database = array();
235
236 protected $databases;
237
238 protected $fulltext_support = false;
239
240 /**
241 * WPDA_Design_Table_Form constructor.
242 *
243 * @since 1.1.0
244 */
245 public function __construct() {
246 if ( isset( $_REQUEST['page'] ) ) {
247 $this->page = sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ); // input var okay.
248 } else {
249 wp_die( __( 'ERROR: Wrong arguments [page not found]', 'wp-data-access' ) );
250 }
251
252 if ( isset( $_REQUEST['action'] ) ) {
253 $this->action = sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ); // input var okay.
254 }
255
256 if ( isset( $_REQUEST['action2'] ) ) {
257 $this->action2 = sanitize_text_field( wp_unslash( $_REQUEST['action2'] ) ); // input var okay.
258 $this->action2_posted = $this->action2;
259 }
260
261 if ( isset( $_REQUEST['design_mode'] ) ) {
262 $this->design_mode = sanitize_text_field( wp_unslash( $_REQUEST['design_mode'] ) ); // input var okay.
263 } else {
264 $this->design_mode = WPDA::get_option( WPDA::OPTION_BE_DESIGN_MODE ); // Default design mode.
265 }
266
267 if ( isset( $_REQUEST['caller'] ) ) {
268 $this->caller = sanitize_text_field( wp_unslash( $_REQUEST['caller'] ) ); // input var okay.
269 }
270
271 $this->fulltext_support = get_option( 'wpda_fulltext_support' );
272
273 global $wpdb;
274
275 if ( 'init' === $this->action2 ) {
276 if ( isset( $_REQUEST['wpda_table_name'] ) && isset( $_REQUEST['wpda_schema_name'] ) ) {
277 // Check if table is already in repository.
278 $wpdb->get_results(
279 $wpdb->prepare(
280 'select * from `%1s` where wpda_schema_name = %s and wpda_table_name = %s ', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
281 array(
282 WPDA::remove_backticks( WPDA_Design_Table_Model::get_base_table_name() ),
283 sanitize_text_field( wp_unslash( $_REQUEST['wpda_schema_name'] ) ),
284 sanitize_text_field( wp_unslash( $_REQUEST['wpda_table_name'] ) ),
285 )
286 )
287 );
288 if ( 1 === $wpdb->num_rows ) {
289 // Table already in repository.
290 $this->action2 = 'edit';
291 } else {
292 // Table not in repository.
293 $this->action2 = 'wpda_reverse_engineering';
294 }
295 } else {
296 wp_die( __( 'ERROR: Wrong arguments [table not found]', 'wp-data-access' ) );
297 }
298 }
299
300 if ( 'wpda_reverse_engineering' === $this->action2 || 'wpda_reconcile' === $this->action2 ) {
301 if ( isset( $_REQUEST['wpda_table_name_re'] ) && isset( $_REQUEST['wpda_schema_name_re'] ) ) {
302 $wpda_table_name_re = sanitize_text_field( wp_unslash( $_REQUEST['wpda_table_name_re'] ) );
303 $wpda_schema_name_re = sanitize_text_field( wp_unslash( $_REQUEST['wpda_schema_name_re'] ) );
304 if ( 'wpda_reconcile' === $this->action2 ) {
305 // Before table can be reconciled old table structure must be deleted.
306 $wpdb->query(
307 $wpdb->prepare(
308 'delete from `%1s` where wpda_table_name = %s and wpda_schema_name = %s ', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
309 array(
310 WPDA::remove_backticks( WPDA_Design_Table_Model::get_base_table_name() ),
311 $wpda_table_name_re,
312 $wpda_schema_name_re,
313 )
314 )
315 );
316 }
317 // Start reverse engineering table.
318 $wpda_reverse_engineering = new WPDA_Reverse_Engineering( $wpda_table_name_re, $wpda_schema_name_re );
319 $this->design_mode = isset( $_REQUEST['design_mode_re'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['design_mode_re'] ) ) : $this->design_mode; // input var okay.
320 $table_structure = $wpda_reverse_engineering->get_designer_format( $this->design_mode );
321 if ( count( $table_structure ) > 0 ) {//phpcs:ignore - 8.1 proof
322 if ( isset( $_REQUEST['wpda_table_name'] ) && '' !== trim( $_REQUEST['wpda_table_name'] ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
323 $this->wpda_table_name = sanitize_text_field( wp_unslash( $_REQUEST['wpda_table_name'] ) );
324 } else {
325 $this->wpda_table_name = $wpda_table_name_re;
326 }
327 if ( isset( $_REQUEST['wpda_schema_name'] ) && '' !== trim( $_REQUEST['wpda_schema_name'] ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
328 $this->wpda_schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpda_schema_name'] ) );
329 } else {
330 $this->wpda_schema_name = $wpda_schema_name_re;
331 }
332 $this->wpda_table_design = $table_structure;
333 } else {
334 wp_die( __( 'ERROR: Reverse engineering table failed [invalid structure]', 'wp-data-access' ) );
335 }
336 if ( ! WPDA_Design_Table_Model::insert_reverse_engineered( $this->wpda_table_name, $this->wpda_schema_name, $this->wpda_table_design ) ) {
337 wp_die( __( 'ERROR: Reverse engineering table failed [insert failed]', 'wp-data-access' ) );
338 } else {
339 // Convert named array to object (needed to display structure).
340 $this->wpda_table_design = json_decode( json_encode( $table_structure ) );
341 }
342 $this->action2 = 'edit';
343 } else {
344 wp_die( __( 'ERROR: Wrong arguments [table not found]', 'wp-data-access' ) );
345 }
346 } elseif ( isset( $_REQUEST['wpda_table_name'] ) && isset( $_REQUEST['wpda_schema_name'] ) ) {
347 $this->wpda_table_name = sanitize_text_field( wp_unslash( $_REQUEST['wpda_table_name'] ) );
348 $this->wpda_schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpda_schema_name'] ) );
349 $this->model = new WPDA_Design_Table_Model();
350
351 if ( 'new' === $this->action2 ) {
352 $insert_result = $this->model->insert();
353 if ( false === $insert_result || $insert_result < 1 ) {
354 wp_die( __( 'ERROR: Insert failed', 'wp-data-access' ) );
355 }
356 $this->action2 = 'edit'; // Show saved records and allow editing.
357 } elseif ( 'edit' === $this->action2 && 'init' !== $this->action2_posted ) {
358 $result_update = $this->model->update();
359 if ( false === $result_update ) {
360 $msg = new WPDA_Message_Box(
361 array(
362 'message_text' => __( 'Update failed', 'wp-data-access' ),
363 'message_type' => 'error',
364 'message_is_dismissible' => false,
365 )
366 );
367 $msg->box();
368 }
369 if ( 0 === $result_update ) {
370 $msg = new WPDA_Message_Box(
371 array(
372 'message_text' => __( 'Nothing to save', 'wp-data-access' ),
373 )
374 );
375 $msg->box();
376 } else {
377 $msg = new WPDA_Message_Box(
378 array(
379 'message_text' => __( 'Succesfully saved changes to database', 'wp-data-access' ),
380 )
381 );
382 $msg->box();
383 }
384 }
385
386 $this->model->query();
387 $structure_messages = $this->model->validate();
388 foreach ( $structure_messages as $messages ) {
389 if ( 'ERR' === $messages[0] ) {
390 $msg = new WPDA_Message_Box(
391 array(
392 'message_text' => $messages[1],
393 'message_type' => 'error',
394 'message_is_dismissible' => false,
395 )
396 );
397 $msg->box();
398 } else {
399 $msg = new WPDA_Message_Box(
400 array(
401 'message_text' => $messages[1],
402 )
403 );
404 $msg->box();
405 }
406 }
407 $this->wpda_table_design = $this->model->get_table_design();
408 $this->design_mode = $this->wpda_table_design->design_mode;
409
410 $this->action2 = 'edit'; // Editing mode.
411 } else {
412 $this->action2 = 'new'; // Design new table from scratch.
413 }
414
415 // Remove backticks from schema and table name to prevent sql injection
416 $this->wpda_schema_name = str_replace( '`', '', (string) $this->wpda_schema_name );
417 $this->wpda_table_name = str_replace( '`', '', (string) $this->wpda_table_name );
418
419 if ( null !== $this->wpda_table_name && null !== $this->wpda_schema_name ) {
420 // Check if table name already exists in database.
421 if ( $this->wpda_schema_name === $wpdb->dbname ) {
422 $wp_tables = array_flip( $wpdb->tables( 'all', true ) );
423 if ( isset( $wp_tables[ $this->wpda_table_name ] ) ) {
424 $this->is_wp_table = true;
425 $this->table_exists = true;
426 } else {
427 $this->does_table_exist();
428 }
429 } else {
430 $this->does_table_exist();
431 }
432
433 // Get design structure for real database table.
434 $this->get_table_structure();
435
436 if (
437 'create_table' === $this->action2_posted ||
438 'show_create_table_script' === $this->action2_posted
439 ) {
440 // Perform create table (and indexes) script.
441 $this->create_table();
442 $this->does_table_exist();
443 $this->get_table_structure();
444 } elseif ( 'alter_table' === $this->action2_posted ) {
445 // Generate alter table script and perform script.
446 $this->do_alter_table();
447 $this->get_table_structure();
448 } elseif ( 'show_alter_table_script' === $this->action2_posted ) {
449 // Generate alter table script and show result in overlay.
450 $this->alter_table();
451 } elseif ( 'create_table_index' === $this->action2_posted ) {
452 // Perform create index(es) script.
453 $this->create_index();
454 $this->get_table_structure();
455 } elseif ( 'drop_table' === $this->action2_posted ) {
456 // Perform drop table script.
457 $this->drop_table();
458 $this->does_table_exist();
459 } elseif ( 'drop_table_index' === $this->action2_posted ) {
460 // Perform drop table script.
461 $this->drop_indexes();
462 $this->get_table_structure();
463 }
464
465 if ( $this->table_exists ) {
466 // Get database table structure.
467 $wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $this->wpda_schema_name, $this->wpda_table_name );
468 $table_columns = $wpda_list_columns->get_table_columns();
469
470 // Convert indexed array to named array to improve access.
471 foreach ( $table_columns as $table_column ) {
472 $this->table_columns[ $table_column['column_name'] ] = $table_column;
473 }
474 }
475 }
476
477 $this->databases = WPDA_Dictionary_Lists::get_db_schemas();
478 }
479
480 public function prepare_form() {}
481
482 /**
483 * Get table and index structure from design
484 *
485 * @since 2.0.14
486 */
487 private function get_table_structure() {
488 if ( $this->table_exists ) {
489 $get_table_structure = new WPDA_Reverse_Engineering( $this->wpda_table_name, $this->wpda_schema_name );
490 $real_structure = $get_table_structure->get_designer_format( $this->design_mode );
491 $this->real_table = $real_structure['table'];
492 $this->real_indexes = $real_structure['indexes'];
493 }
494 }
495
496 /**
497 * Check if table exists in our database
498 *
499 * @since 2.0.14
500 */
501 private function does_table_exist() {
502 $wpda_dictionary_exists = new WPDA_Dictionary_Exist( $this->wpda_schema_name, $this->wpda_table_name );
503 $this->table_exists = $wpda_dictionary_exists->plain_table_exists();
504 if ( ! $this->table_exists ) {
505 $this->real_table = null;
506 $this->real_indexes = null;
507 }
508 }
509
510 /**
511 * Perform alter table
512 *
513 * Call $this->alter_table() to generate alter table script and process result taken
514 * from $this->create_table_statement.
515 *
516 * @see WPDA_Design_Table_Form::alter_table()
517 * @see WPDA_Design_Table_Form::create_table_statement
518 *
519 * @since 2.0.14
520 */
521 protected function do_alter_table() {
522 $this->alter_table();
523
524 $wpdadb = WPDADB::get_db_connection( $this->wpda_schema_name );
525 if ( null === $wpdadb ) {
526 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->wpda_schema_name ) ) );
527 }
528
529 $suppress = $wpdadb->suppress_errors( true );
530 $create_table_statement = str_replace( self::NEW_LINE, "\n", $this->create_table_statement );
531 if ( '' !== $create_table_statement ) {
532 // Process alter table script (store in $create_table_statement)
533 $sql_end = strpos( $create_table_statement, ";\n" );
534 while ( false !== $sql_end ) {
535 $sql = rtrim( substr( $create_table_statement, 0, $sql_end ) );
536 $create_table_statement = substr( $create_table_statement, strpos( $create_table_statement, $sql ) + strlen( $sql ) + 1 );
537 if ( ! $wpdadb->query( $sql ) ) {
538 $this->wpdb_error = $wpdadb->last_error;
539 $this->alter_table_succeeded = false;
540
541 return;
542 }
543 $sql_end = strpos( $create_table_statement, ";\n" );
544 }
545 }
546 $wpdadb->suppress_errors( $suppress );
547 }
548
549 /**
550 * Generate alter table script
551 *
552 * Alter table script is written to $this->create_table_statement.
553 *
554 * @see WPDA_Design_Table_Form::create_table_statement
555 *
556 * @since 2.0.14
557 */
558 protected function alter_table() {
559 $create_keys_design = array();
560 $create_keys_real = array();
561
562 // Find deleted and changed indexes
563 foreach ( $this->real_indexes as $real_index ) {
564 $drop_real_index = false;
565 $design_index_found = false;
566 foreach ( $this->wpda_table_design->indexes as $design_index ) {
567 if ( $real_index['index_name'] === $design_index->index_name ) {
568 $design_index_found = true;
569 if (
570 $real_index['unique'] != $design_index->unique ||
571 $real_index['column_names'] != $design_index->column_names
572 ) {
573 $drop_real_index = true;
574 break;
575 }
576 break;
577 }
578 }
579 if ( $drop_real_index || ! $design_index_found ) {
580 $this->create_table_statement .=
581 'DROP INDEX `' . str_replace( '`', '', $real_index['index_name'] ) . "` ON `{$this->wpda_table_name}`;" . self::NEW_LINE;
582 }
583 }
584 if ( '' !== $this->create_table_statement ) {
585 $this->create_table_statement .= self::NEW_LINE;
586 }
587
588 // Find new and changed columns
589 foreach ( $this->wpda_table_design->table as $design_column ) {
590 $design_column_found = false;
591 foreach ( $this->real_table as $real_column ) {
592 if ( $real_column->column_name === $design_column->column_name ) {
593 if ( $real_column != $design_column ) {
594 // Modify column
595 $this->alter_table_column( $design_column, 'MODIFY' );
596 }
597 $design_column_found = true;
598 break;
599 }
600 }
601
602 if ( ! $design_column_found ) {
603 // Add new column
604 $this->alter_table_column( $design_column, 'ADD' );
605 }
606
607 if ( 'Yes' === $design_column->key ) {
608 $create_keys_design[] = $design_column->column_name;
609 }
610 }
611
612 // Find deleted columns
613 foreach ( $this->real_table as $real_column ) {
614 $real_column_found = false;
615 foreach ( $this->wpda_table_design->table as $design_column ) {
616 if ( $real_column->column_name === $design_column->column_name ) {
617 $real_column_found = true;
618 break;
619 }
620 }
621
622 if ( ! $real_column_found ) {
623 // Drop column
624 //phpcs:ignore - 8.1 proof
625 array_push(
626 $this->alter_table_statement,
627 'DROP COLUMN `' . str_replace( '`', '', $real_column->column_name ) . '`,' . self::NEW_LINE
628 );
629 }
630
631 if ( 'Yes' === $real_column->key ) {
632 $create_keys_real[] = $real_column->column_name;
633 }
634 }
635
636 if ( 0 < count( $this->alter_table_statement ) ) {//phpcs:ignore - 8.1 proof
637 $this->create_table_statement .= "ALTER TABLE `{$this->wpda_table_name}` ";
638 foreach ( $this->alter_table_statement as $sql ) {
639 $this->create_table_statement .= $sql;
640 }
641 $this->create_table_statement =
642 substr( $this->create_table_statement, 0, strrpos( $this->create_table_statement, ',' ) ) .
643 ';' . self::NEW_LINE . self::NEW_LINE;
644
645 $array_difference_1 = array_diff( $create_keys_design, $create_keys_real ); //phpcs:ignore - 8.1 proof
646 $array_difference_2 = array_diff( $create_keys_real, $create_keys_design ); //phpcs:ignore - 8.1 proof
647 if ( 0 !== count( $array_difference_1 ) || 0 !== count( $array_difference_2 ) ) { //phpcs:ignore - 8.1 proof
648 if ( 0 < count( $create_keys_real ) ) { //phpcs:ignore - 8.1 proof
649 $this->create_table_statement =
650 "ALTER TABLE `{$this->wpda_table_name}` DROP PRIMARY KEY;" .
651 self::NEW_LINE . self::NEW_LINE . $this->create_table_statement;
652 }
653 if ( 0 < count( $create_keys_design ) ) { //phpcs:ignore - 8.1 proof
654 $alter_table_statement =
655 "ALTER TABLE `{$this->wpda_table_name}` ADD PRIMARY KEY ";
656 foreach ( $create_keys_design as $key ) {
657 $alter_table_statement .= $key === reset( $create_keys_design ) ? '(' : ',';//phpcs:ignore - 8.1 proof
658 $alter_table_statement .= '`' . str_replace( '`', '', $key ) . '`';
659 }
660 $alter_table_statement .= ');' . self::NEW_LINE . self::NEW_LINE;
661
662 $this->create_table_statement .= $alter_table_statement;
663 }
664 }
665 }
666
667 // Add new and changed indexes
668 foreach ( $this->wpda_table_design->indexes as $design_index ) {
669 $real_index_found = false;
670 $create_new_index = false;
671 foreach ( $this->real_indexes as $real_index ) {
672 if ( $real_index['index_name'] === $design_index->index_name ) {
673 $real_index_found = true;
674 if (
675 $real_index['unique'] != $design_index->unique ||
676 $real_index['column_names'] != $design_index->column_names
677 ) {
678 $create_new_index = true;
679 break;
680 }
681 break;
682 }
683 }
684 if ( ! $real_index_found || $create_new_index ) {
685 $unique = '';
686 if ( 'Yes' === $design_index->unique ) {
687 $unique = 'UNIQUE';
688 } elseif ( 'FULLTEXT' === $design_index->unique ) {
689 if ( 'on' === $this->fulltext_support ) {
690 $unique = 'FULLTEXT';
691 } else {
692 $unique = '';
693 }
694 }
695 $column_names_array = explode( ',', ( string ) $design_index->column_names );//phpcs:ignore - 8.1 proof
696 $column_names = '`' . implode( '`,`', $column_names_array ) . '`';
697 $this->create_table_statement .=
698 "CREATE $unique INDEX `" . str_replace( '`', '', $design_index->index_name ) . "` ON `{$this->wpda_table_name}` ($column_names);" .
699 self::NEW_LINE;
700 }
701 }
702 }
703
704 /**
705 * Alter column format
706 *
707 * @param object $design_column Column definition
708 * @param string $keyword ADD or MODIFY
709 *
710 * @since 2.0.14
711 */
712 private function alter_table_column( $design_column, $keyword ) {
713 $alter_table_statement = "$keyword COLUMN `" . str_replace( '`', '', $design_column->column_name ) . '` ';
714 $alter_table_statement .= $design_column->data_type;
715 if ( '' !== $design_column->max_length ) {
716 $alter_table_statement .= "($design_column->max_length)";
717 }
718 if ( 'enum' === $design_column->data_type || 'set' === $design_column->data_type ) {
719 $alter_table_statement .= '(' . $design_column->list . ')';
720 }
721 $alter_table_statement .= ' ';
722 $alter_table_statement .= 'Yes' === $design_column->mandatory ? 'NOT NULL' : 'NULL';
723 if ( '' !== $design_column->default ) {
724 $alter_table_statement .= " DEFAULT {$design_column->default}";
725 }
726 if ( '' !== $design_column->extra ) {
727 $alter_table_statement .= ' ';
728 $alter_table_statement .= $design_column->extra;
729 }
730 $alter_table_statement .= ',' . self::NEW_LINE;
731
732 array_push(
733 $this->alter_table_statement,
734 $alter_table_statement
735 );//phpcs:ignore - 8.1 proof
736 }
737
738 /**
739 * Drop database table
740 *
741 * Does not drop WordPress tables.
742 *
743 * @since 2.0.14
744 */
745 protected function drop_table() {
746 if ( $this->is_wp_table ) {
747 $msg = new WPDA_Message_Box(
748 array(
749 'message_text' => sprintf( __( 'Cannot drop WordPress table `%s`', 'wp-data-access' ), $this->wpda_table_name ),
750 'message_type' => 'error',
751 'message_is_dismissible' => false,
752 )
753 );
754 $msg->box();
755
756 return;
757 }
758
759 if ( $this->table_exists ) {
760 $wpdadb = WPDADB::get_db_connection( $this->wpda_schema_name );
761 if ( null === $wpdadb ) {
762 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->wpda_schema_name ) ) );
763 }
764
765 $suppress = $wpdadb->suppress_errors( true );
766 $drop_table_statement = "DROP TABLE `{$this->wpda_table_name}`";
767 if ( $wpdadb->query( $drop_table_statement ) ) {
768 $msg = new WPDA_Message_Box(
769 array(
770 'message_text' => sprintf( __( 'Table `%s` dropped', 'wp-data-access' ), $this->wpda_table_name ),
771 )
772 );
773 $msg->box();
774 } else {
775 $msg = new WPDA_Message_Box(
776 array(
777 'message_text' => __( 'DROP TABLE failed', 'wp-data-access' ),
778 'message_type' => 'error',
779 'message_is_dismissible' => false,
780 )
781 );
782 $msg->box();
783 $this->create_table_statement = $drop_table_statement;
784 }
785 $wpdadb->suppress_errors( $suppress );
786 }
787 }
788
789 /**
790 * Perform create table statement
791 *
792 * @since 1.1.0
793 */
794 protected function create_table() {
795 $is_valid = true;
796 $this->create_table_statement = "CREATE TABLE `{$this->wpda_table_name}`" . self::NEW_LINE;
797
798 $create_keys = array();
799 foreach ( $this->wpda_table_design->table as $row ) {
800 $this->create_table_statement .= $row === reset( $this->wpda_table_design->table ) ? '(' : ',';//phpcs:ignore - 8.1 proof
801 $this->create_table_statement .= '`' . str_replace( '`', '', $row->column_name ) . '`';
802 $this->create_table_statement .= ' ';
803 $this->create_table_statement .= $row->data_type;
804 if ( '' !== $row->max_length ) {
805 $this->create_table_statement .= "($row->max_length)";
806 } else {
807 if (
808 'varchar' === $row->data_type ||
809 'char' === $row->data_type ||
810 'varbinary' === $row->data_type ||
811 'binary' === $row->data_type
812 ) {
813 $is_valid = false;
814 $msg = new WPDA_Message_Box(
815 array(
816 'message_text' => "Column {$row->column_name} of {$row->data_type} must have a max length",
817 'message_type' => 'error',
818 'message_is_dismissible' => false,
819 )
820 );
821 $msg->box();
822 }
823 }
824 if ( '' !== $row->type_attribute ) {
825 $this->create_table_statement .= " {$row->type_attribute} ";
826 }
827 if ( 'enum' === $row->data_type || 'set' === $row->data_type ) {
828 $this->create_table_statement .= '(' . $row->list . ')';
829 }
830 $this->create_table_statement .= ' ';
831 $this->create_table_statement .= 'Yes' === $row->mandatory ? 'NOT NULL' : 'NULL';
832 if ( '' !== $row->default ) {
833 $this->create_table_statement .= " DEFAULT {$row->default}";
834 }
835 if ( '' !== $row->extra ) {
836 $this->create_table_statement .= ' ';
837 $this->create_table_statement .= $row->extra;
838 }
839 if ( 'Yes' === $row->key ) {
840 $create_keys[] = $row->column_name;
841 }
842 $this->create_table_statement .= self::NEW_LINE;
843 }
844 if ( 0 < count( $create_keys ) ) {//phpcs:ignore - 8.1 proof
845 $this->create_table_statement .= ',PRIMARY KEY ';
846 foreach ( $create_keys as $key ) {
847 $this->create_table_statement .= $key === reset( $create_keys ) ? '(' : ',';//phpcs:ignore - 8.1 proof
848 $this->create_table_statement .= '`' . str_replace( '`', '', $key ) . '`';
849 }
850 $this->create_table_statement .= ')';
851 $this->create_table_statement .= self::NEW_LINE;
852 }
853 $this->create_table_statement .= ')';
854 if ( isset( $this->wpda_table_design->engine ) && '' !== $this->wpda_table_design->engine ) {
855 $this->create_table_statement .= ' ENGINE ' . $this->wpda_table_design->engine;
856 }
857 if ( isset( $this->wpda_table_design->collation ) && '' !== $this->wpda_table_design->collation ) {
858 $collation = explode( '_', $this->wpda_table_design->collation );//phpcs:ignore - 8.1 proof
859 $this->create_table_statement .= ' DEFAULT CHARACTER SET ' . $collation[0] . ' COLLATE=' . $this->wpda_table_design->collation;
860 }
861 $this->create_table_statement .= ';' . self::NEW_LINE . self::NEW_LINE;
862
863 if ( ! $is_valid ) {
864 return;
865 }
866
867 if ( 'show_create_table_script' === $this->action2_posted ) {
868 // Just show CREATE TABLE script!
869 // SQL script is available in $this->create_table_statement and can be shown on the page.
870 $this->create_index();
871 } else {
872 // Create table and indexes.
873 $wpdadb = WPDADB::get_db_connection( $this->wpda_schema_name );
874 if ( null === $wpdadb ) {
875 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->wpda_schema_name ) ) );
876 }
877
878 $suppress = $wpdadb->suppress_errors( true );
879
880 $this->create_table_succeeded = $wpdadb->query( str_replace( self::NEW_LINE, '', $this->create_table_statement ) );
881 if ( $this->create_table_succeeded ) {
882 $msg = new WPDA_Message_Box(
883 array(
884 'message_text' => __( 'Table created', 'wp-data-access' ),
885 )
886 );
887 $msg->box();
888 } else {
889 $msg = new WPDA_Message_Box(
890 array(
891 'message_text' => __( 'CREATE TABLE failed', 'wp-data-access' ),
892 'message_type' => 'error',
893 'message_is_dismissible' => false,
894 )
895 );
896 $msg->box();
897
898 $this->wpdb_error = $wpdadb->last_error;
899 }
900
901 $wpdadb->suppress_errors( $suppress );
902 }
903 }
904
905 /**
906 * Show Data Designer form
907 *
908 * @since 1.1.0
909 */
910 public function show() {
911 ?>
912 <script type='text/javascript'>
913 var row_num = 1;
914 var index_num = 1;
915
916 var table_updated = false;
917 var index_updated = false;
918
919 var no_cols_selected = 'no column(s) selected';
920
921 function disable_page() {
922 jQuery(".wpda_view").prop("readonly", true).prop("disabled", true).addClass("disabled");
923 disable_table();
924 disable_index();
925 disable_create_buttons();
926 jQuery('#reconcile_button').prop("readonly", true).prop("disabled", true).addClass("disabled");
927 jQuery('.design_mode').prop("readonly", true).prop("disabled", true).addClass("disabled");
928 jQuery('.column_names').prop("readonly", true).prop("disabled", true).addClass("disabled");
929 }
930
931 function disable_table() {
932 jQuery(".wpda_view_table").prop("readonly", true).prop("disabled", true).addClass("disabled");
933 }
934
935 function disable_index() {
936 jQuery(".wpda_view_index").prop("readonly", true).prop("disabled", true).addClass("disabled");
937 }
938
939 function disable_create_buttons() {
940 jQuery("#button_show_create_table").prop("readonly", true).prop("disabled", true).addClass("disabled");
941 jQuery("#button_show_alter_table").prop("readonly", true).prop("disabled", true).addClass("disabled");
942 jQuery("#button_create_table").prop("readonly", true).prop("disabled", true).addClass("disabled");
943 jQuery("#button_alter_table").prop("readonly", true).prop("disabled", true).addClass("disabled");
944 jQuery("#button_create_index").prop("readonly", true).prop("disabled", true).addClass("disabled");
945 jQuery("#button_recreate_index").prop("readonly", true).prop("disabled", true).addClass("disabled");
946 }
947
948 function rem_row(e) {
949 var curr_id = e.target.parentNode.parentNode.id;
950 if (confirm("Delete column?")) {
951 jQuery("#" + curr_id).remove();
952 updated_table();
953 }
954 }
955
956 function rem_index(e) {
957 var curr_id = e.target.parentNode.parentNode.id;
958 if (confirm("Delete index?")) {
959 jQuery("#" + curr_id).remove();
960 updated_indexes();
961 }
962 }
963
964 function updated_table() {
965 disable_create_buttons();
966 disable_index();
967 table_updated = true;
968 }
969
970 function updated_indexes() {
971 disable_create_buttons();
972 disable_table();
973 index_updated = true;
974 }
975
976 function check_basic_data_type(row_num) {
977 check_numeric_items_off();
978 switch (jQuery('#basic_data_type_' + row_num).val()) {
979 case 'Text':
980 jQuery('#data_type_' + row_num).val('text');
981 jQuery('#max_length_' + row_num).val('').attr('class', 'wpda_nodataentryallowed wpda_view_table');
982 break;
983 case 'Integer':
984 jQuery('#data_type_' + row_num).val('int');
985 jQuery('#max_length_' + row_num).attr('class', 'wpda_digits_only wpda_view_table');
986 break;
987 case 'Real':
988 jQuery('#data_type_' + row_num).val('float');
989 jQuery('#max_length_' + row_num).attr('class', 'wpda_real wpda_view_table');
990 break;
991 case 'List':
992 jQuery('#data_type_' + row_num).val('enum');
993 jQuery('#max_length_' + row_num).val('').attr('class', 'wpda_nodataentryallowed wpda_view_table');
994 break;
995 case 'Boolean':
996 jQuery('#data_type_' + row_num).val('tinyint');
997 jQuery('#max_length_' + row_num).attr('class', 'wpda_digits_only wpda_view_table');
998 break;
999 case 'Datetime':
1000 jQuery('#data_type_' + row_num).val('datetime');
1001 jQuery('#max_length_' + row_num).val('').attr('class', 'wpda_nodataentryallowed wpda_view_table');
1002 break;
1003 case 'Binary':
1004 jQuery('#data_type_' + row_num).val('binary');
1005 jQuery('#max_length_' + row_num).attr('class', 'wpda_digits_only wpda_view_table');
1006 break;
1007 case 'Blob':
1008 jQuery('#data_type_' + row_num).val('blob');
1009 jQuery('#max_length_' + row_num).val('').attr('class', 'wpda_nodataentryallowed wpda_view_table');
1010 break;
1011 case '*ID':
1012 jQuery('#data_type_' + row_num).val('int');
1013 jQuery('#key_' + row_num).val('Yes');
1014 jQuery('#mandatory_' + row_num).val('Yes');
1015 jQuery('#max_length_' + row_num).val('').attr('class', 'wpda_digits_only wpda_view_table');
1016 jQuery('#extra_' + row_num).val('AUTO_INCREMENT');
1017 jQuery('#default_' + row_num).val('');
1018 jQuery('#list_' + row_num).val('');
1019 break;
1020 case '*TimestampC':
1021 jQuery('#data_type_' + row_num).val('timestamp');
1022 jQuery('#key_' + row_num).val('No');
1023 jQuery('#mandatory_' + row_num).val('No');
1024 jQuery('#max_length_' + row_num).val('').attr('class', 'wpda_nodataentryallowed wpda_view_table');
1025 jQuery('#extra_' + row_num).val('');
1026 jQuery('#default_' + row_num).val('CURRENT_TIMESTAMP');
1027 jQuery('#list_' + row_num).val('');
1028 break;
1029 case '*TimestampU':
1030 jQuery('#data_type_' + row_num).val('timestamp');
1031 jQuery('#key_' + row_num).val('No');
1032 jQuery('#mandatory_' + row_num).val('No');
1033 jQuery('#max_length_' + row_num).val('').attr('class', 'wpda_nodataentryallowed wpda_view_table');
1034 jQuery('#extra_' + row_num).val('ON UPDATE CURRENT_TIMESTAMP');
1035 jQuery('#default_' + row_num).val('CURRENT_TIMESTAMP');
1036 jQuery('#list_' + row_num).val('');
1037 break;
1038 }
1039 check_numeric_items_on();
1040 }
1041
1042 function check_data_type(row_num) {
1043 check_numeric_items_off();
1044 switch (jQuery('#data_type_' + row_num + ' :selected').parent().attr('label')) {
1045 case 'Integer':
1046 jQuery('#basic_data_type_' + row_num).val('Integer');
1047 jQuery('#max_length_' + row_num).attr('class', 'wpda_digits_only wpda_view_table');
1048 break;
1049 case 'Text':
1050 jQuery('#basic_data_type_' + row_num).val('Text');
1051 switch (jQuery('#data_type_' + row_num + ' :selected').val()) {
1052 case 'char':
1053 case 'varchar':
1054 jQuery('#max_length_' + row_num).attr('class', 'wpda_digits_only wpda_view_table');
1055 break;
1056 default:
1057 jQuery('#max_length_' + row_num).val('').attr('class', 'wpda_nodataentryallowed wpda_view_table');
1058 }
1059 break;
1060 case 'List':
1061 jQuery('#basic_data_type_' + row_num).val('List');
1062 jQuery('#max_length_' + row_num).val('').attr('class', 'wpda_nodataentryallowed wpda_view_table');
1063 break;
1064 case 'Date and Time':
1065 jQuery('#basic_data_type_' + row_num).val('Datetime');
1066 jQuery('#max_length_' + row_num).val('').attr('class', 'wpda_nodataentryallowed wpda_view_table');
1067 break;
1068 case 'Real':
1069 jQuery('#basic_data_type_' + row_num).val('Real');
1070 jQuery('#max_length_' + row_num).attr('class', 'wpda_real wpda_view_table');
1071 break;
1072 case 'Binary':
1073 switch (jQuery('#data_type_' + row_num + ' :selected').val()) {
1074 case 'binary':
1075 case 'varbinary':
1076 jQuery('#basic_data_type_' + row_num).val('Binary');
1077 jQuery('#max_length_' + row_num).attr('class', 'wpda_digits_only wpda_view_table');
1078 break;
1079 default:
1080 jQuery('#basic_data_type_' + row_num).val('Blob');
1081 jQuery('#max_length_' + row_num).val('').attr('class', 'wpda_nodataentryallowed wpda_view_table');
1082 }
1083 break;
1084 case 'Boolean':
1085 jQuery('#basic_data_type_' + row_num).val('Boolean');
1086 jQuery('#max_length_' + row_num).attr('class', 'wpda_digits_only wpda_view_table');
1087 break;
1088 }
1089 check_numeric_items_on();
1090 }
1091
1092 function check_numeric_items_off() {
1093 jQuery('.wpda_digits_only').off('keyup paste');
1094 jQuery('.wpda_real').off('keyup paste');
1095 jQuery('.wpda_nodataentryallowed').off('keyup paste');
1096 }
1097
1098 function check_numeric_items_on() {
1099 jQuery('.wpda_digits_only').on('keyup paste', function () {
1100 this.value = this.value.replace(/[^\d]/g, '');
1101 });
1102 jQuery('.wpda_real').on('keyup paste', function () {
1103 this.value = this.value.replace(/[^0-9,]/g, '');
1104 });
1105 jQuery('.wpda_nodataentryallowed').on('keyup paste', function () {
1106 this.value = '';
1107 });
1108 }
1109
1110 function pre_submit() {
1111 if (jQuery('#wpda_table_name').val() === '') {
1112 alert('<?php echo __( 'Table name cannot be empty' ); ?>');
1113 return false;
1114 }
1115 if ('<?php echo esc_attr( $this->action2 ); ?>' === 'new') {
1116 if (wpda_db_table_name[jQuery('#wpda_table_name').val()]) {
1117 alert('<?php echo __( 'Table name already used for another table design' ); ?>');
1118 return false;
1119 }
1120 }
1121 var all_columns_entered = true;
1122 jQuery("input[name='column_name[]']").each(function () {
1123 if (jQuery(this).val() === '') {
1124 alert('<?php echo __( 'Column names cannot be empty' ); ?>');
1125 all_columns_entered = false;
1126 }
1127 });
1128 if (!all_columns_entered) {
1129 return false;
1130 }
1131 // Enable all listboxes that have been disable to add arguments to request.
1132 jQuery("select[id^='key']").each(function () {
1133 jQuery(this).attr('disabled', false);
1134 });
1135 jQuery("select[id^='mandatory']").each(function () {
1136 jQuery(this).attr('disabled', false);
1137 });
1138 return true;
1139 }
1140
1141 function add_row(design_mode, init = false, column_name = '', basic_data_type = '', data_type = '', type_attribute = '', key = '', mandatory = '', max_length = '', extra = '', default_value = '', list = '', row_action = '') {
1142 var row_class = '';
1143 switch (row_action) {
1144 case 'u':
1145 row_class = 'wpda_column_updated';
1146 break;
1147 case 'i':
1148 row_class = 'wpda_column_inserted';
1149 break;
1150 case 'd':
1151 row_class = 'wpda_column_deleted';
1152 }
1153 var basic_columns = '<td>' +
1154 '<select name="basic_data_type[]" id="basic_data_type_' + row_num + '" onchange="check_basic_data_type(' + row_num + ')" class="wpda_view_table">' +
1155 ' <option value="Text" ' + (basic_data_type === 'Text' ? 'selected' : '') + '>Text</option>' +
1156 ' <option value="Integer" ' + (basic_data_type === 'Integer' ? 'selected' : '') + '>Integer</option>' +
1157 ' <option value="Real" ' + (basic_data_type === 'Real' ? 'selected' : '') + '>Real</option>' +
1158 ' <option value="List" ' + (basic_data_type === 'List' ? 'selected' : '') + '}>List</option>' +
1159 ' <option value="Boolean" ' + (basic_data_type === 'Boolean' ? 'selected' : '') + '>Boolean</option>' +
1160 ' <option value="Datetime" ' + (basic_data_type === 'Datetime' ? 'selected' : '') + '>Datetime</option>' +
1161 ' <option value="Binary" ' + (basic_data_type === 'Binary' ? 'selected' : '') + '>Binary</option>' +
1162 ' <option value="Blob" ' + (basic_data_type === 'Blob' ? 'selected' : '') + '>Blob</option>' +
1163 ' <option value="*ID" ' + (basic_data_type === '*ID' ? 'selected' : '') + '>* Numeric ID (auto increment)</option>' +
1164 ' <option value="*TimestampC" ' + (basic_data_type === '*TimestampC' ? 'selected' : '') + '>* Timestamp (date created)</option>' +
1165 ' <option value="*TimestampU" ' + (basic_data_type === '*TimestampU' ? 'selected' : '') + '>* Timestamp (last updated)</option>' +
1166 '</select>' +
1167 '<input type="hidden" name="data_type[]" id="data_type_' + row_num + '" value="' + data_type + '">' +
1168 '<input type="hidden" name="type_attribute[]" id="type_attribute_' + row_num + '" value="' + type_attribute + '">' +
1169 '</td>';
1170 var advanced_columns = '<td>' +
1171 '<select name="data_type[]" id="data_type_' + row_num + '" onchange="check_data_type(' + row_num + ')" class="wpda_view_table">' +
1172 ' <option value="" ' + (data_type === '' ? 'selected' : '') + '></option>' +
1173 ' <optgroup label="Integer">' +
1174 ' <option value="bit" ' + (data_type === 'bit' ? 'selected' : '') + '>bit</option>' +
1175 ' <option value="tinyint" ' + (data_type === 'tinyint' ? 'selected' : '') + '>tinyint</option>' +
1176 ' <option value="smallint" ' + (data_type === 'smallint' ? 'selected' : '') + '>smallint</option>' +
1177 ' <option value="mediumint" ' + (data_type === 'mediumint' ? 'selected' : '') + '>mediumint</option>' +
1178 ' <option value="int" ' + (data_type === 'int' ? 'selected' : '') + '>int</option>' +
1179 ' <option value="bigint" ' + (data_type === 'bigint' ? 'selected' : '') + '>bigint</option>' +
1180 ' </optgroup>' +
1181 ' <optgroup label="Text">' +
1182 ' <option value="char" ' + (data_type === 'char' ? 'selected' : '') + '>char</option>' +
1183 ' <option value="varchar" ' + (data_type === 'varchar' ? 'selected' : '') + '>varchar</option>' +
1184 ' <option disabled="disabled">-</option>' +
1185 ' <option value="tinytext" ' + (data_type === 'tinytext' ? 'selected' : '') + '>tinytext</option>' +
1186 ' <option value="text" ' + (data_type === 'text' ? 'selected' : '') + '>text</option>' +
1187 ' <option value="mediumtext" ' + (data_type === 'mediumtext' ? 'selected' : '') + '>mediumtext</option>' +
1188 ' <option value="longtext" ' + (data_type === 'longtext' ? 'selected' : '') + '>longtext</option>' +
1189 ' </optgroup>' +
1190 ' <optgroup label="List">' +
1191 ' <option value="enum" ' + (data_type === 'enum' ? 'selected' : '') + '>enum</option>' +
1192 ' <option value="set" ' + (data_type === 'set' ? 'selected' : '') + '>set</option>' +
1193 ' </optgroup>' +
1194 ' <optgroup label="Date and Time">' +
1195 ' <option value="date" ' + (data_type === 'date' ? 'selected' : '') + '>date</option>' +
1196 ' <option value="datetime" ' + (data_type === 'datetime' ? 'selected' : '') + '>datetime</option>' +
1197 ' <option value="timestamp" ' + (data_type === 'timestamp' ? 'selected' : '') + '>timestamp</option>' +
1198 ' <option value="time" ' + (data_type === 'time' ? 'selected' : '') + '>time</option>' +
1199 ' <option value="year" ' + (data_type === 'year' ? 'selected' : '') + '>year</option>' +
1200 ' </optgroup>' +
1201 ' <optgroup label="Real">' +
1202 ' <option value="decimal" ' + (data_type === 'decimal' ? 'selected' : '') + '>decimal</option>' +
1203 ' <option value="double" ' + (data_type === 'double' ? 'selected' : '') + '>double</option>' +
1204 ' <option value="float" ' + (data_type === 'float' ? 'selected' : '') + '>float</option>' +
1205 ' </optgroup>' +
1206 ' <optgroup label="Binary">' +
1207 ' <option value="binary" ' + (data_type === 'binary' ? 'selected' : '') + '>binary</option>' +
1208 ' <option value="varbinary" ' + (data_type === 'varbinary' ? 'selected' : '') + '>varbinary</option>' +
1209 ' <option disabled="disabled">-</option>' +
1210 ' <option value="tinyblob" ' + (data_type === 'tinyblob' ? 'selected' : '') + '>tinyblob</option>' +
1211 ' <option value="blob" ' + (data_type === 'blob' ? 'selected' : '') + '>blob</option>' +
1212 ' <option value="mediumblob" ' + (data_type === 'mediumblob' ? 'selected' : '') + '>mediumblob</option>' +
1213 ' <option value="longblob" ' + (data_type === 'longblob' ? 'selected' : '') + '>longblob</option>' +
1214 ' </optgroup>' +
1215 ' <optgroup label="Boolean">' +
1216 ' <option value="boolean" ' + (data_type === 'boolean' ? 'selected' : '') + '>boolean</option>' +
1217 ' </optgroup>' +
1218 '</select>' +
1219 '<input type="hidden" name="basic_data_type[]" id="basic_data_type_' + row_num + '" value="' + basic_data_type + '">' +
1220 '</td>' +
1221 '<td>' +
1222 ' <select name="type_attribute[]" id="type_attribute_' + row_num + '" class="wpda_view_table">' +
1223 ' <option value=""></option>' +
1224 ' <option value="unsigned" ' + (type_attribute === 'unsigned' ? 'selected' : '') + '>unsigned</option>' +
1225 ' <option value="unsigned zerofill" ' + (type_attribute === 'unsigned zerofill' ? 'selected' : '') + '>unsigned zerofill</option>' +
1226 ' </select>' +
1227 '</td>';
1228 var new_row = '<tr id="row_num_' + row_num + '" class="' + row_class + '">' +
1229 '<td class="wpda-table-structure-first-column-move">' +
1230 ' <span class="dashicons dashicons-move grabbable" style="float:left;"></span>' +
1231 '</td>' +
1232 '<td>' +
1233 ' <input type="text" name="column_name[]" id="column_name_' + row_num + '"' +
1234 ' maxlength="64" value="' + column_name + '" class="wpda_mysql_names wpda_view_table">' +
1235 '</td>' +
1236 (design_mode === 'basic' ? basic_columns : advanced_columns) +
1237 '<td>' +
1238 ' <select name="key[]" id="key_' + row_num + '" class="wpda_view_table">' +
1239 ' <option value="No" ' + (key === 'No' ? 'selected' : '') + '>No</option>' +
1240 ' <option value="Yes" ' + (key === 'Yes' ? 'selected' : '') + '>Yes</option>' +
1241 ' </select>' +
1242 '</td>' +
1243 '<td>' +
1244 ' <select name="mandatory[]" id="mandatory_' + row_num + '" class="wpda_view_table">' +
1245 ' <option value="No"' + (mandatory === 'No' ? 'selected' : '') + '>No</option>' +
1246 ' <option value="Yes"' + (mandatory === 'Yes' ? 'selected' : '') + '>Yes</option>' +
1247 ' </select>' +
1248 '</td>' +
1249 '<td>' +
1250 ' <input type="text" name="max_length[]" id="max_length_' + row_num + '"' +
1251 ' value="' + (max_length === '0' ? '' : max_length) + '" class="' + (basic_data_type === 'Real' ? 'wpda_float' : 'wpda_digits_only') + ' wpda_view_table">' +
1252 '</td>' +
1253 '<td>' +
1254 ' <input type="text" name="extra[]" id="extra_' + row_num + '" value="' + extra + '" class="wpda_view_table">' +
1255 '</td>' +
1256 '<td>' +
1257 ' <input type="text" name="default[]" id="default_' + row_num + '" value="' + default_value + '" class="wpda_view_table">' +
1258 '</td>' +
1259 '<td>' +
1260 ' <input type="text" name="list[]" id="list_' + row_num + '" value="' + list + '" class="wpda_view_table">' +
1261 ' <input type="hidden" name="row_action[]" value="' + row_action + '">' +
1262 '</td>' +
1263 '<td class="wpda-table-structure-last-column">' +
1264 ' <a href="javascript:void(0)" onclick="rem_row(event)" class="dashicons dashicons-trash wpda_view_table wpda_tooltip" title="Remove column from table design"></a>' +
1265 '</td>' +
1266 '</tr>';
1267 if (jQuery("#wpda_table_structure tr").length === 0) {
1268 jQuery("#wpda_table_structure").append(new_row);
1269 } else {
1270 jQuery("#wpda_table_structure tr:last").after(new_row);
1271 }
1272 <?php if ( 'basic' === $this->design_mode ) { ?>
1273 check_basic_data_type(row_num);
1274 <?php } else { ?>
1275 check_data_type(row_num)
1276 <?php } ?>
1277 row_num++;
1278 jQuery('.wpda_mysql_names').off('keyup paste');
1279 jQuery('.wpda_mysql_names').on('keyup paste', function () {
1280 this.value = this.value.replace(/[^\w\_]/g, '');
1281 });
1282 check_numeric_items_off();
1283 check_numeric_items_on();
1284 jQuery(".wpda_view_table").off('change paste keyup', updated_table);
1285 jQuery(".wpda_view_table").on('change paste keyup', updated_table);
1286 jQuery("a.wpda_view_table").off();
1287 jQuery("a.wpda_view_table").on('click', updated_table);
1288 jQuery(".wpda_column_deleted").find("input,select").attr('disabled', true);
1289 if (!init) {
1290 updated_table();
1291 }
1292 }
1293
1294 function select_available(e) {
1295
1296 var option = jQuery("#columns_available option:selected");
1297 var add_to = jQuery("#columns_selected");
1298
1299 option.remove();
1300 new_option = add_to.append(option);
1301
1302 if (jQuery("#columns_selected option[value='']").length > 0) {
1303 // Remove ALL from selected list.
1304 jQuery("#columns_selected option[value='']").remove();
1305 }
1306
1307 jQuery('select#columns_selected option').prop("selected", false);
1308
1309 }
1310
1311 function select_selected(e) {
1312
1313 var option = jQuery("#columns_selected option:selected");
1314 if (option[0].value === '') {
1315 // Cannot remove ALL.
1316 return;
1317 }
1318
1319 var add_to = jQuery("#columns_available");
1320
1321 option.remove();
1322 add_to.append(option);
1323
1324 if (jQuery('select#columns_selected option').length === 0) {
1325 jQuery("#columns_selected").append(jQuery('<option></option>').attr('value', '').text(no_cols_selected));
1326 }
1327
1328 jQuery('select#columns_available option').prop("selected", false);
1329 }
1330
1331 function show_index_dialog(e) {
1332 if ('<?php echo esc_attr( $this->action ); ?>' === 'view') {
1333 return;
1334 }
1335
1336 var item_id = e.target.id;
1337 var index_row_num = item_id.substr(item_id.lastIndexOf("_") + 1);
1338
1339 if (jQuery('#add_columns_' + index_row_num).hasClass('disabled') === true) {
1340 return;
1341 }
1342
1343 var columns_available = jQuery(
1344 '<select id="columns_available" name="columns_available[]" multiple size="8" style="width:200px" onchange="select_available()">' +
1345 '</select>'
1346 );
1347 jQuery("input[name='column_name[]']").each(function () {
1348 columns_available.append(jQuery('<option></option>').attr('value', jQuery(this).val()).text(jQuery(this).val()));
1349 });
1350
1351 var columns_selected = jQuery(
1352 '<select id="columns_selected" name="columns_selected[]" multiple size="8" style="width:200px" onchange="select_selected()">' +
1353 '<option value="">' + no_cols_selected + '</option>' +
1354 '</select>'
1355 );
1356
1357 var dialog_table = jQuery('<table style="width:410px"></table>');
1358 var dialog_table_row = dialog_table.append(jQuery('<tr></tr>'));
1359 dialog_table_row.append(jQuery('<td width="50%"></td>').append(columns_available));
1360 dialog_table_row.append(jQuery('<td width="50%"></td>').append(columns_selected));
1361
1362 // var dialog_table_row_available = dialog_table.append(jQuery('<tr></tr>').append(jQuery('<td width="50%"></td>')));
1363 // dialog_table_row_available.append(columns_available);
1364 //
1365 // var dialog_table_row_selected = dialog_table.append(jQuery('<tr></tr>').append(jQuery('<td width="50%"></td>')));
1366 // dialog_table_row_selected.append(columns_selected);
1367
1368 var dialog_text = jQuery('<div style="width:410px"></div>');
1369 var dialog = jQuery('<div></div>');
1370
1371 dialog.append(dialog_text);
1372 dialog.append(dialog_table);
1373
1374 jQuery(dialog).dialog(
1375 {
1376 dialogClass: 'wp-dialog no-close',
1377 title: 'Add column(s) to index',
1378 modal: true,
1379 autoOpen: true,
1380 closeOnEscape: false,
1381 resizable: false,
1382 width: 'auto',
1383 buttons: {
1384 "Close": function () {
1385 var selected_columns = '';
1386 jQuery("#columns_selected option").each(
1387 function () {
1388 selected_columns += jQuery(this).val() + ',';
1389 }
1390 );
1391
1392 if (selected_columns !== '') {
1393 selected_columns = selected_columns.slice(0, -1);
1394 }
1395 jQuery('#column_names_' + index_row_num).val(selected_columns);
1396
1397 jQuery(this).dialog('destroy').remove();
1398 updated_indexes();
1399 },
1400 "Cancel": function () {
1401 jQuery(this).dialog('destroy').remove();
1402 }
1403 }
1404 }
1405 );
1406
1407 wpda_add_icons_to_dialog_buttons();
1408 jQuery(".ui-button-icon-only").hide();
1409 }
1410
1411 function add_index(init = false, index_name = '', unique = '', column_names = '', row_action = '') {
1412 var row_class = '';
1413 switch (row_action) {
1414 case 'u':
1415 row_class = 'wpda_column_updated';
1416 break;
1417 case 'i':
1418 row_class = 'wpda_column_inserted';
1419 break;
1420 case 'd':
1421 row_class = 'wpda_column_deleted';
1422 }
1423 <?php if ( 'on' === $this->fulltext_support ) { ?>
1424 var fulltext_support = '<option value="FULLTEXT"' + (unique === 'FULLTEXT' ? 'selected' : '') + '>Full Text</option>';
1425 <?php } else { ?>
1426 var fulltext_support = '';
1427 <?php } ?>
1428 var new_index = '<tr id="idx_row_num_' + index_num + '" class="' + row_class + '">' +
1429 '<td style="padding-left:10px;">' +
1430 ' <input type="text" name="index_name[]" id="index_name_' + index_num + '"' +
1431 ' value="' + index_name + '" class="wpda_view_index wpda_mysql_names">' +
1432 '</td>' +
1433 '<td>' +
1434 ' <select name="unique[]" id="unique_' + index_num + '" class="wpda_view_index">' +
1435 ' <option value="No"' + (unique === 'No' ? 'selected' : '') + '>Non unique</option>' +
1436 ' <option value="Yes"' + (unique === 'Yes' ? 'selected' : '') + '>Unique</option>' +
1437 fulltext_support +
1438 ' </select>' +
1439 '</td>' +
1440 '<td>' +
1441 ' <input type="text" name="column_names[]" id="column_names_' + index_num + '" class="column_names"' +
1442 ' value="' + column_names + '" onclick="show_index_dialog(event)" readonly>' +
1443 '</td>' +
1444 '<td>' +
1445 '</td>' +
1446 ' <input type="button" name="add_columns[]" id="add_columns_' + index_num + '"' +
1447 ' value="Add column(s)" onclick="show_index_dialog(event)" class="wpda_view_index">' +
1448 ' <input type="hidden" name="row_action[]" value="' + row_action + '">' +
1449 '</td>' +
1450 '<td class="wpda-table-structure-last-column" style="width:20px;">' +
1451 ' <a href="javascript:void(0)" onclick="rem_index(event)" class="dashicons dashicons-trash wpda_view_index wpda_tooltip" title="Remove index from table design"></a>' +
1452 ' </td>' +
1453 '</tr>';
1454 if (jQuery("#wpda_index_structure tr").length === 0) {
1455 jQuery("#wpda_index_structure").append(new_index);
1456 } else {
1457 jQuery("#wpda_index_structure tr:last").after(new_index);
1458 }
1459 index_num++;
1460 jQuery('.wpda_mysql_names').off('keyup paste');
1461 jQuery('.wpda_mysql_names').on('keyup paste', function () {
1462 this.value = this.value.replace(/[^\w\_]/g, '');
1463 });
1464 jQuery('#submit_indexes').attr('disabled', false);
1465 jQuery(".wpda_view_index").off('change paste keyup', updated_indexes);
1466 jQuery(".wpda_view_index").on('change paste keyup', updated_indexes);
1467 jQuery("a.wpda_view_index").off();
1468 jQuery("a.wpda_view_index").on('click', updated_indexes);
1469 jQuery(".wpda_column_deleted").find("input,select").attr('disabled', true);
1470 if (!init) {
1471 updated_indexes();
1472 }
1473 }
1474
1475 function switch_mode(e) {
1476 if ('new' === '<?php echo esc_attr( $this->action2 ); ?>' && !table_updated && !index_updated) {
1477 if (e.target.value !== '<?php echo esc_attr( $this->design_mode ); ?>') {
1478 if (confirm('Switch to ' + e.target.value + ' mode?')) {
1479 jQuery('#switch_mode_form').submit();
1480 } else {
1481 return false;
1482 }
1483 }
1484 } else if ('edit' === '<?php echo esc_attr( $this->action2 ); ?>' || table_updated || index_updated) {
1485 if (e.target.value !== '<?php echo esc_attr( $this->design_mode ); ?>') {
1486 if (confirm('Switch to ' + e.target.value + ' mode?')) {
1487 jQuery('#design_table_form').submit();
1488 } else {
1489 return false;
1490 }
1491 }
1492 }
1493 }
1494
1495 function pre_submit_re() {
1496 if (wpda_db_table_name[jQuery('select[name="wpda_table_name_re"]').val()]) {
1497 alert('<?php echo __( 'Table name already used for another table design' ); ?>');
1498 return false;
1499 }
1500 jQuery('#design_mode_re').val(jQuery('input[name="design_mode"]:checked').val());
1501 return true;
1502 }
1503
1504 function get_tables() {
1505 schema_name = jQuery('#wpda_schema_name_re_list').val();
1506 var url = location.pathname + '?action=wpda_get_tables&hideviews=TRUE';
1507 var data = {
1508 wpdaschema_name: schema_name,
1509 wpda_wpnonce: '<?php echo esc_attr( wp_create_nonce( 'wpda-getdata-access-' . WPDA::get_current_user_login() ) ); ?>'
1510 };
1511 jQuery.post(
1512 url,
1513 data,
1514 function (data) {
1515 jQuery('#wpda_table_name_re_list').find('option').remove();
1516 var jsonData = JSON.parse(data);
1517 for (i = 0; i < jsonData.length; i++) {
1518 jQuery('#wpda_table_name_re_list').append(
1519 jQuery("<option></option>")
1520 .attr("value", jsonData[i]['table_name'])
1521 .text(jsonData[i]['table_name'])
1522 );
1523 }
1524 }
1525 );
1526 }
1527 </script>
1528 <div class="wrap">
1529 <h1>
1530 <a
1531 href="?page=<?php echo '' === $this->caller ? esc_attr( $this->page ) : esc_attr( \WP_Data_Access_Admin::PAGE_MAIN ); ?>"
1532 style="display: inline-block; vertical-align: unset;"
1533 class="dashicons dashicons-arrow-left-alt2 wpda_tooltip"
1534 title="<?php echo __( 'List', 'wp-data-access' ); ?>"
1535 ></a>
1536 Data Designer
1537 </h1>
1538 <div style="display:none;">
1539 <form id="wpda_create_table_form"
1540 action="?page=<?php echo esc_attr( $this->page ); ?>"
1541 method="post">
1542 <input type="hidden" name="action" value="edit"/>
1543 <input type="hidden" name="action2" value="create_table"/>
1544 <input type="hidden" name="wpda_table_name"
1545 value="<?php echo esc_attr( $this->wpda_table_name ); ?>"/>
1546 <input type="hidden" name="wpda_schema_name"
1547 value="<?php echo esc_attr( $this->wpda_schema_name ); ?>"/>
1548 <input type='hidden' name='caller' value='<?php echo esc_attr( $this->caller ); ?>'/>
1549 </form>
1550 <form id="wpda_alter_table_form"
1551 action="?page=<?php echo esc_attr( $this->page ); ?>"
1552 method="post">
1553 <input type="hidden" name="action" value="edit"/>
1554 <input type="hidden" name="action2" value="alter_table"/>
1555 <input type="hidden" name="wpda_table_name"
1556 value="<?php echo esc_attr( $this->wpda_table_name ); ?>"/>
1557 <input type="hidden" name="wpda_schema_name"
1558 value="<?php echo esc_attr( $this->wpda_schema_name ); ?>"/>
1559 <input type='hidden' name='caller' value='<?php echo esc_attr( $this->caller ); ?>'/>
1560 </form>
1561 <form id="wpda_drop_table_form"
1562 action="?page=<?php echo esc_attr( $this->page ); ?>"
1563 method="post">
1564 <input type="hidden" name="action" value="edit"/>
1565 <input type="hidden" name="action2" value="drop_table"/>
1566 <input type="hidden" name="wpda_table_name"
1567 value="<?php echo esc_attr( $this->wpda_table_name ); ?>"/>
1568 <input type="hidden" name="wpda_schema_name"
1569 value="<?php echo esc_attr( $this->wpda_schema_name ); ?>"/>
1570 <input type='hidden' name='caller' value='<?php echo esc_attr( $this->caller ); ?>'/>
1571 </form>
1572 <form id="wpda_create_index_form"
1573 action="?page=<?php echo esc_attr( $this->page ); ?>"
1574 method="post" style="margin-left:1px;margin-right:1px;">
1575 <input type="hidden" name="action" value="edit"/>
1576 <input type="hidden" name="action2" value="create_table_index"/>
1577 <input type="hidden" name="wpda_table_name"
1578 value="<?php echo esc_attr( $this->wpda_table_name ); ?>"/>
1579 <input type="hidden" name="wpda_schema_name"
1580 value="<?php echo esc_attr( $this->wpda_schema_name ); ?>"/>
1581 <input type='hidden' name='caller' value='<?php echo esc_attr( $this->caller ); ?>'/>
1582 </form>
1583 <form id="wpda_drop_index_form"
1584 action="?page=<?php echo esc_attr( $this->page ); ?>"
1585 method="post" style="margin-left:1px;margin-right:1px;">
1586 <input type="hidden" name="action" value="edit"/>
1587 <input type="hidden" name="action2" value="drop_table_index"/>
1588 <input type="hidden" name="wpda_table_name"
1589 value="<?php echo esc_attr( $this->wpda_table_name ); ?>"/>
1590 <input type="hidden" name="wpda_schema_name"
1591 value="<?php echo esc_attr( $this->wpda_schema_name ); ?>"/>
1592 <input type='hidden' name='caller' value='<?php echo esc_attr( $this->caller ); ?>'/>
1593 </form>
1594 </div>
1595 <style>
1596 #overlay_show_create_table {
1597 height: 400px;
1598 width: 600px;
1599 position: fixed;
1600 display: none;
1601 top: 50%;
1602 left: 50%;
1603 transform: translate(-50%, -50%);
1604 -ms-transform: translate(-50%, -50%);
1605 right: 0;
1606 bottom: 0;
1607 background-color: #f9f9f9;
1608 opacity: .95;
1609 border: 1px solid #ccc;
1610 cursor: pointer;
1611 z-index: 1000;
1612 }
1613
1614 #overlay_show_create_table_text {
1615 height: 360px;
1616 width: 400px;
1617 padding: 10px;
1618 position: relative;
1619 top: 50%;
1620 left: 220px;
1621 transform: translate(-50%, -50%);
1622 -ms-transform: translate(-50%, -50%);
1623 color: black;
1624 overflow-y: auto;
1625 background-color: white;
1626 border: 1px solid #ccc;
1627 }
1628 </style>
1629 <div id="overlay_show_create_table">
1630 <div id="overlay_show_create_table_text">
1631 <?php echo $this->create_table_statement . $this->create_index_statement; // phpcs:ignore WordPress.Security.EscapeOutput ?>
1632 </div>
1633 <div style="position: absolute; bottom: 0; right: 0; padding-right: 10px; padding-bottom: 10px;">
1634 <a id="button-copy-clipboard" href="javascript:void(0)" class="button button-secondary"
1635 style="text-align:center;width:150px;"
1636 data-clipboard-text="<?php echo str_replace( self::NEW_LINE, "\n", $this->create_table_statement ) . str_replace( self::NEW_LINE, "\n", $this->create_index_statement ); // phpcs:ignore WordPress.Security.EscapeOutput ?>">
1637 <i class="fas fa-clipboard wpda_icon_on_button"></i>
1638 <?php echo __( 'Copy to clipboard' ); ?>
1639 </a>
1640 <br/>
1641 <div style="height: 5px;"></div>
1642 <a href="javascript:void(0)" class="button button-primary"
1643 style="text-align:center;width:150px;"
1644 onclick="jQuery('#overlay_show_create_table').hide()">
1645 <i class="fas fa-times-circle wpda_icon_on_button"></i>
1646 <?php echo __( 'Close' ); ?>
1647 </a>
1648 </div>
1649 </div>
1650 <script type='text/javascript'>
1651 jQuery(function () {
1652 <?php if ( 'show_create_table_script' === $this->action2_posted || 'show_alter_table_script' === $this->action2_posted ) { ?>
1653 jQuery('#overlay_show_create_table').show();
1654 <?php } ?>
1655 var sql_to_clipboard = new ClipboardJS('#button-copy-clipboard');
1656 sql_to_clipboard.on('success', function (e) {
1657 jQuery.notify('<?php echo __( 'SQL successfully copied to clipboard!' ); ?>','info');
1658 });
1659 sql_to_clipboard.on('error', function (e) {
1660 jQuery.notify('<?php echo __( 'Could not copy SQL to clipboard!' ); ?>','error');
1661 });
1662 jQuery('#wpda_table_structure').sortable();
1663 jQuery( '.wpda_tooltip' ).tooltip();
1664 });
1665 </script>
1666 <?php
1667 if ( ! $this->wpda_table_design ) {
1668 // Allow loading table from database into designer (reverse engineering).
1669 $table_list = WPDA_Dictionary_Lists::get_tables( false );
1670 ?>
1671 <div id="wpda_reverse_engineering" style="display: none">
1672 <br/>
1673 <div class="wpda_reverse_engineering">
1674 <form id="wpda_reverse_engineering_form"
1675 action="?page=<?php echo esc_attr( $this->page ); ?>" method="post">
1676 <label><?php echo __( 'Load table from database' ); ?> </label>
1677 <select name="wpda_schema_name_re" id="wpda_schema_name_re_list" onchange="get_tables()">
1678 <?php
1679 global $wpdb;
1680 foreach ( $this->databases as $database ) {
1681 if ( null === $this->wpda_schema_name || '' === $this->wpda_schema_name ) {
1682 $dbs = WPDA::get_user_default_scheme();
1683 } else {
1684 $dbs = $this->wpda_schema_name;
1685 }
1686 $selected = $dbs === $database['schema_name'] ? 'selected' : '';
1687 if ( $wpdb->dbname === $database['schema_name'] ) {
1688 $database_printed = "WordPress database ({$database['schema_name']})";
1689 } else {
1690 $database_printed = $database['schema_name'];
1691 }
1692 echo "<option value='{$database['schema_name']}' $selected>{$database_printed}</option>"; // phpcs:ignore WordPress.Security.EscapeOutput
1693 }
1694 ?>
1695 </select>
1696 <select name="wpda_table_name_re" id="wpda_table_name_re_list">
1697 <?php
1698 foreach ( $table_list as $key => $value ) {
1699 echo '<option value="' . esc_attr( $value['table_name'] ) . '">' . esc_attr( $value['table_name'] ) . '</option>';
1700 }
1701 ?>
1702 </select>
1703 <input type="hidden" name="action" value="edit"/>
1704 <input type="hidden" name="action2" value="wpda_reverse_engineering"/>
1705 <input type="hidden" name="wpda_table_name" id="wpda_table_name_re"
1706 value="<?php echo esc_attr( $this->wpda_table_name ); ?>"/>
1707 <input type="hidden" name="wpda_schema_name" id="wpda_schema_name_re"
1708 value="<?php echo esc_attr( $this->wpda_schema_name ); ?>"/>
1709 <input type="hidden" id="design_mode_re" name="design_mode_re"/>
1710 <input type='hidden' name='caller' value='<?php echo esc_attr( $this->caller ); ?>'/>
1711 <input type="submit"
1712 class="button button-primary"
1713 value="Start Reverse Engineering"
1714 onclick="return pre_submit_re()"
1715 >
1716 <a href="javascript:void(0)" onclick="jQuery('#wpda_reverse_engineering').hide()"
1717 class="button"><?php echo __( 'Dismiss' ); ?></a>
1718 </form>
1719 </div>
1720 </div>
1721 <?php
1722
1723 }
1724 if ( $this->table_exists ) {
1725 // Add reconcile form.
1726 ?>
1727 <div style="display:none;">
1728 <form id="wpda_reconcile_form"
1729 action="?page=<?php echo esc_attr( $this->page ); ?>" method="post">
1730 <input type="hidden" name="action" value="edit"/>
1731 <input type="hidden" name="action2" value="wpda_reconcile"/>
1732 <input type="hidden" name="wpda_table_name_re"
1733 value="<?php echo esc_attr( $this->wpda_table_name ); ?>"/>
1734 <input type="hidden" name="wpda_schema_name_re"
1735 value="<?php echo esc_attr( $this->wpda_schema_name ); ?>"/>
1736 <input type='hidden' name='caller' value='<?php echo esc_attr( $this->caller ); ?>'/>
1737 </form>
1738 </div>
1739 <?php
1740 }
1741 ?>
1742 <div style="text-align:right">
1743 <a href="https://wpdataaccess.com/docs/data-designer/data-designer-getting-started/"
1744 target="_blank" style="text-decoration:none">
1745 > What is the difference between a table design and a database table?
1746 </a>
1747 </div>
1748 <div>
1749 <div style="display:none;">
1750 <form id="show_create_table_form" action="?page=<?php echo esc_attr( $this->page ); ?>"
1751 method="post">
1752 <input type="hidden" name="action" value="edit"/>
1753 <input type="hidden" name="action2" value="show_create_table_script"/>
1754 <input type="hidden" name="wpda_table_name"
1755 value="<?php echo esc_attr( $this->wpda_table_name ); ?>"/>
1756 <input type="hidden" name="wpda_schema_name"
1757 value="<?php echo esc_attr( $this->wpda_schema_name ); ?>"/>
1758 <input type='hidden' name='caller' value='<?php echo esc_attr( $this->caller ); ?>'/>
1759 </form>
1760 <form id="show_alter_table_form" action="?page=<?php echo esc_attr( $this->page ); ?>"
1761 method="post">
1762 <input type="hidden" name="action" value="edit"/>
1763 <input type="hidden" name="action2" value="show_alter_table_script"/>
1764 <input type="hidden" name="wpda_table_name"
1765 value="<?php echo esc_attr( $this->wpda_table_name ); ?>"/>
1766 <input type="hidden" name="wpda_schema_name"
1767 value="<?php echo esc_attr( $this->wpda_schema_name ); ?>"/>
1768 <input type='hidden' name='caller' value='<?php echo esc_attr( $this->caller ); ?>'/>
1769 </form>
1770 </div>
1771 <form id="design_table_form"
1772 action="?page=<?php echo esc_attr( $this->page ); ?>"
1773 autocomplete="off"
1774 method="post" onsubmit="return pre_submit()">
1775 <fieldset class="wpda_fieldset">
1776 <legend>
1777 <span>
1778 <?php echo __( 'Table definition', 'wp-data-access' ); ?>
1779 <?php
1780 if (
1781 '' !== $this->wpda_schema_name &&
1782 '' !== $this->wpda_table_name &&
1783 null !== $this->wpda_table_design
1784 ) {
1785 $table_structure = json_decode( json_encode( $this->wpda_table_design ), true );
1786 if ( isset( $table_structure['table'] ) ) {
1787 $column_names = array_column( (array) $table_structure['table'], 'column_name' ); //phpcs:ignore - 8.1 proof
1788 } else {
1789 $column_names = array();
1790 }
1791 // Validate schema, table and column names
1792 $warning = WPDA::validate_names( $this->wpda_schema_name, $this->wpda_table_name, $column_names );
1793 if ( '' !== $warning ) {
1794 echo $warning; // phpcs:ignore WordPress.Security.EscapeOutput
1795 }
1796 }
1797 ?>
1798 </span>
1799 </legend>
1800 <table class="wpda-table-structure">
1801 <thead>
1802 <tr>
1803 <td class="wpda-table-structure-first-column">
1804 <label for "wpda_schema_name"><?php echo __( 'Database' ); ?> </label>
1805 </td>
1806 <td>
1807 <select name="wpda_schema_name" id="wpda_schema_name" style="width:100%;max-width:100%;">
1808 <?php
1809 global $wpdb;
1810 foreach ( $this->databases as $database ) {
1811 if ( null === $this->wpda_schema_name || '' === $this->wpda_schema_name ) {
1812 $dbs = WPDA::get_user_default_scheme();
1813 } else {
1814 $dbs = $this->wpda_schema_name;
1815 }
1816 $selected = $dbs === $database['schema_name'] ? 'selected' : '';
1817 if ( $wpdb->dbname === $database['schema_name'] ) {
1818 $database_printed = "WordPress database ({$database['schema_name']})";
1819 } else {
1820 $database_printed = $database['schema_name'];
1821 }
1822 echo "<option value='{$database['schema_name']}' $selected>{$database_printed}</option>"; // phpcs:ignore WordPress.Security.EscapeOutput
1823 }
1824 ?>
1825 </select>
1826 </td>
1827 <td colspan="4">
1828 </td>
1829 <td colspan="4" class="wpda-table-structure-last-column">
1830 <span style="float:right;">
1831 <label>
1832 <input type="radio"
1833 name="design_mode"
1834 value="basic"
1835 class="design_mode"
1836 onclick="return switch_mode(event)"
1837 <?php echo 'basic' === $this->design_mode ? 'checked' : ''; ?>
1838 >
1839 <?php echo __( 'Basic Design Mode' ); ?>
1840 </label>
1841 <label>
1842 <input type="radio"
1843 name="design_mode"
1844 value="advanced"
1845 class="design_mode"
1846 onclick="return switch_mode(event)"
1847 <?php echo 'advanced' === $this->design_mode ? 'checked' : ''; ?>
1848 >
1849 <?php echo __( 'Advanced Design Mode' ); ?>
1850 </label>
1851 </span>
1852 </td> </tr>
1853 <tr>
1854 <td class="wpda-table-structure-first-column">
1855 <label for "wpda_table_name"><?php echo __( 'Table name' ); ?> </label>
1856 </td>
1857 <td>
1858 <input type="text" name="wpda_table_name" id="wpda_table_name" maxlength="64"
1859 style="width:100%;max-width:100%;"
1860 value="<?php echo esc_attr( $this->wpda_table_name ); ?>"
1861 onchange="jQuery('#wpda_table_name_re').val(jQuery(this).val())"
1862 class="wpda_mysql_names wpda_view_table"
1863 />
1864 </td>
1865 <td colspan="4">
1866 <?php
1867 if ( $this->table_exists ) {
1868 if ( $this->is_wp_table ) {
1869 ?>
1870 <span style="vertical-align:-webkit-baseline-middle; cursor:pointer;"
1871 title="<?php echo __( 'You cannot use a WordPress table name', 'wp-data-access' ); ?>"
1872 class="dashicons dashicons-flag wpda_tooltip">
1873 </span>
1874 <?php
1875 } else {
1876 ?>
1877 <i title="<?php echo __( 'A table with this name already exists in the database', 'wp-data-access' ); ?>"
1878 class="fas fa-info-circle pointer wpda_tooltip" style="padding: 0 5px; font-size: 24px; line-height: 30px"></i>
1879 <?php
1880 }
1881 ?>
1882 <a href="javascript:void(0)"
1883 id="reconcile_button"
1884 onclick="if (confirm('<?php echo __( 'Reconcile table? Your current modifications will be lost!' ); ?>')) { jQuery('#wpda_reconcile_form').submit(); }"
1885 class="button wpda_tooltip"
1886 title="Update table design from database table (overwrites current design)">
1887 <i class="fas fa-redo wpda_icon_on_button"></i>
1888 <?php echo __( 'Reconcile' ); ?>
1889 </a>
1890 <?php
1891 } else {
1892 $title = __( 'New table', 'wp-data-access' );
1893 ?>
1894 <span style="vertical-align:-webkit-baseline-middle; cursor:pointer;"
1895 title="<?php echo $title; // phpcs:ignore WordPress.Security.EscapeOutput ?>"
1896 class="dashicons dashicons-warning wpda_tooltip">
1897 </span>
1898 <?php
1899 }
1900 ?>
1901 <input type="hidden" name="wpda_table_name_original"
1902 value="<?php echo esc_attr( $this->wpda_table_name ); ?>"/>
1903 <input type="hidden" name="wpda_schema_name_original"
1904 value="<?php echo esc_attr( $this->wpda_schema_name ); ?>"/>
1905 <?php
1906 if ( ! $this->wpda_table_design ) {
1907 ?>
1908 <a href="javascript:void(0)"
1909 onclick="jQuery('#wpda_reverse_engineering').show()"
1910 class="button wpda_view_table wpda_tooltip"
1911 title="<?php echo __( 'Load table from database' ); ?>"
1912 >
1913 <?php echo __( 'Reverse engineering' ); ?>
1914 </a>
1915 <?php
1916 }
1917 ?>
1918 </td>
1919 <td colspan="4" class="wpda-table-structure-last-column">
1920 </td>
1921 </tr>
1922 <?php if ( 'advanced' === $this->design_mode ) { ?>
1923 <tr>
1924 <td class="wpda-table-structure-first-column">
1925 <label for "engine"><?php echo __( 'Engine' ); ?> </label>
1926 </td>
1927 <td>
1928 <select name="engine" id="engine" style="width:100%;max-width:100%;" class="wpda_view_table">
1929 <?php
1930 $engines = WPDA_Dictionary_Lists::get_engines();
1931 $engine_saved = isset( $this->wpda_table_design->engine ) ? $this->wpda_table_design->engine : '';
1932 foreach ( $engines as $engine ) {
1933 $selected_tag = '';
1934 if ( '' === $engine_saved ) {
1935 if ( 'DEFAULT' === $engine['support'] ) {
1936 $selected_tag = 'selected';
1937 }
1938 } else {
1939 if ( $engine_saved === $engine['engine'] ) {
1940 $selected_tag = 'selected';
1941 }
1942 }
1943 ?>
1944 <option value="<?php echo esc_attr( $engine['engine'] ); ?>" <?php echo esc_attr( $selected_tag ); ?>>
1945 <?php echo esc_attr( $engine['engine'] ); ?>
1946 </option>
1947 <?php
1948 }
1949 ?>
1950 </select>
1951 </td>
1952 <td colspan="8" class="wpda-table-structure-last-column">
1953 <span style="float:right;">
1954 <a id="button_show_create_table" href="javascript:void(0)"
1955 class="button button-secondary wpda_tooltip"
1956 title="Generates a create table script from table and index design."
1957 onclick="jQuery('#show_create_table_form').submit();">
1958 <i class="fas fa-code wpda_icon_on_button"></i>
1959 <?php echo __( 'Show CREATE TABLE script' ); ?>
1960 </a>
1961 <a id="button_show_alter_table" href="javascript:void(0)"
1962 class="button button-secondary wpda_tooltip"
1963 title="Generates a alter table script from table and index design."
1964 onclick="jQuery('#show_alter_table_form').submit();">
1965 <i class="fas fa-code wpda_icon_on_button"></i>
1966 <?php echo __( 'Show ALTER TABLE script' ); ?>
1967 </a>
1968 </span>
1969 </td>
1970 </tr>
1971 <tr>
1972 <td class="wpda-table-structure-first-column">
1973 <label for "collation"><?php echo __( 'Collation' ); ?> </label>
1974 </td>
1975 <td>
1976 <select name="collation" id="collation" style="width:100%;max-width:100%;"
1977 class="wpda_view_table">
1978 <?php
1979 $character_set_name = '';
1980 $default_collation = WPDA_Dictionary_Lists::get_default_collation();
1981 $collations = WPDA_Dictionary_Lists::get_collations();
1982 $collation_saved = isset( $this->wpda_table_design->collation ) ? $this->wpda_table_design->collation : '';
1983 foreach ( $collations as $collation ) {
1984 if ( $character_set_name !== $collation['character_set_name'] ) {
1985 if ( '' !== $character_set_name ) {
1986 echo '</optgroup>';
1987 }
1988 $character_set_name = $collation['character_set_name'];
1989 echo '<optgroup label="' . esc_attr( $collation['character_set_name'] ) . '">';
1990 }
1991 $selected_tag = '';
1992 if ( '' === $collation_saved ) {
1993 if ( $collation['collation_name'] === $default_collation[0]['default_collation_name'] ) {
1994 $selected_tag = 'selected';
1995 }
1996 } else {
1997 if ( $collation_saved === $collation['collation_name'] ) {
1998 $selected_tag = 'selected';
1999 }
2000 }
2001 ?>
2002 <option value="<?php echo esc_attr( $collation['collation_name'] ); ?>" <?php echo esc_attr( $selected_tag ); ?>>
2003 <?php echo esc_attr( $collation['collation_name'] ); ?>
2004 </option>
2005 <?php
2006 }
2007 ?>
2008 </select>
2009 <?php echo '</optgroup>'; ?>
2010 </td>
2011 <td colspan="8" class="wpda-table-structure-last-column">
2012 <span style="float:right;">
2013 <label id="checkbox_show_deleted_label">
2014 <input id="checkbox_show_deleted" type="checkbox"
2015 onclick="if (jQuery(this).is(':checked')) { jQuery('.wpda_column_deleted').show(); } else { jQuery('.wpda_column_deleted').hide(); }">
2016 <?php echo __( 'Show deleted columns and indexes' ); ?>
2017 </label>
2018 </span>
2019 </td>
2020 </tr>
2021 <?php } ?>
2022 </thead>
2023 </table>
2024 </fieldset>
2025 <br/>
2026 <fieldset class="wpda_fieldset">
2027 <legend>
2028 <span>
2029 <?php echo __( 'Add columns', 'wp-data-access' ); ?>
2030 </span>
2031 </legend>
2032 <table class="wpda-table-structure" style="border-collapse: collapse;">
2033 <thead>
2034 <tr>
2035 <th class="wpda-table-structure-first-column-move"></th>
2036 <th>
2037 <?php echo __( 'Column name' ); ?>
2038 </th>
2039 <th>
2040 <?php echo __( 'Column type' ); ?>
2041 </th>
2042 <?php if ( 'advanced' === $this->design_mode ) { ?>
2043 <th>
2044 <?php echo __( 'Type attribute' ); ?>
2045 </th>
2046 <?php } ?>
2047 <th style="min-width:60px;">
2048 <?php echo __( 'Key?' ); ?>
2049 </th>
2050 <th style="min-width:90px;">
2051 <?php echo __( 'Mandatory?' ); ?>
2052 </th>
2053 <th>
2054 <?php echo __( 'Max length' ); ?>
2055 </th>
2056 <th>
2057 <?php echo __( 'Extra' ); ?>
2058 <i title="Possible values:
2059
2060 auto_increment
2061 on update current_timestamp (for column types: timestamp and datetime)
2062 virtual generated
2063 virtual stored
2064 default_generated
2065 stored generated
2066
2067 Or combined:
2068 default_generated on update current_timestamp" class="fas fa-circle-question pointer wpda_tooltip"></i>
2069 </th>
2070 <th>
2071 <?php echo __( 'Default value' ); ?>
2072 </th>
2073 <th>
2074 <?php echo __( 'List values' ); ?>
2075 </th>
2076 <th class="wpda-table-structure-last-column">
2077 <a href="javascript:void(0)"
2078 onclick="add_row('<?php echo esc_attr( $this->design_mode ); ?>')"
2079 style="vertical-align:-webkit-baseline-middle;"
2080 class="dashicons dashicons-plus wpda_view_table wpda_tooltip"
2081 title="Add new column to table design"
2082 ></a>
2083 </th>
2084 </tr>
2085 </thead>
2086 <tbody id="wpda_table_structure"></tbody>
2087 <tfoot>
2088 <tr>
2089 <td colspan="<?php echo 'basic' === $this->design_mode ? '9' : '10'; ?>">
2090 <input type="hidden" name="submitted_changes" value="table"/>
2091 <input type="hidden" name="action" value="edit"/>
2092 <input type="hidden" name="action2"
2093 value="<?php echo esc_attr( $this->action2 ); ?>"
2094 />
2095 <?php if ( 'basic' === $this->design_mode ) { ?>
2096 <input type="hidden" name="engine" id="engine"
2097 value="<?php echo isset( $this->wpda_table_design->engine ) ? esc_attr( $this->wpda_table_design->engine ) : ''; ?>"
2098 />
2099 <input type="hidden" name="collation" id="collation"
2100 value="<?php echo isset( $this->wpda_table_design->collation ) ? esc_attr( $this->wpda_table_design->collation ) : ''; ?>"
2101 />
2102 <?php } ?>
2103 <a href="javascript:void(0)"
2104 title="Creates database table from design. Does not create indexes."
2105 class="button wpda_tooltip wpda_view
2106 <?php
2107 if ( $this->table_exists ) {
2108 echo ' disabled';
2109 }
2110 ?>
2111 "
2112 onclick="if ( confirm('Create database table `<?php echo WPDA::remove_backticks( $this->wpda_schema_name ); // phpcs:ignore WordPress.Security.EscapeOutput ?>`.`<?php echo WPDA::remove_backticks( $this->wpda_table_name ); // phpcs:ignore WordPress.Security.EscapeOutput ?>`?\nDoes not create indexes!') ) { jQuery('#wpda_create_table_form').submit(); }"
2113 <?php
2114 if ( $this->table_exists || 'new' === strtolower( $this->action2 ) ) {
2115 echo ' readonly disabled';
2116 }
2117 ?>
2118 >
2119 <i class="fas fa-check wpda_icon_on_button"></i>
2120 <?php echo __( 'CREATE TABLE', 'wp-data-access' ); ?>
2121 </a>
2122 <a id="button_alter_table" href="javascript:void(0)" class="button wpda_view wpda_tooltip"
2123 title="Writes design changes to database table and indexes."
2124 onclick="if ( confirm('Alter database table `<?php echo WPDA::remove_backticks( $this->wpda_schema_name ); // phpcs:ignore WordPress.Security.EscapeOutput ?>`.`<?php echo WPDA::remove_backticks( $this->wpda_table_name ); // phpcs:ignore WordPress.Security.EscapeOutput ?>`?\nAlters modified indexes as well!') ) { jQuery('#wpda_alter_table_form').submit(); }"
2125 >
2126 <i class="fas fa-redo wpda_icon_on_button"></i>
2127 <?php echo __( 'ALTER TABLE', 'wp-data-access' ); ?>
2128 </a>
2129 <a href="javascript:void(0)"
2130 title="This action drops your database table! Not your table design... This cannot be undone."
2131 class="button wpda_tooltip wpda_view
2132 <?php
2133 if ( ! $this->table_exists ) {
2134 echo ' disabled';
2135 }
2136 ?>
2137 "
2138 onclick="if ( confirm('Drop database table `<?php echo WPDA::remove_backticks( $this->wpda_schema_name ); // phpcs:ignore WordPress.Security.EscapeOutput ?>`.`<?php echo WPDA::remove_backticks( $this->wpda_table_name ); // phpcs:ignore WordPress.Security.EscapeOutput ?>`?\nTable design will not be deleted!') ) { jQuery('#wpda_drop_table_form').submit(); }"
2139 <?php
2140 if ( ! $this->table_exists ) {
2141 echo ' readonly disabled';
2142 }
2143 ?>
2144 >
2145 <i class="fas fa-trash wpda_icon_on_button"></i>
2146 <?php echo __( 'DROP TABLE', 'wp-data-access' ); ?>
2147 </a>
2148 <input type='hidden' name='caller'
2149 value='<?php echo esc_attr( $this->caller ); ?>'/>
2150 <button type="submit" class="button button-primary wpda_view_table wpda_tooltip"
2151 title="This does NOT create the table! Is just saves your table design..."
2152 >
2153 <i class="fas fa-check wpda_icon_on_button"></i>
2154 Save Table Design
2155 </button>
2156 </td>
2157 </tr>
2158 </tfoot>
2159 </table>
2160 </fieldset>
2161 </form>
2162 <form id="wpda_reset_form" action="?page=<?php echo esc_attr( $this->page ); ?>" method="post">
2163 <input type="hidden" name="action" value="edit"/>
2164 <?php
2165 if ( 'new' !== $this->action2 ) {
2166 ?>
2167 <input type="hidden" name="wpda_table_name"
2168 value="<?php echo esc_attr( $this->wpda_table_name ); ?>"/>
2169 <input type="hidden" name="wpda_schema_name"
2170 value="<?php echo esc_attr( $this->wpda_schema_name ); ?>"/>
2171 <?php
2172 }
2173 ?>
2174 <input type='hidden' name='caller' value='<?php echo esc_attr( $this->caller ); ?>'/>
2175 </form>
2176 <form id="switch_mode_form" method="post"
2177 action="?page=<?php echo esc_attr( $this->page ); ?>">
2178 <input type="hidden" name="design_mode"
2179 value="<?php echo 'basic' === $this->design_mode ? 'advanced' : 'basic'; // phpcs:ignore WordPress.Security.EscapeOutput ?>">
2180 <input type="hidden" name="action" value="edit">
2181 <input type='hidden' name='caller' value='<?php echo esc_attr( $this->caller ); ?>'/>
2182 </form>
2183 </div>
2184 <br/>
2185 <div>
2186 <form id="design_table_form_indexes" action="?page=<?php echo esc_attr( $this->page ); ?>"
2187 method="post">
2188 <fieldset class="wpda_fieldset">
2189 <legend>
2190 <span>
2191 <?php echo __( 'Add indexes' ); ?>
2192 </span>
2193 </legend>
2194 <table class="wpda-table-structure" style="border-collapse: collapse;">
2195 <thead>
2196 <tr>
2197 <th style="padding-left:10px;">
2198 <?php echo __( 'Index name' ); ?>
2199 </th>
2200 <th>
2201 <?php echo __( 'Type?' ); ?>
2202 </th>
2203 <th>
2204 <?php echo __( 'Column name(s)' ); ?>
2205 </th>
2206 <th></th>
2207 <th class="wpda-table-structure-last-column" style="width:20px;">
2208 <a href="javascript:void(0)" onclick="add_index()"
2209 style="vertical-align: -webkit-baseline-middle;"
2210 class="dashicons dashicons-plus wpda_view_index wpda_tooltip"
2211 title="Add new index to table design"
2212 ></a>
2213 </th>
2214 </tr>
2215 </thead>
2216 <tbody id="wpda_index_structure">
2217 </tbody>
2218 <tfoot>
2219 <tr>
2220 <td colspan="5">
2221 <input type="hidden" name="submitted_changes" value="indexes"/>
2222 <input type="hidden" name="action" value="edit"/>
2223 <input type="hidden" name="action2"
2224 value="<?php echo esc_attr( $this->action2 ); ?>"/>
2225 <input type="hidden" name="wpda_table_name"
2226 value="<?php echo esc_attr( $this->wpda_table_name ); ?>"/>
2227 <input type="hidden" name="wpda_table_name_original"
2228 value="<?php echo esc_attr( $this->wpda_table_name ); ?>"/>
2229 <input type="hidden" name="wpda_schema_name"
2230 value="<?php echo esc_attr( $this->wpda_schema_name ); ?>"/>
2231 <input type="hidden" name="wpda_schema_name_original"
2232 value="<?php echo esc_attr( $this->wpda_schema_name ); ?>"/>
2233 <a id="wpda_create_index" href="javascript:void(0)"
2234 title="Drops all indexes and recreates them."
2235 class="button wpda_view wpda_tooltip"
2236 onclick="if ( confirm('<?php echo __( 'Drop all deleted indexes and recreate all changed indexes for table' . ' `' . $this->wpda_table_name . '`?' ); ?>') ) { jQuery('#wpda_create_index_form').submit(); }"
2237 >
2238 <i class="fas fa-check wpda_icon_on_button"></i>
2239 <?php echo __( '(RE)CREATE INDEXES', 'wp-data-access' ); ?>
2240 </a>
2241 <a id="wpda_drop_index" href="javascript:void(0)"
2242 title="This action drops your indexes from the database! This cannot be undone."
2243 class="button wpda_view wpda_tooltip"
2244 onclick="if ( confirm('<?php echo __( 'Drop all indexes for table' . ' `' . $this->wpda_table_name . '`?\n' . __( 'Does not drop primary key indexes and index designs!' ) ); ?>')) { jQuery('#wpda_drop_index_form').submit(); }"
2245 >
2246 <i class="fas fa-trash wpda_icon_on_button"></i>
2247 <?php echo __( 'DROP INDEXES', 'wp-data-access' ); ?>
2248 </a>
2249 <input type='hidden' name='caller'
2250 value='<?php echo esc_attr( $this->caller ); ?>'/>
2251 <a id="submit_indexes" href="javascript:void(0)"
2252 title="Does NOT create indexes! It just saves your index design..."
2253 onclick="if (!jQuery(this).attr('disabled')) { jQuery('#design_table_form_indexes').submit(); } else { alert('<?php echo __( 'Save table design changes first!' ); ?>'); }"
2254 class="button button-primary wpda_view_index wpda_tooltip">
2255 <i class="fas fa-check wpda_icon_on_button"></i>
2256 <?php echo __( 'Save Indexes' ); ?>
2257 </a>
2258 </td>
2259 </tr>
2260 </tfoot>
2261 </table>
2262 </fieldset>
2263 </form>
2264 </div>
2265 <?php
2266 if ( null !== $this->create_table_statement && false === $this->create_table_succeeded ) {
2267 ?>
2268 <br/>
2269 <div class="wpda_design_table">
2270 <table class="wpda-table-structure">
2271 <tfoot>
2272 <tr>
2273 <td>
2274 <h3><?php echo __( 'The following CREATE TABLE statement failed' ); ?></h3>
2275 <div>
2276 <div style="padding:10px; text-align: left; width: fit-content; margin: 0 auto;">
2277 <?php echo $this->create_table_statement; // phpcs:ignore WordPress.Security.EscapeOutput ?>
2278 </div>
2279 </div>
2280 <div>
2281 <strong><?php echo $this->wpdb_error; // phpcs:ignore WordPress.Security.EscapeOutput ?></strong>
2282 </div>
2283 </td>
2284 </tr>
2285 </tfoot>
2286 </table>
2287 </div>
2288 <?php
2289 }
2290 if ( null !== $this->create_index_failed && 0 < count( $this->create_index_failed ) ) {//phpcs:ignore - 8.1 proof
2291 ?>
2292 <br/>
2293 <div class="wpda_design_table">
2294 <table class="wpda-table-structure">
2295 <tfoot>
2296 <tr>
2297 <td>
2298 <h3><?php echo __( 'The following CREATE INDEX statement(s) failed' ); ?></h3>
2299 <div>
2300 <div style="padding:10px; text-align: left; width: fit-content; margin: 0 auto;">
2301 <?php
2302 foreach ( $this->create_index_failed as $index_failed ) {
2303 echo "$index_failed<br/>"; // phpcs:ignore WordPress.Security.EscapeOutput
2304 }
2305 ?>
2306 </div>
2307 </div>
2308 </td>
2309 </tr>
2310 </tfoot>
2311 </table>
2312 </div>
2313 <?php
2314 }
2315 if ( null !== $this->create_table_statement && false === $this->alter_table_succeeded ) {
2316 ?>
2317 <br/>
2318 <div class="wpda_design_table">
2319 <table class="wpda-table-structure">
2320 <tfoot>
2321 <tr>
2322 <td>
2323 <h3><?php echo __( 'The following ALTER TABLE statement failed' ); ?></h3>
2324 <div>
2325 <div style="padding:10px; text-align: left; width: fit-content; margin: 0 auto;">
2326 <?php echo $this->create_table_statement; // phpcs:ignore WordPress.Security.EscapeOutput ?>
2327 </div>
2328 </div>
2329 <div>
2330 <strong><?php echo $this->wpdb_error; // phpcs:ignore WordPress.Security.EscapeOutput ?></strong>
2331 </div>
2332 </td>
2333 </tr>
2334 </tfoot>
2335 </table>
2336 </div>
2337 <?php
2338 }
2339 ?>
2340
2341 </div>
2342 <?php
2343
2344 if ( $this->wpda_table_design ) {
2345 // Display table design.
2346 foreach ( $this->wpda_table_design->table as $design_column ) {
2347 if ( ! $this->table_exists ) {
2348 // New table cannot be compared with real table.
2349 $column_changed = '';
2350 } else {
2351 // Check for table structure changes.
2352 if ( isset( $this->table_columns[ $design_column->column_name ] ) ) {
2353 // Check column arguments.
2354 $column_changed = '';
2355 foreach ( $this->real_table as $real_column ) {
2356 if ( $real_column->column_name === $design_column->column_name ) {
2357 if ( $real_column != $design_column ) {
2358 if ( strtolower( $real_column->extra ) === 'auto_increment' && strtolower( $design_column->extra ) === 'auto_increment' ) {
2359 $tmp_real_column = clone $real_column;
2360 $tmp_design_column = clone $design_column;
2361 unset( $tmp_real_column->extra );
2362 unset( $tmp_design_column->extra );
2363 if ( $tmp_real_column != $tmp_design_column ) {
2364 $column_changed = 'u';
2365 $this->table_altered = true;
2366 }
2367 } else {
2368 $column_changed = 'u';
2369 $this->table_altered = true;
2370 }
2371 }
2372 }
2373 }
2374 } else {
2375 // New column.
2376 $column_changed = 'i';
2377 $this->table_altered = true;
2378 }
2379 }
2380 ?>
2381 <script type='text/javascript'>
2382 add_row(
2383 '<?php echo esc_attr( $this->design_mode ); ?>',
2384 true,
2385 '<?php echo esc_attr( $design_column->column_name ); ?>',
2386 '<?php echo esc_attr( WPDA_Design_Table_Model::datatype2basic( esc_attr( $design_column->data_type ) ) ); ?>',
2387 '<?php echo esc_attr( $design_column->data_type ); ?>',
2388 '<?php echo esc_attr( $design_column->type_attribute ); ?>',
2389 '<?php echo esc_attr( $design_column->key ); ?>',
2390 '<?php echo esc_attr( $design_column->mandatory ); ?>',
2391 '<?php echo esc_attr( $design_column->max_length ); ?>',
2392 '<?php echo esc_attr( $design_column->extra ); ?>',
2393 '<?php echo esc_attr( $design_column->default ); ?>',
2394 '<?php echo esc_attr( $design_column->list ); ?>',
2395 '<?php echo esc_attr( $column_changed ); ?>'
2396 );
2397 </script>
2398 <?php
2399 }
2400 if ( $this->table_exists ) {
2401 // Check for deleted columns.
2402 foreach ( $this->table_columns as $table_column ) {
2403 $column_found = false;
2404 foreach ( $this->wpda_table_design->table as $design_column ) {
2405 if ( $design_column->column_name === $table_column['column_name'] ) {
2406 $column_found = true;
2407 break;
2408 }
2409 }
2410 if ( ! $column_found ) {
2411 break;
2412 }
2413 }
2414
2415 if ( ! $column_found ) {
2416 // Add deleted column(s) to form and mark as readonly.
2417 foreach ( $this->table_columns as $table_column ) {
2418 $column_found = false;
2419 foreach ( $this->wpda_table_design->table as $design_column ) {
2420 if ( $design_column->column_name === $table_column['column_name'] ) {
2421 $column_found = true;
2422 break;
2423 }
2424 }
2425 if ( ! $column_found ) {
2426 foreach ( $this->real_table as $real_column ) {
2427 if ( $real_column->column_name === $table_column['column_name'] ) {
2428 ?>
2429 <script type='text/javascript'>
2430 add_row(
2431 '<?php echo esc_attr( $this->design_mode ); ?>',
2432 true,
2433 '<?php echo esc_attr( $real_column->column_name ); ?>',
2434 '<?php echo esc_attr( WPDA_Design_Table_Model::datatype2basic( esc_attr( $real_column->data_type ) ) ); ?>',
2435 '<?php echo esc_attr( $real_column->data_type ); ?>',
2436 '<?php echo esc_attr( $real_column->type_attribute ); ?>',
2437 '<?php echo esc_attr( $real_column->key ); ?>',
2438 '<?php echo esc_attr( $real_column->mandatory ); ?>',
2439 '<?php echo esc_attr( $real_column->max_length ); ?>',
2440 '<?php echo esc_attr( $real_column->extra ); ?>',
2441 '<?php echo esc_attr( $real_column->default ); ?>',
2442 '<?php echo esc_attr( $real_column->list ); ?>',
2443 'd'
2444 );
2445 </script>
2446 <?php
2447 $this->table_altered = true;
2448 $this->deleted_columns_and_indexes = true;
2449 }
2450 }
2451 }
2452 }
2453 }
2454 }
2455
2456 // Display indexes.
2457 $indexes_found = false;
2458 foreach ( $this->wpda_table_design->indexes as $design_index ) {
2459 $index_changed = '';
2460 if ( $this->table_exists ) {
2461 $index_found = false;
2462 // Check if index was changed or new.
2463 foreach ( $this->real_indexes as $real_index ) {
2464 if ( $design_index->index_name === $real_index['index_name'] ) {
2465 $index_found = true;
2466 if (
2467 $real_index['unique'] != $design_index->unique ||
2468 $real_index['column_names'] != $design_index->column_names
2469 ) {
2470 $index_changed = 'u';
2471 $this->updated_indexes = true;
2472 }
2473 break;
2474 }
2475 }
2476 if ( ! $index_found ) {
2477 $index_changed = 'i';
2478 $this->updated_indexes = true;
2479 }
2480 }
2481 ?>
2482 <script type='text/javascript'>
2483 add_index(
2484 true,
2485 '<?php echo esc_attr( $design_index->index_name ); ?>',
2486 '<?php echo esc_attr( $design_index->unique ); ?>',
2487 '<?php echo esc_attr( $design_index->column_names ); ?>',
2488 '<?php echo $index_changed; // phpcs:ignore WordPress.Security.EscapeOutput ?>'
2489 );
2490 </script>
2491 <?php
2492 $indexes_found = true;
2493 }
2494
2495 if ( $this->table_exists ) {
2496 foreach ( $this->real_indexes as $real_index ) {
2497 $real_indexes_found = false;
2498 foreach ( $this->wpda_table_design->indexes as $design_index ) {
2499 if ( $real_index['index_name'] === $design_index->index_name ) {
2500 $real_indexes_found = true;
2501 break;
2502 }
2503 }
2504
2505 if ( ! $real_indexes_found ) {
2506 // Index was dropped.
2507 ?>
2508 <script type='text/javascript'>
2509 add_index(
2510 true,
2511 '<?php echo esc_attr( $real_index['index_name'] ); ?>',
2512 '<?php echo esc_attr( $real_index['unique'] ); ?>',
2513 '<?php echo esc_attr( $real_index['column_names'] ); ?>',
2514 '<?php echo 'd'; ?>'
2515 );
2516 </script>
2517 <?php
2518 $this->deleted_columns_and_indexes = true;
2519 $this->updated_indexes = true;
2520 }
2521 }
2522 }
2523
2524 if ( ! $indexes_found ) {
2525 ?>
2526 <script type='text/javascript'>
2527 add_index(true);
2528 </script>
2529 <?php
2530 }
2531 } else {
2532 // Display one empty row.
2533 ?>
2534 <script type='text/javascript'>
2535 add_row('<?php echo esc_attr( $this->design_mode ); ?>', true);
2536 add_index(true);
2537 disable_index();
2538 disable_create_buttons();
2539 </script>
2540 <?php
2541 }
2542
2543 ?>
2544 <script type='text/javascript'>
2545 <?php if ( ! $this->wpda_table_design ) { ?>
2546 jQuery('#button_show_create_table').prop("readonly", true).prop("disabled", true).addClass("disabled");
2547 <?php } ?>
2548 <?php
2549 if ( ! $this->wpda_table_design || ! $this->table_altered ) {
2550 if ( ! $this->updated_indexes ) {
2551 ?>
2552 jQuery("#button_show_alter_table").prop("readonly", true).prop("disabled", true).addClass("disabled");
2553 jQuery("#button_alter_table").prop("readonly", true).prop("disabled", true).addClass("disabled");
2554 <?php
2555 }
2556 }
2557 ?>
2558 <?php if ( ! $this->updated_indexes ) { ?>
2559 jQuery('#wpda_create_index').prop("readonly", true).prop("disabled", true).addClass("disabled");
2560 <?php } ?>
2561 <?php if ( ! $this->real_indexes ) { ?>
2562 jQuery('#wpda_drop_index').prop("readonly", true).prop("disabled", true).addClass("disabled");
2563 <?php } ?>
2564 </script>
2565 <?php
2566
2567 if ( 'view' === $this->action ) {
2568 ?>
2569 <script type='text/javascript'>
2570 disable_page();
2571 </script>
2572 <?php
2573 }
2574
2575 if ( $this->is_wp_table ) {
2576 // WP table names are not allowed: disable create table button.
2577 ?>
2578 <script type='text/javascript'>
2579 disable_page();
2580 </script>
2581 <?php
2582 }
2583
2584 // Save all table names in array table_name check.
2585 ?>
2586 <script type='text/javascript'>
2587 var wpda_db_table_name = [];
2588 <?php
2589 $designer_table_list = WPDA_Design_Table_Model::get_designer_table_list();
2590 foreach ( $designer_table_list as $key => $value ) {
2591 echo 'wpda_db_table_name["' . esc_attr( $value['wpda_table_name'] ) . '"]=true;';
2592 }
2593 if ( ! $this->deleted_columns_and_indexes ) {
2594 echo "jQuery('#checkbox_show_deleted_label').addClass('label_disabled');";
2595 echo "jQuery('#checkbox_show_deleted').attr('disabled', true);";
2596 }
2597 ?>
2598 </script>
2599 <?php
2600 }
2601
2602 /**
2603 * Drop all indexes from database
2604 *
2605 * @since 2.0.14
2606 */
2607 protected function drop_indexes() {
2608 foreach ( $this->real_indexes as $real_index ) {
2609 $this->drop_index( $real_index['index_name'] );
2610 }
2611 }
2612
2613 /**
2614 * Drop a specific index from database
2615 *
2616 * @param string $index_name Name of index to be dropped
2617 *
2618 * @since 2.0.14
2619 */
2620 protected function drop_index( $index_name ) {
2621 $wpdadb = WPDADB::get_db_connection( $this->wpda_schema_name );
2622 if ( null === $wpdadb ) {
2623 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->wpda_schema_name ) ) );
2624 }
2625
2626 $suppress = $wpdadb->suppress_errors( true );
2627
2628 // Index is deleted from table design: drop index
2629 $drop_index_statement = 'DROP INDEX `' . str_replace( '`', '', $index_name ) . "` ON `{$this->wpda_table_name}`";
2630 if ( $wpdadb->query( $drop_index_statement ) ) {
2631 $msg = new WPDA_Message_Box(
2632 array(
2633 'message_text' => sprintf( __( 'Index `%s` dropped', 'wp-data-access' ), esc_attr( $index_name) ),
2634 )
2635 );
2636 $msg->box();
2637 } else {
2638 $msg = new WPDA_Message_Box(
2639 array(
2640 'message_text' => __( 'DROP INDEX failed', 'wp-data-access' ),
2641 'message_type' => 'error',
2642 'message_is_dismissible' => false,
2643 )
2644 );
2645 $msg->box();
2646 $this->create_index_failed[] = $drop_index_statement;
2647 }
2648 $wpdadb->suppress_errors( $suppress );
2649 }
2650
2651 /**
2652 * Create indexes from design
2653 *
2654 * @since 2.0.14
2655 */
2656 protected function create_index() {
2657 $wpdadb = WPDADB::get_db_connection( $this->wpda_schema_name );
2658 if ( null === $wpdadb ) {
2659 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->wpda_schema_name ) ) );
2660 }
2661
2662 $suppress = $wpdadb->suppress_errors( true );
2663
2664 if ( 'show_create_table_script' !== $this->action2_posted ) {
2665 $this->drop_indexes();
2666 }
2667
2668 // Recreate indexes.
2669 foreach ( $this->wpda_table_design->indexes as $index ) {
2670 if ( '' === $index->index_name || '' === $index->column_names ) {
2671 continue;
2672 }
2673
2674 $unique = '';
2675 if ( 'Yes' === $index->unique ) {
2676 $unique = 'UNIQUE';
2677 } elseif ( 'FULLTEXT' === $index->unique ) {
2678 if ( 'on' === $this->fulltext_support ) {
2679 $unique = 'FULLTEXT';
2680 } else {
2681 $unique = '';
2682 }
2683 }
2684 $column_names_array = explode( ',', ( string ) $index->column_names );//phpcs:ignore - 8.1 proof
2685 $column_names = '`' . implode( '`,`', $column_names_array ) . '`';
2686 $create_index_statement =
2687 "CREATE $unique INDEX `" . str_replace( '`', '', $index->index_name ) . "` ON `{$this->wpda_table_name}` ($column_names)";
2688 $this->create_index_statement .= $create_index_statement . ';' . self::NEW_LINE;
2689
2690 if ( 'show_create_table_script' === $this->action2_posted ) {
2691 continue;
2692 }
2693
2694 if ( $wpdadb->query( $create_index_statement ) ) {
2695 $msg = new WPDA_Message_Box(
2696 array(
2697 'message_text' => sprintf( __( 'Index `%s` created', 'wp-data-access' ), $index->index_name ),
2698 )
2699 );
2700 $msg->box();
2701 } else {
2702 $msg = new WPDA_Message_Box(
2703 array(
2704 'message_text' => __( 'CREATE INDEX failed', 'wp-data-access' ),
2705 'message_type' => 'error',
2706 'message_is_dismissible' => false,
2707 )
2708 );
2709 $msg->box();
2710 $this->create_index_failed[] = $create_index_statement;
2711 }
2712 }
2713
2714 $wpdadb->suppress_errors( $suppress );
2715 }
2716 }
2717
2718 }
2719