<?php /** * Suppress "error - 0 - No summary was found for this file" on phpdoc generation * * @package WPDataAccess\Data_Dictionary */ namespace WPDataAccess\Data_Dictionary { use WPDataAccess\Connection\WPDADB; use WPDataAccess\Plugin_Table_Models\WPDA_Table_Settings_Model; use WPDataAccess\WPDA; /** * Class WPDA_List_Columns * * @author Peter Schulz * @since 1.0.0 */ class WPDA_List_Columns { /** * Database connection * * @var null */ protected $wpdadb = null; /** * Database schema name * * @var string */ protected $schema_name; /** * Database table name * * @var string */ protected $table_name; /** * Columns of $this->table_name * * @var array */ protected $table_columns = array(); /** * Columns of $this->searchable_table_columns * * @var array */ protected $searchable_table_columns = array(); /** * Column data type sorted on column name * * @var array */ protected $table_column_data_type = array(); /** * Column type sorted on column name * * @var array */ protected $table_column_type = array(); /** * Primary key columns of $this->table_name * * @var array */ protected $table_primary_key = array(); /** * Primary key columns of $this->table_name (named) * * @var array */ protected $table_primary_key_check = array(); /** * Auto increment column name of $this->table_name or false * * @var bool|string */ protected $auto_increment_column_name = false; /** * Column headers for $this->table_name * * @var array */ protected $table_column_headers = array(); /** * Table settings as define in Data Explorer * * @var null||Object */ protected $table_settings = null; /** * WPDA_List_Columns constructor * * @param string $schema_name Database schema name. * @param string $table_name Database table name. * * @since 1.0.0 */ public function __construct( $schema_name, $table_name ) { // Set schema and table name. if ( '' === $schema_name ) { global $wpdb; $this->schema_name = $wpdb->dbname; } else { $this->schema_name = $schema_name; } $this->wpdadb = WPDADB::get_db_connection( $this->schema_name ); if ( null === $this->wpdadb ) { if ( is_admin() ) { wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name) ) ); } else { die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) ); } } if ( '' !== $table_name ) { $this->table_name = $table_name; // Get table settings $table_settings_db = WPDA_Table_Settings_Model::query( $this->table_name, $this->schema_name ); if ( isset( $table_settings_db[0]['wpda_table_settings'] ) ) { $this->table_settings = json_decode( $table_settings_db[0]['wpda_table_settings'] ); } // Get dictionary info $this->set_table_columns(); $this->set_table_primary_key(); $this->set_table_column_headers(); } } /** * Get column label for list table * * Returns the label of a column according to a pre defined format. Call must contain column name. * Column must be in $this->table_name. * * @param string $column_name Column name as defined in the data dictionary. * * @return string Label for $column_name. * @since 1.0.0 */ public function get_column_label( $column_name ) { if ( isset( $this->table_settings->list_labels->$column_name ) ) { return $this->table_settings->list_labels->$column_name; } else { return $this->get_default_column_label( $column_name ); } } public function get_table_header_labels() { if ( isset( $this->table_settings->list_labels ) ) { return $this->table_settings->list_labels; } else { if ( isset( $this->table_column_headers ) ) { return $this->table_column_headers; } else { return null; } } } /** * Return column data type * * @param $column_name Database column name * * @return string|null * @since 2.7.2 */ public function get_column_data_type( $column_name ) { return is_string( $column_name ) && isset( $this->table_column_data_type[ $column_name ] ) ? $this->table_column_data_type[ $column_name ] : null; } /** * Return column type * * @param $column_name Database column name * * @return string|null * @since 2.7.2 */ public function get_column_type( $column_name ) { return isset( $this->table_column_type[ (string) $column_name ] ) ? $this->table_column_type[ (string) $column_name ] : null; } /** * Get default column label * * Returns the default label of a column according to a pre defined format. Call must contain column name. * Column must be in $this->table_name. * * @param string $column_name Column name as defined in the data dictionary. * * @return string Default label for $column_name. * @since 1.0.0 */ public function get_default_column_label( $column_name ) { return ucwords( str_replace( '_', ' ', $column_name ) ); } /** * Check if column is part of primary key * * @param string $column_name Column name as defined in the data dictionary. * * @return bool TRUE = column is part of primary key, FALSE = column is not part of primary key. * @since 1.0.0 */ public function is_primary_key_column( $column_name ) { return ( isset( $this->table_primary_key_check[ $column_name ] ) ); } /** * Get columns * * @return array Column of $this->table_name. * @since 1.0.0 */ public function get_table_columns() { return $this->table_columns; } /** * Get searchable columns * * @return array Column of $this->table_name. * @since 1.0.0 */ public function get_searchable_table_columns() { return $this->searchable_table_columns; } /** * Set table columns * * Column info is taken from the MySQL data dictionary. For each column in $this->table_name the following * column info is stored: * + Column name * + Data type (MySQL data type) * + Extra (needed to find auto increment columns) * + Column type (needed for columns with data type enum: column type holds allowed values) * + Null values allowed? * * Since MariaDB 10.2.7 and higher handles default values different than other DBMSs we have to take care of * the quotes it places at the beginning and the end. This involves the implication that users cannot use * default values that start and end with a single quote. Which seems common sense for me. * * @since 1.0.0 */ protected function set_table_columns() { $query = $this->wpdadb->prepare( ' SELECT column_name AS column_name, data_type AS data_type, extra AS extra, column_type AS column_type, is_nullable AS is_nullable, IF(LEFT(column_default,1)=\'\'\'\' AND RIGHT(column_default,1)=\'\'\'\', SUBSTR(column_default,2,LENGTH(column_default)-2), column_default) AS column_default, character_maximum_length AS character_maximum_length, numeric_scale AS numeric_scale, numeric_precision AS numeric_precision FROM information_schema.columns WHERE table_schema = %s AND table_name = %s ORDER BY ordinal_position ', array( $this->wpdadb->dbname, $this->table_name, ) ); $this->table_columns = $this->wpdadb->get_results( $query, 'ARRAY_A' ); // phpcs:ignore Standard.Category.SniffName.ErrorCode $this->searchable_table_columns = $this->table_columns; // Contains all columns and is not modified foreach ( $this->table_columns as $column ) { if ( isset( $column['column_name'] ) && isset( $column['data_type'] ) ) { $this->table_column_data_type[ $column['column_name'] ] = $column['data_type']; } if ( isset( $column['column_name'] ) && isset( $column['column_type'] ) ) { $this->table_column_type[ $column['column_name'] ] = $column['column_type']; } } } /** * Get primary key columns * * @return array Primary key columns of $this->table_name. * @since 1.0.0 */ public function get_table_primary_key() { return $this->table_primary_key; } /** * Set primary key columns * * Primary key columns are taken from the MySQL data dictionary. * * Newer versions of MariaDB no longer seem to support JOIN USING. Rewritten to old school join. MySQL supports * both types of joins. * * @since 1.0.0 */ protected function set_table_primary_key() { $result = $this->get_table_unique_indexes(); if ( 0 < $this->wpdadb->num_rows ) { // Check if there is a primary key $has_primary_key = false; foreach ( $result as $row ) { if ( 'PRIMARY' === $row['Key_name'] ) { $this->table_primary_key[] = $row['Column_name']; $this->table_primary_key_check[ $row['Column_name'] ] = true; foreach ( $this->table_columns as $table_column ) { if ( $table_column['column_name'] === $row['Column_name'] && 'auto_increment' === $table_column['extra'] ) { // Save auto_increment column name. $this->auto_increment_column_name = $row['Column_name']; } } $has_primary_key = true; } } if ( ! $has_primary_key ) { // Use non unique index as an alternative $key_name = $result[0]['Key_name']; $this->table_primary_key[] = $result[0]['Column_name']; $this->table_primary_key_check[ $key_name ] = true; $i = 1; while ( $i < count( $result ) ) {//phpcs:ignore - 8.1 proof if ( $key_name === $result[ $i ]['Key_name'] ) { $this->table_primary_key[] = $result[ $i ]['Column_name']; $this->table_primary_key_check[ $result[ $i ]['Column_name'] ] = true; } $i ++; } } } } protected function get_table_unique_indexes() { $suppress = $this->wpdadb->suppress_errors( true ); $query = sprintf( 'SHOW INDEX FROM `%s`.`%s` WHERE non_unique = 0', $this->wpdadb->dbname, str_replace( '`', '', (string) $this->table_name ) ); $result = $this->wpdadb->get_results( $query, 'ARRAY_A' ); $this->wpdadb->suppress_errors( $suppress ); return $result; } public function get_table_alternative_keys() { $result = $this->get_table_unique_indexes(); $return = array(); if ( 0 < $this->wpdadb->num_rows ) { $index_name = ''; $index = array(); foreach ( $result as $row ) { if ( $index_name !== $row['Key_name'] ) { if ( '' !== $index_name ) { array_push( $return, $row['Column_name'] );//phpcs:ignore - 8.1 proof $index = array(); } $index_name = $row['Key_name']; } array_push( $index, $row['Column_name'] );//phpcs:ignore - 8.1 proof } array_push( $return, $index );//phpcs:ignore - 8.1 proof } return $return; } /** * Get column headers * * @return array * @since 1.0.0 */ public function get_table_column_headers() { return $this->table_column_headers; } /** * Set column headers (= column labels in data entry forms) * * For now column headers are defined equal to their names. If a column is part of the primary key, this is * reflected in the column header. * * @since 1.0.0 */ protected function set_table_column_headers() { if ( ! isset( $this->table_columns ) ) { wp_die( __( 'ERROR: Wrong arguments [no columns found]', 'wp-data-access' ) ); } $primary_nr = 0; $this->table_column_headers = array(); foreach ( $this->table_columns as $key => $value ) { if ( isset( $this->table_settings->form_labels ) ) { if ( isset( $this->table_settings->form_labels->{$value['column_name']} ) ) { $label = $this->table_settings->form_labels->{$value['column_name']}; } else { $label = $this->get_default_column_label( $value['column_name'] ); } } else { $label = $this->get_default_column_label( $value['column_name'] ); if ( $this->is_primary_key_column( $value['column_name'] ) ) { $key_text = __( 'key', 'wp-data-access' ); if ( count( $this->table_primary_key ) > 1 ) {//phpcs:ignore - 8.1 proof $label .= " ($key_text #" . ( ++ $primary_nr ) . ')'; } else { $label .= " ($key_text)"; } } } $this->table_column_headers[ $value['column_name'] ] = $label; } } /** * Get name of auto increment column * * @return bool|string Name of auto increment column or false if no auto increment column exists * @since 1.0.0 */ public function get_auto_increment_column_name() { return $this->auto_increment_column_name; } } }