CLI   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 437
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 212
dl 0
loc 437
ccs 0
cts 306
cp 0
rs 9.76
c 5
b 0
f 0
wmc 33

6 Methods

Rating   Name   Duplication   Size   Complexity  
C wp_cli_customers_synchronize() 0 104 12
A wp_cli_organizations_synchronize() 0 2 1
A wp_cli_customers_connect_wp_users() 0 35 2
A __construct() 0 54 1
C wp_cli_payments() 0 102 14
A wp_cli_payments_cancel() 0 64 3
1
<?php
2
/**
3
 * CLI
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2022 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Pay\Mollie
9
 */
10
11
namespace Pronamic\WordPress\Pay\Gateways\Mollie;
12
13
/**
14
 * Title: CLI
15
 * Description:
16
 * Copyright: 2005-2022 Pronamic
17
 * Company: Pronamic
18
 *
19
 * @author  Remco Tolsma
20
 * @version 2.1.0
21
 * @since   2.1.0
22
 * @link    https://github.com/woocommerce/woocommerce/blob/3.9.0/includes/class-wc-cli.php
23
 */
24
class CLI {
25
	/**
26
	 * Customer data store.
27
	 *
28
	 * @var CustomerDataStore
29
	 */
30
	protected $customer_data_store;
31
32
	/**
33
	 * Profile data store.
34
	 *
35
	 * @var ProfileDataStore
36
	 */
37
	protected $profile_data_store;
38
39
	/**
40
	 * Construct CLI.
41
	 */
42
	public function __construct() {
43
		\WP_CLI::add_command(
44
			'pronamic-pay mollie organizations synchronize',
45
			function( $args, $assoc_args ) {
46
				$this->wp_cli_organizations_synchronize( $args, $assoc_args );
47
			},
48
			array(
49
				'shortdesc' => 'Synchronize Mollie organizations to WordPress (not implemented yet).',
50
			)
51
		);
52
53
		\WP_CLI::add_command(
54
			'pronamic-pay mollie customers synchronize',
55
			function( $args, $assoc_args ) {
56
				$this->wp_cli_customers_synchronize( $args, $assoc_args );
57
			},
58
			array(
59
				'shortdesc' => 'Synchronize Mollie customers to WordPress.',
60
			)
61
		);
62
63
		\WP_CLI::add_command(
64
			'pronamic-pay mollie customers connect-wp-users',
65
			function( $args, $assoc_args ) {
66
				$this->wp_cli_customers_connect_wp_users( $args, $assoc_args );
67
			},
68
			array(
69
				'shortdesc' => 'Connect Mollie customers to WordPress users by email.',
70
			)
71
		);
72
73
		\WP_CLI::add_command(
74
			'pronamic-pay mollie payments list',
75
			function( $args, $assoc_args ) {
76
				$this->wp_cli_payments( $args, $assoc_args );
77
			},
78
			array(
79
				'shortdesc' => 'Mollie payments.',
80
			)
81
		);
82
83
		\WP_CLI::add_command(
84
			'pronamic-pay mollie payments cancel',
85
			function( $args, $assoc_args ) {
86
				$this->wp_cli_payments_cancel( $args, $assoc_args );
87
			},
88
			array(
89
				'shortdesc' => 'Cancel Mollie payments.',
90
			)
91
		);
92
93
		// Data Stores.
94
		$this->profile_data_store  = new ProfileDataStore();
95
		$this->customer_data_store = new CustomerDataStore();
96
	}
97
98
	/**
99
	 * CLI organizations synchronize.
100
	 *
101
	 * @link https://docs.mollie.com/reference/v2/organizations-api/current-organization
102
	 * @param array<string> $args       Arguments.
103
	 * @param array<string> $assoc_args Associative arguments.
104
	 * @return void
105
	 */
106
	public function wp_cli_organizations_synchronize( $args, $assoc_args ) {
0 ignored issues
show
Unused Code introduced by
The parameter $assoc_args is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

106
	public function wp_cli_organizations_synchronize( $args, /** @scrutinizer ignore-unused */ $assoc_args ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $args is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

106
	public function wp_cli_organizations_synchronize( /** @scrutinizer ignore-unused */ $args, $assoc_args ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
107
		\WP_CLI::error( 'Command not implemented yet.' );
108
	}
109
110
	/**
111
	 * CLI customers synchronize.
112
	 *
113
	 * @link https://docs.mollie.com/reference/v2/customers-api/list-customers
114
	 * @param array<string> $args       Arguments.
115
	 * @param array<string> $assoc_args Associative arguments.
116
	 * @return void
117
	 */
118
	public function wp_cli_customers_synchronize( $args, $assoc_args ) {
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

118
	public function wp_cli_customers_synchronize( /** @scrutinizer ignore-unused */ $args, $assoc_args ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $assoc_args is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

118
	public function wp_cli_customers_synchronize( $args, /** @scrutinizer ignore-unused */ $assoc_args ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
119
		global $post;
120
		global $wpdb;
121
122
		$query = new \WP_Query(
123
			array(
124
				'post_type'   => 'pronamic_gateway',
125
				'post_status' => 'publish',
126
				'nopaging'    => true,
127
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Slow query allowed on CLI.
128
				'meta_query'  => array(
129
					array(
130
						'key'   => '_pronamic_gateway_id',
131
						'value' => 'mollie',
132
					),
133
					array(
134
						'key'     => '_pronamic_gateway_mollie_api_key',
135
						'compare' => 'EXISTS',
136
					),
137
				),
138
			)
139
		);
140
141
		if ( $query->have_posts() ) {
142
			while ( $query->have_posts() ) {
143
				$query->the_post();
144
145
				$api_key = get_post_meta( $post->ID, '_pronamic_gateway_mollie_api_key', true );
146
147
				\WP_CLI::log( $post->post_title );
148
				\WP_CLI::log( $api_key );
0 ignored issues
show
Bug introduced by
It seems like $api_key can also be of type false; however, parameter $message of WP_CLI::log() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

148
				\WP_CLI::log( /** @scrutinizer ignore-type */ $api_key );
Loading history...
149
				\WP_CLI::log( '' );
150
151
				$client = new Client( $api_key );
0 ignored issues
show
Bug introduced by
It seems like $api_key can also be of type false; however, parameter $api_key of Pronamic\WordPress\Pay\G...e\Client::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

151
				$client = new Client( /** @scrutinizer ignore-type */ $api_key );
Loading history...
152
153
				$urls = array(
154
					'https://api.mollie.com/v2/customers?limit=250',
155
				);
156
157
				$profile = Profile::from_object( $client->get_current_profile() );
158
159
				$profile_id = $this->profile_data_store->save_profile(
160
					$profile,
161
					array(
162
						'api_key_live' => ( 'live_' === substr( $api_key, 0, 5 ) ) ? $api_key : null,
0 ignored issues
show
Bug introduced by
It seems like $api_key can also be of type false and null; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

162
						'api_key_live' => ( 'live_' === substr( /** @scrutinizer ignore-type */ $api_key, 0, 5 ) ) ? $api_key : null,
Loading history...
163
						'api_key_test' => ( 'test_' === substr( $api_key, 0, 5 ) ) ? $api_key : null,
164
					),
165
					array(
166
						'api_key_live' => '%s',
167
						'api_key_test' => '%s',
168
					)
169
				);
170
171
				while ( ! empty( $urls ) ) {
172
					$url = (string) array_shift( $urls );
173
174
					\WP_CLI::log( $url );
175
176
					$response = $client->send_request( $url );
177
178
					if ( isset( $response->count ) ) {
179
						\WP_CLI::log(
180
							\sprintf(
181
								'Found %d customer(s).',
182
								$response->count
183
							)
184
						);
185
					}
186
187
					if ( \property_exists( $response, '_embedded' ) && isset( $response->_embedded->customers ) ) {
188
						\WP_CLI\Utils\format_items(
189
							'table',
190
							$response->_embedded->customers,
191
							array(
192
								'id',
193
								'mode',
194
								'name',
195
								'email',
196
								'locale',
197
							)
198
						);
199
200
						foreach ( $response->_embedded->customers as $object ) {
201
							$customer = Customer::from_object( $object );
202
203
							$customer_id = $this->customer_data_store->save_customer(
0 ignored issues
show
Unused Code introduced by
The assignment to $customer_id is dead and can be removed.
Loading history...
204
								$customer,
205
								array(
206
									'profile_id' => $profile_id,
207
								),
208
								array(
209
									'profile_id' => '%d',
210
								)
211
							);
212
						}
213
					}
214
215
					if ( \property_exists( $response, '_links' ) && isset( $response->_links->next->href ) ) {
216
						$urls[] = $response->_links->next->href;
217
					}
218
				}
219
			}
220
221
			\wp_reset_postdata();
222
		}
223
	}
224
225
	/**
226
	 * CLI connect Mollie customers to WordPress users.
227
	 *
228
	 * @link https://docs.mollie.com/reference/v2/customers-api/list-customers
229
	 * @link https://make.wordpress.org/cli/handbook/internal-api/wp-cli-add-command/
230
	 * @link https://developer.wordpress.org/reference/classes/wpdb/query/
231
	 * @param array<string> $args       Arguments.
232
	 * @param array<string> $assoc_args Associative arguments.
233
	 * @return void
234
	 */
235
	public function wp_cli_customers_connect_wp_users( $args, $assoc_args ) {
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

235
	public function wp_cli_customers_connect_wp_users( /** @scrutinizer ignore-unused */ $args, $assoc_args ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $assoc_args is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

235
	public function wp_cli_customers_connect_wp_users( $args, /** @scrutinizer ignore-unused */ $assoc_args ) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
236
		global $wpdb;
237
238
		$query = "
239
			INSERT IGNORE INTO $wpdb->pronamic_pay_mollie_customer_users (
240
				customer_id,
241
				user_id
242
			)
243
			SELECT
244
				mollie_customer.id AS mollie_customer_id,
245
				wp_user.ID AS wp_user_id
246
			FROM
247
				$wpdb->pronamic_pay_mollie_customers AS mollie_customer
248
					INNER JOIN
249
				$wpdb->users AS wp_user
250
						ON mollie_customer.email = wp_user.user_email
251
			;
252
		";
253
254
		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Prepare is OK.
255
		$result = $wpdb->query( $query );
256
257
		if ( false === $result ) {
258
			\WP_CLI::error(
259
				sprintf(
260
					'Database error: %s.',
261
					$wpdb->last_error
262
				)
263
			);
264
		}
265
266
		\WP_CLI::log(
267
			sprintf(
268
				'Connected %d users and Mollie customers.',
269
				$result
270
			)
271
		);
272
	}
273
274
	/**
275
	 * CLI Mollie payments.
276
	 *
277
	 * @param array<string> $args       Arguments.
278
	 * @param array<string> $assoc_args Associative arguments.
279
	 * @return void
280
	 */
281
	public function wp_cli_payments( $args, $assoc_args ) {
282
		$assoc_args = \wp_parse_args(
283
			$assoc_args,
284
			array(
285
				'api_key' => null,
286
				'api_url' => 'https://api.mollie.com/v2/payments',
287
				'from'    => null,
288
				'limit'   => 250,
289
				'format'  => 'table',
290
			)
291
		);
292
293
		$api_key = $assoc_args['api_key'];
294
		$api_url = $assoc_args['api_url'];
0 ignored issues
show
Unused Code introduced by
The assignment to $api_url is dead and can be removed.
Loading history...
295
		$from    = $assoc_args['from'];
296
		$limit   = $assoc_args['limit'];
297
		$format  = $assoc_args['format'];
298
299
		if ( empty( $api_key ) ) {
300
			\WP_CLI::error( 'This command requires an API key for authentication' );
301
302
			return;
303
		}
304
305
		$client = new Client( $api_key );
306
307
		$payments = array();
308
309
		$api_url = $assoc_args['api_url'];
310
311
		if ( null !== $limit ) {
312
			$api_url = \add_query_arg( 'limit', $limit, $api_url );
313
		}
314
315
		if ( null !== $from ) {
316
			$api_url = \add_query_arg( 'from', $from, $api_url );
317
		}
318
319
		$response = $client->send_request( $api_url );
320
321
		if ( \property_exists( $response, '_embedded' ) && isset( $response->_embedded->payments ) ) {
322
			foreach ( $response->_embedded->payments as $object ) {
323
				$payments[] = $object;
324
			}
325
		}
326
327
		$is_cancelable = \WP_CLI\Utils\get_flag_value( $assoc_args, 'is_cancelable' );
328
329
		if ( null !== $is_cancelable ) {
330
			$payments = \array_filter(
331
				$payments,
332
				function( $payment ) {
333
					if ( ! \property_exists( $payment, 'isCancelable' ) ) {
334
						return false;
335
					}
336
337
					// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- Mollie name.
338
					return $payment->isCancelable;
339
				} 
340
			);
341
		}
342
343
		$data = $payments;
344
345
		if ( 'ids' === $format ) {
346
			$data = \wp_list_pluck( $payments, 'id' );
347
		}
348
349
		if ( empty( $data ) ) {
350
			if ( \property_exists( $response, '_links' ) && isset( $response->_links->next->href ) ) {
351
				\WP_CLI::log(
352
					\sprintf(
353
						'Number Payments: %s, Number Filtered Payments: %s, API URL: %s.',
354
						\count( $response->_embedded->payments ),
355
						\count( $payments ),
356
						$api_url
357
					)
358
				);
359
360
				$automatic = \WP_CLI\Utils\get_flag_value( $assoc_args, 'automatic' );
361
362
				if ( true == $automatic ) {
363
					$new_assoc_args = $assoc_args;
364
365
					$new_assoc_args['api_url'] = $response->_links->next->href;
366
367
					$this->wp_cli_payments( $args, $new_assoc_args );
368
				}
369
370
				return;
371
			}
372
		}
373
374
		\WP_CLI\Utils\format_items(
375
			$format,
376
			$data,
377
			array(
378
				'id',
379
				'createdAt',
380
				'mode',
381
				'description',
382
				'method',
383
			)
384
		);
385
	}
386
387
	/**
388
	 * CLI cancel Mollie payments.
389
	 *
390
	 * @link https://docs.mollie.com/reference/v2/payments-api/list-payments
391
	 * @link https://make.wordpress.org/cli/handbook/internal-api/wp-cli-add-command/
392
	 * @link https://developer.wordpress.org/reference/classes/wpdb/query/
393
	 * @param array<string> $args       Arguments.
394
	 * @param array<string> $assoc_args Associative arguments.
395
	 * @return void
396
	 */
397
	public function wp_cli_payments_cancel( $args, $assoc_args ) {
398
		$assoc_args = \wp_parse_args(
399
			$assoc_args,
400
			array(
401
				'api_key' => null,
402
			)
403
		);
404
405
		$api_key = $assoc_args['api_key'];
406
407
		if ( empty( $api_key ) ) {
408
			\WP_CLI::error( 'This command requires an API key for authentication' );
409
410
			return;
411
		}
412
413
		$client = new Client( $api_key );
414
415
		foreach ( $args as $id ) {
416
			\WP_CLI::log(
417
				\sprintf(
418
					'Try to cancel payment `%s`…',
419
					$id
420
				)
421
			);
422
423
			$url = 'https://api.mollie.com/v2/payments/' . $id;
424
425
			\WP_CLI::log(
426
				\sprintf(
427
					'DELETE %s',
428
					$url
429
				)
430
			);
431
432
			$response = $client->send_request( $url, 'DELETE' );
433
434
			\WP_CLI::log(
435
				\sprintf(
436
					'- status = %s, createdAt = %s, canceledAt = %s',
437
					$response->status,
438
					// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- Mollie name.
439
					$response->createdAt,
440
					// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- Mollie name.
441
					$response->canceledAt
442
				)
443
			);
444
445
			\WP_CLI::log( '' );
446
		}
447
448
		\WP_CLI::log( '' );
449
450
		\WP_CLI::log( 'If you want to cancel the next batch of payments you can run the following command:' );
451
452
		\WP_CLI::log( '' );
453
454
		\WP_CLI::log(
455
			\sprintf(
456
				'wp pronamic-pay mollie payments cancel $( wp pronamic-pay mollie payments list --api_key=%s --from=%s --is_cancelable --format=%s ) --api_key=%s',
457
				\escapeshellarg( $api_key ),
458
				\escapeshellarg( $id ),
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id seems to be defined by a foreach iteration on line 415. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
459
				\escapeshellarg( 'ids' ),
460
				\escapeshellarg( $api_key )
461
			)
462
		);
463
	}
464
}
465