PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 28.2
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v28.2
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
wordpress-seo / lib / migrations / table.php

table.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 28.2, at lib/migrations/table.php

261 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Yoast\WP\Lib\Migrations;
4
5 use Exception;
6
7 /**
8 * Yoast migrations table class.
9 */
10 class Table {
11
12 /**
13 * The adapter.
14 *
15 * @var Adapter
16 */
17 private $adapter;
18
19 /**
20 * The name
21 *
22 * @var string
23 */
24 private $name;
25
26 /**
27 * The options
28 *
29 * @var array
30 */
31 private $options;
32
33 /**
34 * The SQL representation of this table.
35 *
36 * @var string
37 */
38 private $sql = '';
39
40 /**
41 * Whether or not the table has been initialized.
42 *
43 * @var bool
44 */
45 private $initialized = false;
46
47 /**
48 * The columns
49 *
50 * @var Column[]
51 */
52 private $columns = [];
53
54 /**
55 * The primary keys.
56 *
57 * @var string[]
58 */
59 private $primary_keys = [];
60
61 /**
62 * Whether or not to auto generate the id.
63 *
64 * @var bool
65 */
66 private $auto_generate_id = true;
67
68 /**
69 * Creates an instance of the Adapter.
70 *
71 * @param Adapter $adapter The current adapter.
72 * @param string $name The table name.
73 * @param array $options The options.
74 *
75 * @throws Exception If invalid arguments are passed.
76 */
77 public function __construct( $adapter, $name, $options = [] ) {
78 // Sanity checks.
79 if ( ! $adapter instanceof Adapter ) {
80 throw new Exception( 'Invalid MySQL Adapter instance.' );
81 }
82 if ( ! $name ) {
83 throw new Exception( "Invalid 'name' parameter" );
84 }
85 $this->adapter = $adapter;
86 $this->name = $name;
87 $this->options = $options;
88 $this->init_sql( $name, $options );
89 if ( \array_key_exists( 'id', $options ) ) {
90 if ( \is_bool( $options['id'] ) && $options['id'] === false ) {
91 $this->auto_generate_id = false;
92 }
93
94 // If its a string then we want to auto-generate an integer-based
95 // primary key with this name.
96 if ( \is_string( $options['id'] ) ) {
97 $this->auto_generate_id = true;
98 $this->primary_keys[] = $options['id'];
99 }
100 }
101 }
102
103 /**
104 * Create a column
105 *
106 * @param string $column_name The column name.
107 * @param string $type The column type.
108 * @param array $options The options.
109 *
110 * @return void
111 */
112 public function column( $column_name, $type, $options = [] ) {
113 // If there is already a column by the same name then silently fail and continue.
114 foreach ( $this->columns as $column ) {
115 if ( $column->name === $column_name ) {
116 return;
117 }
118 }
119
120 $column_options = [];
121 if ( \array_key_exists( 'primary_key', $options ) ) {
122 if ( $options['primary_key'] ) {
123 $this->primary_keys[] = $column_name;
124 }
125 }
126 if ( \array_key_exists( 'auto_increment', $options ) ) {
127 if ( $options['auto_increment'] ) {
128 $column_options['auto_increment'] = true;
129 }
130 }
131 $column_options = \array_merge( $column_options, $options );
132 $column = new Column( $this->adapter, $column_name, $type, $column_options );
133 $this->columns[] = $column;
134 }
135
136 /**
137 * Shortcut to create timestamps columns (default created_at, updated_at)
138 *
139 * @param string $created_column_name Created at column name.
140 * @param string $updated_column_name Updated at column name.
141 *
142 * @return void
143 */
144 public function timestamps( $created_column_name = 'created_at', $updated_column_name = 'updated_at' ) {
145 $this->column( $created_column_name, 'datetime' );
146 $this->column(
147 $updated_column_name,
148 'timestamp',
149 [
150 'null' => false,
151 'default' => 'CURRENT_TIMESTAMP',
152 'extra' => 'ON UPDATE CURRENT_TIMESTAMP',
153 ],
154 );
155 }
156
157 /**
158 * Get all primary keys
159 *
160 * @return string
161 */
162 private function keys() {
163 if ( \count( $this->primary_keys ) > 0 ) {
164 $lead = ' PRIMARY KEY (';
165 $quoted = [];
166 foreach ( $this->primary_keys as $key ) {
167 $quoted[] = \sprintf( '%s', $this->adapter->identifier( $key ) );
168 }
169 $primary_key_sql = ",\n" . $lead . \implode( ',', $quoted ) . ')';
170 return $primary_key_sql;
171 }
172
173 return '';
174 }
175
176 /**
177 * Table definition
178 *
179 * @param bool $wants_sql Whether or not to return SQL or execute the query. Defaults to false.
180 *
181 * @return bool|string
182 *
183 * @throws Exception If the table definition has not been initialized.
184 */
185 public function finish( $wants_sql = false ) {
186 if ( ! $this->initialized ) {
187 throw new Exception( \sprintf( "Table Definition: '%s' has not been initialized", $this->name ) );
188 }
189 $opt_str = '';
190 if ( \is_array( $this->options ) && \array_key_exists( 'options', $this->options ) ) {
191 $opt_str = $this->options['options'];
192 }
193 elseif ( isset( $this->adapter->db_info['charset'] ) ) {
194 $opt_str = ' DEFAULT CHARSET=' . $this->adapter->db_info['charset'];
195 }
196 else {
197 $opt_str = ' DEFAULT CHARSET=utf8';
198 }
199 $close_sql = \sprintf( ') %s;', $opt_str );
200 $create_table_sql = $this->sql;
201 if ( $this->auto_generate_id === true ) {
202 $this->primary_keys[] = 'id';
203 $primary_id = new Column(
204 $this->adapter,
205 'id',
206 'integer',
207 [
208 'unsigned' => true,
209 'null' => false,
210 'auto_increment' => true,
211 ],
212 );
213 $create_table_sql .= $primary_id->to_sql() . ",\n";
214 }
215 $create_table_sql .= $this->columns_to_str();
216 $create_table_sql .= $this->keys() . $close_sql;
217 if ( $wants_sql ) {
218 return $create_table_sql;
219 }
220 return $this->adapter->execute_ddl( $create_table_sql );
221 }
222
223 /**
224 * Get SQL for all columns.
225 *
226 * @return string The SQL.
227 */
228 private function columns_to_str() {
229 $fields = [];
230 $len = \count( $this->columns );
231 for ( $i = 0; $i < $len; $i++ ) {
232 $c = $this->columns[ $i ];
233 $fields[] = $c->__toString();
234 }
235 return \implode( ",\n", $fields );
236 }
237
238 /**
239 * Init create sql statement.
240 *
241 * @param string $name The name.
242 * @param array $options The options.
243 *
244 * @return void
245 */
246 private function init_sql( $name, $options ) {
247 // Are we forcing table creation? If so, drop it first.
248 if ( \array_key_exists( 'force', $options ) && $options['force'] === true ) {
249 $this->adapter->drop_table( $name );
250 }
251 $temp = '';
252 if ( \array_key_exists( 'temporary', $options ) ) {
253 $temp = ' TEMPORARY';
254 }
255 $create_sql = \sprintf( 'CREATE%s TABLE ', $temp );
256 $create_sql .= \sprintf( "%s (\n", $this->adapter->identifier( $name ) );
257 $this->sql .= $create_sql;
258 $this->initialized = true;
259 }
260 }
261