Widget   F
last analyzed

Complexity

Total Complexity 80

Size/Duplication

Total Lines 526
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 166
c 5
b 0
f 0
dl 0
loc 526
rs 2
wmc 80

55 Methods

Rating   Name   Duplication   Size   Complexity  
A setFields() 0 3 1
A addInToolbar() 0 13 5
A addField() 0 3 1
A addErrorMessage() 0 4 1
A addSubmitInToolbar() 0 4 1
A addToProperty() 0 2 1
A setCaptionCallback() 0 3 1
A getToolbar() 0 5 2
A insertField() 0 4 1
A setModel() 0 3 1
A addDropdownInToolbar() 0 6 2
A swapFields() 0 4 1
A addMessage() 0 4 1
A addButtonInToolbar() 0 3 1
A addLabelledIconButtonInToolbar() 0 4 1
A addButtonsInToolbar() 0 3 1
A setToolbarPosition() 0 3 1
A setEdition() 0 3 1
A _init() 0 8 1
A setInstanceViewer() 0 3 1
A addFields() 0 3 1
A getForm() 0 6 2
A afterCompile() 0 6 2
A insertInField() 0 6 2
A setToolbar() 0 3 1
A _getFieldName() 0 2 1
A countFields() 0 2 1
A setDefaultValueFunction() 0 3 1
A __construct() 0 11 3
A runForm() 0 6 2
A _getFieldIdentifier() 0 2 1
A addItemInToolbar() 0 5 3
A getModelInstance() 0 2 1
A _compileForm() 0 6 3
A show() 0 5 2
A _getFieldCaption() 0 2 1
A setAttached() 0 2 1
A setCaptions() 0 3 1
A hasRules() 0 2 1
A setValidationParams() 0 3 1
A addEditButtonInToolbar() 0 6 1
A setValueFunction() 0 6 2
A addItemsInToolbar() 0 11 4
A asModal() 0 7 2
A setCaption() 0 3 1
A setIdentifierFunction() 0 3 1
A getInstanceViewer() 0 2 1
A moveFieldTo() 0 2 1
A run() 0 4 2
A getModel() 0 2 1
A _getIndex() 0 7 2
A setColor() 0 2 1
A getDefaultValueFunction() 0 2 1
A jsDisabled() 0 2 1
A removeField() 0 6 2

How to fix   Complexity   

Complex Class

