Completed
Branch BUG-8957-add-countries (d46858)
by
unknown
31:05 queued 15:34
created

TableManager::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
namespace EventEspresso\core\services\database;
3
4
defined( 'EVENT_ESPRESSO_VERSION') || exit('No direct script access allowed');
5
/**
6
 *
7
 * Class TableManager
8
 *
9
 * For performing mysql database table schema manipulation
10
 *
11
 * @package         Event Espresso
12
 * @subpackage
13
 * @author				Mike Nelson
14
 * @since		 	   $VID:$
15
 *
16
 */
17
class TableManager extends \EE_Base {
18
19
	/**
20
	 * @var TableAnalysis $table_analysis
21
	 */
22
	private $table_analysis;
23
24
25
26
	/**
27
	 * TableManager constructor.
28
	 *
29
	 * @param TableAnalysis $TableAnalysis
30
	 */
31
	public function __construct( TableAnalysis $TableAnalysis ) {
32
		$this->table_analysis = $TableAnalysis;
33
	}
34
	
35
	/**
36
	 * Gets the injected table analyzer, or throws an exception
37
	 * @return TableAnalysis
38
	 * @throws \EE_Error
39
	 */
40 View Code Duplication
	protected function getTableAnalysis() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
41
		if( $this->table_analysis instanceof TableAnalysis ) {
42
			return $this->table_analysis;
43
		} else {
44
			throw new \EE_Error( 
45
				sprintf( 
46
					__( 'Table analysis class on class %1$s is not set properly.', 'event_espresso'), 
47
					get_class( $this ) 
48
				) 
49
			);
50
		}
51
	}
52
53
54
55
	/**
56
     * @param string $table_name which can optionally start with $wpdb->prefix or not
57
     * @param string $column_name
58
     * @param string $column_info
59
     * @return bool|false|int
60
     */
61
    public function addColumn( $table_name, $column_name, $column_info='INT UNSIGNED NOT NULL' )
62
	{
63
		if( apply_filters( 'FHEE__EEH_Activation__add_column_if_it_doesnt_exist__short_circuit', FALSE ) ){
64
			return FALSE;
65
		}
66
		global $wpdb;
67
		$full_table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix( $table_name );
68
		$columns = $this->getTableColumns($table_name);
69
		if( !in_array( $column_name, $columns)){
70
			$alter_query="ALTER TABLE $full_table_name ADD $column_name $column_info";
71
			return $wpdb->query($alter_query);
72
		}
73
		return TRUE;
74
	}
75
76
	/**
77
	 * Gets the name of all columns on the  table. $table_name can
78
	 * optionally start with $wpdb->prefix or not
79
	 * @global \wpdb $wpdb
80
	 * @param string $table_name
81
	 * @return array
82
	 */
83
	public function getTableColumns( $table_name )
84
	{
85
		global $wpdb;
86
		$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix( $table_name );
87
		$fieldArray = array();
88
		if ( ! empty( $table_name )) {
89
			$columns = $wpdb->get_results("SHOW COLUMNS FROM $table_name ");
90
			if ($columns !== FALSE) {
91
				foreach( $columns as $column ){
92
					$fieldArray[] = $column->Field;
93
				}
94
			}
95
		}
96
		return $fieldArray;
97
	}
98
99
	/**
100
	 * Drops the specified table from the database. $table_name can
101
	 * optionally start with $wpdb->prefix or not
102
	 *
103
	 * @global \wpdb $wpdb
104
	 * @param string $table_name
105
	 * @return int
106
	 */
107
	public function dropTable( $table_name )
108
	{
109
		global $wpdb;
110
		if (  $this->getTableAnalysis()->tableExists( $table_name ) ) {
111
			$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix( $table_name );
112
			return $wpdb->query( "DROP TABLE IF EXISTS $table_name" );
113
		}
114
		return 0;
115
	}
116
	
