Passed
Push — master ( 700b0f...aafb0a )
by Björn
18:25 queued 10s
created

Table   D

Complexity

Total Complexity 59

Size/Duplication

Total Lines 316
Duplicated Lines 9.81 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 59
lcom 1
cbo 2
dl 31
loc 316
rs 4.08
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
F __invoke() 31 49 23
A render() 0 4 1
A buildHeaderCells() 0 18 3
A buildFooterCells() 0 14 3
B buildBodyCells() 0 34 9
A buildMarkupTemplate() 0 19 1
A buildMarkup() 0 21 3
A buildData() 0 7 2
A getTemplate() 0 6 2
A setTemplate() 0 8 2
A getData() 0 3 1
A setData() 0 6 2
A getOptions() 0 10 3
A setOptions() 0 14 4

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

1
<?php
2
/**
3
 * BB's Zend Framework 2 Components
4
 * 
5
 * UI Components
6
 *
7
 * @package     [MyApplication]
8
 * @subpackage  BB's Zend Framework 2 Components
9
 * @subpackage  UI Components
10
 * @author      Björn Bartels <[email protected]>
11
 * @link        https://gitlab.bjoernbartels.earth/groups/zf2
12
 * @license     http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
13
 * @copyright   copyright (c) 2016 Björn Bartels <[email protected]>
14
 */
15
16
namespace UIComponents\View\Helper\Components;
17
18
use UIComponents\Template\Template;
19
20
/**
21
 *
22
 * render a (simple) HTML table
23
 *
24
 */
