Completed
Push — master ( cb204b...65ea96 )
by Pavel
9s
created

Column::isHeaderEscaped()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
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 Ublaboo;
12
use Ublaboo\DataGrid\DataGrid;
13
use Ublaboo\DataGrid\Row;
14
use Ublaboo\DataGrid\Exception\DataGridException;
15
use Ublaboo\DataGrid\Exception\DataGridColumnRendererException;
16
use Nette\Utils\Html;
17
use Ublaboo\DataGrid\Traits;
18
19
abstract class Column extends FilterableColumn
20
{
21
22
	use Traits\TLink;
23
24
	/**
25
	 * @var array
26
	 */
27
	protected $replacements = [];
28
29
	/**
30
	 * @var Renderer|NULL
31
	 */
32
	protected $renderer;
33
34
	/**
35
	 * @var string
36
	 */
37
	protected $template;
38
39
	/**
40
	 * @var bool|string
41
	 */
42
	protected $sortable = FALSE;
43
44
	/**
45
	 * @var bool
46
	 */
47
	protected $sortable_reset_pagination = FALSE;
48
49
	/**
50
	 * @var null|callable
51
	 */
52
	protected $sortable_callback = NULL;
53
54
	/**
55
	 * @var array
56
	 */
57
	protected $sort;
58
59
	/**
60
	 * @var bool
61
	 */
62
	protected $template_escaping = TRUE;
63
64
	/**
65
	 * @var bool
66
	 */
67
	protected $header_escaping = FALSE;
68
69
	
70
	/**
71
	 * @var string
72
	 */
73
	protected $align;
74
75
	/**
76
	 * @var array
77
	 */
78
	protected $template_variables = [];
79
80
	/**
81
	 * @var callable
82
	 */
83
	protected $editable_callback;
84
85
	/**
86
	 * @var array
87
	 */
88
	protected $editable_element = ['textarea', ['class' => 'form-control']];
89
90
	/**
91
	 * Cached html elements
92
	 * @var array
93
	 */
94
	protected $el_cache = [];
95
96
	/**
97
	 * @var bool
98
	 */
99
	protected $default_hide = FALSE;
100
101
102
	/**
103
	 * Render row item into template
104
	 * @param  Row   $row
105
	 * @return mixed
106
	 */
107
	public function render(Row $row)
108
	{
109
		/**
110
		 * Renderer function may be used
111
		 */
112
		try {
113
			return $this->useRenderer($row);
114
		} catch (DataGridColumnRendererException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
115
			/**
116
			 * Do not use renderer
117
			 */
118
		}
119
120
		/**
121
		 * Or replacements may be applied
122
		 */
123
		list($do_replace, $replaced) = $this->applyReplacements($row);
124
		if ($do_replace) {
125
			return $replaced;
126
		}
127
128
		return $this->getColumnValue($row);
129
	}
130
131
132
	/**
133
	 * Try to render item with custom renderer
134
	 * @param  Row   $row
135
	 * @return mixed
136
	 */
137
	public function useRenderer(Row $row)
138
	{
139
		$renderer = $this->getRenderer();
140
141
		if (!$renderer) {
142
			throw new DataGridColumnRendererException;
143
		}
144
145
		if ($renderer->getConditionCallback()) {
146
			if (!call_user_func_array($renderer->getConditionCallback(), [$row->getItem()])) {
147
				throw new DataGridColumnRendererException;
148
			}
149
150
			return call_user_func_array($renderer->getCallback(), [$row->getItem()]);
151
		}
152
153
		return call_user_func_array($renderer->getCallback(), [$row->getItem()]);
154
	}
155
156
157
	/**
158
	 * Should be column values escaped in latte?
159
	 * @param bool $template_escaping
160
	 */
161
	public function setTemplateEscaping($template_escaping = TRUE)
162
	{
163
		$this->template_escaping = (bool) $template_escaping;
164
165
		return $this;
166
	}
167
168
169
	public function isTemplateEscaped()
170
	{
171
		return $this->template_escaping;
172
	}
173
174
	/**
175
	 * Should be column header escaped in latte?
176
	 * @param bool $header_escaping
177
	 */
178
	public function setHeaderEscaping($header_escaping = FALSE)
179
	{
180
		$this->header_escaping = (bool) $header_escaping;
181
182
		return $this;
183
	}
184
	
185
	public function isHeaderEscaped()
186
	{
187
		return $this->header_escaping;
188
	}
189
	
190
	
191
	/**
192
	 * Set column sortable or not
193
	 * @param bool|string $sortable
194
	 */
195
	public function setSortable($sortable = TRUE)
196
	{
197
		$this->sortable = is_string($sortable) ? $sortable : (bool) $sortable;
198
199
		return $this;
200
	}
201
202
203
	/**
204
	 * Tell whether column is sortable
205
	 * @return bool
206
	 */
207
	public function isSortable()
208
	{
209
		return (bool) $this->sortable;
210
	}
211
212
213
	/**
214
	 * Shoud be the pagination reseted after sorting?
215
	 * @param bool $sortable_reset_pagination
216
	 * @return static
217
	 */
218
	public function setSortableResetPagination($sortable_reset_pagination = TRUE)
219
	{
220
		$this->sortable_reset_pagination = (bool) $sortable_reset_pagination;
221
222
		return $this;
223
	}
224
225
226
	/**
227
	 * Do reset pagination after sorting?
228
	 * @return bool
229
	 */
230
	public function sortableResetPagination()
231
	{
232
		return $this->sortable_reset_pagination;
233
	}
234
235
236
	/**
237
	 * Set custom ORDER BY clause
238
	 * @param callable $sortable_callback
239
	 * @return static
240
	 */
241
	public function setSortableCallback(callable $sortable_callback)
242
	{
243
		$this->sortable_callback = $sortable_callback;
244
245
		return $this;
246
	}
247
248
249
	/**
250
	 * Get custom ORDER BY clause
251
	 * @return callable|null
252
	 */
253
	public function getSortableCallback()
254
	{
255
		return $this->sortable_callback;
256
	}
257
258
259
	/**
260
	 * Get column to sort by
261
	 * @return string
262
	 */
263
	public function getSortingColumn()
264
	{
265
		return is_string($this->sortable) ? $this->sortable : $this->column;
266
	}
267
268
269
	/**
270
	 * Get column name
271
	 * @return string
272
	 */
273
	public function getColumnName()
274
	{
275
		return $this->column;
276
	}
277
278
279
	/**
280
	 * Get column value of row item
281
	 * @param  Row   $row
282
	 * @return mixed
283
	 */
284
	public function getColumnValue(Row $row)
285
	{
286
		return $row->getValue($this->column);
287
	}
288
289
290
	/**
291
	 * @return string
292
	 */
293
	public function getName()
294
	{
295
		return $this->name;
296
	}
297
298
299
	/**
300
	 * Set column replacements
301
	 * @param  array $replacements
302
	 * @return Column
303
	 */
304
	public function setReplacement(array $replacements)
305
	{
306
		$this->replacements = $replacements;
307
308
		return $this;
309
	}
310
311
312
	/**
313
	 * Tell whether columns has replacements
314
	 * @return bool
315
	 */
316
	public function hasReplacements()
317
	{
318
		return (bool) $this->replacements;
319
	}
320
321
322
	/**
323
	 * Apply replacements
324
	 * @param  Row   $row
325
	 * @return array
326
	 */
327
	public function applyReplacements(Row $row)
328
	{
329
		$value = $row->getValue($this->column);
330
331
		if ((is_scalar($value) || is_null($value)) && isset($this->replacements[$value])) {
332
			return [TRUE, $this->replacements[$value]];
333
		}
334
335
		return [FALSE, NULL];
336
	}
337
338
339
	/**
340
	 * Set renderer callback and (it may be optional - the condition callback will decide)
341
	 * @param callable $renderer
342
	 */
343
	public function setRenderer($renderer, $condition_callback = NULL)
344
	{
345
		if ($this->hasReplacements()) {
346
			throw new DataGridException(
347
				"Use either Column::setReplacement() or Column::setRenderer, not both."
348
			);
349
		}
350
351
		if (!is_callable($renderer)) {
352
			throw new DataGridException(
353
				"Renderer (method Column::setRenderer()) must be callable."
354
			);
355
		}
356
357
		if (NULL != $condition_callback && !is_callable($condition_callback)) {
358
			throw new DataGridException(
359
				"Renderer (method Column::setRenderer()) must be callable."
360
			);
361
		}
362
363
		$this->renderer = new Renderer($renderer, $condition_callback);
364
365
		return $this;
366
	}
367
368
369
	/**
370
	 * Set renderer callback just if condition is truthy
371
	 * @param callable $renderer
372
	 */
373
	public function setRendererOnCondition($renderer, $condition_callback)
374
	{
375
		return $this->setRenderer($renderer, $condition_callback);
376
	}
377
378
379
	/**
380
	 * Return custom renderer callback
381
	 * @return Renderer|null
382
	 */
383
	public function getRenderer()
384
	{
385
		return $this->renderer;
386
	}
387
388
389
	/**
390
	 * Column may have its own template
391
	 * @param string $template
392
	 */
393
	public function setTemplate($template, array $template_variables = [])
394
	{
395
		$this->template = $template;
396
		$this->template_variables = $template_variables;
397
398
		return $this;
399
	}
400
401
402
	/**
403
	 * Column can have variables that will be passed to custom template scope
404
	 * @return array
405
	 */
406
	public function getTemplateVariables()
407
	{
408
		return $this->template_variables;
409
	}
410
411
412
	/**
413
	 * Tell whether column has its owntemplate
414
	 * @return bool
415
	 */
416
	public function hasTemplate()
417
	{
418
		return (bool) $this->template;
419
	}
420
421
422
	/**
423
	 * Get column template path
424
	 * @return string
425
	 */
426
	public function getTemplate()
427
	{
428
		return $this->template;
429
	}
430
431
432
	/**
433
	 * Tell whether data source is sorted by this collumn
434
	 * @return bool
435
	 */
436
	public function isSortedBy()
437
	{
438
		return (bool) $this->sort;
439
	}
440
441
442
	/**
443
	 * Tell column his sorting options
444
	 * @param array $sort
445
	 */
446
	public function setSort(array $sort)
447
	{
448
		$this->sort = $sort[$this->key];
449
450
		return $this;
451
	}
452
453
454
	/**
455
	 * What sorting will be applied after next click?
456
	 * @return array
457
	 */
458
	public function getSortNext()
459
	{
460
		if ($this->sort == 'ASC') {
461
			return [$this->key => 'DESC'];
462
		} else if ($this->sort == 'DESC') {
463
			return [$this->key => NULL];
464
		}
465
466
		return [$this->key => 'ASC'];
467
	}
468
469
470
	/**
471
	 * Is sorting ascending?
472
	 * @return bool
473
	 */
474
	public function isSortAsc()
475
	{
476
		return $this->sort == 'ASC';
477
	}
478
479
480
	/**
481
	 * Set column alignment
482
	 * @param string $align
483
	 */
484
	public function setAlign($align)
485
	{
486
		$this->align = (string) $align;
487
488
		return $this;
489
	}
490
491
492
	/**
493
	 * Has column some alignment?
494
	 * @return bool [description]
495
	 */
496
	public function hasAlign()
497
	{
498
		return (bool) $this->align;
499
	}
500
501
502
	/**
503
	 * Get column alignment
504
	 * @return string
505
	 */
506
	public function getAlign()
507
	{
508
		return $this->align ?: 'left';
509
	}
510
511
512
	/**
513
	 * Set callback that will be called after inline editing
514
	 * @param callable $editable_callback
515
	 */
516
	public function setEditableCallback(callable $editable_callback)
517
	{
518
		$this->editable_callback = $editable_callback;
519
520
		return $this;
521
	}
522
523
524
	/**
525
	 * Return callback that is used after inline editing
526
	 * @return callable
527
	 */
528
	public function getEditableCallback()
529
	{
530
		return $this->editable_callback;
531
	}
532
533
534
	/**
535
	 * Is column editable?
536
	 * @return bool
537
	 */
538
	public function isEditable()
539
	{
540
		return (bool) $this->getEditableCallback();
541
	}
542
543
544
	/**
545
	 * Element is by default textarea, user can change that
546
	 * @param string $el_type
547
	 * @param array  $attrs
548
	 * @return static
549
	 */
550
	public function setEditableInputType($el_type, array $attrs = [])
551
	{
552
		$this->editable_element = [$el_type, $attrs];
553
554
		return $this;
555
	}
556
557
558
	/**
559
	 * Change small inline edit input type to select
560
	 * @param array  $options
561
	 * @return static
562
	 */
563
	public function setEditableInputTypeSelect(array $options = [])
564
	{
565
		$select = Html::el('select');
566
567
		foreach ($options as $value => $text) {
568
			$select->create('option')
569
				->value($value)
570
				->setText($text);
571
		}
572
573
		$this->addAttributes(['data-datagrid-editable-element' => (string) $select]);
574
575
		return $this->setEditableInputType('select');
576
	}
577
578
579
	/**
580
	 * [getEditableInputType description]
581
	 * @return array
582
	 */
583
	public function getEditableInputType()
584
	{
585
		return $this->editable_element;
586
	}
587
588
589
	/**
590
	 * Set attributes for both th and td element
591
	 * @param array $attrs
592
	 * @return static
593
	 */
594
	public function addAttributes(array $attrs)
595
	{
596
		$this->getElementPrototype('td')->addAttributes($attrs);
597
		$this->getElementPrototype('th')->addAttributes($attrs);
598
599
		return $this;
600
	}
601
602
603
	/**
604
	 * Get th/td column element
605
	 * @param  string   $tag th|td
606
	 * @param  string   $key
607
	 * @param  Row|NULL $row
608
	 * @return Html
609
	 */
610
	public function getElementPrototype($tag, $key = NULL, Row $row = NULL)
611
	{
612
		/**
613
		 * Get cached element
614
		 */
615
		if (empty($this->el_cache[$tag])) {
616
			$this->el_cache[$tag] = $el = $el = Html::el($tag);
617
		} else {
618
			$el = $this->el_cache[$tag];
619
		}
620
621
		/**
622
		 * If class was set by user via $el->class = '', fix it
623
		 */
624
		if (!empty($el->class) && is_string($el->class)) {
625
			$class = $el->class;
626
			unset($el->class);
627
628
			$el->class[] = $class;
629
		}
630
631
		$el->class[] = "text-{$this->getAlign()}";
632
633
		/**
634
		 * Method called from datagrid template, set appropriate classes and another attributes
635
		 */
636
		if ($key !== NULL && $row !== NULL) {
637
			$el->class[] = "col-{$key}";
638
639
			if ($tag == 'td') {
640
				if ($this->isEditable()) {
641
					$link = $this->grid->link('edit!', ['key' => $key, 'id' => $row->getId()]);
642
643
					$el->data('datagrid-editable-url', $link);
644
645
					$el->data('datagrid-editable-type', $this->editable_element[0]);
646
					$el->data('datagrid-editable-attrs', json_encode($this->editable_element[1]));
647
				}
648
			}
649
		}
650
651
		return $el;
652
	}
653
654
655
	/**
656
	 * @param bool $default_hide
657
	 * @return static
658
	 */
659
	public function setDefaultHide($default_hide = TRUE)
660
	{
661
		$this->default_hide = (bool) $default_hide;
662
663
		if ($default_hide) {
664
			$this->grid->setSomeColumnDefaultHide($default_hide);
665
		}
666
667
		return $this;
668
	}
669
670
671
	public function getDefaultHide()
672
	{
673
		return $this->default_hide;
674
	}
675
676
677
	/**
678
	 * Get row item params (E.g. action may be called id => $item->id, name => $item->name, ...)
679
	 * @param  Row   $row
680
	 * @param  array $params_list
681
	 * @return array
682
	 */
683
	protected function getItemParams(Row $row, array $params_list)
684
	{
685
		$return = [];
686
687
		foreach ($params_list as $param_name => $param) {
688
			$return[is_string($param_name) ? $param_name : $param] = $row->getValue($param);
689
		}
690
691
		return $return;
692
	}
693
694
695
	/**
696
	 * @return string
697
	 */
698
	public function getColumn()
699
	{
700
		return $this->column;
701
	}
702
703
}
704