117
	/**
118
	 * Drops all the tables mentioned in a single MYSQL query. Double-checks
119
	 * each table name provided has a wpdb prefix attached, and that it exists.
120
	 * Returns the list actually deleted
121
	 * @global WPDB $wpdb
122
	 * @param array $table_names
123
	 * @return array of table names which we deleted
124
	 */
125
	public function dropTables( $table_names )
126
	{
127
		$tables_to_delete = array();
128
		foreach( $table_names as $table_name ) {
129
			$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix( $table_name );
130
			if( $this->getTableAnalysis()->tableExists( $table_name ) ) {
131
				$tables_to_delete[] = $table_name;
132
			}
133
		}
134
		global $wpdb;
135
		$wpdb->query( 'DROP TABLE ' . implode( ', ', $tables_to_delete ) );
136
		return $tables_to_delete;
137
	}
138
139
	/**
140
	 * Drops the specified index from the specified table. $table_name can
141
	 * optionally start with $wpdb->prefix or not
142
	 *
143
	 * @global \wpdb $wpdb
144
	 * @param string $table_name
145
	 * @param string $indexName
146
	 * @return int
147
	 */
148
	public function dropIndex( $table_name, $indexName )
149
	{
150
		if( apply_filters( 'FHEE__EEH_Activation__drop_index__short_circuit', FALSE ) ){
151
			return FALSE;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return FALSE; (false) is incompatible with the return type documented by EventEspresso\core\servi...TableManager::dropIndex of type integer.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
152
		}
153
		global $wpdb;
154
		$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix( $table_name );
155
		$index_exists_query = "SHOW INDEX FROM $table_name WHERE Key_name = '$indexName'";
156
		if (
157
			$this->getTableAnalysis()->tableExists(  $table_name )
158
			&& $wpdb->get_var( $index_exists_query ) === $table_name //using get_var with the $index_exists_query returns the table's name
159
		) {
160
			return $wpdb->query( "ALTER TABLE $table_name DROP INDEX $indexName" );
161
		}
162
		return 0;
163
	}
164
165
	/**
166
	 * Just creates the requested table. $table_name can
167
	 * optionally start with $wpdb->prefix or not
168
	 * @param string $table_name
169
	 * @param string $createSql defining the table's columns and indexes
170
	 * @param string $engine (no need to specify "ENGINE=", that's implied)
171
	 * @return void
172
	 * @throws \EE_Error
173
	 */
174
	public function createTable( $table_name, $createSql, $engine = 'MyISAM' )
175
	{
176
		// does $sql contain valid column information? ( LPT: https://regex101.com/ is great for working out regex patterns )
177
		if ( preg_match( '((((.*?))(,\s))+)', $createSql, $valid_column_data ) ) {
178
			$table_name = $this->getTableAnalysis()->ensureTableNameHasPrefix( $table_name );
179
			$SQL = "CREATE TABLE $table_name ( $createSql ) ENGINE=$engine DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;";
180
			/** @var \wpdb $wpdb */
181
			global $wpdb;
182
			//get $wpdb to echo errors, but buffer them. This way at least WE know an error
183
			//happened. And then we can choose to tell the end user
184
			$old_show_errors_policy = $wpdb->show_errors( TRUE );
185
			$old_error_suppression_policy = $wpdb->suppress_errors( FALSE );
186
			ob_start();
187
			dbDelta( $SQL );
188
			$output = ob_get_contents();
189
			ob_end_clean();
190
			$wpdb->show_errors( $old_show_errors_policy );
191
			$wpdb->suppress_errors( $old_error_suppression_policy );
192
			if( ! empty( $output ) ){
193
				throw new \EE_Error( $output	);
194
			}
195
		} else {
196
			throw new \EE_Error(
197
				sprintf(
198
					__( 'The following table creation SQL does not contain valid information about the table columns: %1$s %2$s', 'event_espresso' ),
199
					'<br />',
200
					$createSql
201
				)
202
			);
203
		}
204
	}
205
206
}
207