Passed
Push — master ( 042452...c272a3 )
by Paul
05:20
created

Builder::mergeArgsWithRequiredDefaults()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.3149

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 0
dl 0
loc 10
ccs 4
cts 7
cp 0.5714
crap 2.3149
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Modules\Html;
4
5
use GeminiLabs\SiteReviews\Defaults\BuilderDefaults;
6
use GeminiLabs\SiteReviews\Helper;
7
use GeminiLabs\SiteReviews\Modules\Html\Attributes;
8
9
class Builder
10
{
11
	const INPUT_TYPES = [
12
		'checkbox', 'date', 'datetime-local', 'email', 'file', 'hidden', 'image', 'month',
13
		'number', 'password', 'radio', 'range', 'reset', 'search', 'submit', 'tel', 'text', 'time',
14
		'url', 'week',
15
	];
16
17
	const TAGS_FORM = [
18
		'input', 'select', 'textarea',
19
	];
20
21
	const TAGS_SINGLE = [
22
		'img',
23
	];
24
25
	const TAGS_STRUCTURE = [
26
		'div', 'form', 'nav', 'ol', 'section', 'ul',
27
	];
28
29
	const TAGS_TEXT = [
30
		'a', 'button', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'i', 'label', 'li', 'option', 'p', 'pre', 'small',
31
		'span',
32
	];
33
34
	/**
35
	 * @var array
36
	 */
37
	public $args = [];
38
39
	/**
40
	 * @var bool
41
	 */
42
	public $render = false;
43
44
	/**
45
	 * @var string
46
	 */
47
	public $tag;
48
49
	/**
50
	 * @param string $method
51
	 * @param array $args
52
	 * @return string|void
53
	 */
54 7
	public function __call( $method, $args )
55
	{
56 7
		$instance = new static;
57 7
		$instance->setTagFromMethod( $method );
58 7
		call_user_func_array( [$instance, 'normalize'], $args += ['',''] );
59 7
		$tags = array_merge( static::TAGS_FORM, static::TAGS_SINGLE, static::TAGS_STRUCTURE, static::TAGS_TEXT );
60 7
		$generatedTag = in_array( $instance->tag, $tags )
61 7
			? $instance->buildTag()
62 7
			: $instance->buildCustomField();
63 7
		if( !$this->render ) {
64 7
			return $generatedTag;
65
		}
66
		echo $generatedTag;
67
	}
68
69
	/**
70
	 * @param string $property
71
	 * @param mixed $value
72
	 * @return void
73
	 */
74
	public function __set( $property, $value )
75
	{
76
		$properties = [
77
			'args' => 'is_array',
78
			'render' => 'is_bool',
79
			'tag' => 'is_string',
80
		];
81
		if( !isset( $properties[$property] )
82
			|| empty( array_filter( [$value], $properties[$property] ))
83
		)return;
84
		$this->$property = $value;
85
	}
86
87
	/**
88
	 * @return string
89
	 */
90 7
	public function getClosingTag()
91
	{
92 7
		return '</'.$this->tag.'>';
93
	}
94
95
	/**
96
	 * @return string
97
	 */
98 7
	public function getOpeningTag()
99
	{
100 7
		$attributes = glsr( Attributes::class )->{$this->tag}( $this->args )->toString();
101 7
		return '<'.trim( $this->tag.' '.$attributes ).'>';
102
	}
103
104
	/**
105
	 * @return string|void
106
	 */
107
	protected function buildCustomField()
108
	{
109
		$className = $this->getCustomFieldClassName();
110
		if( class_exists( $className )) {
111
			return (new $className( $this ))->build();
112
		}
113
		glsr_log()->error( 'Field missing: '.$className );
114
	}
115
116
	/**
117
	 * @return string|void
118
	 */
119 7
	protected function buildDefaultTag( $text = '' )
120
	{
121 7
		if( empty( $text )) {
122 7
			$text = $this->args['text'];
123
		}
124 7
		return $this->getOpeningTag().$text.$this->getClosingTag();
125
	}
126
127
	/**
128
	 * @return string|void
129
	 */
130
	protected function buildFieldDescription()
131
	{
132
		if( empty( $this->args['description'] ))return;
133
		if( $this->args['is_widget'] ) {
134
			return $this->small( $this->args['description'] );
135
		}
136
		return $this->p( $this->args['description'], ['class' => 'description'] );
137
	}
138
139
	/**
140
	 * @return string|void
141
	 */
142
	protected function buildFormInput()
143
	{
144
		if( !in_array( $this->args['type'], ['checkbox', 'radio'] )) {
145
			return $this->buildFormLabel().$this->getOpeningTag();
146
		}
147
		return empty( $this->args['options'] )
148
			? $this->buildFormInputChoice()
149
			: $this->buildFormInputMultiChoice();
150
	}
151
152
	/**
153
	 * @return string|void
154
	 */
155
	protected function buildFormInputChoice()
156
	{
157
		$labelText = !empty( $this->args['text'] )
158
			? $this->args['text']
159
			: $this->args['label'];
160
		return $this->label( $this->getOpeningTag().' '.$labelText, [
1 ignored issue
show
Bug introduced by
The method label() does not exist on GeminiLabs\SiteReviews\Modules\Html\Builder. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

160
		return $this->/** @scrutinizer ignore-call */ label( $this->getOpeningTag().' '.$labelText, [
Loading history...
161
			'class' => 'glsr-'.$this->args['type'].'-label',
162
			'for' => $this->args['id'],
163
		]);
164
	}
165
166
	/**
167
	 * @return string|void
168
	 */
169
	protected function buildFormInputMultiChoice()
170
	{
171
		if( $this->args['type'] == 'checkbox' ) {
172
			$this->args['name'].= '[]';
173
		}
174
		$options = array_reduce( array_keys( $this->args['options'] ), function( $carry, $key ) {
175
			return $carry.$this->li( $this->{$this->args['type']}([
176
				'checked' => in_array( $key, (array)$this->args['value'] ),
177
				'name' => $this->args['name'],
178
				'text' => $this->args['options'][$key],
179
				'value' => $key,
180
			]));
181
		});
182
		return $this->ul( $options, [
183
			'class' => $this->args['class'],
184
			'id' => $this->args['id'],
185
		]);
186
	}
187
188
	/**
189
	 * @return void|string
190
	 */
191
	protected function buildFormLabel()
192
	{
193
		if( empty( $this->args['label'] ) || $this->args['type'] == 'hidden' )return;
194
		return $this->label([
195
			'for' => $this->args['id'],
196
			'text' => $this->args['label'],
197
		]);
198
	}
199
200
	/**
201
	 * @return string|void
202
	 */
203
	protected function buildFormSelect()
204
	{
205
		return $this->buildFormLabel().$this->buildDefaultTag( $this->buildFormSelectOptions() );
206
	}
207
208
	/**
209
	 * @return string|void
210
	 */
211
	protected function buildFormSelectOptions()
212
	{
213
		return array_reduce( array_keys( $this->args['options'] ), function( $carry, $key ) {
214
			return $carry.$this->option([
215
				'selected' => $this->args['value'] == $key,
216
				'text' => $this->args['options'][$key],
217
				'value' => $key,
218
			]);
219
		});
220
	}
221
222
	/**
223
	 * @return string|void
224
	 */
225
	protected function buildFormTextarea()
226
	{
227
		return $this->buildFormLabel().$this->buildDefaultTag( $this->args['value'] );
228
	}
229
230
	/**
231
	 * @return string|void
232
	 */
233 7
	protected function buildTag()
234
	{
235 7
		$this->mergeArgsWithRequiredDefaults();
236 7
		if( in_array( $this->tag, static::TAGS_SINGLE )) {
237
			return $this->getOpeningTag();
238
		}
239 7
		if( !in_array( $this->tag, static::TAGS_FORM )) {
240 7
			return $this->buildDefaultTag();
241
		}
242
		return call_user_func( [$this, 'buildForm'.ucfirst( $this->tag )] ).$this->buildFieldDescription();
243
	}
244
245
	/**
246
	 * @return string
247
	 */
248 7
	protected function getCustomFieldClassName()
249
	{
250 7
		return glsr( Helper::class )->buildClassName( $this->tag, __NAMESPACE__.'\Fields' );
251
	}
252
253
	/**
254
	 * @return void
255
	 */
256 7
	protected function mergeArgsWithRequiredDefaults()
257
	{
258 7
		$className = $this->getCustomFieldClassName();
259 7
		if( class_exists( $className )) {
260
			$this->args = array_merge(
261
				wp_parse_args( $this->args, $className::defaults() ),
262
				$className::required()
263
			);
264
		}
265 7
		$this->args = glsr( BuilderDefaults::class )->merge( $this->args );
266 7
	}
267
268
	/**
269
	 * @param string|array ...$params
270
	 * @return void
271
	 */
272 7
	protected function normalize( ...$params )
273
	{
274 7
		if( is_string( $params[0] ) || is_numeric( $params[0] )) {
275 7
			$this->setNameOrTextAttributeForTag( $params[0] );
276
		}
277 7
		if( is_array( $params[0] )) {
278
			$this->args += $params[0];
279
		}
280 7
		else if( is_array( $params[1] )) {
281 7
			$this->args += $params[1];
282
		}
283 7
	}
284
285
	/**
286
	 * @param string $value
287
	 * @return void
288
	 */
289 7
	protected function setNameOrTextAttributeForTag( $value )
290
	{
291 7
		$attribute = in_array( $this->tag, static::TAGS_FORM )
292
			? 'name'
293 7
			: 'text';
294 7
		$this->args[$attribute] = $value;
295 7
	}
296
297
	/**
298
	 * @param string $method
299
	 * @return void
300
	 */
301 7
	protected function setTagFromMethod( $method )
302
	{
303 7
		$this->tag = strtolower( $method );
304 7
		if( in_array( $this->tag, static::INPUT_TYPES )) {
305
			$this->args['type'] = $this->tag;
306
			$this->tag = 'input';
307
		}
308 7
	}
309
}
310