'; /** * Page name (wpda_designer) * * @var string|null */ protected $page = null; /** * Action argument * * @var string|null */ protected $action = null; /** * Saved value of action2 argument used for later equations * * @var string|null */ protected $action2 = null; /** * Action2 argument * * @var string|null */ protected $action2_posted = null; /** * Object of type WPDA_Design_Table_Model used for data manipulation * * @var object|null */ protected $model = null; /** * Table name * * @var string|null */ protected $wpda_table_name = null; /** * Schema name * * @var string|null */ protected $wpda_schema_name = null; /** * Table design (taken from WPDA_Design_Table_Model) * * @var array|null */ protected $wpda_table_design = null; /** * Indicates whether the table was found in the database * * @var boolean|null */ protected $table_exists = null; /** * Indicates whether the structure of the database table equals the table design * * @var boolean|null */ protected $table_altered = false; /** * Indicates whether the table is a WordPress table * * @var boolean|null */ protected $is_wp_table = false; /** * Create table statement for the designed table at startup. Updates in the user interface are not immediately * reflected. User needs to reload/save the page. * * @var string */ protected $create_table_statement = ''; /** * Alter table statement for the designed table at startup. Updates in the user interface are not immediately * reflected. User needs to reload/save the page. * * @var array */ protected $alter_table_statement = array(); /** * Create index statement(s) for the designed index(es) at startup. Updates in the user interface are not * immediately reflected. User needs to reload/save the page. * * @var string */ protected $create_index_statement = ''; /** * Indicates where a create table statement succeeded * * @var boolean|null */ protected $create_table_succeeded = null; /** * Indicates where a alter table statement succeeded * * @var boolean|null */ protected $alter_table_succeeded = null; /** * Indicates where a create index statement failed * * @var boolean|null */ protected $create_index_failed = null; /** * Named array holding table columns * * @see WPDA_List_Columns_Cache::get_list_columns() * * @var array|null */ protected $table_columns = null; /** * Allowed values are: Basic or Advanced. Can be supplied as an argument. Taken from WPDA class f no argument * is provided. * * @see WPDA::OPTION_BE_DESIGN_MODE * * @var string|null */ protected $design_mode = null; /** * Last error from wpdb * * @var string|null */ protected $wpdb_error = null; /** * Indicates whether columns or indexes were deleted in the actual design. If true checkbox "Show deleted * columns and indexes" will be accessible. * * @var bool */ protected $deleted_columns_and_indexes = false; /** * Indicates whether indexes were updated in the actual design. * * @var bool */ protected $updated_indexes = false; /** * Holds the structure of the real physical database table * * @var array|null */ protected $real_table = null; /** * Holds the structure of the real physical database indexes * * @var array|null */ protected $real_indexes = null; /** * Indicates whether the design has indexes. * * @var bool */ protected $indexes_found = false; /** * Argument which can be used to jump back to another page than the default table list for table designs. * * @var string */ protected $caller = ''; /** * Holds all available databases * * @var array */ protected $database = array(); protected $databases; protected $fulltext_support = false; /** * WPDA_Design_Table_Form constructor. * * @since 1.1.0 */ public function __construct() { if ( isset( $_REQUEST['page'] ) ) { // phpcs:ignore $this->page = sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ); // phpcs:ignore } else { wp_die( esc_attr__( 'ERROR: Wrong arguments [page not found]', 'wp-data-access' ) ); } if ( isset( $_REQUEST['action'] ) ) { // phpcs:ignore $this->action = sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ); // phpcs:ignore } if ( isset( $_REQUEST['action2'] ) ) { // phpcs:ignore $this->action2 = sanitize_text_field( wp_unslash( $_REQUEST['action2'] ) ); // phpcs:ignore $this->action2_posted = $this->action2; } if ( isset( $_REQUEST['design_mode'] ) ) { // phpcs:ignore $this->design_mode = sanitize_text_field( wp_unslash( $_REQUEST['design_mode'] ) ); // phpcs:ignore } else { $this->design_mode = WPDA::get_option( WPDA::OPTION_BE_DESIGN_MODE ); // Default design mode. } if ( isset( $_REQUEST['caller'] ) ) { // phpcs:ignore $this->caller = sanitize_text_field( wp_unslash( $_REQUEST['caller'] ) ); // phpcs:ignore } $this->fulltext_support = get_option( 'wpda_fulltext_support' ); global $wpdb; if ( 'init' === $this->action2 ) { if ( isset( $_REQUEST['wpda_table_name'] ) && isset( $_REQUEST['wpda_schema_name'] ) ) { // phpcs:ignore // Check if table is already in repository. $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->prepare( 'select * from `%1s` where wpda_schema_name = %s and wpda_table_name = %s ', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders array( WPDA::remove_backticks( WPDA_Design_Table_Model::get_base_table_name() ), sanitize_text_field( wp_unslash( $_REQUEST['wpda_schema_name'] ) ), // phpcs:ignore sanitize_text_field( wp_unslash( $_REQUEST['wpda_table_name'] ) ), // phpcs:ignore ) ) ); if ( 1 === $wpdb->num_rows ) { // Table already in repository. $this->action2 = 'edit'; } else { // Table not in repository. $this->action2 = 'wpda_reverse_engineering'; } } else { wp_die( esc_attr__( 'ERROR: Wrong arguments [table not found]', 'wp-data-access' ) ); } } if ( 'wpda_reverse_engineering' === $this->action2 || 'wpda_reconcile' === $this->action2 ) { if ( isset( $_REQUEST['wpda_table_name_re'] ) && isset( $_REQUEST['wpda_schema_name_re'] ) ) { // phpcs:ignore $wpda_table_name_re = sanitize_text_field( wp_unslash( $_REQUEST['wpda_table_name_re'] ) ); // phpcs:ignore $wpda_schema_name_re = sanitize_text_field( wp_unslash( $_REQUEST['wpda_schema_name_re'] ) ); // phpcs:ignore if ( 'wpda_reconcile' === $this->action2 ) { // Before table can be reconciled old table structure must be deleted. $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->prepare( 'delete from `%1s` where wpda_table_name = %s and wpda_schema_name = %s ', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders array( WPDA::remove_backticks( WPDA_Design_Table_Model::get_base_table_name() ), $wpda_table_name_re, $wpda_schema_name_re, ) ) ); } // Start reverse engineering table. $wpda_reverse_engineering = new WPDA_Reverse_Engineering( $wpda_table_name_re, $wpda_schema_name_re ); $this->design_mode = isset( $_REQUEST['design_mode_re'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['design_mode_re'] ) ) : $this->design_mode; // phpcs:ignore $table_structure = $wpda_reverse_engineering->get_designer_format( $this->design_mode ); if ( count( $table_structure ) > 0 ) { // phpcs:ignore -- 8.1 proof if ( isset( $_REQUEST['wpda_table_name'] ) && '' !== trim( $_REQUEST['wpda_table_name'] ) ) { // phpcs:ignore $this->wpda_table_name = sanitize_text_field( wp_unslash( $_REQUEST['wpda_table_name'] ) ); // phpcs:ignore } else { $this->wpda_table_name = $wpda_table_name_re; } if ( isset( $_REQUEST['wpda_schema_name'] ) && '' !== trim( $_REQUEST['wpda_schema_name'] ) ) { // phpcs:ignore $this->wpda_schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpda_schema_name'] ) ); // phpcs:ignore } else { $this->wpda_schema_name = $wpda_schema_name_re; } $this->wpda_table_design = $table_structure; } else { wp_die( esc_attr__( 'ERROR: Reverse engineering table failed [invalid structure]', 'wp-data-access' ) ); } if ( ! WPDA_Design_Table_Model::insert_reverse_engineered( $this->wpda_table_name, $this->wpda_schema_name, $this->wpda_table_design ) ) { wp_die( esc_attr__( 'ERROR: Reverse engineering table failed [insert failed]', 'wp-data-access' ) ); } else { // Convert named array to object (needed to display structure). $this->wpda_table_design = json_decode( json_encode( $table_structure ) ); } $this->action2 = 'edit'; } else { wp_die( esc_attr__( 'ERROR: Wrong arguments [table not found]', 'wp-data-access' ) ); } } elseif ( isset( $_REQUEST['wpda_table_name'] ) && isset( $_REQUEST['wpda_schema_name'] ) ) { // phpcs:ignore $this->wpda_table_name = sanitize_text_field( wp_unslash( $_REQUEST['wpda_table_name'] ) ); // phpcs:ignore $this->wpda_schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpda_schema_name'] ) ); // phpcs:ignore $this->model = new WPDA_Design_Table_Model(); if ( 'new' === $this->action2 ) { $insert_result = $this->model->insert(); if ( false === $insert_result || $insert_result < 1 ) { wp_die( esc_attr__( 'ERROR: Insert failed', 'wp-data-access' ) ); } $this->action2 = 'edit'; // Show saved records and allow editing. } elseif ( 'edit' === $this->action2 && 'init' !== $this->action2_posted ) { $result_update = $this->model->update(); if ( false === $result_update ) { $msg = new WPDA_Message_Box( array( 'message_text' => __( 'Update failed', 'wp-data-access' ), 'message_type' => 'error', 'message_is_dismissible' => false, ) ); $msg->box(); } if ( 0 === $result_update ) { $msg = new WPDA_Message_Box( array( 'message_text' => __( 'Nothing to save', 'wp-data-access' ), ) ); $msg->box(); } else { $msg = new WPDA_Message_Box( array( 'message_text' => __( 'Succesfully saved changes to database', 'wp-data-access' ), ) ); $msg->box(); } } $this->model->query(); $structure_messages = $this->model->validate(); foreach ( $structure_messages as $messages ) { if ( 'ERR' === $messages[0] ) { $msg = new WPDA_Message_Box( array( 'message_text' => $messages[1], 'message_type' => 'error', 'message_is_dismissible' => false, ) ); $msg->box(); } else { $msg = new WPDA_Message_Box( array( 'message_text' => $messages[1], ) ); $msg->box(); } } $this->wpda_table_design = $this->model->get_table_design(); $this->design_mode = $this->wpda_table_design->design_mode; $this->action2 = 'edit'; // Editing mode. } else { $this->action2 = 'new'; // Design new table from scratch. } // Remove backticks from schema and table name to prevent sql injection $this->wpda_schema_name = str_replace( '`', '', (string) $this->wpda_schema_name ); $this->wpda_table_name = str_replace( '`', '', (string) $this->wpda_table_name ); if ( null !== $this->wpda_table_name && null !== $this->wpda_schema_name ) { // Check if table name already exists in database. if ( $this->wpda_schema_name === $wpdb->dbname ) { $wp_tables = array_flip( $wpdb->tables( 'all', true ) ); if ( isset( $wp_tables[ $this->wpda_table_name ] ) ) { $this->is_wp_table = true; $this->table_exists = true; } else { $this->does_table_exist(); } } else { $this->does_table_exist(); } // Get design structure for real database table. $this->get_table_structure(); if ( 'create_table' === $this->action2_posted || 'show_create_table_script' === $this->action2_posted ) { // Perform create table (and indexes) script. $this->create_table(); $this->does_table_exist(); $this->get_table_structure(); } elseif ( 'alter_table' === $this->action2_posted ) { // Generate alter table script and perform script. $this->do_alter_table(); $this->get_table_structure(); } elseif ( 'show_alter_table_script' === $this->action2_posted ) { // Generate alter table script and show result in overlay. $this->alter_table(); } elseif ( 'create_table_index' === $this->action2_posted ) { // Perform create index(es) script. $this->create_index(); $this->get_table_structure(); } elseif ( 'drop_table' === $this->action2_posted ) { // Perform drop table script. $this->drop_table(); $this->does_table_exist(); } elseif ( 'drop_table_index' === $this->action2_posted ) { // Perform drop table script. $this->drop_indexes(); $this->get_table_structure(); } if ( $this->table_exists ) { // Get database table structure. $wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $this->wpda_schema_name, $this->wpda_table_name ); $table_columns = $wpda_list_columns->get_table_columns(); // Convert indexed array to named array to improve access. foreach ( $table_columns as $table_column ) { $this->table_columns[ $table_column['column_name'] ] = $table_column; } } } $this->databases = WPDA_Dictionary_Lists::get_db_schemas(); if ( ! isset( $_REQUEST['_wpnonce'] ) ) { wp_die( esc_attr__( 'Not authorized', 'wp-data-access' ) ); } else { // phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], "wpda-design-table-form-{$this->wpda_table_name}" )) { // direct form access if ( '' === $this->wpda_table_name && ! wp_verify_nonce( $_REQUEST['_wpnonce'], "wpda-design-table-form-" . WPDA_Design_Table_Model::get_base_table_name() ) ) { // insert new table if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], "wpda-alter-{$this->wpda_table_name}" ) ) { // access from alter table button $schema_name = isset( $_POST['wpda_schema_name'] ) ? $_POST['wpda_schema_name'] : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated $table_name = isset( $_POST['wpda_table_name'] ) ? $_POST['wpda_table_name'] : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated $dsg_tbl = 'wpda-query-' . WPDA_Design_Table_Model::get_base_table_name() . '-' . $schema_name . '-' . $table_name; if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], $dsg_tbl ) ) { // access from list table wp_die( esc_attr__( 'Not authorized', 'wp-data-access' ) ); } } } } // phpcs:enable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized } } public function prepare_form() {} /** * Get table and index structure from design * * @since 2.0.14 */ private function get_table_structure() { if ( $this->table_exists ) { $get_table_structure = new WPDA_Reverse_Engineering( $this->wpda_table_name, $this->wpda_schema_name ); $real_structure = $get_table_structure->get_designer_format( $this->design_mode ); $this->real_table = $real_structure['table']; $this->real_indexes = $real_structure['indexes']; } } /** * Check if table exists in our database * * @since 2.0.14 */ private function does_table_exist() { $wpda_dictionary_exists = new WPDA_Dictionary_Exist( $this->wpda_schema_name, $this->wpda_table_name ); $this->table_exists = $wpda_dictionary_exists->plain_table_exists(); if ( ! $this->table_exists ) { $this->real_table = null; $this->real_indexes = null; } } /** * Perform alter table * * Call $this->alter_table() to generate alter table script and process result taken * from $this->create_table_statement. * * @see WPDA_Design_Table_Form::alter_table() * @see WPDA_Design_Table_Form::create_table_statement * * @since 2.0.14 */ protected function do_alter_table() { $this->alter_table(); $wpdadb = WPDADB::get_db_connection( $this->wpda_schema_name ); if ( null === $wpdadb ) { /* translators: %s = remote database name */ wp_die( esc_attr( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), $this->wpda_schema_name ) ) ); } $suppress = $wpdadb->suppress_errors( true ); $create_table_statement = str_replace( self::NEW_LINE, "\n", $this->create_table_statement ); if ( '' !== $create_table_statement ) { // Process alter table script (store in $create_table_statement) $sql_end = strpos( $create_table_statement, ";\n" ); while ( false !== $sql_end ) { $sql = rtrim( substr( $create_table_statement, 0, $sql_end ) ); $create_table_statement = substr( $create_table_statement, strpos( $create_table_statement, $sql ) + strlen( $sql ) + 1 ); if ( ! $wpdadb->query( $sql ) ) { $this->wpdb_error = $wpdadb->last_error; $this->alter_table_succeeded = false; return; } $sql_end = strpos( $create_table_statement, ";\n" ); } } $wpdadb->suppress_errors( $suppress ); } /** * Generate alter table script * * Alter table script is written to $this->create_table_statement. * * @see WPDA_Design_Table_Form::create_table_statement * * @since 2.0.14 */ protected function alter_table() { $create_keys_design = array(); $create_keys_real = array(); // Find deleted and changed indexes foreach ( $this->real_indexes as $real_index ) { $drop_real_index = false; $design_index_found = false; foreach ( $this->wpda_table_design->indexes as $design_index ) { if ( $real_index['index_name'] === $design_index->index_name ) { $design_index_found = true; if ( $real_index['unique'] != $design_index->unique || $real_index['column_names'] != $design_index->column_names ) { $drop_real_index = true; break; } break; } } if ( $drop_real_index || ! $design_index_found ) { $this->create_table_statement .= 'DROP INDEX `' . str_replace( '`', '', $real_index['index_name'] ) . "` ON `{$this->wpda_table_name}`;" . self::NEW_LINE; } } if ( '' !== $this->create_table_statement ) { $this->create_table_statement .= self::NEW_LINE; } // Find new and changed columns foreach ( $this->wpda_table_design->table as $design_column ) { $design_column_found = false; foreach ( $this->real_table as $real_column ) { if ( $real_column->column_name === $design_column->column_name ) { if ( $real_column != $design_column ) { // Modify column $this->alter_table_column( $design_column, 'MODIFY' ); } $design_column_found = true; break; } } if ( ! $design_column_found ) { // Add new column $this->alter_table_column( $design_column, 'ADD' ); } if ( 'Yes' === $design_column->key ) { $create_keys_design[] = $design_column->column_name; } } // Find deleted columns foreach ( $this->real_table as $real_column ) { $real_column_found = false; foreach ( $this->wpda_table_design->table as $design_column ) { if ( $real_column->column_name === $design_column->column_name ) { $real_column_found = true; break; } } if ( ! $real_column_found ) { // Drop column // phpcs:ignore -- 8.1 proof array_push( $this->alter_table_statement, 'DROP COLUMN `' . str_replace( '`', '', $real_column->column_name ) . '`,' . self::NEW_LINE ); } if ( 'Yes' === $real_column->key ) { $create_keys_real[] = $real_column->column_name; } } if ( 0 < count( $this->alter_table_statement ) ) { // phpcs:ignore -- 8.1 proof $this->create_table_statement .= "ALTER TABLE `{$this->wpda_table_name}` "; foreach ( $this->alter_table_statement as $sql ) { $this->create_table_statement .= $sql; } $this->create_table_statement = substr( $this->create_table_statement, 0, strrpos( $this->create_table_statement, ',' ) ) . ';' . self::NEW_LINE . self::NEW_LINE; $array_difference_1 = array_diff( $create_keys_design, $create_keys_real ); // phpcs:ignore -- 8.1 proof $array_difference_2 = array_diff( $create_keys_real, $create_keys_design ); // phpcs:ignore -- 8.1 proof if ( 0 !== count( $array_difference_1 ) || 0 !== count( $array_difference_2 ) ) { // phpcs:ignore -- 8.1 proof if ( 0 < count( $create_keys_real ) ) { // phpcs:ignore -- 8.1 proof $this->create_table_statement = "ALTER TABLE `{$this->wpda_table_name}` DROP PRIMARY KEY;" . self::NEW_LINE . self::NEW_LINE . $this->create_table_statement; } if ( 0 < count( $create_keys_design ) ) { // phpcs:ignore -- 8.1 proof $alter_table_statement = "ALTER TABLE `{$this->wpda_table_name}` ADD PRIMARY KEY "; foreach ( $create_keys_design as $key ) { $alter_table_statement .= $key === reset( $create_keys_design ) ? '(' : ','; // phpcs:ignore -- 8.1 proof $alter_table_statement .= '`' . str_replace( '`', '', $key ) . '`'; } $alter_table_statement .= ');' . self::NEW_LINE . self::NEW_LINE; $this->create_table_statement .= $alter_table_statement; } } } // Add new and changed indexes foreach ( $this->wpda_table_design->indexes as $design_index ) { $real_index_found = false; $create_new_index = false; foreach ( $this->real_indexes as $real_index ) { if ( $real_index['index_name'] === $design_index->index_name ) { $real_index_found = true; if ( $real_index['unique'] != $design_index->unique || $real_index['column_names'] != $design_index->column_names ) { $create_new_index = true; break; } break; } } if ( ! $real_index_found || $create_new_index ) { $unique = ''; if ( 'Yes' === $design_index->unique ) { $unique = 'UNIQUE'; } elseif ( 'FULLTEXT' === $design_index->unique ) { if ( 'on' === $this->fulltext_support ) { $unique = 'FULLTEXT'; } else { $unique = ''; } } $column_names_array = explode( ',', ( string ) $design_index->column_names ); // phpcs:ignore -- 8.1 proof $column_names = '`' . implode( '`,`', $column_names_array ) . '`'; $this->create_table_statement .= "CREATE $unique INDEX `" . str_replace( '`', '', $design_index->index_name ) . "` ON `{$this->wpda_table_name}` ($column_names);" . self::NEW_LINE; } } } /** * Alter column format * * @param object $design_column Column definition * @param string $keyword ADD or MODIFY * * @since 2.0.14 */ private function alter_table_column( $design_column, $keyword ) { $alter_table_statement = "$keyword COLUMN `" . str_replace( '`', '', $design_column->column_name ) . '` '; $alter_table_statement .= $design_column->data_type; if ( '' !== $design_column->max_length ) { $alter_table_statement .= "($design_column->max_length)"; } if ( 'enum' === $design_column->data_type || 'set' === $design_column->data_type ) { $alter_table_statement .= '(' . $design_column->list . ')'; } $alter_table_statement .= ' '; $alter_table_statement .= 'Yes' === $design_column->mandatory ? 'NOT NULL' : 'NULL'; if ( '' !== $design_column->default ) { $alter_table_statement .= " DEFAULT {$design_column->default}"; } if ( '' !== $design_column->extra ) { $alter_table_statement .= ' '; $alter_table_statement .= $design_column->extra; } $alter_table_statement .= ',' . self::NEW_LINE; array_push( $this->alter_table_statement, $alter_table_statement ); // phpcs:ignore -- 8.1 proof } /** * Drop database table * * Does not drop WordPress tables. * * @since 2.0.14 */ protected function drop_table() { if ( $this->is_wp_table ) { // phpcs:disable WordPress.WP.I18n.MissingTranslatorsComment $msg = new WPDA_Message_Box( array( /* translators: %s = table name */ 'message_text' => sprintf( __( 'Cannot drop WordPress table `%s`', 'wp-data-access' ), $this->wpda_table_name ), 'message_type' => 'error', 'message_is_dismissible' => false, ) ); // phpcs:enable WordPress.WP.I18n.MissingTranslatorsComment $msg->box(); return; } if ( $this->table_exists ) { $wpdadb = WPDADB::get_db_connection( $this->wpda_schema_name ); if ( null === $wpdadb ) { /* translators: %s = remote database name */ wp_die( esc_attr( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), $this->wpda_schema_name ) ) ); } $suppress = $wpdadb->suppress_errors( true ); $drop_table_statement = "DROP TABLE `{$this->wpda_table_name}`"; if ( $wpdadb->query( $drop_table_statement ) ) { // phpcs:disable WordPress.WP.I18n.MissingTranslatorsComment $msg = new WPDA_Message_Box( array( /* translators: %s = table name */ 'message_text' => sprintf( __( 'Table `%s` dropped', 'wp-data-access' ), $this->wpda_table_name ), ) ); // phpcs:enable WordPress.WP.I18n.MissingTranslatorsComment $msg->box(); } else { $msg = new WPDA_Message_Box( array( 'message_text' => __( 'DROP TABLE failed', 'wp-data-access' ), 'message_type' => 'error', 'message_is_dismissible' => false, ) ); $msg->box(); $this->create_table_statement = $drop_table_statement; } $wpdadb->suppress_errors( $suppress ); } } /** * Perform create table statement * * @since 1.1.0 */ protected function create_table() { $is_valid = true; $this->create_table_statement = "CREATE TABLE `{$this->wpda_table_name}`" . self::NEW_LINE; $create_keys = array(); foreach ( $this->wpda_table_design->table as $row ) { $this->create_table_statement .= $row === reset( $this->wpda_table_design->table ) ? '(' : ','; // phpcs:ignore -- 8.1 proof $this->create_table_statement .= '`' . str_replace( '`', '', $row->column_name ) . '`'; $this->create_table_statement .= ' '; $this->create_table_statement .= $row->data_type; if ( '' !== $row->max_length ) { $this->create_table_statement .= "($row->max_length)"; } else { if ( 'varchar' === $row->data_type || 'char' === $row->data_type || 'varbinary' === $row->data_type || 'binary' === $row->data_type ) { $is_valid = false; $msg = new WPDA_Message_Box( array( 'message_text' => "Column {$row->column_name} of {$row->data_type} must have a max length", 'message_type' => 'error', 'message_is_dismissible' => false, ) ); $msg->box(); } } if ( '' !== $row->type_attribute ) { $this->create_table_statement .= " {$row->type_attribute} "; } if ( 'enum' === $row->data_type || 'set' === $row->data_type ) { $this->create_table_statement .= '(' . $row->list . ')'; } $this->create_table_statement .= ' '; $this->create_table_statement .= 'Yes' === $row->mandatory ? 'NOT NULL' : 'NULL'; if ( '' !== $row->default ) { $this->create_table_statement .= " DEFAULT {$row->default}"; } if ( '' !== $row->extra ) { $this->create_table_statement .= ' '; $this->create_table_statement .= $row->extra; } if ( 'Yes' === $row->key ) { $create_keys[] = $row->column_name; } $this->create_table_statement .= self::NEW_LINE; } if ( 0 < count( $create_keys ) ) { // phpcs:ignore -- 8.1 proof $this->create_table_statement .= ',PRIMARY KEY '; foreach ( $create_keys as $key ) { $this->create_table_statement .= $key === reset( $create_keys ) ? '(' : ','; // phpcs:ignore -- 8.1 proof $this->create_table_statement .= '`' . str_replace( '`', '', $key ) . '`'; } $this->create_table_statement .= ')'; $this->create_table_statement .= self::NEW_LINE; } $this->create_table_statement .= ')'; if ( isset( $this->wpda_table_design->engine ) && '' !== $this->wpda_table_design->engine ) { $this->create_table_statement .= ' ENGINE ' . $this->wpda_table_design->engine; } if ( isset( $this->wpda_table_design->collation ) && '' !== $this->wpda_table_design->collation ) { $collation = explode( '_', $this->wpda_table_design->collation ); // phpcs:ignore -- 8.1 proof $this->create_table_statement .= ' DEFAULT CHARACTER SET ' . $collation[0] . ' COLLATE=' . $this->wpda_table_design->collation; } $this->create_table_statement .= ';' . self::NEW_LINE . self::NEW_LINE; if ( ! $is_valid ) { return; } if ( 'show_create_table_script' === $this->action2_posted ) { // Just show CREATE TABLE script! // SQL script is available in $this->create_table_statement and can be shown on the page. $this->create_index(); } else { // Create table and indexes. $wpdadb = WPDADB::get_db_connection( $this->wpda_schema_name ); if ( null === $wpdadb ) { /* translators: %s = remote database name */ wp_die( esc_attr( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), $this->wpda_schema_name ) ) ); } $suppress = $wpdadb->suppress_errors( true ); $this->create_table_succeeded = $wpdadb->query( str_replace( self::NEW_LINE, '', $this->create_table_statement ) ); if ( $this->create_table_succeeded ) { $msg = new WPDA_Message_Box( array( 'message_text' => __( 'Table created', 'wp-data-access' ), ) ); $msg->box(); } else { $msg = new WPDA_Message_Box( array( 'message_text' => __( 'CREATE TABLE failed', 'wp-data-access' ), 'message_type' => 'error', 'message_is_dismissible' => false, ) ); $msg->box(); $this->wpdb_error = $wpdadb->last_error; } $wpdadb->suppress_errors( $suppress ); } } /** * Show Data Designer form * * @since 1.1.0 */ public function show() { ?>

