HtmlTableContent   B
last analyzed

Complexity

Total Complexity 52

Size/Duplication

Total Lines 285
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 52
c 0
b 0
f 0
lcom 1
cbo 3
dl 0
loc 285
rs 7.9487

29 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 3
A setRowCount() 0 14 2
A getTdTagName() 0 3 1
A createItem() 0 10 2
A newRow() 0 3 1
A addRow() 0 3 1
A _addRow() 0 3 1
A getCell() 0 7 2
A getRow() 0 3 1
A setCellValue() 0 7 2
B setValues() 0 18 5
A setColValues() 0 11 3
A addColVariations() 0 7 2
A setRowValues() 0 8 2
A colAlign() 0 9 3
A colCenter() 0 3 1
A colRight() 0 3 1
A colLeft() 0 3 1
A getRowCount() 0 3 1
A getColCount() 0 6 2
A delete() 0 11 3
A mergeCol() 0 3 1
A mergeRow() 0 3 1
A setFullWidth() 0 3 1
A sort() 0 3 1
A conditionalCellFormat() 0 7 2
A conditionalRowFormat() 0 7 2
A applyCells() 0 7 2
A applyRows() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like HtmlTableContent 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 HtmlTableContent, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Ajax\semantic\html\content\table;
4
5
use Ajax\semantic\html\base\HtmlSemCollection;
6
use Ajax\service\JArray;
7
8
/**
9
 * a table content (thead, tbody or tfoot)
10
 * @author jc
11
 *
12
 */
