Completed
Push — branch-8.9 ( a3d28a...06f932 )
by Jeremy
93:32 queued 84:51
created

Config::on_plugins_loaded()   B

Complexity

Conditions 8
Paths 36

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
nc 36
nop 0
dl 0
loc 18
rs 8.4444
c 0
b 0
f 0
1
<?php
2
/**
3
 * The base Jetpack configuration class file.
4
 *
5
 * @package automattic/jetpack-config
6
 */
7
8
namespace Automattic\Jetpack;
9
10
use Automattic\Jetpack\Connection\Manager;
11
use Automattic\Jetpack\JITMS\JITM as JITMS_JITM;
12
use Automattic\Jetpack\JITM as JITM;
13
use Automattic\Jetpack\Connection\Plugin;
14
use Automattic\Jetpack\Sync\Main as Sync_Main;
15
16
/**
17
 * The configuration class.
18
 */
19
class Config {
20
21
	const FEATURE_ENSURED         = 1;
22
	const FEATURE_NOT_AVAILABLE   = 0;
23
	const FEATURE_ALREADY_ENSURED = -1;
24
25
	/**
26
	 * The initial setting values.
27
	 *
28
	 * @var Array
29
	 */
30
	protected $config = array(
31
		'jitm'       => false,
32
		'connection' => false,
33
		'sync'       => false,
34
	);
35
36
	/**
37
	 * Initialization options stored here.
38
	 *
39
	 * @var array
40
	 */
41
	protected $feature_options = array();
42
43
	/**
44
	 * Creates the configuration class instance.
45
	 */
46
	public function __construct() {
47
		/**
48
		 * Adding the config handler to run on priority 2 because the class itself is
49
		 * being constructed on priority 1.
50
		 */
51
		add_action( 'plugins_loaded', array( $this, 'on_plugins_loaded' ), 2 );
52
53
	}
54
55
	/**
56
	 * Require a feature to be initialized. It's up to the package consumer to actually add
57
	 * the package to their composer project. Declaring a requirement using this method
58
	 * instructs the class to initialize it.
59
	 *
60
	 * @param String $feature the feature slug.
61
	 * @param array  $options Additional options, optional.
62
	 */
63
	public function ensure( $feature, array $options = array() ) {
64
		$this->config[ $feature ] = true;
65
66
		$this->set_feature_options( $feature, $options );
67
	}
68
69
	/**
70
	 * Runs on plugins_loaded hook priority with priority 2.
71
	 *
72
	 * @action plugins_loaded
73
	 */
74
	public function on_plugins_loaded() {
75
		if ( $this->config['connection'] ) {
76
			$this->ensure_class( 'Automattic\Jetpack\Connection\Manager' )
77
				&& $this->ensure_feature( 'connection' );
78
		}
79
80
		if ( $this->config['sync'] ) {
81
			$this->ensure_class( 'Automattic\Jetpack\Sync\Main' )
82
				&& $this->ensure_feature( 'sync' );
83
		}
84
85
		if ( $this->config['jitm'] ) {
86
			// Check for the JITM class in both namespaces. The namespace was changed in jetpack-jitm v1.6.
87
			( $this->ensure_class( 'Automattic\Jetpack\JITMS\JITM', false )
88
				|| $this->ensure_class( 'Automattic\Jetpack\JITM' ) )
89
			&& $this->ensure_feature( 'jitm' );
90
		}
91
	}
92
93
	/**
94
	 * Returns true if the required class is available and alerts the user if it's not available
95
	 * in case the site is in debug mode.
96
	 *
97
	 * @param String  $classname a fully qualified class name.
98
	 * @param Boolean $log_notice whether the E_USER_NOTICE should be generated if the class is not found.
99
	 *
100
	 * @return Boolean whether the class is available.
101
	 */
102
	protected function ensure_class( $classname, $log_notice = true ) {
103
		$available = class_exists( $classname );
104
105
		if ( $log_notice && ! $available && defined( 'WP_DEBUG' ) && WP_DEBUG ) {
106
			trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
107
				sprintf(
108
					/* translators: %1$s is a PHP class name. */
109
					esc_html__(
110
						'Unable to load class %1$s. Please add the package that contains it using composer and make sure you are requiring the Jetpack autoloader',
111
						'jetpack'
112
					),
113
					esc_html( $classname )
114
				),
115
				E_USER_NOTICE
116
			);
117
		}
118
119
		return $available;
120
	}