Data Designer

create_nonce(); ?>
create_nonce(); ?>
create_nonce(); ?>
create_nonce(); ?>
create_nonce(); ?>
create_table_statement . $this->create_index_statement; // phpcs:ignore WordPress.Security.EscapeOutput ?>
create_table_statement ) . str_replace( self::NEW_LINE, "\n", $this->create_index_statement ); // phpcs:ignore WordPress.Security.EscapeOutput ?>">
wpda_table_design ) { // Allow loading table from database into designer (reverse engineering). $table_list = WPDA_Dictionary_Lists::get_tables( false ); ?> table_exists ) { // Add reconcile form. ?>
create_nonce(); ?>
> What is the difference between a table design and a database table?
create_nonce(); ?>
create_nonce(); ?>
wpda_schema_name && '' !== $this->wpda_table_name && null !== $this->wpda_table_design ) { $table_structure = json_decode( json_encode( $this->wpda_table_design ), true ); if ( isset( $table_structure['table'] ) ) { $column_names = array_column( (array) $table_structure['table'], 'column_name' ); // phpcs:ignore -- 8.1 proof } else { $column_names = array(); } // Validate schema, table and column names $warning = WPDA::validate_names( $this->wpda_schema_name, $this->wpda_table_name, $column_names ); if ( '' !== $warning ) { echo $warning; // phpcs:ignore WordPress.Security.EscapeOutput } } ?> design_mode ) { ?>
table_exists ) { if ( $this->is_wp_table ) { ?> wpda_table_design ) { ?>
'; ?>

design_mode ) { ?>
design_mode ) { ?> table_exists || 'new' === strtolower( $this->action2 ) ) { echo ' readonly disabled'; } ?> > table_exists ) { echo ' readonly disabled'; } ?> >
create_nonce(); ?>
action2 ) { ?> create_nonce(); ?>
create_nonce(); ?>

create_nonce(); ?>
create_table_statement && false === $this->create_table_succeeded ) { ?>

create_table_statement; // phpcs:ignore WordPress.Security.EscapeOutput ?>
wpdb_error ); ?>
create_index_failed && 0 < count( $this->create_index_failed ) ) { // phpcs:ignore -- 8.1 proof ?>

create_index_failed as $index_failed ) { echo "$index_failed
"; // phpcs:ignore WordPress.Security.EscapeOutput } ?>
create_table_statement && false === $this->alter_table_succeeded ) { ?>

create_table_statement; // phpcs:ignore WordPress.Security.EscapeOutput ?>
wpdb_error ); ?>
wpda_table_design ) { // Display table design. foreach ( $this->wpda_table_design->table as $design_column ) { if ( ! $this->table_exists ) { // New table cannot be compared with real table. $column_changed = ''; } else { // Check for table structure changes. if ( isset( $this->table_columns[ $design_column->column_name ] ) ) { // Check column arguments. $column_changed = ''; foreach ( $this->real_table as $real_column ) { if ( $real_column->column_name === $design_column->column_name ) { if ( $real_column != $design_column ) { if ( strtolower( $real_column->extra ) === 'auto_increment' && strtolower( $design_column->extra ) === 'auto_increment' ) { $tmp_real_column = clone $real_column; $tmp_design_column = clone $design_column; unset( $tmp_real_column->extra ); unset( $tmp_design_column->extra ); if ( $tmp_real_column != $tmp_design_column ) { $column_changed = 'u'; $this->table_altered = true; } } else { $column_changed = 'u'; $this->table_altered = true; } } } } } else { // New column. $column_changed = 'i'; $this->table_altered = true; } } ?> table_exists ) { // Check for deleted columns. foreach ( $this->table_columns as $table_column ) { $column_found = false; foreach ( $this->wpda_table_design->table as $design_column ) { if ( $design_column->column_name === $table_column['column_name'] ) { $column_found = true; break; } } if ( ! $column_found ) { break; } } if ( ! $column_found ) { // Add deleted column(s) to form and mark as readonly. foreach ( $this->table_columns as $table_column ) { $column_found = false; foreach ( $this->wpda_table_design->table as $design_column ) { if ( $design_column->column_name === $table_column['column_name'] ) { $column_found = true; break; } } if ( ! $column_found ) { foreach ( $this->real_table as $real_column ) { if ( $real_column->column_name === $table_column['column_name'] ) { ?> table_altered = true; $this->deleted_columns_and_indexes = true; } } } } } } // Display indexes. $indexes_found = false; foreach ( $this->wpda_table_design->indexes as $design_index ) { $index_changed = ''; if ( $this->table_exists ) { $index_found = false; // Check if index was changed or new. foreach ( $this->real_indexes as $real_index ) { if ( $design_index->index_name === $real_index['index_name'] ) { $index_found = true; if ( $real_index['unique'] != $design_index->unique || $real_index['column_names'] != $design_index->column_names ) { $index_changed = 'u'; $this->updated_indexes = true; } break; } } if ( ! $index_found ) { $index_changed = 'i'; $this->updated_indexes = true; } } ?> table_exists ) { foreach ( $this->real_indexes as $real_index ) { $real_indexes_found = false; foreach ( $this->wpda_table_design->indexes as $design_index ) { if ( $real_index['index_name'] === $design_index->index_name ) { $real_indexes_found = true; break; } } if ( ! $real_indexes_found ) { // Index was dropped. ?> deleted_columns_and_indexes = true; $this->updated_indexes = true; } } } if ( ! $indexes_found ) { ?> action ) { ?> is_wp_table ) { // WP table names are not allowed: disable create table button. ?> wpda_table_name ) { return wp_nonce_field( "wpda-design-table-form-" . WPDA_Design_Table_Model::get_base_table_name() ); } return wp_nonce_field( "wpda-design-table-form-{$this->wpda_table_name}" ); } /** * Drop all indexes from database * * @since 2.0.14 */ protected function drop_indexes() { foreach ( $this->real_indexes as $real_index ) { $this->drop_index( $real_index['index_name'] ); } } /** * Drop a specific index from database * * @param string $index_name Name of index to be dropped * * @since 2.0.14 */ protected function drop_index( $index_name ) { $wpdadb = WPDADB::get_db_connection( $this->wpda_schema_name ); if ( null === $wpdadb ) { /* translators: %s = remote database name */ wp_die( esc_attr( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), $this->wpda_schema_name ) ) ); } $suppress = $wpdadb->suppress_errors( true ); // Index is deleted from table design: drop index $drop_index_statement = 'DROP INDEX `' . str_replace( '`', '', $index_name ) . "` ON `{$this->wpda_table_name}`"; if ( $wpdadb->query( $drop_index_statement ) ) { // phpcs:disable WordPress.WP.I18n.MissingTranslatorsComment $msg = new WPDA_Message_Box( array( /* translators: %s = index name */ 'message_text' => sprintf( __( 'Index `%s` dropped', 'wp-data-access' ), esc_attr( $index_name) ), ) ); // phpcs:enable WordPress.WP.I18n.MissingTranslatorsComment $msg->box(); } else { $msg = new WPDA_Message_Box( array( 'message_text' => __( 'DROP INDEX failed', 'wp-data-access' ), 'message_type' => 'error', 'message_is_dismissible' => false, ) ); $msg->box(); $this->create_index_failed[] = $drop_index_statement; } $wpdadb->suppress_errors( $suppress ); } /** * Create indexes from design * * @since 2.0.14 */ protected function create_index() { $wpdadb = WPDADB::get_db_connection( $this->wpda_schema_name ); if ( null === $wpdadb ) { /* translators: %s = remote database name */ wp_die( esc_attr( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), $this->wpda_schema_name ) ) ); } $suppress = $wpdadb->suppress_errors( true ); if ( 'show_create_table_script' !== $this->action2_posted ) { $this->drop_indexes(); } // Recreate indexes. foreach ( $this->wpda_table_design->indexes as $index ) { if ( '' === $index->index_name || '' === $index->column_names ) { continue; } $unique = ''; if ( 'Yes' === $index->unique ) { $unique = 'UNIQUE'; } elseif ( 'FULLTEXT' === $index->unique ) { if ( 'on' === $this->fulltext_support ) { $unique = 'FULLTEXT'; } else { $unique = ''; } } $column_names_array = explode( ',', ( string ) $index->column_names ); // phpcs:ignore -- 8.1 proof $column_names = '`' . implode( '`,`', $column_names_array ) . '`'; $create_index_statement = "CREATE $unique INDEX `" . str_replace( '`', '', $index->index_name ) . "` ON `{$this->wpda_table_name}` ($column_names)"; $this->create_index_statement .= $create_index_statement . ';' . self::NEW_LINE; if ( 'show_create_table_script' === $this->action2_posted ) { continue; } if ( $wpdadb->query( $create_index_statement ) ) { // phpcs:disable WordPress.WP.I18n.MissingTranslatorsComment $msg = new WPDA_Message_Box( array( /* translators: %s = index name */ 'message_text' => sprintf( __( 'Index `%s` created', 'wp-data-access' ), $index->index_name ), ) ); // phpcs:enable WordPress.WP.I18n.MissingTranslatorsComment $msg->box(); } else { $msg = new WPDA_Message_Box( array( 'message_text' => __( 'CREATE INDEX failed', 'wp-data-access' ), 'message_type' => 'error', 'message_is_dismissible' => false, ) ); $msg->box(); $this->create_index_failed[] = $create_index_statement; } } $wpdadb->suppress_errors( $suppress ); } } }