Passed
Push — master ( b3d616...379d80 )
by Paul
04:39
created

Builder::raw()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
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
	public function __call( $method, $args )
55
	{
56
		$instance = new static;
57
		$instance->setTagFromMethod( $method );
58
		call_user_func_array( [$instance, 'normalize'], $args += ['',''] );
59
		$tags = array_merge( static::TAGS_FORM, static::TAGS_SINGLE, static::TAGS_STRUCTURE, static::TAGS_TEXT );
60
		do_action_ref_array( 'site-reviews/builder', [&$instance] );
61
		$generatedTag = in_array( $instance->tag, $tags )
62
			? $instance->buildTag()
63
			: $instance->buildCustomField();
64
		if( !$this->render ) {
65
			return $generatedTag;
66
		}
67
		echo $generatedTag;
68
	}
69
70
	/**
71
	 * @param string $property
72
	 * @param mixed $value
73
	 * @return void
74
	 */
75
	public function __set( $property, $value )
76
	{
77
		$properties = [
78
			'args' => 'is_array',
79
			'render' => 'is_bool',
80
			'tag' => 'is_string',
81
		];
82
		if( !isset( $properties[$property] )
83
			|| empty( array_filter( [$value], $properties[$property] ))
84
		)return;
85
		$this->$property = $value;
86
	}
87
88
	/**
89
	 * @return void|string
90
	 */
91
	public function getClosingTag()
92
	{
93
		if( empty( $this->tag ))return;
94
		return '</'.$this->tag.'>';
95
	}
96
97
	/**
98
	 * @return void|string
99
	 */
100
	public function getOpeningTag()
101
	{
102
		if( empty( $this->tag ))return;
103
		$attributes = glsr( Attributes::class )->{$this->tag}( $this->args )->toString();
104
		return '<'.trim( $this->tag.' '.$attributes ).'>';
105
	}
106
107
	/**
108
	 * @return string
109
	 */
110
	public function raw( array $field )
111
	{
112
		unset( $field['label'] );
113
		return $this->{$field['type']}( $field );
114
	}
115
116
	/**
117
	 * @return string|void
118
	 */
119
	protected function buildCustomField()
120
	{
121
		$className = $this->getCustomFieldClassName();
122
		if( class_exists( $className )) {
123
			return (new $className( $this ))->build();
124
		}
125
		glsr_log()->error( 'Field missing: '.$className );
126
	}
127
128
	/**
129
	 * @return string|void
130
	 */
131
	protected function buildDefaultTag( $text = '' )
132
	{
133
		if( empty( $text )) {
134
			$text = $this->args['text'];
135
		}
136
		return $this->getOpeningTag().$text.$this->getClosingTag();
137
	}
138
139
	/**
140
	 * @return string|void
141
	 */
142
	protected function buildFieldDescription()
143
	{
144
		if( empty( $this->args['description'] ))return;
145
		if( $this->args['is_widget'] ) {
146
			return $this->small( $this->args['description'] );
147
		}
148
		return $this->p( $this->args['description'], ['class' => 'description'] );
149
	}
150
151
	/**
152
	 * @return string|void
153
	 */
154
	protected function buildFormInput()
155
	{
156
		if( !in_array( $this->args['type'], ['checkbox', 'radio'] )) {
157
			if( isset( $this->args['multiple'] )) {
158
				$this->args['name'].= '[]';
159
			}
160
			return $this->buildFormLabel().$this->getOpeningTag();
161
		}
162
		return empty( $this->args['options'] )
163
			? $this->buildFormInputChoice()
164
			: $this->buildFormInputMultiChoice();
165
	}
166
167
	/**
168
	 * @return string|void
169
	 */
170
	protected function buildFormInputChoice()
171
	{
172
		if( !empty( $this->args['text'] )) {
173
			$this->args['label'] = $this->args['text'];
174
		}
175
		return $this->getOpeningTag().$this->buildFormLabel([
176
			'class' => 'glsr-'.$this->args['type'].'-label',
177
			'text' => $this->args['label'].'<span></span>',
178
		]);
179
	}
180
181
	/**
182
	 * @return string|void
183
	 */
184
	protected function buildFormInputMultiChoice()
