Completed
Push — master ( 22ba15...552305 )
by Jean-Christophe
03:10
created

HtmlDropdown   C

Complexity

Total Complexity 56

Size/Duplication

Total Lines 285
Duplicated Lines 4.56 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 0
Metric Value
wmc 56
lcom 1
cbo 8
dl 13
loc 285
rs 6.5957
c 0
b 0
f 0

34 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
A getField() 0 3 1
A addItem() 0 5 1
A addIcon() 0 4 1
A insertItem() 0 8 1
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
A addItems() 11 11 4
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 6 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

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
26
	public function __construct($identifier, $value="", $items=array()) {
27
		parent::__construct($identifier, "div");
28
		$this->_template=include dirname(__FILE__).'/../templates/tplDropdown.php';
29
		$this->setProperty("class", "ui dropdown");
30
		$content=new HtmlSemDoubleElement("text-".$this->identifier,"div");
31
		$content->setClass("text");
32
		$this->setValue($value);
33
		$content->wrap("",new HtmlIcon("", "dropdown"));
34
		$this->content=array($content);
35
		$this->tagName="div";
36
		$this->addItems($items);
37
	}
38
39
	public function getField(){
40
		return $this->input;
41
	}
42
43
	public function addItem($item,$value=NULL,$image=NULL,$description=NULL){
44
		$itemO=$this->beforeAddItem($item,$value,$image,$description);
45
		$this->items[]=$itemO;
46
		return $itemO;
47
	}
48
49
	public function addIcon($icon,$before=true,$labeled=false){
50
		$this->addIconP($icon,$before,$labeled);
51
		return $this->getElementById("text-".$this->identifier, $this->content)->setWrapAfter("");
52
	}
53
54
	/**
55
	 * Insert an item at a position
56
	 * @param mixed $item
57
	 * @param number $position
58
	 * @return \Ajax\semantic\html\content\HtmlDropdownItem|unknown
59
	 */
60
	public function insertItem($item,$position=0){
61
		$itemO=$this->beforeAddItem($item);
62
		 $start = array_slice($this->items, 0, $position);
63
		 $end = array_slice($this->items, $position);
64
		 $start[] = $item;
65
		 $this->items=array_merge($start, $end);
66
		 return $itemO;
67
	}
68
69
	protected function beforeAddItem($item,$value=NULL,$image=NULL,$description=NULL){
70
		$itemO=$item;
71
		if(\is_array($item)){
72
			$description=JArray::getValue($item, "description", 3);
73
			$value=JArray::getValue($item, "value", 1);
74
			$image=JArray::getValue($item, "image", 2);
75
			$item=JArray::getValue($item, "item", 0);
76
		}
77
		if(!$item instanceof HtmlDropdownItem){
78
			$itemO=new HtmlDropdownItem("dd-item-".$this->identifier."-".\sizeof($this->items),$item,$value,$image,$description);
79
		}elseif($itemO instanceof HtmlDropdownItem){
80
			$this->addToProperty("class", "vertical");
81
		}
82
		return $itemO;
83
	}
84
85
	/* (non-PHPdoc)
86
	 * @see \Ajax\bootstrap\html\base\BaseHtml::fromDatabaseObject()
87
	 */
88
	public function fromDatabaseObject($object, $function) {
89
		$this->addItem($function($object));
90
	}
91
92
	public function addInput($name){
93
		if(!isset($name))
94
			$name="input-".$this->identifier;
95
		$this->setAction("activate");
96
		$this->input=new HtmlInput($name,"hidden");
97
	}
98
99
	/**
100
	 * Adds a search input item
101
	 * @param string $placeHolder
102
	 * @param string $icon
103
	 * @return \Ajax\semantic\html\content\HtmlDropdownItem
104
	 */
105
	public function addSearchInputItem($placeHolder=NULL,$icon=NULL){
106
		return $this->addItem(HtmlDropdownItem::searchInput($placeHolder,$icon));
107
	}
108
109
	/**
110
	 * Adds a divider item
111
	 * @return \Ajax\semantic\html\content\HtmlDropdownItem
112
	 */
113
	public function addDividerItem(){
114
		return $this->addItem(HtmlDropdownItem::divider());
115
	}
116
117
	/**
118
	 * Adds an header item
119
	 * @param string $caption
120
	 * @param string $icon
121
	 * @return \Ajax\semantic\html\content\HtmlDropdownItem|unknown
122
	 */
123
	public function addHeaderItem($caption=NULL,$icon=NULL){
124
		return $this->addItem(HtmlDropdownItem::header($caption,$icon));
125
	}
126
127
	/**
128
	 * Adds an item with a circular label
129
	 * @param string $caption
130
	 * @param string $color
131
	 * @return \Ajax\semantic\html\content\HtmlDropdownItem|unknown
132
	 */
133
	public function addCircularLabelItem($caption,$color){
134
		return $this->addItem(HtmlDropdownItem::circular($caption, $color));
135
	}
