Completed
Pull Request — master (#258)
by
unknown
10:36
created

Column   B

Complexity

Total Complexity 49

Size/Duplication

Total Lines 390
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 96.81%

Importance

Changes 5
Bugs 1 Features 0
Metric Value
wmc 49
c 5
b 1
f 0
lcom 1
cbo 6
dl 0
loc 390
ccs 91
cts 94
cp 0.9681
rs 8.5454

29 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A setSortable() 0 5 1
A setReplacement() 0 5 1
A setColumn() 0 5 1
A setDefaultSort() 0 5 1
A setCustomRender() 0 7 1
A setCustomRenderExport() 0 5 1
A setCellCallback() 0 5 1
A getCellPrototype() 0 16 4
B getHeaderPrototype() 0 15 5
A getColumn() 0 4 1
A getSort() 0 14 4
A getCustomRender() 0 4 1
A getCustomRenderVariables() 0 4 1
A getLabel() 0 6 2
A isSortable() 0 4 1
A hasFilter() 0 4 1
A render() 0 9 2
A renderExport() 0 9 2
A getValue() 0 18 3
B applyReplacement() 0 8 5
A formatValue() 0 8 2
A setFilterText() 0 4 1
A setFilterDate() 0 4 1
A setFilterDateRange() 0 4 1
A setFilterCheck() 0 4 1
A setFilterSelect() 0 4 1
A setFilterNumber() 0 4 1
A setFilterCustom() 0 4 1

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
/**
4
 * This file is part of the Grido (http://grido.bugyik.cz)
5
 *
6
 * Copyright (c) 2011 Petr Bugyík (http://petr.bugyik.cz)
7
 *
8
 * For the full copyright and license information, please view
9
 * the file LICENSE.md that was distributed with this source code.
10
 */
11
12
namespace Grido\Components\Columns;
13
14
use Grido\Helpers;
15
use Grido\Exception;
16
17
/**
18
 * Column grid.
19
 *
20
 * @package     Grido
21
 * @subpackage  Components\Columns
22
 * @author      Petr Bugyík
23
 *
24
 * @property-read string $sort
25
 * @property-read \Nette\Utils\Html $cellPrototype
26
 * @property-read \Nette\Utils\Html $headerPrototype
27
 * @property-write callback $cellCallback
28
 * @property-write string $defaultSorting
29
 * @property-write mixed $customRender
30
 * @property-write array $customRenderVariables
31
 * @property-write mixed $customRenderExport
32
 * @property-write array $replacements
33
 * @property-write bool $sortable
34
 * @property string $column
35
 */
36
abstract class Column extends \Grido\Components\Component
37 1
{
38
    const ID = 'columns';
39
40
    const VALUE_IDENTIFIER = '%value';
41
42
    const ORDER_ASC = 'asc';
43
    const ORDER_DESC = 'desc';
44
45
    /** @var string */
46
    protected $sort;
47
48
    /** @var string */
49
    protected $column;
50
51
    /** @var \Nette\Utils\Html <td> html tag */
52
    protected $cellPrototype;
53
54
    /** @var callback returns td html element; function($row, Html $td) */
55
    protected $cellCallback;
56
57
    /** @var \Nette\Utils\Html <th> html tag */
58
    protected $headerPrototype;
59
60
    /** @var mixed custom rendering */
61
    protected $customRender;
62
63
    /** @var array custom rendering template variables */
64
    protected $customRenderVariables = [];
65
66
    /** @var mixed custom export rendering */
67
    protected $customRenderExport;
68
69
    /** @var bool */
70
    protected $sortable = FALSE;
71
72
    /** @var array of arrays('pattern' => 'replacement') */
73
    protected $replacements = [];
74 1
75
    /**
76
     * @param \Grido\Grid $grid
77
     * @param string $name
78
     * @param string $label
79
     */
80
    public function __construct($grid, $name, $label)
81
    {
82 1
        $this->addComponentToGrid($grid, Helpers::formatColumnName($name));
83
84 1
        $this->column = $name;
85
86 1
        $this->type = get_class($this);
87 1
        $this->label = $label;
88 1
    }
89
90
    /**
91
     * @param bool $sortable
92
     * @return Column
93
     */
94
    public function setSortable($sortable = TRUE)
95
    {
96 1
        $this->sortable = (bool) $sortable;
97 1
        return $this;
98
    }
99
100
    /**
101
     * @param array $replacement array('pattern' => 'replacement')
102
     * @return Column
103
     */
104
    public function setReplacement(array $replacement)
105
    {
106 1
        $this->replacements = $this->replacements + $replacement;
107 1
        return $this;
108
    }
109
110
    /**
111
     * @param mixed $column
112
     * @return Column
113
     */
114
    public function setColumn($column)
115
    {
116 1
        $this->column = $column;
117 1
        return $this;
118
    }
119
120
    /**
121
     * @param string $dir
122
     * @return Column
123
     */
124
    public function setDefaultSort($dir)
125
    {
126 1
        $this->grid->setDefaultSort([$this->getName() => $dir]);
127 1
        return $this;
128
    }
129
130
    /**
131
     * @param mixed $callback callback or string for name of template filename
132
     * @param array $variables - template variables
133
     * @return Column
134
     */
135
    public function setCustomRender($callback, $variables = [])
136
    {
137 1
        $this->customRender = $callback;
138 1
        $this->customRenderVariables = $variables;
139
140 1
        return $this;
141
    }
142
143
    /**
144
     * @param mixed $callback |
145
     * @return Column
146
     */
147
    public function setCustomRenderExport($callback)
148
    {
149 1
        $this->customRenderExport = $callback;
150 1
        return $this;
151
    }
152
153
    /**
154
     * @param callback $callback
155
     * @return Column
156
     */
157
    public function setCellCallback($callback)
158
    {
159 1
        $this->cellCallback = $callback;
160 1
        return $this;
161
    }
162
163
    /**********************************************************************************************/
164
165
    /**
166
     * Returns cell prototype (<td> html tag).
167
     * @param mixed $row
168
     * @return \Nette\Utils\Html
169
     */
170
    public function getCellPrototype($row = NULL)
171
    {
172 1
        $td = $this->cellPrototype;
173
174 1
        if ($td === NULL) { //cache
175 1
            $td = $this->cellPrototype = \Nette\Utils\Html::el('td')
176 1
                ->setClass(['grid-cell-' . $this->getName()]);
177 1
        }
178
179 1
        if ($this->cellCallback && $row !== NULL) {
180 1
            $td = clone $td;
181 1
            $td = call_user_func_array($this->cellCallback, [$row, $td]);
182 1
        }
183
184 1
        return $td;
185
    }
186
187
    /**
188
     * Returns header cell prototype (<th> html tag).
189
     * @return \Nette\Utils\Html
190
     */
191
    public function getHeaderPrototype()
192
    {
193 1
        if ($this->headerPrototype === NULL) {
194 1
            $this->headerPrototype = \Nette\Utils\Html::el('th')
195 1
                ->setClass(['column', 'grid-header-' . $this->getName()]);
196 1
        }
197
198 1
        if ($this->isSortable() && $this->getSort()) {
199 1
            $this->headerPrototype->class[] = $this->getSort() == self::ORDER_DESC
200 1
                ? 'desc'
201 1
                : 'asc';
202 1
        }
203
204 1
        return $this->headerPrototype;
205
    }
206
207
    /**
208
     * @return mixed
209
     * @internal
210
     */
211
    public function getColumn()
212
    {
213 1
        return $this->column;
214
    }
215
216
    /**
217
     * @return string
218
     * @internal
219
     */
220
    public function getSort()
221
    {
222 1
        if ($this->sort === NULL) {
223 1
            $name = $this->getName();
224
225 1
            $sort = isset($this->grid->sort[$name])
226 1
                ? $this->grid->sort[$name]
227 1
                : NULL;
228
229 1
            $this->sort = $sort === NULL ? NULL : $sort;
230 1
        }
231
232 1
        return $this->sort;
233
    }
234
235
    /**
236
     * @return mixed
237
     * @internal
238
     */
239
    public function getCustomRender()
240
    {
241 1
        return $this->customRender;
242
    }
243
244
    /**
245
     * @return array
246
     * @internal
247
     */
248
    public function getCustomRenderVariables()
249
    {
250 1
        return $this->customRenderVariables;
251
    }
252
253
    /**
254
     * @return mixed
255
     * @internal
256
     */
257
    public function getLabel()
258
    {
259 1
        return is_string($this->label)
260 1
            ? $this->translate($this->label)
261 1
            : $this->label;
262
    }
263
264
    /**********************************************************************************************/
265
266
    /**
267
     * @return bool
268
     * @internal
269
     */
270 1
    public function isSortable()
271
    {
272 1
        return $this->sortable;
273
    }
274
275
    /**
276
     * @return bool
277
     * @internal
278
     */
279
    public function hasFilter()
280 1
    {
281 1
        return (bool) $this->grid->getFilter($this->getName(), FALSE);
282
    }
283
284
    /**********************************************************************************************/
285
286
    /**
287
     * @param mixed $row
288
     * @return string
289
     * @internal
290 1
     */
291
    public function render($row)
292
    {
293 1
        if (is_callable($this->customRender)) {
294 1
            return call_user_func_array($this->customRender, [$row]);
295
        }
296
297 1
        $value = $this->getValue($row);
298 1
        return $this->formatValue($value);
299
    }
300
301 1
    /**
302
     * @param mixed $row
303
     * @return string
304
     * @internal
305
     */
306
    public function renderExport($row)
307
    {
308 1
        if (is_callable($this->customRenderExport)) {
309 1
            return call_user_func_array($this->customRenderExport, [$row]);
310
        }
311 1
312 1
        $value = $this->getValue($row);
313 1
        return strip_tags($this->applyReplacement($value));
314
    }
315
316
    /**
317
     * @param mixed $row
318
     * @throws Exception
319
     * @return mixed
320
     */
321 1
    protected function getValue($row)
322
    {
323 1
        $column = $this->getColumn();
324
325
326
327
328 1
        if (is_string($column)) {
329 1
            return $this->grid->getProperty($row, Helpers::unformatColumnName($column));
330
331
332
        } elseif (is_callable($column)) {
333
            return call_user_func_array($column, [$row]);
334
335
        } else {
336
            throw new Exception('Column must be string or callback.');
337
        }
338
    }
339
340
    /**
341
     * @param mixed $value
342
     * @return mixed
343
     */
344
    protected function applyReplacement($value)
345
    {
346 1
        return (is_scalar($value) || $value === NULL) && isset($this->replacements[$value])
347 1
            ? is_string($value)
348 1
                ? str_replace(static::VALUE_IDENTIFIER, $value, $this->replacements[$value])
349 1
                : $this->replacements[$value]
350 1
            : $value;
351
    }
352
353
    /**
354
     * @param mixed $value
355
     * @return mixed
356
     */
357
    protected function formatValue($value)
358
    {
359 1
        $value = is_string($value)
360 1
            ? \Latte\Runtime\Filters::escapeHtml($value)
361 1
            : $value;
362
363 1
        return $this->applyReplacement($value);
364
    }
365
366
    /******************************* Aliases for filters ******************************************/
367
368
    /**
369
     * @return \Grido\Components\Filters\Text
370
     */
371
    public function setFilterText()
372
    {
373 1
        return $this->grid->addFilterText($this->getName(), $this->label);
374
    }
375
376
    /**
377
     * @return \Grido\Components\Filters\Date
378
     */
379
    public function setFilterDate()
380
    {
381 1
        return $this->grid->addFilterDate($this->getName(), $this->label);
382
    }
383
384
    /**
385
     * @return \Grido\Components\Filters\DateRange
386
     */
387
    public function setFilterDateRange()
388
    {
389 1
        return $this->grid->addFilterDateRange($this->getName(), $this->label);
390
    }
391
392
    /**
393
     * @return \Grido\Components\Filters\Check
394
     */
395
    public function setFilterCheck()
396
    {
397 1
        return $this->grid->addFilterCheck($this->getName(), $this->label);
398
    }
399
400
    /**
401
     * @param array $items
402
     * @return \Grido\Components\Filters\Select
403
     */
404
    public function setFilterSelect(array $items = NULL)
405
    {
406 1
        return $this->grid->addFilterSelect($this->getName(), $this->label, $items);
407
    }
408
409
    /**
410
     * @return \Grido\Components\Filters\Number
411
     */
412
    public function setFilterNumber()
413
    {
414 1
        return $this->grid->addFilterNumber($this->getName(), $this->label);
415
    }
416
417
    /**
418
     * @param \Nette\Forms\IControl $formControl
419
     * @return \Grido\Components\Filters\Custom
420
     */
421
    public function setFilterCustom(\Nette\Forms\IControl $formControl)
422
    {
423 1
        return $this->grid->addFilterCustom($this->getName(), $formControl);
424
    }
425
}
426