Complex classes like Widget often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Widget, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Ajax\common;
3
4
use Ajax\common\html\HtmlDoubleElement;
5
use Ajax\semantic\html\elements\HtmlButton;
6
use Ajax\semantic\widgets\datatable\PositionInTable;
7
use Ajax\semantic\html\collections\menus\HtmlMenu;
8
use Ajax\semantic\widgets\base\FieldAsTrait;
9
use Ajax\semantic\html\elements\HtmlButtonGroups;
10
use Ajax\semantic\widgets\base\InstanceViewer;
11
use Ajax\semantic\html\modules\HtmlDropdown;
12
use Ajax\service\JArray;
13
use Ajax\service\Javascript;
14
use Ajax\semantic\html\collections\form\HtmlForm;
15
use Ajax\JsUtils;
16
use Ajax\semantic\html\collections\form\HtmlFormField;
17
use Ajax\semantic\html\collections\form\traits\FormTrait;
18
use Ajax\common\html\BaseWidget;
19
use Ajax\semantic\html\modules\HtmlModal;
20
use Ajax\common\html\traits\BaseHooksTrait;
21
22
abstract class Widget extends HtmlDoubleElement {
23
	use FieldAsTrait,FormTrait,BaseHooksTrait;
24
25
	/**
26
	 *
27
	 * @var string classname
28
	 */
29
	protected $_model;
30
31
	protected $_modelInstance;
32
33
	/**
34
	 *
35
	 * @var InstanceViewer
36
	 */
37
	protected $_instanceViewer;
38
39
	/**
40
	 *
41
	 * @var HtmlMenu
42
	 */
43
	protected $_toolbar;
44
45
	/**
46
	 *
47
	 * @var string
48
	 */
49
	protected $_toolbarPosition;
50
51
	/**
52
	 *
53
	 * @var boolean
54
	 */
55
	protected $_edition;
56
57
	/**
58
	 *
59
	 * @var HtmlForm
60
	 */
61
	protected $_form;
62
63
	protected $_generated;
64
65
	protected $_runned;
66
67
	protected $_hasRules;
68
69
	public function __construct($identifier, $model, $modelInstance = NULL) {
70
		parent::__construct($identifier);
71
		$this->_template = "%wrapContentBefore%%content%%wrapContentAfter%";
72
		$this->setModel($model);
73
		if (isset($modelInstance)) {
74
			if (\is_object($modelInstance)) {
75
				$this->_model = \get_class($modelInstance);
76
			}
77
			$this->show($modelInstance);
78
		}
79
		$this->_generated = false;
80
	}
81
82
	protected function _init($instanceViewer, $contentKey, $content, $edition) {
83
		$this->_instanceViewer = $instanceViewer;
84
		$this->content = [
85
			$contentKey => $content
86
		];
87
		$this->_self = $content;
88
		$this->_toolbarPosition = PositionInTable::BEFORETABLE;
89
		$this->_edition = $edition;
90
	}
91
92
	/**
93
	 *
94
	 * @param int|string $fieldName
95
	 * @return int|string|boolean
96
	 */
97
	protected function _getIndex($fieldName) {
98
		$index = $fieldName;
99
		if (\is_string($fieldName)) {
100
			$fields = $this->_instanceViewer->getVisibleProperties();
101
			$index = \array_search($fieldName, $fields);
102
		}
103
		return $index;
104
	}
105
106
	protected function _getFieldIdentifier($prefix, $name = "") {
107
		return $this->identifier . "-{$prefix}-" . $this->_instanceViewer->getIdentifier();
108
	}
109
110
	protected function _getFieldName($index) {
111
		return $this->_instanceViewer->getFieldName($index);
112
	}
113
114
	protected function _getFieldCaption($index) {
115
		return $this->_instanceViewer->getCaption($index);
116
	}
117
118
	abstract protected function _setToolbarPosition($table, $captions = NULL);
119
120
	public function show($modelInstance) {
121
		if (\is_array($modelInstance)) {
122
			$modelInstance = \json_decode(\json_encode($modelInstance), FALSE);
123
		}
124
		$this->_modelInstance = $modelInstance;
125
	}
126
127
	public function getModel() {
128
		return $this->_model;
129
	}
130
131
	public function setModel($_model) {
132
		$this->_model = $_model;
133
		return $this;
134
	}
135
136
	public function getInstanceViewer() {
137
		return $this->_instanceViewer;
138
	}
139
140
	public function setInstanceViewer($_instanceViewer) {
141
		$this->_instanceViewer = $_instanceViewer;
142
		return $this;
143
	}
144
145
	abstract public function getHtmlComponent();
146
147
	public function setAttached($value = true) {
148
		return $this->getHtmlComponent()->setAttached($value);
149
	}
150
151
	/**
152
	 * Associates a $callback function after the compilation of the field at $index position
153
	 * The $callback function can take the following arguments : $field=>the compiled field, $instance : the active instance of the object, $index: the field position
154
	 *
155
	 * @param int $index
156
	 *        	postion of the compiled field
157
	 * @param callable $callback
158
	 *        	function called after the field compilation
159
	 * @return Widget
160
	 */
161
	public function afterCompile($index, $callback) {
162
		$index = $this->_getIndex($index);
163
		if ($index !== false) {
0 ignored issues
show
introduced by
The condition $index !== false is always true.
Loading history...
164
			$this->_instanceViewer->afterCompile($index, $callback);
165
		}
166
		return $this;
167
	}
168
169
	public function setColor($color) {
170
		return $this->getHtmlComponent()->setColor($color);
171
	}
172
173
	public function setCaptions($captions) {
174
		$this->_instanceViewer->setCaptions($captions);
175
		return $this;
176
	}
177
178
	public function setCaption($index, $caption) {
179
		$this->_instanceViewer->setCaption($this->_getIndex($index), $caption);
180
		return $this;
181
	}
182
183
	public function setFields($fields) {
184
		$this->_instanceViewer->setVisibleProperties($fields);
185
		return $this;
186
	}
187
188
	public function addField($field, $key = null) {
189
		$this->_instanceViewer->addField($field, $key);
190
		return $this;
191
	}
192
193
	public function addFields($fields) {
194
		$this->_instanceViewer->addFields($fields);
195
		return $this;
196
	}
197
198
	public function countFields() {
199
		return $this->_instanceViewer->visiblePropertiesCount();
200
	}
201
202
	public function addMessage($attributes = NULL, $fieldName = "message") {
203
		$this->_instanceViewer->addField($fieldName);
204
		$count = $this->_instanceViewer->visiblePropertiesCount();
205
		return $this->fieldAsMessage($count - 1, $attributes);
206
	}
207
208
	public function addErrorMessage() {
209
		return $this->addMessage([
210
			"error" => true
211
		], "message");
212
	}
213
214
	public function insertField($index, $field, $key = null) {
215
		$index = $this->_getIndex($index);
216
		$this->_instanceViewer->insertField($index, $field, $key);
217
		return $this;
218
	}
219
220
	public function insertInField($index, $field, $key = null) {
221
		$index = $this->_getIndex($index);
222
		if ($index !== false) {
223
			$this->_instanceViewer->insertInField($index, $field, $key);
224
		}
225
		return $this;
226
	}
227
228
	/**
229
	 * Defines the function which displays the field value
230
	 *
231
	 * @param int|string $index
232
	 *        	index or name of the field to display
233
	 * @param callable $callback
234
	 *        	function parameters are : $value : the field value, $instance : the active instance of model, $fieldIndex : the field index, $rowIndex : the row index
235
	 * @return Widget
236
	 */
237
	public function setValueFunction($index, $callback) {
238
		$index = $this->_getIndex($index);
239
		if ($index !== false) {
240
			$this->_instanceViewer->setValueFunction($index, $callback);
241
		}
242
		return $this;
243
	}
244
245
	public function setIdentifierFunction($callback) {
246
		$this->_instanceViewer->setIdentifierFunction($callback);
247
		return $this;
248
	}
249
250
	/**
251
	 *
252
	 * @return \Ajax\semantic\html\collections\menus\HtmlMenu
253
	 */
254
	public function getToolbar() {
255
		if (isset($this->_toolbar) === false) {
256
			$this->_toolbar = new HtmlMenu("toolbar-" . $this->identifier);
257
		}
258
		return $this->_toolbar;
259
	}
260
261
	/**
262
	 * Adds a new element in toolbar
263
	 *
264
	 * @param mixed $element
265
	 * @param callable $callback
266
	 *        	function to call on $element
267
	 * @return \Ajax\common\html\HtmlDoubleElement
268
	 */
269
	public function addInToolbar($element, $callback = NULL) {
270
		$tb = $this->getToolbar();
271
		if ($element instanceof BaseWidget) {
272
			if ($element->getIdentifier() === "") {
273
				$element->setIdentifier("tb-item-" . $this->identifier . "-" . $tb->count());
274
			}
275
		}
276
		if (isset($callback)) {
277
			if (\is_callable($callback)) {
278
				$callback($element);
279
			}
280
		}
281
		return $tb->addItem($element);
282
	}
283
284
	/**
285
	 *
286
	 * @param string $caption
287
	 * @param string $icon
288
	 * @param callable $callback
289
	 *        	function($element)
290
	 * @return \Ajax\common\html\HtmlDoubleElement
291
	 */
292
	public function addItemInToolbar($caption, $icon = NULL, $callback = NULL) {
293
		$result = $this->addInToolbar($caption, $callback);
294
		if (isset($icon) && method_exists($result, "addIcon"))
295
			$result->addIcon($icon);
296
		return $result;
297
	}
298
299
	/**
300
	 *
301
	 * @param array $items
302
	 * @param callable $callback
303
	 *        	function($element)
304
	 * @return \Ajax\common\Widget
305
	 */
306
	public function addItemsInToolbar(array $items, $callback = NULL) {
307
		if (JArray::isAssociative($items)) {
308
			foreach ($items as $icon => $item) {
309
				$this->addItemInToolbar($item, $icon, $callback);
310
			}
311
		} else {
312
			foreach ($items as $item) {
313
				$this->addItemInToolbar($item, null, $callback);
314
			}
315
		}
316
		return $this;
317
	}
318
319
	/**
320
	 *
321
	 * @param mixed $value
322
	 * @param array $items
323
	 * @param callable $callback
324
	 *        	function($element)
325
	 * @return \Ajax\common\html\HtmlDoubleElement
326
	 */
327
	public function addDropdownInToolbar($value, $items, $callback = NULL) {
328
		$dd = $value;
329
		if (\is_string($value)) {
330
			$dd = new HtmlDropdown("dropdown-" . $this->identifier . "-" . $value, $value, $items);
331
		}
332
		return $this->addInToolbar($dd, $callback);
333
	}
334
335
	/**
336
	 *
337
	 * @param string $caption
338
	 * @param string $cssStyle
339
	 * @param callable $callback
340
	 *        	function($element)
341
	 * @return \Ajax\common\html\HtmlDoubleElement
342
	 */
343
	public function addButtonInToolbar($caption, $cssStyle = null, $callback = NULL) {
344
		$bt = new HtmlButton("bt-" . $caption, $caption, $cssStyle);
345
		return $this->addInToolbar($bt, $callback);
346
	}
347
348
	/**
349
	 *
350
	 * @param array $captions
351
	 * @param boolean $asIcon
352
	 * @param callable $callback
353
	 *        	function($element)
354
	 * @return \Ajax\common\html\HtmlDoubleElement
355
	 */
356
	public function addButtonsInToolbar(array $captions, $asIcon = false, $callback = NULL) {
357
		$bts = new HtmlButtonGroups("", $captions, $asIcon);
358
		return $this->addInToolbar($bts, $callback);
359
	}
360
361
	/**
362
	 *
363
	 * @param string $caption
364
	 * @param string $icon
365
	 * @param boolean $before
366
	 * @param boolean $labeled
367
	 * @return \Ajax\common\html\HtmlDoubleElement
368
	 */
369
	public function addLabelledIconButtonInToolbar($caption, $icon, $before = true, $labeled = false) {
370
		$bt = new HtmlButton("", $caption);
371
		$bt->addIcon($icon, $before, $labeled);
372
		return $this->addInToolbar($bt);
373
	}
374
375
	public function addSubmitInToolbar($identifier, $value, $cssStyle = NULL, $url = NULL, $responseElement = NULL, $parameters = NULL) {
376
		$button = new HtmlButton($identifier, $value, $cssStyle);
377
		$this->_buttonAsSubmit($button, "click", $url, $responseElement, $parameters);
378
		return $this->addInToolbar($button);
379
	}
380
381
	/**
382
	 * Defines a callback function to call for modifying captions
383
	 * function parameters 0are $captions: the captions to modify and $instance: the active model instance
384
	 *
385
	 * @param callable $captionCallback
386
	 * @return Widget
387
	 */
388
	public function setCaptionCallback($captionCallback) {
389
		$this->_instanceViewer->setCaptionCallback($captionCallback);
390
		return $this;
391
	}
392
393
	/**
394
	 * Makes the input fields editable
395
	 *
396
	 * @param boolean $_edition
397
	 * @return \Ajax\common\Widget
398
	 */
399
	public function setEdition($_edition = true) {
400
		$this->_edition = $_edition;
401
		return $this;
402
	}
403
404
	/**
405
	 * Defines the default function which displays fields value
406
	 *
407
	 * @param callable $defaultValueFunction
408
	 *        	function parameters are : $name : the field name, $value : the field value ,$index : the field index, $instance : the active instance of model
409
	 * @return \Ajax\common\Widget
410
	 */
411
	public function setDefaultValueFunction($defaultValueFunction) {
412
		$this->_instanceViewer->setDefaultValueFunction($defaultValueFunction);
413
		return $this;
414
	}
415
416
	/**
417
	 *
418
	 * @return callable
419
	 */
420
	public function getDefaultValueFunction() {
421
		return $this->_instanceViewer->getDefaultValueFunction();
422
	}
423
424
	/**
425
	 *
426
	 * @param string|boolean $disable
427
	 * @return string
428
	 */
429
	public function jsDisabled($disable = true) {
430
		return "$('#" . $this->identifier . " .ui.input,#" . $this->identifier . " .ui.dropdown,#" . $this->identifier . " .ui.checkbox').toggleClass('disabled'," . $disable . ");";
431
	}
432
433
	/**
434
	 *
435
	 * @param string $caption
436
	 * @param callable $callback
437
	 *        	function($element)
438
	 * @return \Ajax\common\html\HtmlDoubleElement
439
	 */
440
	public function addEditButtonInToolbar($caption, $callback = NULL) {
441
		$bt = new HtmlButton($this->identifier . "-editBtn", $caption);
442
		$bt->setToggle();
443
		$bt->setActive($this->_edition);
444
		$bt->onClick($this->jsDisabled(Javascript::prep_value("!$(event.target).hasClass('active')")));
445
		return $this->addInToolbar($bt, $callback);
446
	}
447
448
	public function setToolbar(HtmlMenu $_toolbar) {
449
		$this->_toolbar = $_toolbar;
450
		return $this;
451
	}
452
453
	public function setToolbarPosition($_toolbarPosition) {
454
		$this->_toolbarPosition = $_toolbarPosition;
455
		return $this;
456
	}
457
458
	public function getForm() {
459
		if (! isset($this->_form)) {
460
			$this->_form = new HtmlForm("frm-" . $this->identifier);
461
			$this->setEdition(true);
462
		}
463
		return $this->_form;
464
	}
465
466
	public function run(JsUtils $js) {
467
		parent::run($js);
468
		if (isset($this->_form)) {
469
			$this->runForm($js);
470
		}
471
	}
472
473
	protected function runForm(JsUtils $js) {
474
		$fields = $this->getContentInstances(HtmlFormField::class);
475
		foreach ($fields as $field) {
476
			$this->_form->addField($field);
477
		}
478
		return $this->_form->run($js);
479
	}
480
481
	protected function _compileForm() {
482
		if (isset($this->_form)) {
483
			$noValidate = "";
484
			if (\sizeof($this->_form->getValidationParams()) > 0)
485
				$noValidate = "novalidate";
486
			$this->wrapContent("<form class='" . $this->_form->getProperty('class') . "' id='frm-" . $this->identifier . "' name='frm-" . $this->identifier . "' " . $noValidate . ">", "</form>");
487
		}
488
	}
489
490
	/**
491
	 * Sets the parameters for the Form validation (on, inline, delay...)
492
	 *
493
	 * @param array $_validationParams
494
	 *        	example : ["on"=>"blur","inline"=>true]
495
	 * @return Widget
496
	 * @see https://semantic-ui.com/behaviors/form.html#/settings
497
	 */
498
	public function setValidationParams(array $_validationParams) {
499
		$this->getForm()->setValidationParams($_validationParams);
500
		return $this;
501
	}
502
503
	public function moveFieldTo($from, $to) {
504
		return $this->_instanceViewer->moveFieldTo($from, $to);
505
	}
506
507
	public function swapFields($index1, $index2) {
508
		$index1 = $this->_getIndex($index1);
509
		$index2 = $this->_getIndex($index2);
510
		return $this->_instanceViewer->swapFields($index1, $index2);
511
	}
512
513
	public function removeField($index) {
514
		$index = $this->_getIndex($index);
515
		if ($index !== false) {
516
			$this->_instanceViewer->removeField($index);
517
		}
518
		return $this;
519
	}
520
521
	public function asModal($header = null) {
522
		$modal = new HtmlModal("modal-" . $this->identifier, $header);
523
		$modal->setContent($this);
524
		if (isset($this->_form)) {
525
			$this->_form->onSuccess($modal->jsHide());
526
		}
527
		return $modal;
528
	}
529
530
	public function addToProperty($name, $value, $separator = " ") {
531
		return $this->getHtmlComponent()->addToProperty($name, $value, $separator);
532
	}
533
534
	/**
535
	 *
536
	 * @return mixed
537
	 */
538
	public function getModelInstance() {
539
		return $this->_modelInstance;
540
	}
541
542
	/**
543
	 *
544
	 * @return mixed true if widget has validation rules
545
	 */
546
	public function hasRules() {
547
		return $this->_hasRules;
548
	}
549
}
550