136
137
	/**
138
	 * @param string $caption
139
	 * @param string $image
140
	 * @return \Ajax\semantic\html\content\HtmlDropdownItem
141
	 */
142
	public function addMiniAvatarImageItem($caption,$image){
143
		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...
144
	}
145
146 View Code Duplication
	public function addItems($items){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
147
		if(JArray::isAssociative($items)){
148
			foreach ($items as $k=>$v){
149
				$this->addItem($v)->setData($k);
150
			}
151
		}else{
152
			foreach ($items as $item){
153
				$this->addItem($item);
154
			}
155
		}
156
	}
157
158
	public function getItem($index){
159
		return $this->items[$index];
160
	}
161
162
	/**
163
	 * @return int
164
	 */
165
	public function count(){
166
		return \sizeof($this->items);
167
	}
168
	/**
169
	 * @param boolean $dropdown
170
	 */
171
	public function asDropdown($dropdown){
172
		if($dropdown===false){
173
			$this->_template=include dirname(__FILE__).'/../templates/tplDropdownMenu.php';
174
			$dropdown="menu";
175
		}else{
176
			$dropdown="dropdown";
177
			$this->mClass="menu";
178
		}
179
		return $this->addToPropertyCtrl("class", $dropdown,array("menu","dropdown"));
180
	}
181
182
	public function setVertical(){
183
		return $this->addToPropertyCtrl("class", "vertical",array("vertical"));
184
	}
185
186
	public function setInline(){
187
		return $this->addToPropertyCtrl("class", "inline",["inline"]);
188
	}
189
190
	public function setSimple(){
191
		return $this->addToPropertyCtrl("class", "simple",array("simple"));
192
	}
193
194
	public function asButton($floating=false){
195
		if($floating)
196
			$this->addToProperty("class", "floating");
197
		$this->removePropertyValue("class", "selection");
198
		return $this->addToProperty("class", "button");
199
	}
200
201
	public function asSelect($name=NULL,$multiple=false,$selection=true){
202
		if(isset($name))
203
			$this->addInput($name);
204
		if($multiple)
205
			$this->addToProperty("class", "multiple");
206
		if ($selection){
207
			if($this->propertyContains("class", "button")===false)
208
				$this->addToPropertyCtrl("class", "selection",array("selection"));
209
		}
210
		return $this;
211
	}
212
213
	public function asSearch($name=NULL,$multiple=false,$selection=true){
214
		$this->asSelect($name,$multiple,$selection);
215
		return $this->addToProperty("class", "search");
216
	}
217
218
	public function setSelect($name=NULL,$multiple=false){
219
		if(!isset($name))
220
			$name="select-".$this->identifier;
221
		$this->input=null;
222
		if($multiple){
223
			$this->setProperty("multiple", true);
224
			$this->addToProperty("class", "multiple");
225
		}
226
		$this->setAction("activate");
227
		$this->tagName="select";
228
		$this->setProperty("name", $name);
229
		$this->content=null;
230
		foreach ($this->items as $item){
231
			$item->asOption();
232
		}
233
		return $this;
234
	}
235
236
	public function asSubmenu($pointing=NULL){
237
		$this->setClass("ui dropdown link item");
238
		if(isset($pointing)){
239
			$this->setPointing($pointing);
240
		}
241
		return $this;
242
	}
243
244
	public function setPointing($value=Direction::NONE){
245
		return $this->addToPropertyCtrl("class", $value." pointing",Direction::getConstantValues("pointing"));
246
	}
247
248
	public function setValue($value){
249
		$this->value=$value;
250
		return $this;
251
	}
252
	private function applyValue(){
253
		$value=$this->value;
254
		if(isset($this->input) && isset($value)){
255
			$this->input->setProperty("value", $value);
256
		}else{
257
			$this->setProperty("value", $value);
258
		}
259
			$textElement=$this->getElementById("text-".$this->identifier, $this->content);
260
			if(isset($textElement))
261
				$textElement->setContent($value);
262
		return $this;
263
	}
264
265
	/*
266
	 * (non-PHPdoc)
267
	 * @see BaseHtml::run()
268
	 */
269
	public function run(JsUtils $js) {
270
		if($this->propertyContains("class", "simple")===false){
271 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...
272
				$this->_bsComponent=$js->semantic()->dropdown("#".$this->identifier,$this->_params);
273
			$this->addEventsOnRun($js);
274
			return $this->_bsComponent;
275
		}
276
	}
277
278
	public function setCompact(){
279
		return $this->addToPropertyCtrl("class", "compact", array("compact"));
280
	}
281
282
	public function setAction($action){
283
		$this->_params["action"]=$action;
284
	}
285
286
	public function setFullTextSearch($value){
287
		$this->_params["fullTextSearch"]=$value;
288
	}
289
290
	public function compile(JsUtils $js=NULL, &$view=NULL) {
291
		$this->applyValue();
292
		return parent::compile($js,$view);
293
	}
294
295
	public function getInput() {
296
		return $this->input;
297
	}
298
299
}