1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @copyright Copyright (c) 2015 ublaboo <[email protected]> |
5
|
|
|
* @author Pavel Janda <[email protected]> |
6
|
|
|
* @package Ublaboo |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace Ublaboo\DataGrid\Column; |
10
|
|
|
|
11
|
|
|
use Nette\InvalidArgumentException; |
12
|
|
|
use Ublaboo; |
13
|
|
|
use Ublaboo\DataGrid\Row; |
14
|
|
|
use Ublaboo\DataGrid\Exception\DataGridException; |
15
|
|
|
|
16
|
|
|
abstract class Column extends Ublaboo\DataGrid\Object |
17
|
|
|
{ |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* @var string |
21
|
|
|
*/ |
22
|
|
|
protected $column; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* @var string |
26
|
|
|
*/ |
27
|
|
|
protected $name; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @var array |
31
|
|
|
*/ |
32
|
|
|
protected $replacements = []; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @var Renderer|NULL |
36
|
|
|
*/ |
37
|
|
|
protected $renderer; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @var string |
41
|
|
|
*/ |
42
|
|
|
protected $template; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @var boolean |
46
|
|
|
*/ |
47
|
|
|
protected $is_sortable = FALSE; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* @var array |
51
|
|
|
*/ |
52
|
|
|
protected $sort; |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* @var bool |
56
|
|
|
*/ |
57
|
|
|
protected $template_escaping = TRUE; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* @var string |
61
|
|
|
*/ |
62
|
|
|
protected $align; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* @var array |
66
|
|
|
*/ |
67
|
|
|
protected $template_variables; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* @var callable |
71
|
|
|
*/ |
72
|
|
|
protected $editable_callback; |
73
|
|
|
|
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @param string $column |
77
|
|
|
* @param string $name |
78
|
|
|
*/ |
79
|
|
|
public function __construct($column, $name) |
80
|
|
|
{ |
81
|
|
|
$this->column = $column; |
82
|
|
|
$this->name = $name; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Render row item into template |
88
|
|
|
* @param Row $row |
89
|
|
|
* @return mixed |
90
|
|
|
*/ |
91
|
|
|
public function render(Row $row) |
92
|
|
|
{ |
93
|
|
|
/** |
94
|
|
|
* Renderer function may be used |
95
|
|
|
*/ |
96
|
|
View Code Duplication |
if ($renderer = $this->getRenderer()) { |
|
|
|
|
97
|
|
|
if (!$renderer->getConditionCallback()) { |
98
|
|
|
return call_user_func_array($renderer->getCallback(), [$row->getItem()]); |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
if (call_user_func_array($renderer->getConditionCallback(), [$row->getItem()])) { |
102
|
|
|
return call_user_func_array($renderer->getCallback(), [$row->getItem()]); |
103
|
|
|
} |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* Or replacements may be applied |
108
|
|
|
*/ |
109
|
|
|
list($do_replace, $replaced) = $this->applyReplacements($row); |
110
|
|
|
if ($do_replace) { |
111
|
|
|
return $replaced; |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
return $this->getColumnValue($row); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* Should be column values escaped in latte? |
120
|
|
|
* @param boolean $template_escaping |
121
|
|
|
*/ |
122
|
|
|
public function setTemplateEscaping($template_escaping = TRUE) |
123
|
|
|
{ |
124
|
|
|
$this->template_escaping = (bool) $template_escaping; |
125
|
|
|
|
126
|
|
|
return $this; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
|
130
|
|
|
public function isTemplateEscaped() |
131
|
|
|
{ |
132
|
|
|
return $this->template_escaping; |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Set column sortable or not |
138
|
|
|
* @param bool $sortable |
139
|
|
|
*/ |
140
|
|
|
public function setSortable($sortable = TRUE) |
141
|
|
|
{ |
142
|
|
|
$this->is_sortable = (bool) $sortable; |
143
|
|
|
|
144
|
|
|
return $this; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Tell whether column is sortable |
150
|
|
|
* @return boolean |
151
|
|
|
*/ |
152
|
|
|
public function isSortable() |
153
|
|
|
{ |
154
|
|
|
return $this->is_sortable; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Get column name |
160
|
|
|
* @return string |
161
|
|
|
*/ |
162
|
|
|
public function getColumnName() |
163
|
|
|
{ |
164
|
|
|
return $this->column; |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* Get column value of row item |
170
|
|
|
* @param Row $row |
171
|
|
|
* @return mixed |
172
|
|
|
*/ |
173
|
|
|
public function getColumnValue(Row $row) |
174
|
|
|
{ |
175
|
|
|
return $row->getValue($this->column); |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
|
179
|
|
|
public function getName() |
180
|
|
|
{ |
181
|
|
|
return $this->name; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* Set column replacements |
187
|
|
|
* @param array $replacements |
188
|
|
|
* @return Column |
189
|
|
|
*/ |
190
|
|
|
public function setReplacement(array $replacements) |
191
|
|
|
{ |
192
|
|
|
$this->replacements = $replacements; |
193
|
|
|
|
194
|
|
|
return $this; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Tell whether columns has replacements |
200
|
|
|
* @return boolean |
201
|
|
|
*/ |
202
|
|
|
public function hasReplacements() |
203
|
|
|
{ |
204
|
|
|
return (bool) $this->replacements; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
|
208
|
|
|
/** |
209
|
|
|
* Apply replacements |
210
|
|
|
* @param Row $row |
211
|
|
|
* @return array |
212
|
|
|
*/ |
213
|
|
|
public function applyReplacements(Row $row) |
214
|
|
|
{ |
215
|
|
|
$value = $row->getValue($this->column); |
216
|
|
|
|
217
|
|
|
if ((is_scalar($value) || is_null($value)) && isset($this->replacements[$value])) { |
218
|
|
|
return [TRUE, $this->replacements[$value]]; |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
return [FALSE, NULL]; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* Set renderer callback and (it may be optional - the condition callback will decide) |
227
|
|
|
* @param callable $renderer |
228
|
|
|
*/ |
229
|
|
|
public function setRenderer($renderer, $condition_callback = NULL) |
230
|
|
|
{ |
231
|
|
|
if ($this->hasReplacements()) { |
232
|
|
|
throw new DataGridException( |
233
|
|
|
"Use either Column::setReplacement() or Column::setRenderer, not both." |
234
|
|
|
); |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
if (!is_callable($renderer)) { |
238
|
|
|
throw new DataGridException( |
239
|
|
|
"Renderer (method Column::setRenderer()) must be callable." |
240
|
|
|
); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
if (NULL != $condition_callback && !is_callable($condition_callback)) { |
244
|
|
|
throw new DataGridException( |
245
|
|
|
"Renderer (method Column::setRenderer()) must be callable." |
246
|
|
|
); |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
$this->renderer = new Renderer($renderer, $condition_callback); |
250
|
|
|
|
251
|
|
|
return $this; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* Set renderer callback just if condition is truthy |
257
|
|
|
* @param callable $renderer |
258
|
|
|
*/ |
259
|
|
|
public function setRendererOnCondition($renderer, $condition_callback) |
260
|
|
|
{ |
261
|
|
|
return $this->setRenderer($renderer, $condition_callback); |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Return custom renderer callback |
267
|
|
|
* @return Renderer|null |
268
|
|
|
*/ |
269
|
|
|
public function getRenderer() |
270
|
|
|
{ |
271
|
|
|
return $this->renderer; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
|
275
|
|
|
/** |
276
|
|
|
* Column may have its own template |
277
|
|
|
* @param string $template |
278
|
|
|
*/ |
279
|
|
|
public function setTemplate($template, array $template_variables = []) |
280
|
|
|
{ |
281
|
|
|
$this->template = $template; |
282
|
|
|
$this->template_variables = $template_variables; |
283
|
|
|
|
284
|
|
|
return $this; |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
|
288
|
|
|
/** |
289
|
|
|
* Column can have variables that will be passed to custom template scope |
290
|
|
|
* @return array |
291
|
|
|
*/ |
292
|
|
|
public function getTemplateVariables() |
293
|
|
|
{ |
294
|
|
|
return $this->template_variables; |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
|
298
|
|
|
/** |
299
|
|
|
* Tell whether column has its owntemplate |
300
|
|
|
* @return bool |
301
|
|
|
*/ |
302
|
|
|
public function hasTemplate() |
303
|
|
|
{ |
304
|
|
|
return (bool) $this->template; |
305
|
|
|
} |
306
|
|
|
|
307
|
|
|
|
308
|
|
|
/** |
309
|
|
|
* Get column template path |
310
|
|
|
* @return string |
311
|
|
|
*/ |
312
|
|
|
public function getTemplate() |
313
|
|
|
{ |
314
|
|
|
return $this->template; |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
|
318
|
|
|
/** |
319
|
|
|
* Tell whether data source is sorted by this collumn |
320
|
|
|
* @return boolean |
321
|
|
|
*/ |
322
|
|
|
public function isSortedBy() |
323
|
|
|
{ |
324
|
|
|
return (bool) $this->sort; |
325
|
|
|
} |
326
|
|
|
|
327
|
|
|
|
328
|
|
|
/** |
329
|
|
|
* Tell column his sorting options |
330
|
|
|
* @param array $sort |
331
|
|
|
*/ |
332
|
|
|
public function setSort(array $sort) |
333
|
|
|
{ |
334
|
|
|
$this->sort = $sort[$this->column]; |
335
|
|
|
|
336
|
|
|
return $this; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
|
340
|
|
|
/** |
341
|
|
|
* What sorting will be applied after next click? |
342
|
|
|
* @return array |
343
|
|
|
*/ |
344
|
|
|
public function getSortNext() |
345
|
|
|
{ |
346
|
|
|
if ($this->sort == 'ASC') { |
347
|
|
|
return [$this->column => 'DESC']; |
348
|
|
|
} else if ($this->sort == 'DESC') { |
349
|
|
|
return [$this->column => NULL]; |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
return [$this->column => 'ASC']; |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
|
356
|
|
|
/** |
357
|
|
|
* Is sorting ascending? |
358
|
|
|
* @return boolean |
359
|
|
|
*/ |
360
|
|
|
public function isSortAsc() |
361
|
|
|
{ |
362
|
|
|
return $this->sort == 'ASC'; |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
|
366
|
|
|
/** |
367
|
|
|
* Set column alignment |
368
|
|
|
* @param string $align |
369
|
|
|
*/ |
370
|
|
|
public function setAlign($align) |
371
|
|
|
{ |
372
|
|
|
$this->align = (string) $align; |
373
|
|
|
|
374
|
|
|
return $this; |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
|
378
|
|
|
/** |
379
|
|
|
* Has column some alignment? |
380
|
|
|
* @return boolean [description] |
381
|
|
|
*/ |
382
|
|
|
public function hasAlign() |
383
|
|
|
{ |
384
|
|
|
return (bool) $this->align; |
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
|
388
|
|
|
/** |
389
|
|
|
* Get column alignment |
390
|
|
|
* @return string |
391
|
|
|
*/ |
392
|
|
|
public function getAlign() |
393
|
|
|
{ |
394
|
|
|
return $this->align; |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
|
398
|
|
|
/** |
399
|
|
|
* Set callback that will be called after inline editing |
400
|
|
|
* @param callable $editable_callback |
401
|
|
|
*/ |
402
|
|
|
public function setEditableCallback(callable $editable_callback) |
403
|
|
|
{ |
404
|
|
|
$this->editable_callback = $editable_callback; |
405
|
|
|
|
406
|
|
|
return $this; |
407
|
|
|
} |
408
|
|
|
|
409
|
|
|
|
410
|
|
|
/** |
411
|
|
|
* Return callback that is used after inline editing |
412
|
|
|
* @return callable |
413
|
|
|
*/ |
414
|
|
|
public function getEditableCallback() |
415
|
|
|
{ |
416
|
|
|
return $this->editable_callback; |
417
|
|
|
} |
418
|
|
|
|
419
|
|
|
|
420
|
|
|
/** |
421
|
|
|
* Is column editable? |
422
|
|
|
* @return boolean |
423
|
|
|
*/ |
424
|
|
|
public function isEditable() |
425
|
|
|
{ |
426
|
|
|
return (bool) $this->getEditableCallback(); |
427
|
|
|
} |
428
|
|
|
|
429
|
|
|
|
430
|
|
|
/** |
431
|
|
|
* Create link to custom destination |
432
|
|
|
* @param string $href |
433
|
|
|
* @param array $params |
434
|
|
|
* @return string |
435
|
|
|
* @throws DataGridHasToBeAttachedToPresenterComponentException |
436
|
|
|
* @throws InvalidArgumentException |
437
|
|
|
*/ |
438
|
|
|
protected function createLink($href, $params) |
439
|
|
|
{ |
440
|
|
|
try { |
441
|
|
|
$parent = $this->grid->getParent(); |
|
|
|
|
442
|
|
|
|
443
|
|
|
return $parent->link($href, $params); |
444
|
|
|
} catch (DataGridHasToBeAttachedToPresenterComponentException $e) { |
|
|
|
|
445
|
|
|
$parent = $this->grid->getPresenter(); |
|
|
|
|
446
|
|
|
|
447
|
|
|
} catch (InvalidArgumentException $e) { |
448
|
|
|
$parent = $this->grid->getPresenter(); |
|
|
|
|
449
|
|
|
|
450
|
|
|
} |
451
|
|
|
|
452
|
|
|
return $parent->link($href, $params); |
453
|
|
|
} |
454
|
|
|
|
455
|
|
|
} |
456
|
|
|
|
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.