Completed
Push — develop ( 0f41f0...4939cc )
by Zack
25:11 queued 19:29
created

gvlogic   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 283
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 94.44%

Importance

Changes 0
Metric Value
dl 0
loc 283
ccs 102
cts 108
cp 0.9444
rs 8.5599
c 0
b 0
f 0
wmc 48
lcom 1
cbo 4

8 Methods

Rating   Name   Duplication   Size   Complexity  
A add() 0 9 1
B callback() 0 35 9
A authorized() 0 6 2
A get_operator() 0 15 4
A get_value() 0 15 4
D get_output() 0 78 20
A get_operators() 0 18 2
B parse_atts() 0 41 6

How to fix   Complexity   

Complex Class

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

1
<?php
2
namespace GV\Shortcodes;
3
4
/** If this file is called directly, abort. */
5
if ( ! defined( 'GRAVITYVIEW_DIR' ) ) {
6
	die();
7
}
8
9
/**
10
 * The [gvlogic] shortcode.
11
 */
12
class gvlogic extends \GV\Shortcode {
13
	/**
14
	 * {@inheritDoc}
15
	 */
16
	public $name = 'gvlogic';
17
18
	/**
19
	 * {@inheritDoc}
20
	 */
21
	public static function add( $name = null ) {
22
		parent::add(); // Me, myself and...
23
24
		/**
25
		 * ...some aliases.
26
		 */
27
		parent::add( 'gvlogic2' );
28
		parent::add( 'gvlogicelse' );
29
	}
30
31
	/**
32
	 * Process and output the [gvfield] shortcode.
33
	 *
34
	 * @param array $atts The attributes passed.
35
	 * @param string $content The content inside the shortcode.
36
	 * @param string $tag The tag.
37
	 *
38
	 * @return string The output.
39
	 */
40 25
	public function callback( $atts, $content = '', $tag = '' ) {
41 25
		$request = gravityview()->request;
42
43 25
		if ( $request->is_admin() ) {
44
			return apply_filters( 'gravityview/shortcodes/gvlogic/output', '', $atts );
45
		}
46
47 25
		$atts = $this->parse_atts( $atts, $content, $tag );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $atts is correct as $this->parse_atts($atts, $content, $tag) (which targets GV\Shortcodes\gvlogic::parse_atts()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
48
49
		// An invalid operation
50 25
		if ( is_null( \GV\Utils::get( $atts, 'logged_in', null ) ) && false === \GV\Utils::get( $atts, 'if', false ) ) {
51 2
			gravityview()->log->error( '$atts->if/logged_in is empty.', array( 'data' => $atts ) );
52 2
			return apply_filters( 'gravityview/shortcodes/gvlogic/output', '', $atts );
53
		}
54
55 24
		$authed   = $this->authorized( $atts );
56 24
		$operator = $this->get_operator( $atts );
57 24
		$value    = $this->get_value( $atts );
58
59 24
		if ( false === $operator && is_null( $value ) ) {
60 5
			if ( false !== $atts['if'] ) { // Only-if test
61 4
				$match = $authed && ! in_array( strtolower( $atts['if'] ), array( '', '0', 'false', 'no' ) );
62
			} else {
63 5
				$match = $authed; // Just login test
64
			}
65
		} else { // Regular test
66 24
			$match = $authed && \GVCommon::matches_operation( $atts['if'], $value, $operator );
67
		}
68
69
		// Output and get recursive!
70 24
		$output = do_shortcode( $this->get_output( $match, $atts, $content ) );
71 24
		$output = \GFCommon::replace_variables( $output, array(), array(), false, true, false );
72
73 24
		return apply_filters( 'gravityview/shortcodes/gvlogic/output', $output, $atts );
74
	}
75
76
	/**
77
	 * Are we authorized to follow the if path?
78
	 *
79
	 * @param array $atts The attributes.
80
	 *
81
	 * @return bool Yes, or no.
82
	 */
83 24
	private function authorized( $atts ) {
84 24
		if ( is_null( $needs_login  = \GV\Utils::get( $atts, 'logged_in', null ) ) ) {
85 24
			return true; // No auth requirements have been set
86
		}
87 1
		return ! $needs_login ^ is_user_logged_in(); // XNOR
88
	}
89
90
	/**
91
	 * Fetch the operator.
92
	 *
93
	 * @param array $atts The attributes.
94
	 *
95
	 * @return bool|string The operator.
96
	 */
97 24
	private function get_operator( $atts ) {
98 24
		$valid_ops = $this->get_operators( false );
99
100 24
		foreach ( $atts as $op => $value ) {
101 24
			if ( in_array( $op, array( 'if', 'else' ) ) ) {
102 24
				continue;
103
			}
104
105 24
			if ( in_array( $op, $valid_ops, true ) ) {
106 24
				return $op;
107
			}
108
		}
109
110 5
		return false;
111
	}
112
113
	/**
114
	 * Fetch the value.
115
	 *
116
	 * @param array $atts The attributes.
117
	 *
118
	 * @return null|string The value.
119
	 */
120 24
	private function get_value( $atts ) {
121 24
		$valid_ops = $this->get_operators( false );
122
123 24
		foreach ( $atts as $op => $value ) {
124 24
			if ( in_array( $op, array( 'if', 'else' ) ) ) {
125 24
				continue;
126
			}
127
128 24
			if ( in_array( $op, $valid_ops, true ) ) {
129 24
				return $value;
130
			}
131
		}
132
133 5
		return null;
134
	}
135
136
	/**
137
	 * Get the ouput content.
138
	 *
139
	 * @param bool $match if or else?
140
	 * @param array $atts The attributes.
141
	 * @param string $content The content.
142
	 *
143
	 * @return string The output.
144
	 */
145 24
	private function get_output( $match, $atts, $content ) {
146 24
		if ( ! $match && ! empty( $atts['else'] ) ) {
147 4
			return $atts['else']; // Attributized else is easy :)
148
		}
149
150 24
		$if = '';
151 24
		$else = '';
152
153 24
		$opens = 0; // inner opens
154 24
		$found = false; // found split position
155
156 24
		while ( $content ) { // scan
157 24
			if ( ! preg_match( '#(.*?)(\[\/?(gvlogic|else).*?])(.*)#', $content, $matches ) ) {
158 24
				if ( ! $found ) { // We're still iffing.
159 20
					$if .= $content;
160
				} else { // We are elsing
161 8
					$else .= $content;
162
				}
163 24
				break; // No more shortcodes
164
			}
165
166 8
			list( $_, $before_shortcode, $shortcode, $_, $after_shortcode ) = $matches;
167
168 8
			if ( ! $found ) { // We're still iffing.
169 8
				$if .= $before_shortcode;
170
			} else { // We are elsing
171 1
				$else .= $before_shortcode;
172
			}
173
174 8
			if ( strpos( $shortcode, '[else]' ) === 0 && $opens === 0 ) {
175
				// This is the else we need!
176 8
				$found = true;
177 8
				if ( $match ) {
178 8
					break; // We just need the if on a match, no need to analyze further
179
				}
180 2
			} else if ( $match && strpos( $shortcode, '[else if' ) === 0 && $opens === 0 ) {
181 1
				$found = true; // We found a match, do not process further
182 1
				break;
183
			} else {
184
				// Increment inner tracking counters
185 2
				if ( strpos( $shortcode, '[gvlogic' ) === 0 ) {
186 1
					$opens++;
187
				}
188
189 2
				if ( strpos( $shortcode, '[/gvlogic' ) === 0 ) {
190 1
					$opens--;
191
				}
192
193
				// Tack on the shortcode
194 2
				if ( ! $found ) { // We're still iffing.
195 2
					$if .= $shortcode;
196
				} else { // We are elsing
197 1
					$else .= $shortcode;
198
				}
199
			}
200
201 8
			$content = $after_shortcode;
202
		}
203
204 24
		gravityview()->log->error( 'if => {if}, else => {else}', array( 'if' => $if, 'else' => $else ) );
205
		
206 24
		if ( ! $match ) {
207 16
			while ( ( $position = strpos( $if, '[else if=' ) ) !== false ) {
208
				// Try to match one of the elseif's
209 1
				$sentinel = wp_generate_password( 32, false );
210 1
				$if = substr( $if, $position ); // ...by replacing it with a gvlogic shortcode
211
				// ..and executing it!
212 1
				$result = do_shortcode( preg_replace( '#\[else if#', '[gvlogic if', $if, 1 ) . "[else]{$sentinel}[/gvlogic]" );
213 1
				if ( $result !== $sentinel ) {
214
					// We have an elseif match!
215 1
					return $result;
216
				}
217 1
				$if = substr( $if, 1 ); // Move over to get the next elseif match.. and repeat
218
			}
219
		}
220
221 24
		return $match ? $if : $else;
222
	}
223
224
	/**
225
	 * Get array of supported operators
226
	 * @param bool $with_values
227
	 *
228
	 * @return array
229
	 */
230 25
	private function get_operators( $with_values = false ) {
231
232
		$operators = array(
233 25
			'is', 'isnot', 'contains', 'starts_with', 'ends_with',
234
			'greater_than', 'less_than', 'in', 'not_in', 'isnot',
235
			'contains', 'equals', 'greater_than_or_is', 'greater_than_or_equals',
236
			'less_than_or_is', 'less_than_or_equals', 'not_contains',
237
		);
238
239 25
		if ( $with_values ) {
240 25
			return array_combine( 
241 25
				$operators,
242 25
				array_fill( 0, count( $operators ), '' )
243
			);
244
		}
245
246 24
		return $operators;
247
	}
248
249
	/**
250
	 * Process the attributes passed to the shortcode. Make sure they're valid
251
	 * @return void
252
	 */
253 25
	private function parse_atts( $atts, $content, $tag ) {
0 ignored issues
show
Unused Code introduced by
The parameter $content 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...
254 25
		$supplied_atts = $atts;
255
256 25
		if ( empty( $supplied_atts ) ) {
257 1
			$supplied_atts = array();
258
		}
259
260 25
		$atts = shortcode_atts( array(
261
			'if'        => null,
262
			'else'      => null,
263
			'logged_in' => null,
264 25
		) + $this->get_operators( true ), $atts, $tag );
265
266
		// Only keep the passed attributes after making sure that they're valid pairs
267 25
		$atts = array_intersect_key( $supplied_atts, $atts );
268
269
		// Strip whitespace if it's not default false
270 25
		if ( isset( $atts['if'] ) && is_string( $atts['if'] ) ) {
271 24
			$atts['if'] = trim( $atts['if'] );
272
		} else {
273 2
			$atts['if'] = false;
274
		}
275
276 25
		if ( isset( $atts['logged_in'] ) ) {
277
			// Truthy
278 1
			if ( in_array( strtolower( $atts['logged_in'] ), array( '0', 'false', 'no' ) ) ) {
279 1
				$atts['logged_in'] = false;
280
			} else {
281 1
				$atts['logged_in'] = true;
282
			}
283
		}
284
285
		/**
286
		 * @filter `gravityview/gvlogic/atts` The logic attributes.
287
		 *
288
		 * @since develop
289
		 *
290
		 * @param[in,out] array $atts The logic attributes.
291
		 */
292 25
		return apply_filters( 'gravityview/gvlogic/atts', $atts );
293
	}
294
}
295