WordPoints_Installable   B
last analyzed

Complexity

Total Complexity 53

Size/Duplication

Total Lines 500
Duplicated Lines 10.2 %

Importance

Changes 0
Metric Value
dl 51
loc 500
rs 7.4757
c 0
b 0
f 0
wmc 53

27 Methods

Rating   Name   Duplication   Size   Complexity  
A get_slug() 0 2 1
C get_uninstall_routines() 0 33 7
A get_db_tables() 0 2 1
A set_option() 10 10 1
A unset_network_update_skipped() 0 2 1
A get_installed_site_ids_option_name() 0 11 3
A is_network_installed() 0 8 1
A set_db_version() 0 21 3
A get_uninstall_routine_factories() 0 21 3
B get_db_tables_install_routines() 12 27 4
A add_installed_site_id() 0 15 3
A get_update_routine_factories() 0 2 1
A get_custom_caps_install_routines() 0 11 2
A unset_db_version() 0 17 2
A get_installed_site_ids() 0 17 2
A get_custom_caps() 0 2 1
A unset_network_install_skipped() 0 2 1
A get_all_site_ids() 0 7 1
A delete_installed_site_ids() 0 2 1
A validate_site_ids() 16 16 3
A get_install_routines() 0 5 1
A unset_network_installed() 0 2 1
A set_network_installed() 0 2 1
A get_db_version() 0 18 4
A set_network_update_skipped() 0 7 2
A set_network_install_skipped() 0 2 1
A unset_option() 10 10 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like WordPoints_Installable 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.

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 WordPoints_Installable, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Installable class.
5
 *
6
 * @package WordPoints
7
 * @since   2.4.0
8
 */
9
10
/**
11
 * Represents an installable entity.
12
 *
13
 * Provides info about the entity and getters and setters for some stored data
14
 * relating to it.
15
 *
16
 * @since 2.4.0
17
 */
