Completed
Push — master ( 8f54cc...872df9 )
by Jean-Christophe
03:13
created

HtmlDropdown   C

Complexity

Total Complexity 65

Size/Duplication

Total Lines 313
Duplicated Lines 0.64 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 0
Metric Value
wmc 65
lcom 1
cbo 8
dl 2
loc 313
rs 5.7894
c 0
b 0
f 0

38 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 17 2
A getField() 0 3 1
A getDataField() 0 3 1
A addItem() 0 5 1
A addIcon() 0 5 1
A addIcons() 0 6 3
A insertItem() 0 8 1
A removeArrow() 0 6 2
A beforeAddItem() 0 15 4
A fromDatabaseObject() 0 3 1
A addInput() 0 6 2
A addSearchInputItem() 0 3 1
A addDividerItem() 0 3 1
A addHeaderItem() 0 3 1
A addCircularLabelItem() 0 3 1
A addMiniAvatarImageItem() 0 3 1
B addItems() 0 11 5
A getItem() 0 3 1
A count() 0 3 1
A asDropdown() 0 10 2
A setVertical() 0 3 1
A setInline() 0 3 1
A setSimple() 0 3 1
A asButton() 0 7 2
B asSelect() 0 11 5
A asSearch() 0 4 1
A setSelect() 0 17 4
A asSubmenu() 0 7 2
A setPointing() 0 3 1
A setValue() 0 4 1
A applyValue() 0 12 4
A run() 2 8 3
A setCompact() 0 3 1
A setAction() 0 3 1
A setFullTextSearch() 0 3 1
A compile() 0 4 1
A getInput() 0 3 1
A addAction() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like HtmlDropdown 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 HtmlDropdown, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Ajax\semantic\html\modules;
4
5
use Ajax\semantic\html\base\HtmlSemDoubleElement;
6
use Ajax\semantic\html\content\HtmlDropdownItem;
7
use Ajax\semantic\html\elements\HtmlIcon;
8
use Ajax\common\html\html5\HtmlInput;
9
use Ajax\service\JArray;
10
use Ajax\semantic\html\base\constants\Direction;
11
use Ajax\semantic\html\base\traits\LabeledIconTrait;
12
use Ajax\JsUtils;
13
use Ajax\semantic\html\collections\form\traits\FieldTrait;
14
15
class HtmlDropdown extends HtmlSemDoubleElement {
16
	use FieldTrait,LabeledIconTrait {
17
		addIcon as addIconP;
18
	}
19
	protected $mClass="menu";
20
	protected $mTagName="div";
21
	protected $items=array ();
22
	protected $_params=array("action"=>"nothing","on"=>"hover");
23
	protected $input;
24
	protected $value;
25
	protected $_associative;
26
27
	public function __construct($identifier, $value="", $items=array(),$associative=true) {
28
		parent::__construct($identifier, "div");
29
		$this->_template=include dirname(__FILE__).'/../templates/tplDropdown.php';
30
		$this->setProperty("class", "ui dropdown");
31
		$content=[];
32
		if(isset($value)){
33
			$text=new HtmlSemDoubleElement("text-".$this->identifier,"div");
34
			$text->setClass("text");
35
			$content=[$text];
36
			$this->setValue($value);
37
		}
38
		$content["arrow"]=new HtmlIcon("", "dropdown");
39
		$this->content=$content;
40
		$this->tagName="div";
41
		$this->_associative=$associative;
42
		$this->addItems($items);
43
	}
44
45
	public function getField(){
46
		return $this->input;
47
	}
48
49
	public function getDataField(){
50
		return $this->input;
51
	}
52
53
	public function addItem($item,$value=NULL,$image=NULL,$description=NULL){
54
		$itemO=$this->beforeAddItem($item,$value,$image,$description);
55
		$this->items[]=$itemO;
56
		return $itemO;
57
	}
58
59
	public function addIcon($icon,$before=true,$labeled=false){
60
		$this->removeArrow();
61
		$this->addIconP($icon,$before,$labeled);
62
		return $this->getElementById("text-".$this->identifier, $this->content)->setWrapAfter("");
63
	}
64
65
	public function addIcons($icons){
66
		$count=$this->count();
67
		for ($i=0;$i<\sizeof($icons) && $i<$count;$i++){
68
			$this->getItem($i)->addIcon($icons[$i]);
69
		}
70
	}
71
72
	/**
73
	 * Insert an item at a position
74
	 * @param mixed $item
75
	 * @param number $position
76
	 * @return \Ajax\semantic\html\content\HtmlDropdownItem|unknown
77
	 */
78
	public function insertItem($item,$position=0){
79
		$itemO=$this->beforeAddItem($item);
80
		 $start = array_slice($this->items, 0, $position);
81
		 $end = array_slice($this->items, $position);
82
		 $start[] = $item;
83
		 $this->items=array_merge($start, $end);
84
		 return $itemO;
85
	}
86
87
	protected function removeArrow(){
88
		if(\sizeof($this->content)>1){
89
			unset($this->content["arrow"]);
90
			$this->content=\array_values($this->content);
91
		}
92
	}
93
94
	protected function beforeAddItem($item,$value=NULL,$image=NULL,$description=NULL){
95
		$itemO=$item;
96
		if(\is_array($item)){
97
			$description=JArray::getValue($item, "description", 3);
98
			$value=JArray::getValue($item, "value", 1);
99
			$image=JArray::getValue($item, "image", 2);
100
			$item=JArray::getValue($item, "item", 0);
101
		}
102
		if(!$item instanceof HtmlDropdownItem){
103
			$itemO=new HtmlDropdownItem("dd-item-".$this->identifier."-".\sizeof($this->items),$item,$value,$image,$description);
104
		}elseif($itemO instanceof HtmlDropdownItem){
105
			$this->addToProperty("class", "vertical");
106
		}
107
		return $itemO;
108
	}
109
110
	/* (non-PHPdoc)
111
	 * @see \Ajax\bootstrap\html\base\BaseHtml::fromDatabaseObject()
112
	 */
113
	public function fromDatabaseObject($object, $function) {
114
		$this->addItem($function($object));
115
	}
116
117
	public function addInput($name){
118
		if(!isset($name))
119
			$name="input-".$this->identifier;
120
		$this->setAction("activate");
121
		$this->input=new HtmlInput($name,"hidden");
122
	}
123
124
	/**
125
	 * Adds a search input item
126
	 * @param string $placeHolder
127
	 * @param string $icon
128
	 * @return \Ajax\semantic\html\content\HtmlDropdownItem
129
	 */
130
	public function addSearchInputItem($placeHolder=NULL,$icon=NULL){
131
		return $this->addItem(HtmlDropdownItem::searchInput($placeHolder,$icon));
132
	}
133
134
	/**
135
	 * Adds a divider item
136
	 * @return \Ajax\semantic\html\content\HtmlDropdownItem
137
	 */
138
	public function addDividerItem(){
139
		return $this->addItem(HtmlDropdownItem::divider());
140
	}
141
142
	/**
143
	 * Adds an header item
144
	 * @param string $caption
145
	 * @param string $icon
146
	 * @return \Ajax\semantic\html\content\HtmlDropdownItem|unknown
147
	 */
148
	public function addHeaderItem($caption=NULL,$icon=NULL){
149
		return $this->addItem(HtmlDropdownItem::header($caption,$icon));
150
	}
151
152
	/**
153
	 * Adds an item with a circular label
154
	 * @param string $caption
155
	 * @param string $color
156
	 * @return \Ajax\semantic\html\content\HtmlDropdownItem|unknown
157
	 */
158
	public function addCircularLabelItem($caption,$color){
159
		return $this->addItem(HtmlDropdownItem::circular($caption, $color));
160
	}
161
162
	/**
163
	 * @param string $caption
164
	 * @param string $image
165
	 * @return \Ajax\semantic\html\content\HtmlDropdownItem
166
	 */
167
	public function addMiniAvatarImageItem($caption,$image){
168
		return $this->addItem(HtmlDropdownItem::avatar($caption, $image));
0 ignored issues
show
Documentation introduced by
$caption is of type string, but the function expects a object<Ajax\semantic\html\content\unknown>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
$image is of type string, but the function expects a object<Ajax\semantic\html\content\unknown>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
169
	}
170
171
	public function addItems($items){
172
		if(\is_array($items) && $this->_associative){
173
			foreach ($items as $k=>$v){
174
				$this->addItem($v)->setData($k);
175
			}
176
		}else{
177
			foreach ($items as $item){
178
				$this->addItem($item);
179
			}
180
		}
181
	}
182
183
	public function getItem($index){
184
		return $this->items[$index];
185
	}
186
187
	/**
188
	 * @return int
189
	 */
190
	public function count(){
191
		return \sizeof($this->items);
192
	}
193
	/**
194
	 * @param boolean $dropdown
195
	 */
196
	public function asDropdown($dropdown){
197
		if($dropdown===false){
198
			$this->_template=include dirname(__FILE__).'/../templates/tplDropdownMenu.php';
199
			$dropdown="menu";
200
		}else{
201
			$dropdown="dropdown";
202
			$this->mClass="menu";
203
		}
204
		return $this->addToPropertyCtrl("class", $dropdown,array("menu","dropdown"));
205
	}
206
207
	public function setVertical(){
208
		return $this->addToPropertyCtrl("class", "vertical",array("vertical"));
209
	}
210
211
	public function setInline(){
212
		return $this->addToPropertyCtrl("class", "inline",["inline"]);
213
	}
214
215
	public function setSimple(){
216
		return $this->addToPropertyCtrl("class", "simple",array("simple"));
217
	}
218
219
	public function asButton($floating=false){
220
		$this->removeArrow();
221
		if($floating)
222
			$this->addToProperty("class", "floating");
223
		$this->removePropertyValue("class", "selection");
224
		return $this->addToProperty("class", "button");
225
	}
226
227
	public function asSelect($name=NULL,$multiple=false,$selection=true){
228
		if(isset($name))
229
			$this->addInput($name);
230
		if($multiple)
231
			$this->addToProperty("class", "multiple");
232
		if ($selection){
233
			if($this->propertyContains("class", "button")===false)
234
				$this->addToPropertyCtrl("class", "selection",array("selection"));
235
		}
236
		return $this;
237
	}
238
239
	public function asSearch($name=NULL,$multiple=false,$selection=true){
240
		$this->asSelect($name,$multiple,$selection);
241
		return $this->addToProperty("class", "search");
242
	}
243
244
	public function setSelect($name=NULL,$multiple=false){
245
		if(!isset($name))
246
			$name="select-".$this->identifier;
247
		$this->input=null;
248
		if($multiple){
249
			$this->setProperty("multiple", true);
250
			$this->addToProperty("class", "multiple");
251
		}
252
		$this->setAction("activate");
253
		$this->tagName="select";
254
		$this->setProperty("name", $name);
255
		$this->content=null;
256
		foreach ($this->items as $item){
257
			$item->asOption();
258
		}
259
		return $this;
260
	}
261
262
	public function asSubmenu($pointing=NULL){
263
		$this->setClass("ui dropdown link item");
264
		if(isset($pointing)){
265
			$this->setPointing($pointing);
266
		}
267
		return $this;
268
	}
269
270
	public function setPointing($value=Direction::NONE){
271
		return $this->addToPropertyCtrl("class", $value." pointing",Direction::getConstantValues("pointing"));
272
	}
273
274
	public function setValue($value){
275
		$this->value=$value;
276
		return $this;
277
	}
278
	private function applyValue(){
279
		$value=$this->value;
280
		if(isset($this->input) && isset($value)){
281
			$this->input->setProperty("value", $value);
282
		}else{
283
			$this->setProperty("value", $value);
284
		}
285
			$textElement=$this->getElementById("text-".$this->identifier, $this->content);
286
			if(isset($textElement))
287
				$textElement->setContent($value);
288
		return $this;
289
	}
290
291
	/*
292
	 * (non-PHPdoc)
293
	 * @see BaseHtml::run()
294
	 */
295
	public function run(JsUtils $js) {
296
		if($this->propertyContains("class", "simple")===false){
297 View Code Duplication
			if(isset($this->_bsComponent)===false)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
298
				$this->_bsComponent=$js->semantic()->dropdown("#".$this->identifier,$this->_params);
299
			$this->addEventsOnRun($js);
300
			return $this->_bsComponent;
301
		}
302
	}
303
304
	public function setCompact(){
305
		return $this->addToPropertyCtrl("class", "compact", array("compact"));
306
	}
307
308
	public function setAction($action){
309
		$this->_params["action"]=$action;
310
	}
311
312
	public function setFullTextSearch($value){
313
		$this->_params["fullTextSearch"]=$value;
314
	}
315
316
	public function compile(JsUtils $js=NULL, &$view=NULL) {
317
		$this->applyValue();
318
		return parent::compile($js,$view);
319
	}
320
321
	public function getInput() {
322
		return $this->input;
323
	}
324
	public function addAction($action, $direction=Direction::RIGHT, $icon=NULL, $labeled=false) {
325
		return $this->_addAction($this, $action,$direction,$icon,$labeled);
0 ignored issues
show
Bug introduced by
The method _addAction() does not exist on Ajax\semantic\html\modules\HtmlDropdown. Did you maybe mean addAction()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
326
	}
327
}