121
122
	/**
123
	 * Ensures a feature is enabled, sets it up if it hasn't already been set up.
124
	 * Run the options method (if exists) every time the method is called.
125
	 *
126
	 * @param String $feature slug of the feature.
127
	 * @return Integer either FEATURE_ENSURED, FEATURE_ALREADY_ENSURED or FEATURE_NOT_AVAILABLE constants.
128
	 */
129
	protected function ensure_feature( $feature ) {
130
		$method = 'enable_' . $feature;
131
		if ( ! method_exists( $this, $method ) ) {
132
			return self::FEATURE_NOT_AVAILABLE;
133
		}
134
135
		$method_options = 'ensure_options_' . $feature;
136
		if ( method_exists( $this, $method_options ) ) {
137
			$this->{ $method_options }();
138
		}
139
140
		if ( did_action( 'jetpack_feature_' . $feature . '_enabled' ) ) {
141
			return self::FEATURE_ALREADY_ENSURED;
142
		}
143
144
		$this->{ $method }();
145
146
		/**
147
		 * Fires when a specific Jetpack package feature is initalized using the Config package.
148
		 *
149
		 * @since 8.2.0
150
		 */
151
		do_action( 'jetpack_feature_' . $feature . '_enabled' );
152
153
		return self::FEATURE_ENSURED;
154
	}
155
156
	/**
157
	 * Enables the JITM feature.
158
	 */
159
	protected function enable_jitm() {
160
		if ( class_exists( 'Automattic\Jetpack\JITMS\JITM' ) ) {
161
			JITMS_JITM::configure();
162
		} else {
163
			// Provides compatibility with jetpack-jitm <v1.6.
164
			JITM::configure();
165
		}
166
167
		return true;
168
	}
169
170
	/**
171
	 * Enables the Sync feature.
172
	 */
173
	protected function enable_sync() {
174
		Sync_Main::configure();
175
176
		return true;
177
	}
178
179
	/**
180
	 * Enables the Connection feature.
181
	 */
182
	protected function enable_connection() {
183
		Manager::configure();
184
185
		return true;
186
	}
187
188
	/**
189
	 * Setup the Connection options.
190
	 */
191
	protected function ensure_options_connection() {
192
		$options = $this->get_feature_options( 'connection' );
193
194
		if ( ! empty( $options['slug'] ) ) {
195
			// The `slug` and `name` are removed from the options because they need to be passed as arguments.
196
			$slug = $options['slug'];
197
			unset( $options['slug'] );
198
199
			$name = $slug;
200
			if ( ! empty( $options['name'] ) ) {
201
				$name = $options['name'];
202
				unset( $options['name'] );
203
			}
204
205
			( new Plugin( $slug ) )->add( $name, $options );
206
		}
207
208
		return true;
209
	}
210
211
	/**
212
	 * Temporary save initialization options for a feature.
213
	 *
214
	 * @param string $feature The feature slug.
215
	 * @param array  $options The options.
216
	 *
217
	 * @return bool
218
	 */
219
	protected function set_feature_options( $feature, array $options ) {
220
		if ( $options ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $options of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
221
			$this->feature_options[ $feature ] = $options;
222
		}
223
224
		return true;
225
	}
226
227
	/**
228
	 * Get initialization options for a feature from the temporary storage.
229
	 *
230
	 * @param string $feature The feature slug.
231
	 *
232
	 * @return array
233
	 */
234
	protected function get_feature_options( $feature ) {
235
		return empty( $this->feature_options[ $feature ] ) ? array() : $this->feature_options[ $feature ];
236
	}
237
238
}
239