Completed
Push — develop ( 0382bd...a61784 )
by Zack
21:58 queued 06:07
created

gvlogic::get_output()   D

Complexity

Conditions 20
Paths 36

Size

Total Lines 84

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 44
CRAP Score 20

Importance

Changes 0
Metric Value
cc 20
nc 36
nop 3
dl 0
loc 84
ccs 44
cts 44
cp 1
crap 20
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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