Completed
Push — add/recommended-features-state ( f510df...b9c995 )
by
unknown
130:08 queued 122:48
created

Config::ensure_feature()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 5
nop 1
dl 0
loc 26
rs 9.504
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;
12
use Automattic\Jetpack\Connection\Plugin;
13
use Automattic\Jetpack\Plugin\Tracking as Plugin_Tracking;
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
		'tracking'   => false,
35
		'tos'        => false,
36
	);
37
38
	/**
39
	 * Initialization options stored here.
40
	 *
41
	 * @var array
42
	 */
43
	protected $feature_options = array();
44
45
	/**
46
	 * Creates the configuration class instance.
47
	 */
48
	public function __construct() {
49
		/**
50
		 * Adding the config handler to run on priority 2 because the class itself is
51
		 * being constructed on priority 1.
52
		 */
53
		add_action( 'plugins_loaded', array( $this, 'on_plugins_loaded' ), 2 );
54
55
	}
56
57
	/**
58
	 * Require a feature to be initialized. It's up to the package consumer to actually add
59
	 * the package to their composer project. Declaring a requirement using this method
60
	 * instructs the class to initialize it.
61
	 *
62
	 * @param String $feature the feature slug.
63
	 * @param array  $options Additional options, optional.
64
	 */
65
	public function ensure( $feature, array $options = array() ) {
66
		$this->config[ $feature ] = true;
67
68
		$this->set_feature_options( $feature, $options );
69
	}
70
71
	/**
72
	 * Runs on plugins_loaded hook priority with priority 2.
73
	 *
74
	 * @action plugins_loaded
75
	 */
76
	public function on_plugins_loaded() {
77
		if ( $this->config['connection'] ) {
78
			$this->ensure_class( 'Automattic\Jetpack\Connection\Manager' )
79
				&& $this->ensure_feature( 'connection' );
80
		}
81
82
		if ( $this->config['tracking'] ) {
83
			$this->ensure_class( 'Automattic\Jetpack\Terms_Of_Service' )
84
				&& $this->ensure_class( 'Automattic\Jetpack\Tracking' )
85
				&& $this->ensure_feature( 'tracking' );
86
		}
87
88
		if ( $this->config['sync'] ) {
89
			$this->ensure_class( 'Automattic\Jetpack\Sync\Main' )
90
				&& $this->ensure_feature( 'sync' );
91
		}
92
93
		if ( $this->config['jitm'] ) {
94
			$this->ensure_class( 'Automattic\Jetpack\JITMS\JITM' )
95
				&& $this->ensure_feature( 'jitm' );
96
		}
97
	}
98
99
	/**
100
	 * Returns true if the required class is available and alerts the user if it's not available
101
	 * in case the site is in debug mode.
102
	 *
103
	 * @param String $classname a fully qualified class name.
104
	 * @return Boolean whether the class is available.
105
	 */
106
	protected function ensure_class( $classname ) {
107
		$available = class_exists( $classname );
108
109
		if ( ! $available && defined( 'WP_DEBUG' ) && WP_DEBUG ) {
110
			trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
111
				sprintf(
112
					/* translators: %1$s is a PHP class name. */
113
					esc_html__(
114
						'Unable to load class %1$s. Please add the package that contains it using composer and make sure you are requiring the Jetpack autoloader',
115
						'jetpack'
116
					),
117
					esc_html( $classname )
118
				),
119
				E_USER_NOTICE
120
			);
121
		}
122
123
		return $available;
124
	}
125
126
	/**
127
	 * Ensures a feature is enabled, sets it up if it hasn't already been set up.
128
	 * Run the options method (if exists) every time the method is called.
129
	 *
130
	 * @param String $feature slug of the feature.
131
	 * @return Integer either FEATURE_ENSURED, FEATURE_ALREADY_ENSURED or FEATURE_NOT_AVAILABLE constants.
132
	 */
133
	protected function ensure_feature( $feature ) {
134
		$method = 'enable_' . $feature;
135
		if ( ! method_exists( $this, $method ) ) {
136
			return self::FEATURE_NOT_AVAILABLE;
137
		}
138
139
		$method_options = 'ensure_options_' . $feature;
140
		if ( method_exists( $this, $method_options ) ) {
141
			$this->{ $method_options }();
142
		}
143
144
		if ( did_action( 'jetpack_feature_' . $feature . '_enabled' ) ) {
145
			return self::FEATURE_ALREADY_ENSURED;
146
		}
147
148
		$this->{ $method }();
149
150
		/**
151
		 * Fires when a specific Jetpack package feature is initalized using the Config package.
152
		 *
153
		 * @since 8.2.0
154
		 */
155
		do_action( 'jetpack_feature_' . $feature . '_enabled' );
156
157
		return self::FEATURE_ENSURED;
158
	}
159
160
	/**
161
	 * Dummy method to enable Terms of Service.
162
	 */
163
	protected function enable_tos() {
164
		return true;
165
	}
166
167
	/**
168
	 * Enables the tracking feature. Depends on the Terms of Service package, so enables it too.
169
	 */
170
	protected function enable_tracking() {
171
172
		// Enabling dependencies.
173
		$this->ensure_feature( 'tos' );
174
175
		$terms_of_service = new Terms_Of_Service();
176
		$tracking         = new Plugin_Tracking();
177
		if ( $terms_of_service->has_agreed() ) {
178
			add_action( 'init', array( $tracking, 'init' ) );
179
		} else {
180
			/**
181
			 * Initialize tracking right after the user agrees to the terms of service.
182
			 */
183
			add_action( 'jetpack_agreed_to_terms_of_service', array( $tracking, 'init' ) );
184
		}
185
186
		return true;
187
	}
188
189
	/**
190
	 * Enables the JITM feature.
191
	 */
192
	protected function enable_jitm() {
193
		JITM::configure();
194
195
		return true;
196
	}
197
198
	/**
199
	 * Enables the Sync feature.
200
	 */
201
	protected function enable_sync() {
202
		Sync_Main::configure();
203
204
		return true;
205
	}
206
207
	/**
208
	 * Enables the Connection feature.
209
	 */
210
	protected function enable_connection() {
211
		Manager::configure();
212
213
		return true;
214
	}
215
216
	/**
217
	 * Setup the Connection options.
218
	 */
219
	protected function ensure_options_connection() {
220
		$options = $this->get_feature_options( 'connection' );
221
222
		if ( ! empty( $options['slug'] ) ) {
223
			// The `slug` and `name` are removed from the options because they need to be passed as arguments.
224
			$slug = $options['slug'];
225
			unset( $options['slug'] );
226
227
			$name = $slug;
228
			if ( ! empty( $options['name'] ) ) {
229
				$name = $options['name'];
230
				unset( $options['name'] );
231
			}
232
233
			( new Plugin( $slug ) )->add( $name, $options );
234
		}
235
236
		return true;
237
	}
238
239
	/**
240
	 * Temporary save initialization options for a feature.
241
	 *
242
	 * @param string $feature The feature slug.
243
	 * @param array  $options The options.
244
	 *
245
	 * @return bool
246
	 */
247
	protected function set_feature_options( $feature, array $options ) {
248
		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...
249
			$this->feature_options[ $feature ] = $options;
250
		}
251
252
		return true;
253
	}
254
255
	/**
256
	 * Get initialization options for a feature from the temporary storage.
257
	 *
258
	 * @param string $feature The feature slug.
259
	 *
260
	 * @return array
261
	 */
262
	protected function get_feature_options( $feature ) {
263
		return empty( $this->feature_options[ $feature ] ) ? array() : $this->feature_options[ $feature ];
264
	}
265
266
}
267