13
class HtmlTableContent extends HtmlSemCollection {
14
	protected $_tdTagNames=[ "thead" => "th","tbody" => "td","tfoot" => "th" ];
15
16
	/**
17
	 *
18
	 * @param string $identifier
19
	 * @param string $tagName
20
	 * @param int $rowCount
21
	 * @param int $colCount
22
	 */
23
	public function __construct($identifier, $tagName="tbody", $rowCount=NULL, $colCount=NULL) {
24
		parent::__construct($identifier, $tagName, "");
25
		if (isset($rowCount) && isset($colCount))
26
			$this->setRowCount($rowCount, $colCount);
27
	}
28
29
	/**
30
	 *
31
	 * @param int $rowCount
32
	 * @param int $colCount
33
	 * @return \Ajax\semantic\html\content\table\HtmlTableContent
34
	 */
35
	public function setRowCount($rowCount, $colCount) {
36
		$count=$this->count();
37
		for($i=$count; $i < $rowCount; $i++) {
38
			$this->addItem($colCount);
39
		}
40
		/*
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
41
		 * for($i=0; $i < $rowCount; $i++) {
42
		 * $item=$this->content[$i];
43
		 * $item->setTdTagName($this->_tdTagNames[$this->tagName]);
44
		 * $this->content[$i]->setColCount($colCount);
45
		 * }
46
		 */
47
		return $this;
48
	}
49
50
	public function getTdTagName($tagName) {
0 ignored issues
show
Unused Code introduced by
The parameter $tagName is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
51
		return $this->_tdTagNames[$this->tagName];
52
	}
53
54
	/**
55
	 *
56
	 * {@inheritDoc}
57
	 *
58
	 * @see \Ajax\common\html\HtmlCollection::createItem()
59
	 */
60
	protected function createItem($value) {
61
		$count=$this->count();
62
		$tr=new HtmlTR("", $value);
0 ignored issues
show
Unused Code introduced by
The call to HtmlTR::__construct() has too many arguments starting with $value.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
63
		$tr->setContainer($this, $count);
64
		$tr->setTdTagName($this->_tdTagNames[$this->tagName]);
65
		if (isset($value) === true) {
66
			$tr->setColCount($value);
67
		}
68
		return $tr;
69
	}
70
71
	public function newRow($value) {
72
		return $this->createItem($value);
73
	}
74
75
	public function addRow($colCount) {
76
		return $this->addItem($colCount);
77
	}
78
79
	public function _addRow($row) {
80
		$this->addItem($row);
81
	}
82
83
	/**
84
	 * Returns the cell (HtmlTD) at position $row,$col
85
	 * @param int $row
86
	 * @param int $col
87
	 * @return \Ajax\semantic\html\content\HtmlTD
88
	 */
89
	public function getCell($row, $col) {
90
		$row=$this->getItem($row);
91
		if (isset($row)) {
92
			$col=$row->getItem($col);
93
		}
94
		return $col;
95
	}
96
97
	/**
98
	 *
99
	 * @param int $index
100
	 * @return \Ajax\semantic\html\content\HtmlTR
101
	 */
102
	public function getRow($index) {
103
		return $this->getItem($index);
104
	}
105
106
	/**
107
	 *
108
	 * @param int $row
109
	 * @param int $col
110
	 * @param mixed $value
111
	 * @return \Ajax\semantic\html\content\table\HtmlTableContent
112
	 */
113
	public function setCellValue($row, $col, $value="") {
114
		$cell=$this->getCell($row, $col);
115
		if (isset($cell) === true) {
116
			$cell->setValue($value);
117
		}
118
		return $this;
119
	}
120
121
	/**
122
	 * Sets the cells values
123
	 * @param mixed $values
124
	 */
125
	public function setValues($values=array()) {
126
		$count=$this->count();
127
		$isArray=true;
128
		if (\is_array($values) === false) {
129
			$values=\array_fill(0, $count, $values);
130
			$isArray=false;
131
		}
132
		if (JArray::dimension($values) == 1 && $isArray)
133
			$values=[ $values ];
134
135
		$count=\min(\sizeof($values), $count);
136
137
		for($i=0; $i < $count; $i++) {
138
			$row=$this->content[$i];
139
			$row->setValues($values[$i]);
140
		}
141
		return $this;
142
	}
143
144
	public function setColValues($colIndex, $values=array()) {
145
		$count=$this->count();
146
		if (\is_array($values) === false) {
147
			$values=\array_fill(0, $count, $values);
148
		}
149
		$count=\min(\sizeof($values), $count);
150
		for($i=0; $i < $count; $i++) {
151
			$this->getCell($i, $colIndex)->setValue($values[$i]);
152
		}
153
		return $this;
154
	}
155
156
	public function addColVariations($colIndex, $variations=array()) {
157
		$count=$this->count();
158
		for($i=0; $i < $count; $i++) {
159
			$this->getCell($i, $colIndex)->addVariations($variations);
160
		}
161
		return $this;
162
	}
163
164
	public function setRowValues($rowIndex, $values=array()) {
165
		$count=$this->count();
166
		if (\is_array($values) === false) {
167
			$values=\array_fill(0, $count, $values);
168
		}
169
		$this->getItem($rowIndex)->setValues($values);
0 ignored issues
show
Bug introduced by
The method setValues() does not exist on Ajax\common\html\HtmlDoubleElement. Did you maybe mean setValue()?

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...
170
		return $this;
171
	}
172
173
	private function colAlign($colIndex, $function) {
174
		$count=$this->count();
175
		for($i=0; $i < $count; $i++) {
176
			$index=$this->content[$i]->getColPosition($colIndex);
177
			if ($index !== NULL)
178
				$this->getCell($i, $index)->$function();
179
		}
180
		return $this;
181
	}
182
183
	public function colCenter($colIndex) {
184
		return $this->colAlign($colIndex, "textCenterAligned");
185
	}
186
187
	public function colRight($colIndex) {
188
		return $this->colAlign($colIndex, "textRightAligned");
189
	}
190
191
	public function colLeft($colIndex) {
192
		return $this->colAlign($colIndex, "textLeftAligned");
193
	}
194
195
	/**
196
	 * Returns the number of rows (TR)
197
	 * @return int
198
	 */
199
	public function getRowCount() {
200
		return $this->count();
201
	}
202
203
	/**
204
	 * Returns the number of columns (TD)
205
	 * @return int
206
	 */
207
	public function getColCount() {
208
		$result=0;
209
		if ($this->count() > 0)
210
			$result=$this->getItem(0)->getColCount();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajax\common\html\HtmlDoubleElement as the method getColCount() does only exist in the following sub-classes of Ajax\common\html\HtmlDoubleElement: Ajax\semantic\html\content\table\HtmlTableContent. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
211
		return $result;
212
	}
213
214
	/**
215
	 * Removes the cell at position $rowIndex,$colIndex
216
	 * @param int $rowIndex
217
	 * @param int $colIndex
218
	 * @return \Ajax\semantic\html\content\table\HtmlTableContent
219
	 */
220
	public function delete($rowIndex, $colIndex=NULL) {
221
		if (isset($colIndex)) {
222
			$row=$this->getItem($rowIndex);
223
			if (isset($row) === true) {
224
				$row->delete($colIndex);
225
			}
226
		} else {
227
			$this->removeItem($rowIndex);
228
		}
229
		return $this;
230
	}
231
232
	public function mergeCol($rowIndex=0, $colIndex=0) {
233
		return $this->getItem($rowIndex)->mergeCol($colIndex);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajax\common\html\HtmlDoubleElement as the method mergeCol() does only exist in the following sub-classes of Ajax\common\html\HtmlDoubleElement: Ajax\semantic\html\content\table\HtmlTD, Ajax\semantic\html\content\table\HtmlTR, Ajax\semantic\html\content\table\HtmlTableContent. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
234
	}
235
236
	public function mergeRow($rowIndex=0, $colIndex=0) {
237
		return $this->getItem($rowIndex)->mergeRow($colIndex);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Ajax\common\html\HtmlDoubleElement as the method mergeRow() does only exist in the following sub-classes of Ajax\common\html\HtmlDoubleElement: Ajax\semantic\html\content\table\HtmlTD, Ajax\semantic\html\content\table\HtmlTR, Ajax\semantic\html\content\table\HtmlTableContent. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
238
	}
239
240
	public function setFullWidth() {
241
		return $this->addToProperty("class", "full-width");
242
	}
243
244
	public function sort($colIndex) {
245
		$this->content[0]->getItem($colIndex)->addToProperty("class", "sorted ascending");
246
	}
247
248
	/**
249
	 * @param mixed $callback
250
	 * @param string $format
251
	 * @return \Ajax\semantic\html\content\table\HtmlTableContent
252
	 */
253
	public function conditionalCellFormat($callback, $format) {
254
		$rows=$this->content;
255
		foreach ( $rows as $row ) {
256
			$row->conditionalCellFormat($callback, $format);
257
		}
258
		return $this;
259
	}
260
261
	/**
262
	 * @param mixed $callback
263
	 * @param string $format
264
	 * @return \Ajax\semantic\html\content\table\HtmlTableContent
265
	 */
266
	public function conditionalRowFormat($callback, $format) {
267
		$rows=$this->content;
268
		foreach ( $rows as $row ) {
269
			$row->conditionalRowFormat($callback, $format);
270
		}
271
		return $this;
272
	}
273
274
	/**
275
	 * @param mixed $callback
276
	 * @return \Ajax\semantic\html\content\table\HtmlTableContent
277
	 */
278
	public function applyCells($callback) {
279
		$rows=$this->content;
280
		foreach ( $rows as $row ) {
281
			$row->applyCells($callback);
282
		}
283
		return $this;
284
	}
285
286
	/**
287
	 * @param mixed $callback
288
	 * @return \Ajax\semantic\html\content\table\HtmlTableContent
289
	 */
290
	public function applyRows($callback) {
291
		$rows=$this->content;
292
		foreach ( $rows as $row ) {
293
			$row->apply($callback);
294
		}
295
		return $this;
296
	}
297
}