Completed
Push — develop ( faed85...5d0bd3 )
by Zack
04:39
created

GravityView_Extension   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 363
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 0
loc 363
rs 8.2608
c 0
b 0
f 0
wmc 40
lcom 1
cbo 4

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 22 2
A tab_settings() 0 4 1
B add_metabox_tab() 0 37 3
B load_plugin_textdomain() 0 35 6
A get_license() 0 10 2
D settings() 0 36 9
A admin_notice() 0 17 3
B add_notice() 0 13 5
A add_hooks() 0 1 1
A save_post() 0 1 1
A tooltips() 0 5 1
B is_extension_supported() 0 35 6

How to fix   Complexity   

Complex Class

Complex classes like GravityView_Extension 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 GravityView_Extension, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @package GravityView
4
 * @license   GPL2+
5
 * @author    Katz Web Services, Inc.
6
 * @link      https://gravityview.co
7
 * @copyright Copyright 2015, Katz Web Services, Inc.
8
 */
9
10
/**
11
 * Extend this class to create a GravityView extension that gets updates from GravityView.co
12
 *
13
 * @since 1.1
14
 *
15
 * @version 1.1.2 Fixed `/lib/` include path for EDDSL
16
 */
17
abstract class GravityView_Extension {
18
19
	/**
20
	 * @var string Name of the plugin in gravityview.co
21
	 */
22
	protected $_title = NULL;
0 ignored issues
show
Coding Style introduced by
TRUE, FALSE and NULL must be lowercase; expected null, but found NULL.
Loading history...
23
24
	/**
25
	 * @var string Version number of the plugin
26
	 */
27
	protected $_version = NULL;
0 ignored issues
show
Coding Style introduced by
TRUE, FALSE and NULL must be lowercase; expected null, but found NULL.
Loading history...
28
29
	/**
30
	 * @var int The ID of the download on gravityview.co
31
	 * @since 1.1
32
	 */
33
	protected $_item_id = NULL;
0 ignored issues
show
Coding Style introduced by
TRUE, FALSE and NULL must be lowercase; expected null, but found NULL.
Loading history...
34
35
	/**
36
	 * @var string Translation textdomain
37
	 */
38
	protected $_text_domain = 'gravityview';
39
40
	/**
41
	 * @var string Minimum version of GravityView the Extension requires
42
	 */
43
	protected $_min_gravityview_version = '1.1.5';
44
45
	/**
46
	 * @var string Minimum version of GravityView the Extension requires
47
	 */
48
	protected $_min_php_version = '5.2.4';
49
50
	/**
51
	 * @var string The URL to fetch license info from. Do not change unless you know what you're doing.
52
	 */
53
	protected $_remote_update_url = 'https://gravityview.co';
54
55
	/**
56
	 * @var string Author of plugin, sent when fetching license info.
57
	 */
58
	protected $_author = 'Katz Web Services, Inc.';
59
60
	/**
61
	 * @var array Admin notices to display
62
	 */
63
	static private $admin_notices = array();
64
65
	/**
66
	 * @var bool Is the extension able to be run based on GV version and whether GV is activated
67
	 */
68
	static $is_compatible = true;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $is_compatible.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
69
70
	function __construct() {
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...
71
72
		add_action( 'init', array( $this, 'load_plugin_textdomain' ) );
73
74
		add_action( 'admin_init', array( $this, 'settings') );
0 ignored issues
show
introduced by
No space before closing parenthesis of array is bad style
Loading history...
75
76
		add_action( 'admin_notices', array( $this, 'admin_notice' ), 100 );
77
78
		add_action( 'gravityview/metaboxes/before_render', array( $this, 'add_metabox_tab' ) );
79
80
		if( false === $this->is_extension_supported() ) {
81
			return;
82
		}
83
84
		add_filter( 'gravityview_tooltips', array( $this, 'tooltips' ) );
85
86
		// Save the form configuration. Run at 14 so that View metadata is already saved (at 10)
87
		add_action( 'save_post', array( $this, 'save_post' ), 14 );
88
89
		$this->add_hooks();
90
91
	}
92
93
	/**
94
	 * Add a tab to GravityView Edit View tabbed metabox. By overriding this method, you will add a tab to View settings
95
	 *
96
	 * @since 1.8 (Extension version 1.0.7)
97
	 *
98
	 * @see https://gist.github.com/zackkatz/6cc381bcf54849f2ed41 For example of adding a metabox
99
	 *
100
	 * @return array Array of metabox
101
	 */
102
	protected function tab_settings() {
103
		// When overriding, return array with expected keys
104
		return array();
105
	}
106
107
	/**
108
	 * If Extension overrides tab_settings() and passes its own tab, add it to the tabbed settings metabox
109
	 *
110
	 * @since 1.8 (Extension version 1.0.7)
111
	 *
112
	 * @return void
113
	 */
114
	function add_metabox_tab() {
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...
115
116
		$tab_settings = $this->tab_settings();
117
118
		// Don't add a tab if it's empty.
119
		if( empty( $tab_settings ) ) {
120
			return;
121
		}
122
123
		$tab_defaults = array(
124
			'id' => '',
125
			'title' => '',
126
			'callback' => '',
127
			'icon-class' => '',
128
			'file' => '',
129
			'callback_args' => '',
130
			'context' => 'side',
131
			'priority' => 'default',
132
		);
133
134
		$tab = wp_parse_args( $tab_settings, $tab_defaults );
135
136
		// Force the screen to be GravityView
137
		$tab['screen'] = 'gravityview';
138
139
		if( class_exists('GravityView_Metabox_Tab') ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
140
141
			$metabox = new GravityView_Metabox_Tab( $tab['id'], $tab['title'], $tab['file'], $tab['icon-class'], $tab['callback'], $tab['callback_args'] );
142
143
			GravityView_Metabox_Tabs::add( $metabox );
144
145
		} else {
146
147
			add_meta_box( 'gravityview_'.$tab['id'], $tab['title'], $tab['callback'], $tab['screen'], $tab['context'], $tab['priority'] );
148
149
		}
150
	}
151
152
	/**
153
	 * Load translations for the extension
154
	 *
155
	 * 1. Check  `wp-content/languages/gravityview/` folder and load using `load_textdomain()`
156
	 * 2. Check  `wp-content/plugins/gravityview/languages/` folder for `gravityview-[locale].mo` file and load using `load_textdomain()`
157
	 * 3. Load default file using `load_plugin_textdomain()` from `wp-content/plugins/gravityview/languages/`
158
	 *
159
	 * @return void
160
	 */
161
	public function load_plugin_textdomain() {
162
163
		if( empty( $this->_text_domain ) ) {
164
			do_action( 'gravityview_log_debug', __METHOD__ . ': Extension translation cannot be loaded; the `_text_domain` variable is not defined', $this );
165
			return;
166
		}
167
168
		// Backward compat for Ratings & Reviews / Maps
169
		$path = isset( $this->_path ) ? $this->_path : ( isset( $this->plugin_file ) ? $this->plugin_file : '' );
0 ignored issues
show
Bug introduced by
The property _path does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Bug introduced by
The property plugin_file does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
170
171
		// Set filter for plugin's languages directory
172
		$lang_dir = dirname( plugin_basename( $path ) ) . '/languages/';
173
174
		// Traditional WordPress plugin locale filter
175
		$locale = apply_filters( 'plugin_locale',  get_locale(), $this->_text_domain );
176
177
		$mofile = sprintf( '%1$s-%2$s.mo', $this->_text_domain, $locale );
178
179
		// Setup paths to current locale file
180
		$mofile_local  = $lang_dir . $mofile;
181
		$mofile_global = WP_LANG_DIR . '/' . $this->_text_domain . '/' . $mofile;
182
183
		if ( file_exists( $mofile_global ) ) {
184
			// Look in global /wp-content/languages/[plugin-dir]/ folder
185
			load_textdomain( $this->_text_domain, $mofile_global );
186
		}
187
		elseif ( file_exists( $mofile_local ) ) {
188
			// Look in local /wp-content/plugins/[plugin-dir]/languages/ folder
189
			load_textdomain( $this->_text_domain, $mofile_local );
190
		}
191
		else {
192
			// Load the default language files
193
			load_plugin_textdomain( $this->_text_domain, false, $lang_dir );
194
		}
195
	}
196
197
	/**
198
	 * Get license information from GravityView
199
	 *
200
	 * @since 1.8 (Extension version 1.0.7)
201
	 * @return bool|array False: GravityView_Settings class does not exist. Array: array of GV license data.
202
	 */
203
	protected function get_license() {
204
205
		if( !class_exists( 'GravityView_Settings' ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
206
			return false;
207
		}
208
209
		$license = GravityView_Settings::getSetting('license');
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
210
211
		return $license;
212
	}
213
214
	/**
215
	 * Register the updater for the Extension using GravityView license information
216
	 *
217
	 * @return void
218
	 */
219
	public function settings() {
220
221
		// If doing ajax, get outta here
222
		if( ! is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) )  {
223
			return;
224
		}
225
226
		if( !class_exists( 'EDD_SL_Plugin_Updater' ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
227
228
			$file_path = plugin_dir_path( __FILE__ ) . 'lib/EDD_SL_Plugin_Updater.php';
229
230
			// This file may be in the lib/ directory already
231
			if( ! file_exists( $file_path ) ) {
232
				$file_path = plugin_dir_path( __FILE__ ) . '/EDD_SL_Plugin_Updater.php';
233
			}
234
235
			include_once $file_path;
236
		}
237
238
		$license = $this->get_license();
239
240
		// Don't update if invalid license.
241
		if( false === $license || empty( $license['status'] ) || strtolower( $license['status'] ) !== 'valid' ) { return; }
0 ignored issues
show
introduced by
Found "!== '". Use Yoda Condition checks, you must
Loading history...
242
243
		new EDD_SL_Plugin_Updater(
244
			$this->_remote_update_url,
245
			$this->_path,
246
			array(
247
            	'version'	=> $this->_version, // current version number
248
            	'license'	=> $license['license'],
249
	            'item_id'   => $this->_item_id, // The ID of the download on _remote_update_url
250
            	'item_name' => $this->_title,  // name of this plugin
251
            	'author' 	=> strip_tags( $this->_author )  // author of this plugin
252
          	)
253
        );
254
	}
255
256
	/**
257
	 * Outputs the admin notices generated by the plugin
258
	 *
259
	 * @return void
260
	 */
261
	public function admin_notice() {
262
263
		if( empty( self::$admin_notices ) ) {
264
			return;
265
		}
266
267
		foreach( self::$admin_notices as $key => $notice ) {
268
269
			echo '<div id="message" class="'. esc_attr( $notice['class'] ).'">';
270
			echo wpautop( $notice['message'] );
0 ignored issues
show
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'wpautop'
Loading history...
271
			echo '<div class="clear"></div>';
272
			echo '</div>';
273
		}
274
275
		//reset the notices handler
276
		self::$admin_notices = array();
277
	}
278
279
	/**
280
	 * Add a notice to be displayed in the admin.
281
	 * @param array $notice Array with `class` and `message` keys. The message is not escaped.
282
	 */
283
	public static function add_notice( $notice = array() ) {
284
285
		if( is_array( $notice ) && !isset( $notice['message'] ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
286
			do_action( 'gravityview_log_error', __CLASS__.'[add_notice] Notice not set', $notice );
287
			return;
288
		} else if( is_string( $notice ) ) {
289
			$notice = array( 'message' => $notice );
290
		}
291
292
		$notice['class'] = empty( $notice['class'] ) ? 'error' : $notice['class'];
293
294
		self::$admin_notices[] = $notice;
295
	}
296
297
	/**
298
	 * Extensions should override this hook to add their hooks instead of
299
	 */
300
	public function add_hooks() { }
301
302
	/**
303
	 * Store the filter settings in the `_gravityview_filters` post meta
304
	 * @param  int $post_id Post ID
305
	 * @return void
306
	 */
307
	public function save_post( $post_id ) {}
0 ignored issues
show
Unused Code introduced by
The parameter $post_id 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...
308
309
	/**
310
	 * Add tooltips for the extension.
311
	 *
312
	 * Add a tooltip with an array using the `title` and `value` keys. The `title` key is the H6 tag value of the tooltip; it's the headline. The `value` is the tooltip content, and can contain any HTML.
313
	 *
314
	 * The tooltip key must be `gv_{name_of_setting}`. If the name of the setting is "example_extension_setting", the code would be:
315
	 *
316
	 * <code>
317
	 * $tooltips['gv_example_extension_setting'] = array(
318
	 * 	'title'	=> 'About Example Extension Setting',
319
	 *  'value'	=> 'When you do [x] with [y], [z] happens.'
320
	 * );
321
	 * </code>
322
	 *
323
	 * @param  array  $tooltips Existing GV tooltips, with `title` and `value` keys
324
	 * @return array           Modified tooltips
325
	 */
326
	public function tooltips( $tooltips = array() ) {
327
328
		return $tooltips;
329
330
	}
331
332
	/**
333
	 * Check whether the extension is supported:
334
	 *
335
	 * - Checks if GravityView and Gravity Forms exist
336
	 * - Checks GravityView and Gravity Forms version numbers
337
	 * - Checks PHP version numbers
338
	 * - Sets self::$is_compatible to boolean value
339
	 *
340
	 * @uses GravityView_Admin::check_gravityforms()
341
	 * @return boolean Is the extension supported?
342
	 */
343
	protected function is_extension_supported() {
344
345
		self::$is_compatible = true;
346
347
		$message = '';
348
349
		if( !class_exists( 'GravityView_Plugin' ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
350
351
			$message = sprintf( __('Could not activate the %s Extension; GravityView is not active.', 'gravityview'), $this->_title );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
352
353
		} else if( false === version_compare(GravityView_Plugin::version, $this->_min_gravityview_version , ">=") ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
Coding Style Comprehensibility introduced by
The string literal >= does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
354
355
			$message = sprintf( __('The %s Extension requires GravityView Version %s or newer.', 'gravityview' ), $this->_title, '<tt>'.$this->_min_gravityview_version.'</tt>' );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
introduced by
Expected next thing to be a escaping function, not '$this'
Loading history...
356
357
		} else if( isset( $this->_min_php_version ) && false === version_compare( phpversion(), $this->_min_php_version , ">=") ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
Coding Style Comprehensibility introduced by
The string literal >= does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
358
359
			$message = sprintf( __('The %s Extension requires PHP Version %s or newer. Please ask your host to upgrade your server\'s PHP.', 'gravityview' ), $this->_title, '<tt>'.$this->_min_php_version.'</tt>' );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
introduced by
Expected next thing to be a escaping function, not '$this'
Loading history...
360
361
		} else {
362
363
			self::$is_compatible = GravityView_Compatibility::is_valid();
0 ignored issues
show
Deprecated Code introduced by
The method GravityView_Compatibility::is_valid() has been deprecated.

This method has been deprecated.

Loading history...
364
365
		}
366
367
		if ( ! empty( $message ) ) {
368
369
			self::add_notice( $message );
370
371
			do_action( 'gravityview_log_error', __METHOD__. ' ' . $message );
372
373
			self::$is_compatible = false;
374
		}
375
376
		return self::$is_compatible;
377
	}
378
379
}
380