Completed
Pull Request — master (#648)
by
unknown
12:11
created

Row   B

Complexity

Total Complexity 42

Size/Duplication

Total Lines 304
Duplicated Lines 20.39 %

Coupling/Cohesion

Components 2
Dependencies 9

Test Coverage

Coverage 42.35%

Importance

Changes 4
Bugs 0 Features 1
Metric Value
wmc 42
c 4
b 0
f 1
lcom 2
cbo 9
dl 62
loc 304
rs 8.295
ccs 36
cts 85
cp 0.4235

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 2
A getId() 0 4 1
C getValue() 0 27 7
A getControl() 0 4 1
A getControlClass() 0 8 2
B getActiveRowProperty() 18 24 5
B getLeanMapperEntityProperty() 22 23 4
B getNextrasEntityProperty() 22 23 4
B getDoctrineEntityProperty() 0 24 5
A getItem() 0 4 1
A hasGroupAction() 0 6 2
A hasAction() 0 6 2
A hasInlineEdit() 0 6 2
A applyColumnCallback() 0 10 2
A formatDibiRowKey() 0 8 2

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

1
<?php declare(strict_types = 1);
2
3
namespace Ublaboo\DataGrid;
4
5
use Dibi\Row as DibiRow;
6
use LeanMapper;
7
use Nette;
8
use Nette\Database\Table\ActiveRow;
9
use Nette\SmartObject;
10
use Nette\Utils\Html;
11
use Nextras;
12
use Ublaboo\DataGrid\Exception\DataGridException;
13
use Ublaboo\DataGrid\Utils\PropertyAccessHelper;
14
15
class Row
16
{
17
18
	use SmartObject;
19
20
	/**
21 1
	 * @var DataGrid
22
	 */
23
	protected $datagrid;
24 1
25
	/**
26
	 * @var mixed
27
	 */
28
	protected $item;
29
30
	/**
31
	 * @var string
32
	 */
33
	protected $primary_key;
34
35
	/**
36
	 * @var mixed
37
	 */
38
	protected $id;
39
40
	/**
41
	 * @var Html
42
	 */
43
	protected $control;
44
45
/**
46
 * @param mixed    $item
47
 * @param string   $primary_key
48
 */
49
	public function __construct(DataGrid $datagrid, $item, $primary_key)
50
	{
51
		$this->control = Html::el('tr');
52
		$this->datagrid = $datagrid;
53
		$this->item = $item;
54
		$this->primary_key = $primary_key;
55
		$this->id = $this->getValue($primary_key);
56
57
		if ($datagrid->hasColumnsSummary()) {
58
			$datagrid->getColumnsSummary()->add($this);
59 1
		}
60 1
	}
61 1
62 1
63 1
	/**
64
	 * Get id value of item
65 1
	 *
66
	 * @return mixed
67
	 */
68 1
	public function getId()
69
	{
70
		return $this->id;
71
	}
72
73
74
	/**
75
	 * Get item value of key
76
	 *
77 1
	 * @param  mixed $key
78
	 * @return mixed
79
	 */
80
	public function getValue($key)
81
	{
82
		if ($this->item instanceof LeanMapper\Entity) {
83
			return $this->getLeanMapperEntityProperty($this->item, $key);
84
85
		} elseif ($this->item instanceof Nextras\Orm\Entity\Entity) {
86
			return $this->getNextrasEntityProperty($this->item, $key);
87
88 1
		} elseif ($this->item instanceof DibiRow) {
89 1
			return $this->item->{$this->formatDibiRowKey($key)};
90
91 1
		} elseif ($this->item instanceof ActiveRow) {
92
			return $this->getActiveRowProperty($this->item, $key);
93
94 1
		} elseif ($this->item instanceof Nette\Database\Row) {
95
			return $this->item->{$key};
96
97 1
		} elseif (is_array($this->item)) {
98
			return $this->item[$key];
99
100 1
		} else {
101
			/**
102
			 * Doctrine entity
103 1
			 */
104 1
			return $this->getDoctrineEntityProperty($this->item, $key);
105
		}
106
	}
107
108
109
	public function getControl(): Html
110 1
	{
111
		return $this->control;
112
	}
113
114
115
	public function getControlClass(): string
116
	{
117
		if (!$class = $this->control->class) {
118
			return '';
119
		}
120 1
121
		return implode(' ', array_keys($class));
122
	}
123
124
125
	/**
126
	 * @return mixed|NULL
127
	 */
128
	public function getActiveRowProperty(ActiveRow $item, string $key)
129 1
	{
130 View Code Duplication
		if (preg_match('/^:([a-zA-Z0-9_$]+)\.([a-zA-Z0-9_$]+)(:([a-zA-Z0-9_$]+))?$/', $key, $matches)) {
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...
131
			$relatedTable = $matches[1];
132
			$relatedColumn = $matches[2];
133 1
			$throughColumn = $matches[4] ?? null;
134
135
			$relatedRow = $item->related($relatedTable, $throughColumn)->fetch();
136
137
			return $relatedRow ? $relatedRow->{$relatedColumn} : null;
138
		}
139
140 View Code Duplication
		if (preg_match('/^([a-zA-Z0-9_$]+)\.([a-zA-Z0-9_$]+)(:([a-zA-Z0-9_$]+))?$/', $key, $matches)) {
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...
141
			$referencedTable = $matches[1];
142
			$referencedColumn = $matches[2];
143
			$throughColumn = $matches[4] ?? null;
144
145
			$referencedRow = $item->ref($referencedTable, $throughColumn);
146
147
			return $referencedRow ? $referencedRow->{$referencedColumn} : null;
148
		}
149
150
		return $item->{$key};
151
	}
152
153
154
	/**
155
	 * LeanMapper: Access object properties to get a item value
156
	 *
157
	 * @param  mixed             $key
158
	 * @return mixed
159
	 */
160 View Code Duplication
	public function getLeanMapperEntityProperty(LeanMapper\Entity $item, $key)
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...
161
	{
162
		$properties = explode('.', $key);
163
		$value = $item;
164
165
		while ($property = array_shift($properties)) {
166
			if (!isset($value->{$property})) {
167
				if ($this->datagrid->strict_entity_property) {
168
					throw new DataGridException(sprintf(
169
						'Target Property [%s] is not an object or is empty, trying to get [%s]',
170
						$value,
171
						str_replace('.', '->', $key)
172
					));
173
				}
174
175
				return null;
176 1
			}
177 1
178
			$value = $value->{$property};
179 1
		}
180 1
181
		return $value;
182
	}
183
184
185
	/**
186
	 * Nextras: Access object properties to get a item value
187
	 *
188
	 * @return mixed
189
	 */
190 View Code Duplication
	public function getNextrasEntityProperty(Nextras\Orm\Entity\Entity $item, string $key)
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...
191 1
	{
192
		$properties = explode('.', $key);
193
		$value = $item;
194 1
195
		while ($property = array_shift($properties)) {
196
			if (!isset($value->{$property})) {
197
				if ($this->datagrid->strict_entity_property) {
198
					throw new DataGridException(sprintf(
199
						'Target Property [%s] is not an object or is empty, trying to get [%s]',
200
						$value,
201
						str_replace('.', '->', $key)
202
					));
203
				}
204
205
				return null;
206
			}
207
208
			$value = $value->{$property};
209
		}
210
211
		return $value;
212
	}
213
214
215
	/**
216
	 * Doctrine: Access object properties to get a item value
217
	 *
218
	 * @param  mixed $item
219
	 * @param  mixed $key
220
	 * @return mixed
221
	 */
222
	public function getDoctrineEntityProperty($item, $key)
223
	{
224
		$properties = explode('.', $key);
225
		$value = $item;
226
		$accessor = PropertyAccessHelper::getAccessor();
227
228
		while ($property = array_shift($properties)) {
229
			if (!is_object($value) && !$value) {
230
				if ($this->datagrid->strict_entity_property) {
231
					throw new DataGridException(sprintf(
232
						'Target Property [%s] is not an object or is empty, trying to get [%s]',
233
						$value,
234
						str_replace('.', '->', $key)
235
					));
236 1
				}
237 1
238 1
				return null;
239
			}
240 1
241 1
			$value = $accessor->getValue($value, $property);
242
		}
243
244
		return $value;
245
	}
246
247
248
	/**
249
	 * Get original item
250
	 *
251
	 * @return mixed
252 1
	 */
253
	public function getItem()
254
	{
255 1
		return $this->item;
256
	}
257
258
259
	/**
260
	 * Has particular row group actions allowed?
261
	 */
262
	public function hasGroupAction(): bool
263
	{
264
		$condition = $this->datagrid->getRowCondition('group_action');
265 1
266
		return $condition ? $condition($this->item) : true;
267
	}
268
269
270
	/**
271
	 * Has particular row a action allowed?
272
	 *
273
	 * @param  mixed  $key
274
	 */
275
	public function hasAction($key): bool
276
	{
277
		$condition = $this->datagrid->getRowCondition('action', $key);
278
279
		return $condition ? $condition($this->item) : true;
280
	}
281
282
283
	/**
284
	 * Has particular row inlie edit allowed?
285
	 */
286
	public function hasInlineEdit(): bool
287
	{
288
		$condition = $this->datagrid->getRowCondition('inline_edit');
289
290
		return $condition ? $condition($this->item) : true;
291
	}
292
293
294
	public function applyColumnCallback(string $key, Column\Column $column): Column\Column
295
	{
296
		$callback = $this->datagrid->getColumnCallback($key);
297
298
		if ($callback !== null) {
299
			call_user_func($callback, $column, $this->getItem());
300
		}
301
302
		return $column;
303
	}
304
305
306
	/**
307
	 * Key may contain ".", get rid of it (+ the table alias)
308
	 */
309
	private function formatDibiRowKey(string $key): string
310
	{
311
		if ($offset = strpos($key, '.')) {
312
			return substr($key, $offset + 1);
313
		}
314
315
		return $key;
316
	}
317
318
}
319