18
abstract class WordPoints_Installable implements WordPoints_InstallableI {
19
20
	/**
21
	 * The type of entity.
22
	 *
23
	 * For example, 'module' or 'component'.
24
	 *
25
	 * Note that this is singular, even though in the 'wordpoints_data' option the
26
	 * plural forms are used for legacy reasons.
27
	 *
28
	 * @since 2.4.0
29
	 *
30
	 * @var string
31
	 */
32
	protected $type;
33
34
	/**
35
	 * The slug of this entity.
36
	 *
37
	 * @since 2.4.0
38
	 *
39
	 * @var string
40
	 */
41
	protected $slug;
42
43
	/**
44
	 * @since 2.4.0
45
	 */
46
	public function get_slug() {
47
		return $this->slug;
48
	}
49
50
	/**
51
	 * @since 2.4.0
52
	 */
53
	public function get_db_version( $network = false ) {
54
55
		$wordpoints_data = wordpoints_get_maybe_network_array_option(
56
			'wordpoints_data'
57
			, $network
58
		);
59
60
		if ( 'wordpoints' === $this->slug ) {
61
62
			if ( isset( $wordpoints_data['version'] ) ) {
63
				return $wordpoints_data['version'];
64
			}
65
66
		} elseif ( isset( $wordpoints_data[ "{$this->type}s" ][ $this->slug ]['version'] ) ) {
67
			return $wordpoints_data[ "{$this->type}s" ][ $this->slug ]['version'];
68
		}
69
70
		return false;
71
	}
72
73
	/**
74
	 * @since 2.4.0
75
	 */
76
	public function set_db_version( $version = null, $network = false ) {
77
78
		if ( null === $version ) {
79
			$version = $this->get_version();
80
		}
81
82
		$wordpoints_data = wordpoints_get_maybe_network_array_option(
83
			'wordpoints_data'
84
			, $network
85
		);
86
87
		if ( 'wordpoints' === $this->slug ) {
88
			$wordpoints_data['version'] = $version;
89
		} else {
90
			$wordpoints_data[ "{$this->type}s" ][ $this->slug ]['version'] = $version;
91
		}
92
93
		wordpoints_update_maybe_network_option(
94
			'wordpoints_data'
95
			, $wordpoints_data
96
			, $network
97
		);
98
	}
99
100
	/**
101
	 * @since 2.4.0
102
	 */
103
	public function unset_db_version( $network = false ) {
104
105
		$wordpoints_data = wordpoints_get_maybe_network_array_option(
106
			'wordpoints_data'
107
			, $network
108
		);
109
110
		if ( 'wordpoints' === $this->slug ) {
111
			unset( $wordpoints_data['version'] );
112
		} else {
113
			unset( $wordpoints_data[ "{$this->type}s" ][ $this->slug ]['version'] );
114
		}
115
116
		wordpoints_update_maybe_network_option(
117
			'wordpoints_data'
118
			, $wordpoints_data
119
			, $network
120
		);
121
	}
122
123
	/**
124
	 * @since 2.4.0
125
	 */
126
	public function is_network_installed() {
127
128
		$network_installed = wordpoints_get_array_option(
129
			'wordpoints_network_installed'
130
			, 'site'
131
		);
132
133
		return isset( $network_installed[ $this->type ][ $this->slug ] );
134
	}
135
136
	/**
137
	 * @since 2.4.0
138
	 */
139
	public function set_network_installed() {
140
		$this->set_option( 'network_installed' );
141
	}
142
143
	/**
144
	 * @since 2.4.0
145
	 */
146
	public function unset_network_installed() {
147
		$this->unset_option( 'network_installed' );
148
	}
149
150
	/**
151
	 * @since 2.4.0
152
	 */
153
	public function set_network_install_skipped() {
154
		$this->set_option( 'network_install_skipped' );
155
	}
156
157
	/**
158
	 * @since 2.4.0
159
	 */
160
	public function unset_network_install_skipped() {
161
		$this->unset_option( 'network_install_skipped' );
162
	}
163
164
	/**
165
	 * @since 2.4.0
166
	 */
167
	public function set_network_update_skipped( $updating_from = null ) {
168
169
		if ( ! isset( $updating_from ) ) {
170
			$updating_from = $this->get_db_version( true );
171
		}
172
173
		$this->set_option( 'network_update_skipped', $updating_from );
174
	}
175
176
	/**
177
	 * @since 2.4.0
178
	 */
179
	public function unset_network_update_skipped() {
180
		$this->unset_option( 'network_update_skipped' );
181
	}
182
183
	/**
184
	 * Sets an option in the database for this entity.
185
	 *
186
	 * @since 2.4.0
187
	 *
188
	 * @param string $option The name of the option to set.
189
	 * @param mixed  $value  The value of the option.
190
	 */
191 View Code Duplication
	protected function set_option( $option, $value = true ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
192
193
		$data = wordpoints_get_array_option(
194
			"wordpoints_{$option}"
195
			, 'site'
196
		);
197
198
		$data[ $this->type ][ $this->slug ] = $value;
199
200
		update_site_option( "wordpoints_{$option}", $data );
0 ignored issues
show
Bug introduced by
The function update_site_option was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

200
		/** @scrutinizer ignore-call */ 
201
  update_site_option( "wordpoints_{$option}", $data );
Loading history...
201
	}
202
203
	/**
204
	 * Deletes an option in the database for this entity.
205
	 *
206
	 * @since 2.4.0
207
	 *
208
	 * @param string $option The name of the option to delete.
209
	 */
210 View Code Duplication
	protected function unset_option( $option ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
211
212
		$data = wordpoints_get_array_option(
213
			"wordpoints_{$option}"
214
			, 'site'
215
		);
216
217
		unset( $data[ $this->type ][ $this->slug ] );
218
219
		update_site_option( "wordpoints_{$option}", $data );
0 ignored issues
show
Bug introduced by
The function update_site_option was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

219
		/** @scrutinizer ignore-call */ 
220
  update_site_option( "wordpoints_{$option}", $data );
Loading history...
220
	}
221
222
	/**
223
	 * @since 2.4.0
224
	 */
225
	public function get_installed_site_ids() {
226
227
		if ( $this->is_network_installed() ) {
228
229
			$site_ids = $this->get_all_site_ids();
230
231
		} else {
232
233
			$site_ids = wordpoints_get_array_option(
234
				$this->get_installed_site_ids_option_name()
235
				, 'site'
236
			);
237
238
			$site_ids = $this->validate_site_ids( $site_ids );
239
		}
240
241
		return $site_ids;
242
	}
243
244
	/**
245
	 * Gets the name of the option where the list of installed sites is stored.
246
	 *
247
	 * @since 2.4.0
248
	 *
249
	 * @return string The option name.
250
	 */
251
	protected function get_installed_site_ids_option_name() {
252
253
		if ( 'wordpoints' === $this->slug ) {
254
			$option_prefix = 'wordpoints';
255
		} elseif ( 'component' === $this->type ) {
256
			$option_prefix = "wordpoints_{$this->slug}";
257
		} else {
258
			$option_prefix = "wordpoints_{$this->type}_{$this->slug}";
259
		}
260
261
		return "{$option_prefix}_installed_sites";
262
	}
263
264
	/**
265
	 * Gets the IDs of all sites on the network.
266
	 *
267
	 * @since 2.4.0
268
	 *
269
	 * @return array The IDs of all sites on the network.
270
	 */
271
	protected function get_all_site_ids() {
272
273
		return get_sites(
0 ignored issues
show
Bug introduced by
The function get_sites was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

273
		return /** @scrutinizer ignore-call */ get_sites(
Loading history...
274
			array(
275
				'fields'     => 'ids',
276
				'network_id' => get_current_network_id(),
0 ignored issues
show
Bug introduced by
The function get_current_network_id was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

276
				'network_id' => /** @scrutinizer ignore-call */ get_current_network_id(),
Loading history...
277
				'number'     => 0,
278
			)
279
		);
280
	}
281
282
	/**
283
	 * Validates a list of site IDs against the database.
284
	 *
285
	 * @since 2.4.0
286
	 *
287
	 * @param array $site_ids The site IDs to validate.
288
	 *
289
	 * @return int[] The validated site IDs.
290
	 */
291 View Code Duplication
	protected function validate_site_ids( $site_ids ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
292
293
		if ( empty( $site_ids ) || ! is_array( $site_ids ) ) {
294
			return array();
295
		}
296
297
		$site_ids = get_sites(
0 ignored issues
show
Bug introduced by
The function get_sites was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

297
		$site_ids = /** @scrutinizer ignore-call */ get_sites(
Loading history...
298
			array(
299
				'fields'     => 'ids',
300
				'network_id' => get_current_network_id(),
0 ignored issues
show
Bug introduced by
The function get_current_network_id was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

300
				'network_id' => /** @scrutinizer ignore-call */ get_current_network_id(),
Loading history...
301
				'number'     => 0,
302
				'site__in'   => $site_ids,
303
			)
304
		);
305
306
		return $site_ids;
307
	}
308
309
	/**
310
	 * @since 2.4.0
311
	 */
312
	public function add_installed_site_id( $id = null ) {
313
314
		if ( empty( $id ) ) {
315
			$id = get_current_blog_id();
0 ignored issues
show
Bug introduced by
The function get_current_blog_id was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

315
			$id = /** @scrutinizer ignore-call */ get_current_blog_id();
Loading history...
316
		}
317
318
		$option_name = $this->get_installed_site_ids_option_name();
319
320
		$sites = wordpoints_get_array_option( $option_name, 'site' );
321
322
		if ( ! in_array( $id, $sites, true ) ) {
323
324
			$sites[] = $id;
325
326
			update_site_option( $option_name, $sites );
0 ignored issues
show
Bug introduced by
The function update_site_option was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

326
			/** @scrutinizer ignore-call */ 
327
   update_site_option( $option_name, $sites );
Loading history...
327
		}
328
	}
329
330
	/**
331
	 * @since 2.4.0
332
	 */
333
	public function delete_installed_site_ids() {
334
		delete_site_option( $this->get_installed_site_ids_option_name() );
0 ignored issues
show
Bug introduced by
The function delete_site_option was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

334
		/** @scrutinizer ignore-call */ 
335
  delete_site_option( $this->get_installed_site_ids_option_name() );
Loading history...
335
	}
336
337
	/**
338
	 * @since 2.4.0
339
	 */
340
	public function get_install_routines() {
341
342
		return array_merge_recursive(
343
			$this->get_db_tables_install_routines()
344
			, $this->get_custom_caps_install_routines()
345
		);
346
	}
347
348
	/**
349
	 * Gets the install routines for database tables for this entity.
350
	 *
351
	 * @since 2.4.0
352
	 *
353
	 * @return WordPoints_Installer_DB_Tables[] Routines for installing DB tables.
354
	 */
355
	protected function get_db_tables_install_routines() {
356
357
		$routines = array();
358
359
		$db_tables = wordpoints_map_context_shortcuts( $this->get_db_tables() );
360
361 View Code Duplication
		if ( isset( $db_tables['single'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
362
			$routines['single'][] = new WordPoints_Installer_DB_Tables(
363
				$db_tables['single']
364
				, 'base'
365
			);
366
		}
367
368
		if ( isset( $db_tables['site'] ) ) {
369
			$routines['site'][] = new WordPoints_Installer_DB_Tables(
370
				$db_tables['site']
371
			);
372
		}
373
374 View Code Duplication
		if ( isset( $db_tables['network'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
375
			$routines['network'][] = new WordPoints_Installer_DB_Tables(
376
				$db_tables['network']
377
				, 'base'
378
			);
379
		}
380
381
		return $routines;
382
	}
383
384
	/**
385
	 * Gets database tables for this entity.
386
	 *
387
	 * An array of arrays, where each sub-array holds the tables for a particular
388
	 * context. Within each sub-array, the value of each element is the DB field
389
	 * schema for a table (i.e., the part of the CREATE TABLE query within the main
390
	 * parentheses), and the keys are the table names. The base DB prefix will be
391
	 * prepended to table names for $single and $network, while $site tables will be
392
	 * prepended with blog prefix instead.
393
	 *
394
	 * @since 2.4.0
395
	 *
396
	 * @return  string[][] $db_tables {
397
	 *      @type string[] $single    Tables for a single site (non-multisite) install.
398
	 *      @type string[] $site      Tables for each site in a multisite network.
399
	 *      @type string[] $network   Tables for a multisite network.
400
	 *      @type string[] $local     Tables for $single and $site.
401
	 *      @type string[] $global    Tables for $single and $network.
402
	 *      @type string[] $universal Tables for $single, $site, and $network.
403
	 * }
404
	 */
405
	protected function get_db_tables() {
406
		return array();
407
	}
408
409
	/**
410
	 * Gets install routines for custom capabilities for this entity.
411
	 *
412
	 * @since 2.4.0
413
	 *
414
	 * @return WordPoints_Installer_Caps[][] Custom caps installers.
415
	 */
416
	protected function get_custom_caps_install_routines() {
417
418
		$caps = $this->get_custom_caps();
419
420
		if ( empty( $caps ) ) {
421
			return array();
422
		}
423
424
		return array(
425
			'site'   => array( new WordPoints_Installer_Caps( $caps ) ),
426
			'single' => array( new WordPoints_Installer_Caps( $caps ) ),
427
		);
428
	}
429
430
	/**
431
	 * Gets the custom capabilities used by this entity.
432
	 *
433
	 * The function should return an array of capabilities of the format processed
434
	 * by {@see wordpoints_add_custom_caps()}.
435
	 *
436
	 * @since 2.4.0
437
	 *
438
	 * @return string[] The custom caps (keys) and their corresponding core caps
439
	 *                  (values).
440
	 */
441
	protected function get_custom_caps() {
442
		return array();
443
	}
444
445
	/**
446
	 * @since 2.4.0
447
	 */
448
	public function get_update_routine_factories() {
449
		return array();
450
	}
451
452
	/**
453
	 * @since 2.4.0
454
	 */
455
	public function get_uninstall_routines() {
456
457
		$routines = array(
458
			'single'  => array(),
459
			'site'    => array(),
460
			'network' => array(),
461
		);
462
463
		$factories = $this->get_uninstall_routine_factories();
464
465
		if ( is_multisite() ) {
0 ignored issues
show
Bug introduced by
The function is_multisite was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

465
		if ( /** @scrutinizer ignore-call */ is_multisite() ) {
Loading history...
466
467
			foreach ( $factories as $factory ) {
468
469
				if ( $factory instanceof WordPoints_Uninstaller_Factory_SiteI ) {
470
					$routines['site'] = array_merge( $routines['site'], $factory->get_for_site() );
471
				}
472
473
				if ( $factory instanceof WordPoints_Uninstaller_Factory_NetworkI ) {
474
					$routines['network'] = array_merge( $routines['network'], $factory->get_for_network() );
475
				}
476
			}
477
478
		} else {
479
480
			foreach ( $factories as $factory ) {
481
				if ( $factory instanceof WordPoints_Uninstaller_Factory_SingleI ) {
482
					$routines['single'] = array_merge( $routines['single'], $factory->get_for_single() );
483
				}
484
			}
485
		}
486
487
		return $routines;
488
	}
489
490
	/**
491
	 * Gets a list of factories to create the uninstall routines for this entity.
492
	 *
493
	 * @since 2.4.0
494
	 *
495
	 * @return object[] Uninstall routine factories.
496
	 */
497
	protected function get_uninstall_routine_factories() {
498
499
		$factories = array();
500
501
		$db_tables = $this->get_db_tables();
502
503
		if ( ! empty( $db_tables ) ) {
504
			$factories[] = new WordPoints_Uninstaller_Factory_DB_Tables(
505
				array_map( 'array_keys', $db_tables )
506
			);
507
		}
508
509
		$custom_caps = $this->get_custom_caps();
510
511
		if ( ! empty( $custom_caps ) ) {
512
			$factories[] = new WordPoints_Uninstaller_Factory_Caps(
513
				array_keys( $custom_caps )
514
			);
515
		}
516
517
		return $factories;
518
	}
519
}
520
521
// EOF
522