PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 18.3
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v18.3
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 18.3, at lib/migrations/table.php

258 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 public function column( $column_name, $type, $options = [] ) {
111 // If there is already a column by the same name then silently fail and continue.
112 foreach ( $this->columns as $column ) {
113 if ( $column->name === $column_name ) {
114 return;
115 }
116 }
117
118 $column_options = [];
119 if ( \array_key_exists( 'primary_key', $options ) ) {
120 if ( $options['primary_key'] ) {
121 $this->primary_keys[] = $column_name;
122 }
123 }
124 if ( \array_key_exists( 'auto_increment', $options ) ) {
125 if ( $options['auto_increment'] ) {
126 $column_options['auto_increment'] = true;
127 }
128 }
129 $column_options = \array_merge( $column_options, $options );
130 $column = new Column( $this->adapter, $column_name, $type, $column_options );
131 $this->columns[] = $column;
132 }
133
134 /**
135 * Shortcut to create timestamps columns (default created_at, updated_at)
136 *
137 * @param string $created_column_name Created at column name.
138 * @param string $updated_column_name Updated at column name.
139 */
140 public function timestamps( $created_column_name = 'created_at', $updated_column_name = 'updated_at' ) {
141 $this->column( $created_column_name, 'datetime' );
142 $this->column(
143 $updated_column_name,
144 'timestamp',
145 [
146 'null' => false,
147 'default' => 'CURRENT_TIMESTAMP',
148 'extra' => 'ON UPDATE CURRENT_TIMESTAMP',
149 ]
150 );
151 }
152
153 /**
154 * Get all primary keys
155 *
156 * @return string
157 */
158 private function keys() {
159 if ( \count( $this->primary_keys ) > 0 ) {
160 $lead = ' PRIMARY KEY (';
161 $quoted = [];
162 foreach ( $this->primary_keys as $key ) {
163 $quoted[] = \sprintf( '%s', $this->adapter->identifier( $key ) );
164 }
165 $primary_key_sql = ",\n" . $lead . \implode( ',', $quoted ) . ')';
166 return $primary_key_sql;
167 }
168
169 return '';
170 }
171
172 /**
173 * Table definition
174 *
175 * @param bool $wants_sql Whether or not to return SQL or execute the query. Defaults to false.
176 *
177 * @return bool|string
178 *
179 * @throws Exception If the table definition has not been intialized.
180 */
181 public function finish( $wants_sql = false ) {
182 if ( ! $this->initialized ) {
183 throw new Exception( \sprintf( "Table Definition: '%s' has not been initialized", $this->name ) );
184 }
185 $opt_str = '';
186 if ( \is_array( $this->options ) && \array_key_exists( 'options', $this->options ) ) {
187 $opt_str = $this->options['options'];
188 }
189 else {
190 if ( isset( $this->adapter->db_info['charset'] ) ) {
191 $opt_str = ' DEFAULT CHARSET=' . $this->adapter->db_info['charset'];
192 }
193 else {
194 $opt_str = ' DEFAULT CHARSET=utf8';
195 }
196 }
197 $close_sql = \sprintf( ') %s;', $opt_str );
198 $create_table_sql = $this->sql;
199 if ( $this->auto_generate_id === true ) {
200 $this->primary_keys[] = 'id';
201 $primary_id = new Column(
202 $this->adapter,
203 'id',
204 'integer',
205 [
206 'unsigned' => true,
207 'null' => false,
208 'auto_increment' => true,
209 ]
210 );
211 $create_table_sql .= $primary_id->to_sql() . ",\n";
212 }
213 $create_table_sql .= $this->columns_to_str();
214 $create_table_sql .= $this->keys() . $close_sql;
215 if ( $wants_sql ) {
216 return $create_table_sql;
217 }
218 return $this->adapter->execute_ddl( $create_table_sql );
219 }
220
221 /**
222 * Get SQL for all columns.
223 *
224 * @return string The SQL.
225 */
226 private function columns_to_str() {
227 $str = '';
228 $fields = [];
229 $len = \count( $this->columns );
230 for ( $i = 0; $i < $len; $i++ ) {
231 $c = $this->columns[ $i ];
232 $fields[] = $c->__toString();
233 }
234 return \implode( ",\n", $fields );
235 }
236
237 /**
238 * Init create sql statement.
239 *
240 * @param string $name The name.
241 * @param array $options The options.
242 */
243 private function init_sql( $name, $options ) {
244 // Are we forcing table creation? If so, drop it first.
245 if ( \array_key_exists( 'force', $options ) && $options['force'] === true ) {
246 $this->adapter->drop_table( $name );
247 }
248 $temp = '';
249 if ( \array_key_exists( 'temporary', $options ) ) {
250 $temp = ' TEMPORARY';
251 }
252 $create_sql = \sprintf( 'CREATE%s TABLE ', $temp );
253 $create_sql .= \sprintf( "%s (\n", $this->adapter->identifier( $name ) );
254 $this->sql .= $create_sql;
255 $this->initialized = true;
256 }
257 }
258