Completed
Push — develop ( ecf42a...6659d7 )
by David
14:29
created

Wordlift_Configuration_Service   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 622
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 0
loc 622
rs 8.698
c 0
b 0
f 0
wmc 46
lcom 1
cbo 1

33 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A get_instance() 0 4 1
A get() 0 6 2
A set() 0 8 2
A get_entity_base_path() 0 4 1
A set_entity_base_path() 0 5 1
A is_skip_wizard() 0 4 1
A set_skip_wizard() 0 5 1
A get_key() 0 4 1
A set_key() 0 4 1
A get_language_code() 0 4 1
A set_language_code() 0 5 1
A set_diagnostic_preferences() 0 5 1
A get_diagnostic_preferences() 0 4 1
A get_country_code() 0 4 1
A set_country_code() 0 5 1
A get_publisher_id() 0 4 1
A set_publisher_id() 0 5 1
A get_dataset_uri() 0 4 1
A set_dataset_uri() 0 4 1
A get_package_type() 0 4 1
A set_package_type() 0 4 1
A update_key() 0 20 3
B get_remote_dataset_uri() 0 62 4
A maybe_update_dataset_uri() 0 18 6
A get_accounts_by_key_dataset_uri() 0 4 1
A get_accounts() 0 4 1
A is_link_by_default() 0 4 1
A set_link_by_default() 0 4 2
A get_batch_analysis_url() 0 5 1
A get_autocomplete_url() 0 5 1
A get_deactivation_feedback_url() 0 5 1
A get_api_url() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Wordlift_Configuration_Service often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Wordlift_Configuration_Service, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Wordlift_Configuration_Service class.
4
 *
5
 * The {@link Wordlift_Configuration_Service} class provides helper functions to get configuration parameter values.
6
 *
7
 * @link       https://wordlift.io
8
 *
9
 * @package    Wordlift
10
 * @since      3.6.0
11
 */
12
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Get WordLift's configuration settings stored in WordPress database.
19
 *
20
 * @since 3.6.0
21
 */
