Passed
Push — master ( d8e403...d1c323 )
by Paul
05:05
created

Builder::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 1
crap 1
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 array
41
	 */
42
	public $globals = [];
43
44
	/**
45
	 * @var bool
46
	 */
47
	public $render = false;
48
49
	/**
50
	 * @var string
51
	 */
52
	public $tag;
53
54 7
	public function __construct( array $globals = [] )
55
	{
56 7
		$this->globals = $globals;
57 7
	}
58
59
	/**
60
	 * @param string $method
61
	 * @param array $args
62
	 * @return string|void
63
	 */
64 7
	public function __call( $method, $args )
65
	{
66 7
		$instance = new static( $this->globals );
67 7
		$instance->setTagFromMethod( $method );
68 7
		call_user_func_array( [$instance, 'normalize'], $args += ['',''] );
69 7
		$tags = array_merge( static::TAGS_FORM, static::TAGS_SINGLE, static::TAGS_STRUCTURE, static::TAGS_TEXT );
70 7
		$generatedTag = in_array( $instance->tag, $tags )
71 7
			? $instance->buildTag()
72 7
			: $instance->buildCustomField();
73 7
		if( !$this->render ) {
74 7
			return $generatedTag;
75
		}
76
		echo $generatedTag;
77
	}
78
79
	/**
80
	 * @param string $property
81
	 * @param mixed $value
82
	 * @return void
83
	 */
84
	public function __set( $property, $value )
85
	{
86
		$properties = [
87
			'args' => 'is_array',
88
			'globals' => 'is_array',
89
			'render' => 'is_bool',
90
			'tag' => 'is_string',
91
		];
92
		if( !isset( $properties[$property] )
93
			|| empty( array_filter( [$value], $properties[$property] ))
94
		)return;
95
		$this->$property = $value;
96
	}
97
98
	/**
99
	 * @return string
100
	 */
101 7
	public function getClosingTag()
102
	{
103 7
		return '</'.$this->tag.'>';
104
	}
105
106
	/**
107
	 * @return string
108
	 */
109 7
	public function getOpeningTag()
110
	{
111 7
		$attributes = glsr( Attributes::class )->{$this->tag}( $this->args )->toString();
112 7
		return '<'.trim( $this->tag.' '.$attributes ).'>';
113
	}
114
115
	/**
116
	 * @return string|void
117
	 */
118
	protected function buildCustomField()
119
	{
120
		if( $className = $this->getCustomFieldClassName() ) {
121
			return (new $className( $this ))->build();
122
		}
123
		glsr_log()->error( 'Field missing: '.$className );
0 ignored issues
show
Bug introduced by
Are you sure $className of type false|string can be used in concatenation? ( Ignorable by Annotation )

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

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