185
	{
186
		if( $this->args['type'] == 'checkbox' ) {
187
			$this->args['name'].= '[]';
188
		}
189
		$index = 0;
190
		$options = array_reduce( array_keys( $this->args['options'] ), function( $carry, $key ) use( &$index ) {
191
			return $carry.$this->li( $this->{$this->args['type']}([
192
				'checked' => in_array( $key, (array)$this->args['value'] ),
193
				'id' => $this->args['id'].'-'.$index++,
194
				'name' => $this->args['name'],
195
				'text' => $this->args['options'][$key],
196
				'value' => $key,
197
			]));
198
		});
199
		return $this->ul( $options, [
200
			'class' => $this->args['class'],
201
			'id' => $this->args['id'],
202
		]);
203
	}
204
205
	/**
206
	 * @return void|string
207
	 */
208
	protected function buildFormLabel( array $customArgs = [] )
209
	{
210
		if( empty( $this->args['label'] ) || $this->args['type'] == 'hidden' )return;
211
		return $this->label( wp_parse_args( $customArgs, [
0 ignored issues
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

211
		return $this->/** @scrutinizer ignore-call */ label( wp_parse_args( $customArgs, [
Loading history...
212
			'for' => $this->args['id'],
213
			'is_public' => $this->args['is_public'],
214
			'text' => $this->args['label'],
215
			'type' => $this->args['type'],
216
		]));
217
	}
218
219
	/**
220
	 * @return string|void
221
	 */
222
	protected function buildFormSelect()
223
	{
224
		return $this->buildFormLabel().$this->buildDefaultTag( $this->buildFormSelectOptions() );
225
	}
226
227
	/**
228
	 * @return string|void
229
	 */
230
	protected function buildFormSelectOptions()
231
	{
232
		return array_reduce( array_keys( $this->args['options'] ), function( $carry, $key ) {
233
			return $carry.$this->option([
234
				'selected' => $this->args['value'] == $key,
235
				'text' => $this->args['options'][$key],
236
				'value' => $key,
237
			]);
238
		});
239
	}
240
241
	/**
242
	 * @return string|void
243
	 */
244
	protected function buildFormTextarea()
245
	{
246
		return $this->buildFormLabel().$this->buildDefaultTag( $this->args['value'] );
247
	}
248
249
	/**
250
	 * @return string|void
251
	 */
252
	protected function buildTag()
253
	{
254
		$this->mergeArgsWithRequiredDefaults();
255
		if( in_array( $this->tag, static::TAGS_SINGLE )) {
256
			return $this->getOpeningTag();
257
		}
258
		if( !in_array( $this->tag, static::TAGS_FORM )) {
259
			return $this->buildDefaultTag();
260
		}
261
		return call_user_func( [$this, 'buildForm'.ucfirst( $this->tag )] ).$this->buildFieldDescription();
262
	}
263
264
	/**
265
	 * @return string
266
	 */
267
	protected function getCustomFieldClassName()
268
	{
269
		return glsr( Helper::class )->buildClassName( $this->tag, __NAMESPACE__.'\Fields' );
270
	}
271
272
	/**
273
	 * @return void
274
	 */
275
	protected function mergeArgsWithRequiredDefaults()
276
	{
277
		$className = $this->getCustomFieldClassName();
278
		if( class_exists( $className )) {
279
			$this->args = array_merge(
280
				wp_parse_args( $this->args, $className::defaults() ),
281
				$className::required()
282
			);
283
		}
284
		$this->args = glsr( BuilderDefaults::class )->merge( $this->args );
285
	}
286
287
	/**
288
	 * @param string|array ...$params
289
	 * @return void
290
	 */
291
	protected function normalize( ...$params )
292
	{
293
		if( is_string( $params[0] ) || is_numeric( $params[0] )) {
294
			$this->setNameOrTextAttributeForTag( $params[0] );
295
		}
296
		if( is_array( $params[0] )) {
297
			$this->args += $params[0];
298
		}
299
		else if( is_array( $params[1] )) {
300
			$this->args += $params[1];
301
		}
302
		if( !isset( $this->args['is_public'] )) {
303
			$this->args['is_public'] = false;
304
		}
305
	}
306
307
	/**
308
	 * @param string $value
309
	 * @return void
310
	 */
311
	protected function setNameOrTextAttributeForTag( $value )
312
	{
313
		$attribute = in_array( $this->tag, static::TAGS_FORM )
314
			? 'name'
315
			: 'text';
316
		$this->args[$attribute] = $value;
317
	}
318
319
	/**
320
	 * @param string $method
321
	 * @return void
322
	 */
323
	protected function setTagFromMethod( $method )
324
	{
325
		$this->tag = strtolower( $method );
326
		if( in_array( $this->tag, static::INPUT_TYPES )) {
327
			$this->args['type'] = $this->tag;
328
			$this->tag = 'input';
329
		}
330
	}
331
}
332