22
class Wordlift_Configuration_Service {
23
24
	/**
25
	 * The entity base path option name.
26
	 *
27
	 * @since 3.6.0
28
	 */
29
	const ENTITY_BASE_PATH_KEY = 'wl_entity_base_path';
30
31
	/**
32
	 * The skip wizard (admin installation wizard) option name.
33
	 *
34
	 * @since 3.9.0
35
	 */
36
	const SKIP_WIZARD = 'wl_skip_wizard';
37
38
	/**
39
	 * WordLift's key option name.
40
	 *
41
	 * @since 3.9.0
42
	 */
43
	const KEY = 'key';
44
45
	/**
46
	 * WordLift's configured language option name.
47
	 *
48
	 * @since 3.9.0
49
	 */
50
	const LANGUAGE = 'site_language';
51
52
	/**
53
	 * WordLift's configured country code.
54
	 *
55
	 * @since 3.18.0
56
	 */
57
	const COUNTRY_CODE = 'country_code';
58
59
	/**
60
	 * The publisher entity post ID option name.
61
	 *
62
	 * @since 3.9.0
63
	 */
64
	const PUBLISHER_ID = 'publisher_id';
65
66
	/**
67
	 * The dataset URI option name
68
	 *
69
	 * @since 3.10.0
70
	 */
71
	const DATASET_URI = 'redlink_dataset_uri';
72
73
	/**
74
	 * The link by default option name.
75
	 *
76
	 * @since 3.11.0
77
	 */
78
	const LINK_BY_DEFAULT = 'link_by_default';
79
80
	/**
81
	 * The user preferences about sharing data option.
82
	 *
83
	 * @since 3.19.0
84
	 */
85
	const SEND_DIAGNOSTIC = 'send_diagnostic';
86
87
	/**
88
	 * The package type configuration key.
89
	 *
90
	 * @since 3.20.0
91
	 */
92
	const PACKAGE_TYPE = 'package_type';
93
94
	/**
95
	 * The {@link Wordlift_Log_Service} instance.
96
	 *
97
	 * @since 3.16.0
98
	 *
99
	 * @var \Wordlift_Log_Service $log The {@link Wordlift_Log_Service} instance.
100
	 */
101
	private $log;
102
103
	/**
104
	 * The Wordlift_Configuration_Service's singleton instance.
105
	 *
106
	 * @since  3.6.0
107
	 *
108
	 * @access private
109
	 * @var \Wordlift_Configuration_Service $instance Wordlift_Configuration_Service's singleton instance.
110
	 */
111
	private static $instance;
112
113
	/**
114
	 * Create a Wordlift_Configuration_Service's instance.
115
	 *
116
	 * @since 3.6.0
117
	 */
118
	public function __construct() {
119
120
		$this->log = Wordlift_Log_Service::get_logger( get_class() );
121
122
		self::$instance = $this;
123
124
	}
125
126
	/**
127
	 * Get the singleton instance.
128
	 *
129
	 * @since 3.6.0
130
	 *
131
	 * @return \Wordlift_Configuration_Service
132
	 */
133
	public static function get_instance() {
134
135
		return self::$instance;
136
	}
137
138
	/**
139
	 * Get a configuration given the option name and a key. The option value is
140
	 * expected to be an array.
141
	 *
142
	 * @since 3.6.0
143
	 *
144
	 * @param string $option The option name.
145
	 * @param string $key A key in the option value array.
146
	 * @param string $default The default value in case the key is not found (by default an empty string).
147
	 *
148
	 * @return mixed The configuration value or the default value if not found.
149
	 */
150
	private function get( $option, $key, $default = '' ) {
151
152
		$options = get_option( $option, array() );
153
154
		return isset( $options[ $key ] ) ? $options[ $key ] : $default;
155
	}
156
157
	/**
158
	 * Set a configuration parameter.
159
	 *
160
	 * @since 3.9.0
161
	 *
162
	 * @param string $option Name of option to retrieve. Expected to not be SQL-escaped.
163
	 * @param string $key The value key.
164
	 * @param mixed  $value The value.
165
	 */
166
	private function set( $option, $key, $value ) {
167
168
		$values         = get_option( $option );
169
		$values         = isset( $values ) ? $values : array();
170
		$values[ $key ] = $value;
171
		update_option( $option, $values );
172
173
	}
174
175
	/**
176
	 * Get the entity base path, by default 'entity'.
177
	 *
178
	 * @since 3.6.0
179
	 *
180
	 * @return string The entity base path.
181
	 */
182
	public function get_entity_base_path() {
183
184
		return $this->get( 'wl_general_settings', self::ENTITY_BASE_PATH_KEY, 'entity' );
185
	}
186
187
	/**
188
	 * Get the entity base path.
189
	 *
190
	 * @since 3.9.0
191
	 *
192
	 * @param string $value The entity base path.
193
	 */
194
	public function set_entity_base_path( $value ) {
195
196
		$this->set( 'wl_general_settings', self::ENTITY_BASE_PATH_KEY, $value );
197
198
	}
199
200
	/**
201
	 * Whether the installation skip wizard should be skipped.
202
	 *
203
	 * @since 3.9.0
204
	 *
205
	 * @return bool True if it should be skipped otherwise false.
206
	 */
207
	public function is_skip_wizard() {
208
209
		return $this->get( 'wl_general_settings', self::SKIP_WIZARD, false );
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
210
	}
211
212
	/**
213
	 * Set the skip wizard parameter.
214
	 *
215
	 * @since 3.9.0
216
	 *
217
	 * @param bool $value True to skip the wizard. We expect a boolean value.
218
	 */
219
	public function set_skip_wizard( $value ) {
220
221
		$this->set( 'wl_general_settings', self::SKIP_WIZARD, true === $value );
222
223
	}
224
225
	/**
226
	 * Get WordLift's key.
227
	 *
228
	 * @since 3.9.0
229
	 *
230
	 * @return string WordLift's key or an empty string if not set.
231
	 */
232
	public function get_key() {
233
234
		return $this->get( 'wl_general_settings', self::KEY, '' );
235
	}
236
237
	/**
238
	 * Set WordLift's key.
239
	 *
240
	 * @since 3.9.0
241
	 *
242
	 * @param string $value WordLift's key.
243
	 */
244
	public function set_key( $value ) {
245
246
		$this->set( 'wl_general_settings', self::KEY, $value );
247
	}
248
249
	/**
250
	 * Get WordLift's configured language, by default 'en'.
251
	 *
252
	 * Note that WordLift's language is used when writing strings to the Linked Data dataset, not for the analysis.
253
	 *
254
	 * @since 3.9.0
255
	 *
256
	 * @return string WordLift's configured language code ('en' by default).
257
	 */
258
	public function get_language_code() {
259
260
		return $this->get( 'wl_general_settings', self::LANGUAGE, 'en' );
261
	}
262
263
	/**
264
	 * Set WordLift's language code, used when storing strings to the Linked Data dataset.
265
	 *
266
	 * @since 3.9.0
267
	 *
268
	 * @param string $value WordLift's language code.
269
	 */
270
	public function set_language_code( $value ) {
271
272
		$this->set( 'wl_general_settings', self::LANGUAGE, $value );
273
274
	}
275
276
	/**
277
	 * Set the user preferences about sharing diagnostic with us.
278
	 *
279
	 * @since 3.19.0
280
	 *
281
	 * @param string $value The user preferences(yes/no).
282
	 */
283
	public function set_diagnostic_preferences( $value ) {
284
285
		$this->set( 'wl_general_settings', self::SEND_DIAGNOSTIC, $value );
286
287
	}
288
289
	/**
290
	 * Get the user preferences about sharing diagnostic.
291
	 *
292
	 * @since 3.19.0
293
	 */
294
	public function get_diagnostic_preferences() {
295
296
		return $this->get( 'wl_general_settings', self::SEND_DIAGNOSTIC, 'no' );
297
	}
298
299
	/**
300
	 * Get WordLift's configured country code, by default 'us'.
301
	 *
302
	 * @since 3.18.0
303
	 *
304
	 * @return string WordLift's configured country code ('us' by default).
305
	 */
306
	public function get_country_code() {
307
308
		return $this->get( 'wl_general_settings', self::COUNTRY_CODE, 'us' );
309
	}
310
311
	/**
312
	 * Set WordLift's country code.
313
	 *
314
	 * @since 3.18.0
315
	 *
316
	 * @param string $value WordLift's country code.
317
	 */
318
	public function set_country_code( $value ) {
319
320
		$this->set( 'wl_general_settings', self::COUNTRY_CODE, $value );
321
322
	}
323
324
	/**
325
	 * Get the publisher entity post id.
326
	 *
327
	 * The publisher entity post id points to an entity post which contains the data for the publisher used in schema.org
328
	 * Article markup.
329
	 *
330
	 * @since 3.9.0
331
	 *
332
	 * @return int|NULL The publisher entity post id or NULL if not set.
333
	 */
334
	public function get_publisher_id() {
335
336
		return $this->get( 'wl_general_settings', self::PUBLISHER_ID, null );
337
	}
338
339
	/**
340
	 * Set the publisher entity post id.
341
	 *
342
	 * @since 3.9.0
343
	 *
344
	 * @param int $value The publisher entity post id.
345
	 */
346
	public function set_publisher_id( $value ) {
347
348
		$this->set( 'wl_general_settings', self::PUBLISHER_ID, $value );
349
350
	}
351
352
	/**
353
	 * Get the dataset URI.
354
	 *
355
	 * @since 3.10.0
356
	 *
357
	 * @return string The dataset URI or an empty string if not set.
358
	 */
359
	public function get_dataset_uri() {
360
361
		return $this->get( 'wl_advanced_settings', self::DATASET_URI, null );
362
	}
363
364
	/**
365
	 * Set the dataset URI.
366
	 *
367
	 * @since 3.10.0
368
	 *
369
	 * @param string $value The dataset URI.
370
	 */
371
	public function set_dataset_uri( $value ) {
372
373
		$this->set( 'wl_advanced_settings', self::DATASET_URI, $value );
374
	}
375
376
	/**
377
	 * Get the package type.
378
	 *
379
	 * @since 3.20.0
380
	 *
381
	 * @return string The package type or an empty string if not set.
382
	 */
383
	public function get_package_type() {
384
385
		return $this->get( 'wl_advanced_settings', self::PACKAGE_TYPE, null );
386
	}
387
388
	/**
389
	 * Set the package type.
390
	 *
391
	 * @since 3.20.0
392
	 *
393
	 * @param string $value The package type.
394
	 */
395
	public function set_package_type( $value ) {
396
397
		$this->set( 'wl_advanced_settings', self::PACKAGE_TYPE, $value );
398
	}
399
400
	/**
401
	 * Intercept the change of the WordLift key in order to set the dataset URI.
402
	 *
403
	 *
404
	 * @since 3.20.0 as of #761, we save settings every time a key is set, not only when the key changes, so to
405
	 *               store the configuration parameters such as country or language.
406
	 * @since 3.11.0
407
	 *
408
	 * @see https://github.com/insideout10/wordlift-plugin/issues/761
409
	 *
410
	 * @param array $old_value The old settings.
411
	 * @param array $new_value The new settings.
412
	 */
413
	public function update_key( $old_value, $new_value ) {
0 ignored issues
show
Unused Code introduced by
The parameter $old_value is not used and could be removed.

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

Loading history...
414
415
		// Check the old key value and the new one. We're going to ask for the dataset URI only if the key has changed.
416
		// $old_key = isset( $old_value['key'] ) ? $old_value['key'] : '';
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
417
		$new_key = isset( $new_value['key'] ) ? $new_value['key'] : '';
418
419
		// If the key hasn't changed, don't do anything.
420
		// WARN The 'update_option' hook is fired only if the new and old value are not equal.
421
		//		if ( $old_key === $new_key ) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
422
		//			return;
423
		//		}
424
425
		// If the key is empty, empty the dataset URI.
426
		if ( '' === $new_key ) {
427
			$this->set_dataset_uri( '' );
428
		}
429
430
		// make the request to the remote server.
431
		$this->get_remote_dataset_uri( $new_key );
432
	}
433
434
	/**
435
	 * Handle retrieving the dataset uri from the remote server.
436
	 *
437
	 * If a valid dataset uri is returned it is stored in the appropriate option,
438
	 * otherwise the option is set to empty string.
439
	 *
440
	 * @since 3.17.0 send the site URL and get the dataset URI.
441
	 * @since 3.12.0
442
	 *
443
	 * @param string $key The key to be used.
444
	 */
445
	public function get_remote_dataset_uri( $key ) {
446
447
		$this->log->trace( 'Getting the remote dataset URI and package type...' );
448
449
		/**
450
		 * Allow 3rd parties to change the site_url.
451
		 *
452
		 * @since 3.20.0
453
		 *
454
		 * @see https://github.com/insideout10/wordlift-plugin/issues/850
455
		 *
456
		 * @param string $site_url The site url.
457
		 */
458
		$site_url = apply_filters( 'wl_production_site_url', site_url() );
459
460
		// Build the URL.
461
		$url = $this->get_accounts()
462
		       . '?key=' . rawurlencode( $key )
463
		       . '&url=' . rawurlencode( $site_url )
464
		       . '&country=' . $this->get_country_code()
465
		       . '&language=' . $this->get_language_code();
466
467
		$args     = wp_parse_args( unserialize( WL_REDLINK_API_HTTP_OPTIONS ), array(
468
			'method' => 'PUT',
469
		) );
470
		$response = wp_remote_request( $url, $args );
471
472
		// The response is an error.
473
		if ( is_wp_error( $response ) ) {
474
			$this->log->error( 'An error occurred setting the dataset URI: ' . $response->get_error_message() );
475
476
			$this->set_dataset_uri( '' );
477
			$this->set_package_type( null );
478
479
			return;
480
		}
481
482
		// The response is not OK.
483
		if ( 200 !== (int) $response['response']['code'] ) {
484
			$this->log->error( "Unexpected status code when opening URL $url: " . $response['response']['code'] );
485
486
			$this->set_dataset_uri( '' );
487
			$this->set_package_type( null );
488
489
			return;
490
		}
491
492
		/*
493
		 * We also store the package type.
494
		 *
495
		 * @since 3.20.0
496
		 */
497
		$json         = json_decode( $response['body'] );
498
		$dataset_uri  = $json->datasetURI;
499
		$package_type = isset( $json->packageType ) ? $json->packageType : null;
500
501
		$this->log->info( "Updating [ dataset uri :: $dataset_uri ][ package type :: $package_type ]..." );
502
503
		$this->set_dataset_uri( $dataset_uri );
504
		$this->set_package_type( $package_type );
505
506
	}
507
508
	/**
509
	 * Handle the edge case where a user submits the same key again
510
	 * when he does not have the dataset uri to regain it.
511
	 *
512
	 * This can not be handled in the normal option update hook because
513
	 * it is not being triggered when the save value equals to the one already
514
	 * in the DB.
515
	 *
516
	 * @since 3.12.0
517
	 *
518
	 * @param mixed $value The new, unserialized option value.
519
	 * @param mixed $old_value The old option value.
520
	 *
521
	 * @return mixed The same value in the $value parameter
522
	 */
523
	function maybe_update_dataset_uri( $value, $old_value ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
524
525
		// Check the old key value and the new one. Here we're only handling the
526
		// case where the key hasn't changed and the dataset URI isn't set. The
527
		// other case, i.e. a new key is inserted, is handled at `update_key`.
528
		$old_key = isset( $old_value['key'] ) ? $old_value['key'] : '';
529
		$new_key = isset( $value['key'] ) ? $value['key'] : '';
530
531
		$dataset_uri = $this->get_dataset_uri();
532
533
		if ( ! empty( $new_key ) && $new_key === $old_key && empty( $dataset_uri ) ) {
534
535
			// make the request to the remote server to try to get the dataset uri.
536
			$this->get_remote_dataset_uri( $new_key );
537
		}
538
539
		return $value;
540
	}
541
542
	/**
543
	 * Get the API URI to retrieve the dataset URI using the WordLift Key.
544
	 *
545
	 * @since 3.11.0
546
	 *
547
	 * @param string $key The WordLift key to use.
548
	 *
549
	 * @return string The API URI.
550
	 */
551
	public function get_accounts_by_key_dataset_uri( $key ) {
552
553
		return WL_CONFIG_WORDLIFT_API_URL_DEFAULT_VALUE . "accounts/key=$key/dataset_uri";
554
	}
555
556
	/**
557
	 * Get the `accounts` end point.
558
	 *
559
	 * @since 3.16.0
560
	 *
561
	 * @return string The `accounts` end point.
562
	 */
563
	public function get_accounts() {
564
565
		return WL_CONFIG_WORDLIFT_API_URL_DEFAULT_VALUE . 'accounts';
566
	}
567
568
	/**
569
	 * Get the `link by default` option.
570
	 *
571
	 * @since 3.13.0
572
	 *
573
	 * @return bool True if entities must be linked by default otherwise false.
574
	 */
575
	public function is_link_by_default() {
576
577
		return 'yes' === $this->get( 'wl_general_settings', self::LINK_BY_DEFAULT, 'yes' );
578
	}
579
580
	/**
581
	 * Set the `link by default` option.
582
	 *
583
	 * @since 3.13.0
584
	 *
585
	 * @param bool $value True to enabling linking by default, otherwise false.
586
	 */
587
	public function set_link_by_default( $value ) {
588
589
		$this->set( 'wl_general_settings', self::LINK_BY_DEFAULT, true === $value ? 'yes' : 'no' );
590
	}
591
592
	/**
593
	 * Get the URL to perform batch analyses.
594
	 *
595
	 * @since 3.14.0
596
	 *
597
	 * @return string The URL to call to perform the batch analyzes.
598
	 */
599
	public function get_batch_analysis_url() {
600
601
		return WL_CONFIG_WORDLIFT_API_URL_DEFAULT_VALUE . 'batch-analyses';
602
603
	}
604
605
	/**
606
	 * Get the URL to perform autocomplete request.
607
	 *
608
	 * @since 3.15.0
609
	 *
610
	 * @return string The URL to call to perform the batch analyzes.
611
	 */
612
	public function get_autocomplete_url() {
613
614
		return WL_CONFIG_WORDLIFT_API_URL_DEFAULT_VALUE . 'autocomplete';
615
616
	}
617
618
	/**
619
	 * Get the URL to perform feedback deactivation request.
620
	 *
621
	 * @since 3.19.0
622
	 *
623
	 * @return string The URL to call to perform the feedback deactivation request.
624
	 */
625
	public function get_deactivation_feedback_url() {
626
627
		return WL_CONFIG_WORDLIFT_API_URL_DEFAULT_VALUE . 'feedbacks';
628
629
	}
630
631
	/**
632
	 * Get the base API URL.
633
	 *
634
	 * @since 3.20.0
635
	 *
636
	 * @return string The base API URL.
637
	 */
638
	public function get_api_url() {
639
640
		return WL_CONFIG_WORDLIFT_API_URL_DEFAULT_VALUE;
641
	}
642
643
}
644