Test Failed
Push — develop ( 64bec5...308757 )
by Remco
03:59
created

src/Install.php (1 issue)

Labels
Severity
1
<?php
2
/**
3
 * Mollie install.
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2020 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Pay
9
 */
10
11
namespace Pronamic\WordPress\Pay\Gateways\Mollie;
12
13
/**
14
 * Title: Mollie install.
15
 * Description:
16
 * Copyright: 2005-2020 Pronamic
17
 * Company: Pronamic
18
 *
19
 * @author  Remco Tolsma
20
 * @version 3.0.0
21
 * @since   3.0.0
22
 */
23
class Install {
24
	/**
25
	 * Integration.
26
	 *
27
	 * @var Integration
28
	 */
29
	private $integration;
30
31
	/**
32
	 * Construct install.
33
	 *
34
	 * @link https://github.com/woocommerce/woocommerce/blob/4.0.0/includes/class-woocommerce.php#L368
35
	 * @link https://github.com/woocommerce/woocommerce/blob/4.0.0/includes/class-wc-install.php#L1568
36
	 * @link https://github.com/woocommerce/woocommerce/blob/4.0.0/includes/class-wc-install.php#L153-L166
37
	 * @param Integration $integration Integration.
38
	 */
39
	public function __construct( Integration $integration ) {
40
		$this->integration = $integration;
41
42
		add_action( 'init', array( $this, 'check_version' ), 5 );
43
	}
44
45
	/**
46
	 * Check version.
47
	 *
48
	 * @link https://github.com/woocommerce/woocommerce/blob/4.0.0/includes/class-wc-install.php#L168-L178
49
	 */
50
	public function check_version() {
51
		$version_option = $this->integration->get_version_option();
52
53
		if ( version_compare( $version_option, $this->integration->get_version(), '<' ) ) {
54
			$this->install();
55
		}
56
	}
57
58
	/**
59
	 * Install.
60
	 *
61
	 * @link https://github.com/woocommerce/woocommerce/blob/4.0.0/includes/class-wc-install.php#L272-L306
62
	 */
63
	public function install() {
64
		$this->create_tables();
65
		$this->add_foreign_keys();
66
		$this->convert_user_meta();
67
68
		$this->integration->update_version_option();
69
	}
70
71
	/**
72
	 * Create tables.
73
	 *
74
	 * @link https://github.com/woocommerce/woocommerce/blob/4.0.0/includes/class-wc-install.php#L630-L720
75
	 */
76
	private function create_tables() {
77
		global $wpdb;
78
79
		/**
80
		 * Requirements.
81
		 */
82
		require_once ABSPATH . 'wp-admin/includes/upgrade.php';
83
84
		/**
85
		 * Table options.
86
		 *
87
		 * In MySQL 5.6, InnoDB is the default MySQL storage engine. Unless you
88
		 * have configured a different default storage engine,  issuing a
89
		 * CREATE TABLE statement without an ENGINE= clause creates an InnoDB
90
		 * table.
91
		 *
92
		 * @link https://dev.mysql.com/doc/refman/5.6/en/innodb-introduction.html
93
		 *
94
		 * If a storage engine is specified that is not available, MySQL uses
95
		 * the default engine instead. Normally, this is MyISAM. For example,
96
		 * if a table definition includes the ENGINE=INNODB option but the MySQL
97
		 * server does not support INNODB tables, the table is created as a
98
		 * MyISAM table.
99
		 *
100
		 * @link https://dev.mysql.com/doc/refman/5.6/en/create-table.html
101
		 */
102
		$table_options = 'ENGINE=InnoDB ' . $wpdb->get_charset_collate();
103
104
		/**
105
		 * Queries.
106
		 *
107
		 * @link https://github.com/WordPress/WordPress/blob/5.3/wp-admin/includes/schema.php
108
		 */
109
		$queries = "
110
			CREATE TABLE $wpdb->pronamic_pay_mollie_organizations (
111
				id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
112
				mollie_id varchar(16) NOT NULL,
113
				name varchar(128) DEFAULT NULL,
114
				email varchar(100) DEFAULT NULL,
115
				PRIMARY KEY  ( id ),
116
				UNIQUE KEY mollie_id ( mollie_id )
117
			) $table_options;
118
			CREATE TABLE $wpdb->pronamic_pay_mollie_profiles (
119
				id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
120
				mollie_id varchar(16) NOT NULL,
121
				organization_id bigint(20) unsigned DEFAULT NULL,
122
				name varchar(128) DEFAULT NULL,
123
				email varchar(100) DEFAULT NULL,
124
				api_key_test varchar(35) DEFAULT NULL,
125
				api_key_live varchar(35) DEFAULT NULL,
126
				PRIMARY KEY  ( id ),
127
				UNIQUE KEY mollie_id ( mollie_id ),
128
				KEY organization_id ( organization_id )
129
			) $table_options;
130
			CREATE TABLE $wpdb->pronamic_pay_mollie_customers (
131
				id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
132
				mollie_id varchar(16) NOT NULL,
133
				organization_id bigint(20) unsigned DEFAULT NULL,
134
				profile_id bigint(20) unsigned DEFAULT NULL,
135
				test_mode tinyint(1) NOT NULL,
136
				email varchar(100) DEFAULT NULL,
137
				name varchar(255) DEFAULT NULL,
138
				PRIMARY KEY  ( id ),
139
				UNIQUE KEY mollie_id ( mollie_id ),
140
				KEY organization_id ( organization_id ),
141
				KEY profile_id ( profile_id ),
142
				KEY test_mode ( test_mode ),
143
				KEY email ( email )
144
			) $table_options;
145
			CREATE TABLE $wpdb->pronamic_pay_mollie_customer_users (
146
				id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
147
				customer_id bigint(20) unsigned NOT NULL,
148
				user_id bigint(20) unsigned NOT NULL,
149
				PRIMARY KEY  ( id ),
150
				UNIQUE KEY customer_user ( customer_id, user_id )
151
			) $table_options;
152
		";
153
154
		/**
155
		 * Execute.
156
		 *
157
		 * @link https://developer.wordpress.org/reference/functions/dbdelta/
158
		 * @link https://github.com/WordPress/WordPress/blob/5.3/wp-admin/includes/upgrade.php#L2538-L2915
159
		 */
160
		\dbDelta( $queries );
161
	}
162
163
	/**
164
	 * Add foreign keys.
165
	 */
166
	private function add_foreign_keys() {
167
		global $wpdb;
168
169
		/**
170
		 * Foreign keys.
171
		 *
172
		 * @link https://core.trac.wordpress.org/ticket/19207
173
		 * @link https://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html
174
		 */
175
		$data = array(
176
			(object) array(
177
				'table' => $wpdb->pronamic_pay_mollie_profiles,
178
				'name'  => 'fk_profile_organization_id',
179
				'query' => "
180
					ALTER TABLE  $wpdb->pronamic_pay_mollie_profiles
181
					ADD CONSTRAINT fk_profile_organization_id
182
					FOREIGN KEY ( organization_id )
183
					REFERENCES $wpdb->pronamic_pay_mollie_organizations ( id )
184
					ON DELETE RESTRICT
185
					ON UPDATE RESTRICT
186
					;
187
				",
188
			),
189
			(object) array(
190
				'table' => $wpdb->pronamic_pay_mollie_customers,
191
				'name'  => 'fk_customer_organization_id',
192
				'query' => "
193
					ALTER TABLE $wpdb->pronamic_pay_mollie_customers
194
					ADD CONSTRAINT fk_customer_organization_id
195
					FOREIGN KEY ( organization_id )
196
					REFERENCES $wpdb->pronamic_pay_mollie_organizations ( id )
197
					ON DELETE RESTRICT
198
					ON UPDATE RESTRICT
199
					;
200
				",
201
			),
202
			(object) array(
203
				'table' => $wpdb->pronamic_pay_mollie_customers,
204
				'name'  => 'fk_customer_profile_id',
205
				'query' => "
206
					ALTER TABLE $wpdb->pronamic_pay_mollie_customers
207
					ADD CONSTRAINT fk_customer_profile_id
208
					FOREIGN KEY ( profile_id )
209
					REFERENCES $wpdb->pronamic_pay_mollie_profiles ( id )
210
					ON DELETE RESTRICT
211
					ON UPDATE RESTRICT
212
					;
213
				",
214
			),
215
			(object) array(
216
				'table' => $wpdb->pronamic_pay_mollie_customer_users,
217
				'name'  => 'fk_customer_id',
218
				'query' => "
219
					ALTER TABLE $wpdb->pronamic_pay_mollie_customer_users
220
					ADD CONSTRAINT fk_customer_id
221
					FOREIGN KEY customer_id ( customer_id )
222
					REFERENCES $wpdb->pronamic_pay_mollie_customers ( id )
223
					ON DELETE RESTRICT
224
					ON UPDATE RESTRICT
225
					;
226
				",
227
			),
228
			(object) array(
229
				'table' => $wpdb->pronamic_pay_mollie_customer_users,
230
				'name'  => 'fk_customer_user_id',
231
				'query' => "
232
					ALTER TABLE $wpdb->pronamic_pay_mollie_customer_users
233
					ADD CONSTRAINT fk_customer_user_id
234
					FOREIGN KEY user_id ( user_id )
235
					REFERENCES $wpdb->users ( id )
236
					ON DELETE CASCADE
237
					ON UPDATE CASCADE
238
					;
239
				",
240
			),
241
		);
242
243
		foreach ( $data as $item ) {
244
			try {
245
				$this->add_foreign_key( $item );
246
			} catch ( \Exception $e ) {
247
				// Foreign keys are not strictly required.
248
				continue;
249
			}
250
		}
251
	}
252
253
	/**
254
	 * Add specified foreign key.
255
	 *
256
	 * @param object $item Foreig key data.
257
	 * @throws \Exception Throws exception when adding foreign key fails.
258
	 */
259
	private function add_foreign_key( $item ) {
260
		global $wpdb;
261
262
		/**
263
		 * Check if foreign key exists
264
		 *
265
		 * @link https://github.com/woocommerce/woocommerce/blob/3.9.0/includes/class-wc-install.php#L663-L681
266
		 */
267
		$result = $wpdb->get_var(
268
			$wpdb->prepare(
269
				"
270
			SELECT COUNT(*)
271
			FROM information_schema.TABLE_CONSTRAINTS
272
			WHERE CONSTRAINT_SCHEMA = %s
273
			AND CONSTRAINT_NAME = %s
274
			AND CONSTRAINT_TYPE = 'FOREIGN KEY'
275
			AND TABLE_NAME = %s
276
			",
277
				$wpdb->dbname,
278
				$item->name,
279
				$item->table
280
			)
281
		);
282
283
		if ( null === $result ) {
284
			throw new \Exception(
285
				\sprintf(
286
					'Could not count foreign keys: %s, database error: %s.',
287
					$item->name,
288
					$wpdb->last_error
289
				)
290
			);
291
		}
292
293
		$number_constraints = \intval( $result );
294
295
		if ( 0 === $number_constraints ) {
296
			// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Query is prepared.
297
			$result = $wpdb->query( $item->query );
298
299
			if ( false === $result ) {
300
				throw new \Exception(
301
					\sprintf(
302
						'Could not add foreign key: %s, database error: %s.',
303
						$item->name,
304
						$wpdb->last_error
305
					)
306
				);
307
			}
308
		}
309
	}
310
311
	/**
312
	 * Convert user meta.
313
	 *
314
	 * @throws \Exception Throws exception when database update query fails.
315
	 */
316
	private function convert_user_meta() {
317
		global $wpdb;
318
319
		$query = "
320
			INSERT IGNORE INTO $wpdb->pronamic_pay_mollie_customers (
321
				mollie_id,
322
				test_mode
323
			)
324
			SELECT
325
				meta_value AS mollie_id,
326
				'_pronamic_pay_mollie_customer_id_test' = meta_key AS test_mode
327
			FROM
328
				$wpdb->usermeta
329
			WHERE
330
				meta_key IN (
331
					'_pronamic_pay_mollie_customer_id',
332
					'_pronamic_pay_mollie_customer_id_test'
333
				)
334
					AND
335
				meta_value != ''
336
			;
337
		";
338
339
		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Query is prepared.
340
		$result = $wpdb->query( $query );
341
342
		if ( false === $result ) {
343
			throw new Exception(
0 ignored issues
show
The type Pronamic\WordPress\Pay\Gateways\Mollie\Exception was not found. Did you mean Exception? If so, make sure to prefix the type with \.
Loading history...
344
				sprintf(
345
					'Could not convert user meta, database error: %s.',
346
					$wpdb->last_error
347
				)
348
			);
349
		}
350
351
		$query = "
352
			INSERT IGNORE INTO $wpdb->pronamic_pay_mollie_customer_users (
353
				customer_id,
354
				user_id
355
			)
356
			SELECT
357
				mollie_customer.id AS mollie_customer_id,
358
				wp_user.ID AS wp_user_id
359
			FROM
360
				$wpdb->pronamic_pay_mollie_customers AS mollie_customer
361
					INNER JOIN
362
				$wpdb->usermeta AS wp_user_meta
363
						ON wp_user_meta.meta_value = mollie_customer.mollie_id
364
					INNER JOIN
365
				$wpdb->users AS wp_user
366
						ON wp_user_meta.user_id = wp_user.ID
367
			WHERE
368
				wp_user_meta.meta_key IN (
369
					'_pronamic_pay_mollie_customer_id',
370
					'_pronamic_pay_mollie_customer_id_test'
371
				)
372
					AND
373
				wp_user_meta.meta_value != ''
374
			;
375
		";
376
377
		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Query is prepared.
378
		$result = $wpdb->query( $query );
379
380
		if ( false === $result ) {
381
			throw new Exception(
382
				sprintf(
383
					'Could not convert user meta, database error: %s.',
384
					$wpdb->last_error
385
				)
386
			);
387
		}
388
	}
389
}
390