Passed
Push — develop ( c6dd2a...1f8334 )
by Paul
03:38
created

Base::multiInputArgs()   C

Complexity

Conditions 14
Paths 84

Size

Total Lines 51
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 30
nc 84
nop 3
dl 0
loc 51
rs 5.6426
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
3
namespace GeminiLabs\Castor\Forms\Fields;
4
5
use Exception;
6
use GeminiLabs\Castor\Services\Normalizer;
7
8
abstract class Base
9
{
10
	/**
11
	 * @var array
12
	 */
13
	protected $args;
14
15
	/**
16
	 * @var array
17
	 */
18
	protected $dependencies = [];
19
20
	/**
21
	 * Whether the field has multiple values
22
	 *
23
	 * @var bool
24
	 */
25
	protected $multi = false;
26
27
	/**
28
	 * Whether the field is rendered outside of the form table
29
	 *
30
	 * @var bool
31
	 */
32
	protected $outside = false;
33
34
	/**
35
	 * The field element tag (i.e. "input")
36
	 *
37
	 * @var string
38
	 */
39
	protected $element;
40
41
	public function __construct( array $args = [] )
42
	{
43
		$this->args = $args;
44
	}
45
46
	/**
47
	 * @param string $property
48
	 *
49
	 * @return mixed
50
	 * @throws Exception
51
	 */
52
	public function __get( $property )
53
	{
54
		switch( $property ) {
55
			case 'args':
56
			case 'dependencies':
57
			case 'element':
58
			case 'multi':
59
			case 'outside':
60
				return $this->$property;
61
		}
62
		throw new Exception( sprintf( 'Invalid %s property: %s', __CLASS__, $property ));
63
	}
64
65
	/**
66
	 * Generate the field description
67
	 *
68
	 * @param bool $paragraph
69
	 *
70
	 * @return null|string
71
	 */
72
	public function generateDescription( $paragraph = true )
73
	{
74
		if( !isset( $this->args['desc'] ) || !$this->args['desc'] )return;
75
76
		$tag = ( !!$paragraph || $paragraph == 'p' ) ? 'p' : 'span';
77
78
		return sprintf( '<%1$s class="description">%2$s</%1$s>', $tag, $this->args['desc'] );
79
	}
80
81
	/**
82
	 * Generate the field label
83
	 *
84
	 * @return null|string
85
	 */
86
	public function generateLabel()
87
	{
88
		if( empty( $this->args['label'] ))return;
89
90
		$for = !!$this->args['id']
91
			? " for=\"{$this->args['id']}\""
92
			: '';
93
94
		return sprintf( '<label%s>%s</label>', $for, $this->args['label'] );
95
	}
96
97
	/**
98
	 * Render this field type
99
	 *
100
	 * @return string
101
	 */
102
	abstract public function render();
103
104
	/**
105
	 * Convert a value to camel case.
106
	 *
107
	 * @param string $value
108
	 *
109
	 * @return string
110
	 */
111
	protected function camelCase( $value )
112
	{
113
		$value = ucwords( str_replace( ['-', '_'], ' ', $value ));
114
115
		return lcfirst( str_replace( ' ', '', $value ));
116
	}
117
118
	/**
119
	 * Implode the field attributes
120
	 *
121
	 * @return array
122
	 */
123
	protected function implodeAttributes( $defaults = [] )
124
	{
125
		return $this->normalize( $defaults, 'implode' );
126
	}
127
128
	/**
129
	 * Implode multi-field items
130
	 *
131
	 * @return null|string
132
	 */
133
	protected function implodeOptions( $method = 'select_option', $default = null )
134
	{
135
		$this->args['default'] ?: $this->args['default'] = $default;
136
137
		$method = $this->camelCase( $method );
138
139
		$method = method_exists( $this, $method )
140
			? $method
141
			: 'selectOption';
142
143
		$i = 0;
144
145
		if( $method === 'singleInput' ) {
146
147
			if( !isset( $this->args['options'] ) || empty( $this->args['options'] ))return;
148
149
			// hack to make sure unset single checkbox values start at 1 instead of 0
150
			if( key( $this->args['options'] ) === 0 ) {
151
				$options = ['1' => $this->args['options'][0]];
152
				$this->args['options'] = $options;
153
			}
154
155
			return $this->singleInput();
156
		}
157
158
		return array_reduce( array_keys( $this->args['options'] ), function( $carry, $key ) use ( &$i, $method ) {
159
			return $carry .= $this->$method( $key, $i++ );
160
		});
161
	}
162
163
	/**
164
	 * Normalize attributes for this specific field type
165
	 *
166
	 * @param bool|string $implode
167
	 *
168
	 * @return array
169
	 */
170
	protected function normalize( array $defaults = [], $implode = false )
171
	{
172
		$args = $this->mergeAttributesWith( $defaults );
173
174
		$normalize = new Normalize;
0 ignored issues
show
Bug introduced by
The type GeminiLabs\Castor\Forms\Fields\Normalize was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
175
176
		return ( $this->element && method_exists( $normalize, $this->element ))
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->element &&...$implode ? '' : array() also could return the type string which is incompatible with the documented return type array.
Loading history...
177
			? $normalize->{$this->element}( $args, $implode )
178
			: ( !!$implode ? '' : [] );
179
	}
180
181
	/**
182
	 * Merge and overwrite empty $this->args values with $defaults
183
	 *
184
	 * @return array
185
	 */
186
	protected function mergeAttributesWith( array $defaults )
187
	{
188
		// similar to array_merge except overwrite empty values
189
		foreach( $defaults as $key => $value ) {
190
			if( isset( $this->args[ $key ] ) && !empty( $this->args[ $key ] ))continue;
191
			$this->args[ $key ] = $value;
192
		}
193
194
		$attributes = $this->args['attributes'];
195
196
		// prioritize $attributes over $this->args, don't worry about duplicates
197
		return array_merge( $this->args, $attributes );
198
	}
199
200
	/**
201
	 * Generate checkboxes and radios
202
	 *
203
	 * @param string $optionKey
204
	 * @param string $number
205
	 * @param string $type
206
	 *
207
	 * @return null|string
208
	 */
209
	protected function multiInput( $optionKey, $number, $type = 'radio' )
210
	{
211
		$args = $this->multiInputArgs( $type, $optionKey, $number );
212
213
		if( !$args )return;
214
215
		$attributes = '';
216
217
		foreach( $args['attributes'] as $key => $val ) {
218
			$attributes .= sprintf( '%s="%s" ', $key, $val );
219
		}
220
221
		return sprintf( '<li><label for="%s"><input %s%s/> %s</label></li>',
222
			$args['attributes']['id'],
223
			$attributes,
224
			checked( $args['value'], $args['attributes']['value'], false ),
225
			$args['label']
226
		);
227
	}
228
229
	/**
230
	 * Build the checkbox/radio args
231
	 *
232
	 * @param string $type
233
	 * @param string $optionName
234
	 * @param string $number
235
	 *
236
	 * @return array|null
237
	 */
238
	protected function multiInputArgs( $type, $optionName, $number )
239
	{
240
		$defaults = [
241
			'class' => '',
242
			'name'  => '',
243
			'type'  => $type,
244
			'value' => '',
245
		];
246
247
		$args = [];
248
249
		$value = $this->args['options'][ $optionName ];
250
251
		if( is_array( $value )) {
252
			$args = $value;
253
		}
254
255
		if( is_string( $value )) {
256
			$label = $value;
257
		}
258
259
		isset( $args['name'] ) ?: $args['name'] = $optionName;
260
		isset( $args['value'] ) ?: $args['value'] = $optionName;
261
262
		$args = wp_parse_args( $args, $defaults );
263
264
		if( !isset( $label ) || $args['name'] === '' )return;
265
266
		$args['id']   = $this->args['id'] . "-{$number}";
267
		$args['name'] = $this->args['name'] . ( $type === 'checkbox' && $this->multi ? '[]' : '' );
268
269
		$args = array_filter( $args, function( $value ) {
270
			return $value !== '';
271
		});
272
273
		if( is_array( $this->args['value'] )) {
274
			if( in_array( $args['value'], $this->args['value'] )) {
275
				$this->args['default'] = $args['value'];
276
			}
277
		}
278
		else if( $this->args['value'] ) {
279
			$this->args['default'] = $this->args['value'];
280
		}
281
		else if( $type == 'radio' && !$this->args['default'] ) {
282
			$this->args['default'] = 0;
283
		}
284
285
		return [
286
			'attributes' => $args,
287
			'label'      => $label,
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $label does not seem to be defined for all execution paths leading up to this point.
Loading history...
288
			'value'      => $this->args['default'],
289
		];
290
	}
291
292
	/**
293
	 * Generate checkboxes
294
	 *
295
	 * @param string $optionKey
296
	 * @param string $number
297
	 *
298
	 * @return null|string
299
	 */
300
	protected function multiInputCheckbox( $optionKey, $number )
301
	{
302
		return $this->multiInput( $optionKey, $number, 'checkbox' );
303
	}
304
305
	/**
306
	 * Generate select options
307
	 *
308
	 * @param string $optionKey
309
	 *
310
	 * @return string
311
	 */
312
	protected function selectOption( $optionKey )
313
	{
314
		return sprintf( '<option value="%s"%s>%s</option>',
315
			$optionKey,
316
			selected( $this->args['value'], $optionKey, false ),
317
			$this->args['options'][ $optionKey ]
318
		);
319
	}
320
321
	/**
322
	 * Generate a single checkbox
323
	 *
324
	 * @param string $type
325
	 *
326
	 * @return null|string
327
	 */
328
	protected function singleInput( $type = 'checkbox' )
329
	{
330
		$optionKey = key( $this->args['options'] );
331
332
		$args = $this->multiInputArgs( $type, $optionKey, 1 );
333
334
		if( !$args )return;
335
336
		$atts = $this->normalize();
337
		$atts = wp_parse_args( $args['attributes'], $atts );
338
339
		$attributes = '';
340
341
		foreach( $atts as $key => $val ) {
342
			$attributes .= sprintf( '%s="%s" ', $key, $val );
343
		}
344
345
		return sprintf( '<label for="%s"><input %s%s/> %s</label>',
346
			$atts['id'],
347
			$attributes,
348
			checked( $args['value'], $atts['value'], false ),
349
			$args['label']
350
		);
351
	}
352
}
353