25
class Table extends Element 
26
{
27
    /** @var \UIComponents\Template\Template $template */
28
	public $template = null;
29
30
	/** @var array $data */
31
	public $data = array();
32
33
	/** @var array $options */
34
	public $options = array();
35
36
	/** @var array $tags */
37
	public $tags = array(
38
		"container" =>	"table",
39
		"row"		=>	"tr",
40
		"cell"		=>	"td",
41
		"headcell"	=>	"th"
42
	);
43
	
44
	/**
45
     * View helper entry point:
46
     * Retrieves helper and optionally sets component options to operate on
47
     *
48
     * @param  array|StdClass $config table configuration to operate on
49
     * @param  array|StdClass $options [optional] component options to operate on
50
     * @return self
51
     */
52
    public function __invoke($config = array(), $options = array())
53
    {
54 View Code Duplication
        if ( is_object($options) && method_exists($options, 'toArray') ) {
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...
55
            $options = $options->toArray();
56
        } else if ( is_object($options) ) {
57
            $options = (array)$options;
58
        }
59
        
60 View Code Duplication
        if ( is_object($config) && method_exists($config, 'toArray') ) {
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...
61
            $config = $config->toArray();
62
        } else if ( is_object($options) ) {
63
            $config = (array)$config;
64
        }
65
        
66
        $this->setOptions($config);
67
        
68
        if (isset($options['container']) && (null !== $options['container'])) {
69
            $this->setContainer($options['container']);
70
        }
71
    
72 View Code Duplication
        if (isset($options['tagname']) && (null !== $options['tagname'])) {
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...
73
            $this->setTagname($options['tagname']);
74
        }
75 View Code Duplication
        if (isset($options['class']) && (null !== $options['class'])) {
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...
76
            $this->setClassnames($options['class']);
77
        }
78 View Code Duplication
        if (isset($options['classnames']) && (null !== $options['classnames'])) {
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...
79
            $this->setClassnames($options['classnames']);
80
        }
81
82 View Code Duplication
        if (isset($options['attr']) && (null !== $options['attr'])) {
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...
83
            $this->setAttributes($options['attr']);
84
        }
85 View Code Duplication
        if (isset($options['attributes']) && (null !== $options['attributes'])) {
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...
86
            $this->setAttributes($options['attributes']);
87
        }
88
89 View Code Duplication
        if (isset($options['content']) && (null !== $options['content'])) {
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...
90
            $this->setContent($options['content']);
91
        }
92 View Code Duplication
        if (isset($options['children']) && (null !== $options['children'])) {
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...
93
            $this->setContent($options['children']);
94
        }
95
        
96
        $this->tags = (object)$this->tags;
97
        
98
        $component = clone $this;
99
        return $component;
100
    }
101
102
    /**
103
     * generate framework classnames collection as zend-config object
104
     * 
105
     * @return string
106
     */
107
    public function render()
108
    {
109
    	return $this->buildMarkup();
110
    }
111
    
112
	/**
113
	 * generate table header HTML
114
	 * @param mixed $aHTMLTableColumns
115
	 * @return self
116
	 */
117
	public function buildHeaderCells ($aHTMLTableColumns) {
118
		$sHTMLTableHeader = "";
119
		$sHTMLTableColumnGroup = "";
120
		$aColumns = array();
121
		foreach ((array)$aHTMLTableColumns as $iColumn => $aColumn) {
122
			if ($aColumn["field"]) {
123
				$aColumns[] = $aColumn["field"];
124
				$sHTMLTableHeader .= "<".$this->tags->headcell." class=\"".$aColumn["field"]."\">".$aColumn["title"]."</".$this->tags->headcell.">";
125
				$sHTMLTableColumnGroup .= "<column class=\"".$aColumn["field"]."\" />";
126
			} else {
127
				$sHTMLTableHeader .= "<".$this->tags->headcell." class=\"col_".$iColumn."\">".$aColumn["title"]."</".$this->tags->headcell.">";
128
				$sHTMLTableColumnGroup .= "<column class=\"col_".$iColumn."\" />";
129
			}
130
		}
131
		$this->getTemplate()->set('s', 'HEADERCELLS', $sHTMLTableHeader);
132
		$this->getTemplate()->set('s', 'COLUMNGROUP', "<columns>".$sHTMLTableColumnGroup."</columns>");
133
		return ($this);
134
	}
135
		
136
	/**
137
	 * generate table footer HTML
138
	 * @param mixed $aHTMLTableColumns
139
	 * @return self
140
	 */
141
	public function buildFooterCells ($aHTMLTableColumns) {
142
		$sHTMLTableFooter = "";
143
		$aColumns = array();
144
		foreach ((array)$aHTMLTableColumns as $iColumn => $aColumn) {
145
			if ($aColumn["field"]) {
146
				$aColumns[] = $aColumn["field"];
147
				$sHTMLTableFooter .= "<".$this->tags->cell." class=\"".$aColumn["field"]."\">".$aColumn["title"]."</".$this->tags->cell.">";
148
			} else {
149
				$sHTMLTableFooter .= "<".$this->tags->cell." class=\"col_".$iColumn."\">".$aColumn["title"]."</".$this->tags->cell.">";
150
			}
151
		}
152
		$this->getTemplate()->set('s', 'FOOTERCELLS', $sHTMLTableFooter);
153
		return ($this);
154
	}
155
	
156
	/**
157
	 * generate table body HTML
158
	 * @param array $aRowData
159
	 * @param mixed $aHTMLTableColumns
160
	 * @return array
161
	 */
162
	public function buildBodyCells ($aRowData, $aHTMLTableColumns) {
163
		$aRows = array();
164
		foreach ( (array)$aRowData as $iRow => $oRowData ) {
165
			$sCells = "";
166
			foreach ((array)$aHTMLTableColumns as $iColumn => $aColumn) {
167
				$mCellValue = $oRowData[$aColumn["field"]];
168
				if (!empty($aColumn["callback"]) && function_exists($aColumn["callback"])) {
169
					$mCellValue = call_user_func($aColumn["callback"], $oRowData, $aColumn, $iColumn, $iRow);
170
				}
171
				if ( isset($aColumn["field"]) && isset($oRowData[$aColumn["field"]]) ) {
172
					$sClassname = $aColumn["field"];
173
				} else {
174
					$sClassname = "col_".$iColumn;
175
				}
176
				$sCells .= "<".$this->tags->cell." class=\"".$sClassname."\">".
177
					$mCellValue.
178
				"</".$this->tags->cell.">";
179
			}
180
			
181
			$aRows[] = $sCells;
182
		}
183
		
184
		foreach ($aRows as $iRow => $sRow) {
185
			$this->getTemplate()->set('d', 'ROWID', "row_".$aRowData[$iRow]["productID"]);
186
			$this->getTemplate()->set('d', 'BODYCELLS', $sRow);
187
			if (($iRow % 2) == 0) {
188
				$this->getTemplate()->set('d', 'CSS_CLASS', 'even');
189
			} else {
190
				$this->getTemplate()->set('d', 'CSS_CLASS', 'odd');
191
			}
192
			$this->getTemplate()->next();
193
		
194
		}
195
	}
196
	
197
	/**
198
	 * generate mini table mark-up template
199
	 * @return string
200
	 */
201
	public function buildMarkupTemplate () {
202
		$aHTML = array(
203
			"<".$this->tags->container.">",
204
				"<".$this->tags->row.">",
205
					"{HEADERCELLS}",
206
				"</".$this->tags->row.">",
207
					"<!-- BEGIN:BLOCK -->",
208
						"<".$this->tags->row.">",
209
							"{BODYCELLS}",
210
						"</".$this->tags->row.">",
211
					"<!-- END:BLOCK -->",
212
				"<".$this->tags->row.">",
213
					"{FOOTERCELLS}",
214
				"</".$this->tags->row.">",
215
			"</".$this->tags->container.">"
216
		);
217
		$sHTML = implode("", $aHTML);
218
		return $sHTML;
219
	}
220
	
221
	/**
222
	 * generate table mark-up
223
	 * @return string
224
	 */
225
	public function buildMarkup () {
226
		$sHTML = "";
0 ignored issues
show
Unused Code introduced by
$sHTML is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
227
		
228
		$sTableID = $this->getOptions("formID");
229
		if (!$sTableID) {
230
			$sTableID = "table" . md5(microtime());
231
			$this->options["formID"] = $sTableID;
232
		}
233
		
234
		$this->getTemplate()->reset();
235
		$this->getTemplate()->set('s', 'TABLEID',			$sTableID );
236
		$this->buildHeaderCells( $this->getOptions("columns") );
237
		$this->buildFooterCells( $this->getOptions("footer") );
238
		$this->buildBodyCells( $this->getData(), $this->getOptions("columns") );
239
		$sTemplate = $this->getOptions("template");
240
		if ($sTemplate == "") {
241
			$sTemplate = $this->buildMarkupTemplate();
242
		}
243
		$sHTML = $this->getTemplate()->generate( $sTemplate, true );
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a integer.

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...
244
		return $sHTML;
245
	}
246
	
247
	/**
248
	 * generate table JSON data
249
	 * @return string
250
	 */
251
	public function buildData () {
252
		$sJSON = "[]";
253
		if (!empty($this->data)) {
254
			$sJSON = json_encode($this->data);
255
		}
256
		return $sJSON;
257
	}
258
	
259
	/**
260
	 * return template object
261
	 * @return Template
262
	 */
263
	public function getTemplate() {
264
		if ($this->template == null) {
265
			$this->setTemplate();
266
		}
267
		return $this->template;
268
	}
269
270
	/**
271
	 * generate template object
272
	 * @param Template $template
273
	 * @return ProductTable
274
	 */
275
	public function setTemplate( $template = null ) {
276
		if ($template == null) {
277
			$this->template = new Template;
278
		} else {
279
			$this->template = $template;
280
		}
281
		return ($this);
282
	}
283
	
284
	/**
285
	 * return table data
286
	 * @return mixed
287
	 */
288
	public function getData() {
289
		return $this->data;
290
	}
291
292
	/**
293
	 * set new table data
294
	 * @param mixed $data
295
	 * @return ProductTable
296
	 */
297
	public function setData( $data = null) {
298
		if ( is_array($data) ) {
299
			$this->data = $data;
300
		}
301
		return $this;
302
	}
303
304
	/**
305
	 * return option by key or complete option set
306
	 * @param	string $key	
307
	 * @return	mixed
308
	 */
309
	public function getOptions( $key = "" ) {
310
		if ( !empty($key) ) { 
311
			if ( isset($this->options[$key]) ) {
312
				return $this->options[$key];
313
			} else {
314
				return false;
315
			}
316
		}
317
		return $this->options;
318
	}
319
320
	/**
321
	 * @param object|array $options
322
	 * @return ProductTable
323
	 */
324
	public function setOptions($options) {
325
		if ( is_array($options) ) {
326
			$this->options = $options;
327
		} else if ( is_object($options) ) {
328
			$this->options = (array)$options;
329
		} else {
330
			throw new \Exception("invalid table options");
331
		}
332
		if ( isset($this->options["data"]) ) {
333
			$this->setData($this->getOptions("data"));
334
			unset( $this->options->data );
335
		}
336
		return $this;
337
	}
338
339
340
}