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; |
10
|
|
|
|
11
|
|
|
use Nette; |
12
|
|
|
use Nette\Application\UI\PresenterComponent; |
13
|
|
|
use Ublaboo\DataGrid\Utils\ArraysHelper; |
14
|
|
|
use Nette\Application\UI\Form; |
15
|
|
|
use Ublaboo\DataGrid\Exception\DataGridException; |
16
|
|
|
use Ublaboo\DataGrid\Exception\DataGridHasToBeAttachedToPresenterComponentException; |
17
|
|
|
use Ublaboo\DataGrid\Utils\Sorting; |
18
|
|
|
use Ublaboo\DataGrid\InlineEdit\InlineEdit; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @method onRedraw() |
22
|
|
|
* @method onRender() |
23
|
|
|
* @method onColumnAdd() |
24
|
|
|
*/ |
25
|
|
|
class DataGrid extends Nette\Application\UI\Control |
26
|
|
|
{ |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @var callable[] |
30
|
|
|
*/ |
31
|
|
|
public $onRedraw; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @var callable[] |
35
|
|
|
*/ |
36
|
|
|
public $onRender = []; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @var callable[] |
40
|
|
|
*/ |
41
|
|
|
public $onColumnAdd; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @var string |
45
|
|
|
*/ |
46
|
|
|
public static $icon_prefix = 'fa fa-'; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* When set to TRUE, datagrid throws an exception |
50
|
|
|
* when tring to get related entity within join and entity does not exist |
51
|
|
|
* @var bool |
52
|
|
|
*/ |
53
|
|
|
public $strict_entity_property = FALSE; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* @var int |
57
|
|
|
* @persistent |
58
|
|
|
*/ |
59
|
|
|
public $page = 1; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* @var int|string |
63
|
|
|
* @persistent |
64
|
|
|
*/ |
65
|
|
|
public $per_page; |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* @var array |
69
|
|
|
* @persistent |
70
|
|
|
*/ |
71
|
|
|
public $sort = []; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* @var array |
75
|
|
|
*/ |
76
|
|
|
public $default_sort = []; |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @var array |
80
|
|
|
* @persistent |
81
|
|
|
*/ |
82
|
|
|
public $filter = []; |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* @var callable|null |
86
|
|
|
*/ |
87
|
|
|
protected $sort_callback = NULL; |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* @var bool |
91
|
|
|
*/ |
92
|
|
|
protected $use_happy_components = TRUE; |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* @var callable |
96
|
|
|
*/ |
97
|
|
|
protected $rowCallback; |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* @var array |
101
|
|
|
*/ |
102
|
|
|
protected $items_per_page_list; |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* @var string |
106
|
|
|
*/ |
107
|
|
|
protected $template_file; |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* @var Column\IColumn[] |
111
|
|
|
*/ |
112
|
|
|
protected $columns = []; |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* @var Column\Action[] |
116
|
|
|
*/ |
117
|
|
|
protected $actions = []; |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* @var GroupAction\GroupActionCollection |
121
|
|
|
*/ |
122
|
|
|
protected $group_action_collection; |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* @var Filter\Filter[] |
126
|
|
|
*/ |
127
|
|
|
protected $filters = []; |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* @var Export\Export[] |
131
|
|
|
*/ |
132
|
|
|
protected $exports = []; |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* @var DataModel |
136
|
|
|
*/ |
137
|
|
|
protected $dataModel; |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* @var DataFilter |
141
|
|
|
*/ |
142
|
|
|
protected $dataFilter; |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* @var string |
146
|
|
|
*/ |
147
|
|
|
protected $primary_key = 'id'; |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* @var bool |
151
|
|
|
*/ |
152
|
|
|
protected $do_paginate = TRUE; |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* @var bool |
156
|
|
|
*/ |
157
|
|
|
protected $csv_export = TRUE; |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* @var bool |
161
|
|
|
*/ |
162
|
|
|
protected $csv_export_filtered = TRUE; |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* @var bool |
166
|
|
|
*/ |
167
|
|
|
protected $sortable = FALSE; |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* @var string |
171
|
|
|
*/ |
172
|
|
|
protected $sortable_handler = 'sort!'; |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* @var string |
176
|
|
|
*/ |
177
|
|
|
protected $original_template; |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* @var array |
181
|
|
|
*/ |
182
|
|
|
protected $redraw_item; |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* @var mixed |
186
|
|
|
*/ |
187
|
|
|
protected $translator; |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* @var bool |
191
|
|
|
*/ |
192
|
|
|
protected $force_filter_active; |
193
|
|
|
|
194
|
|
|
/** |
195
|
|
|
* @var callable |
196
|
|
|
*/ |
197
|
|
|
protected $tree_view_children_callback; |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* @var callable |
201
|
|
|
*/ |
202
|
|
|
protected $tree_view_has_children_callback; |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* @var string |
206
|
|
|
*/ |
207
|
|
|
protected $tree_view_has_children_column; |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* @var bool |
211
|
|
|
*/ |
212
|
|
|
protected $outer_filter_rendering = FALSE; |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* @var array |
216
|
|
|
*/ |
217
|
|
|
protected $columns_export_order = []; |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* @var bool |
221
|
|
|
*/ |
222
|
|
|
protected $remember_state = TRUE; |
223
|
|
|
|
224
|
|
|
/** |
225
|
|
|
* @var bool |
226
|
|
|
*/ |
227
|
|
|
protected $refresh_url = TRUE; |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* @var Nette\Http\SessionSection |
231
|
|
|
*/ |
232
|
|
|
protected $grid_session; |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* @var Column\ItemDetail |
236
|
|
|
*/ |
237
|
|
|
protected $items_detail; |
238
|
|
|
|
239
|
|
|
/** |
240
|
|
|
* @var array |
241
|
|
|
*/ |
242
|
|
|
protected $row_conditions = [ |
243
|
|
|
'group_action' => FALSE, |
244
|
|
|
'action' => [] |
245
|
|
|
]; |
246
|
|
|
|
247
|
|
|
/** |
248
|
|
|
* @var array |
249
|
|
|
*/ |
250
|
|
|
protected $column_callbacks = []; |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* @var bool |
254
|
|
|
*/ |
255
|
|
|
protected $can_hide_columns = FALSE; |
256
|
|
|
|
257
|
|
|
/** |
258
|
|
|
* @var array |
259
|
|
|
*/ |
260
|
|
|
protected $columns_visibility = []; |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* @var InlineEdit |
264
|
|
|
*/ |
265
|
|
|
protected $inlineEdit; |
266
|
|
|
|
267
|
|
|
/** |
268
|
|
|
* @var InlineEdit |
269
|
|
|
*/ |
270
|
|
|
protected $inlineAdd; |
271
|
|
|
|
272
|
|
|
/** |
273
|
|
|
* @var bool |
274
|
|
|
*/ |
275
|
|
|
protected $snippets_set = FALSE; |
276
|
|
|
|
277
|
|
|
|
278
|
|
|
/** |
279
|
|
|
* @param Nette\ComponentModel\IContainer|NULL $parent |
280
|
|
|
* @param string $name |
281
|
|
|
*/ |
282
|
|
|
public function __construct(Nette\ComponentModel\IContainer $parent = NULL, $name = NULL) |
283
|
|
|
{ |
284
|
|
|
parent::__construct($parent, $name); |
285
|
|
|
|
286
|
|
|
$this->monitor('Nette\Application\UI\Presenter'); |
287
|
|
|
|
288
|
|
|
/** |
289
|
|
|
* Try to find previous filters/pagination/sort in session |
290
|
|
|
*/ |
291
|
|
|
$this->onRender[] = [$this, 'findSessionFilters']; |
292
|
|
|
$this->onRender[] = [$this, 'findDefaultSort']; |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
|
296
|
|
|
/** |
297
|
|
|
* {inheritDoc} |
298
|
|
|
* @return void |
299
|
|
|
*/ |
300
|
|
|
public function attached($presenter) |
301
|
|
|
{ |
302
|
|
|
parent::attached($presenter); |
303
|
|
|
|
304
|
|
|
if ($presenter instanceof Nette\Application\UI\Presenter) { |
305
|
|
|
/** |
306
|
|
|
* Get session |
307
|
|
|
*/ |
308
|
|
|
if ($this->remember_state) { |
309
|
|
|
$this->grid_session = $presenter->getSession($this->getSessionSectionName()); |
|
|
|
|
310
|
|
|
} |
311
|
|
|
} |
312
|
|
|
} |
313
|
|
|
|
314
|
|
|
|
315
|
|
|
/******************************************************************************** |
316
|
|
|
* RENDERING * |
317
|
|
|
********************************************************************************/ |
318
|
|
|
|
319
|
|
|
|
320
|
|
|
/** |
321
|
|
|
* Render template |
322
|
|
|
* @return void |
323
|
|
|
*/ |
324
|
|
|
public function render() |
325
|
|
|
{ |
326
|
|
|
/** |
327
|
|
|
* Check whether datagrid has set some columns, initiated data source, etc |
328
|
|
|
*/ |
329
|
|
|
if (!($this->dataModel instanceof DataModel)) { |
330
|
|
|
throw new DataGridException('You have to set a data source first.'); |
331
|
|
|
} |
332
|
|
|
|
333
|
|
|
if (empty($this->columns)) { |
334
|
|
|
throw new DataGridException('You have to add at least one column.'); |
335
|
|
|
} |
336
|
|
|
|
337
|
|
|
$this->template->setTranslator($this->getTranslator()); |
|
|
|
|
338
|
|
|
|
339
|
|
|
/** |
340
|
|
|
* Invoke possible events |
341
|
|
|
*/ |
342
|
|
|
$this->onRender($this); |
|
|
|
|
343
|
|
|
|
344
|
|
|
/** |
345
|
|
|
* Prepare data for rendering (datagrid may render just one item) |
346
|
|
|
*/ |
347
|
|
|
$rows = []; |
348
|
|
|
|
349
|
|
|
if (!empty($this->redraw_item)) { |
350
|
|
|
$items = $this->dataModel->filterRow($this->redraw_item); |
351
|
|
|
} else { |
352
|
|
|
$items = Nette\Utils\Callback::invokeArgs( |
353
|
|
|
[$this->dataModel, 'filterData'], |
354
|
|
|
[ |
355
|
|
|
$this->getPaginator(), |
356
|
|
|
new Sorting($this->sort, $this->sort_callback), |
357
|
|
|
$this->assableFilters() |
358
|
|
|
] |
359
|
|
|
); |
360
|
|
|
} |
361
|
|
|
|
362
|
|
|
$callback = $this->rowCallback ?: NULL; |
363
|
|
|
|
364
|
|
|
foreach ($items as $item) { |
365
|
|
|
$rows[] = $row = new Row($this, $item, $this->getPrimaryKey()); |
366
|
|
|
|
367
|
|
|
if ($callback) { |
368
|
|
|
$callback($item, $row->getControl()); |
369
|
|
|
} |
370
|
|
|
} |
371
|
|
|
|
372
|
|
|
if ($this->isTreeView()) { |
373
|
|
|
$this->template->add('tree_view_has_children_column', $this->tree_view_has_children_column); |
|
|
|
|
374
|
|
|
} |
375
|
|
|
|
376
|
|
|
$this->template->add('rows', $rows); |
|
|
|
|
377
|
|
|
|
378
|
|
|
$this->template->add('columns', $this->getColumns()); |
|
|
|
|
379
|
|
|
$this->template->add('actions', $this->actions); |
|
|
|
|
380
|
|
|
$this->template->add('exports', $this->exports); |
|
|
|
|
381
|
|
|
$this->template->add('filters', $this->filters); |
|
|
|
|
382
|
|
|
|
383
|
|
|
$this->template->add('filter_active', $this->isFilterActive()); |
|
|
|
|
384
|
|
|
$this->template->add('original_template', $this->getOriginalTemplateFile()); |
|
|
|
|
385
|
|
|
$this->template->add('icon_prefix', static::$icon_prefix); |
|
|
|
|
386
|
|
|
$this->template->add('items_detail', $this->items_detail); |
|
|
|
|
387
|
|
|
$this->template->add('columns_visibility', $this->columns_visibility); |
|
|
|
|
388
|
|
|
|
389
|
|
|
$this->template->add('inlineEdit', $this->inlineEdit); |
|
|
|
|
390
|
|
|
$this->template->add('inlineAdd', $this->inlineAdd); |
|
|
|
|
391
|
|
|
|
392
|
|
|
/** |
393
|
|
|
* Walkaround for Latte (does not know $form in snippet in {form} etc) |
394
|
|
|
*/ |
395
|
|
|
$this->template->add('filter', $this['filter']); |
|
|
|
|
396
|
|
|
|
397
|
|
|
/** |
398
|
|
|
* Set template file and render it |
399
|
|
|
*/ |
400
|
|
|
$this->template->setFile($this->getTemplateFile()); |
|
|
|
|
401
|
|
|
$this->template->render(); |
|
|
|
|
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
|
405
|
|
|
/******************************************************************************** |
406
|
|
|
* ROW CALLBACK * |
407
|
|
|
********************************************************************************/ |
408
|
|
|
|
409
|
|
|
|
410
|
|
|
/** |
411
|
|
|
* Each row can be modified with user callback |
412
|
|
|
* @param callable $callback |
413
|
|
|
* @return static |
414
|
|
|
*/ |
415
|
|
|
public function setRowCallback(callable $callback) |
416
|
|
|
{ |
417
|
|
|
$this->rowCallback = $callback; |
418
|
|
|
|
419
|
|
|
return $this; |
420
|
|
|
} |
421
|
|
|
|
422
|
|
|
|
423
|
|
|
/******************************************************************************** |
424
|
|
|
* DATA SOURCE * |
425
|
|
|
********************************************************************************/ |
426
|
|
|
|
427
|
|
|
|
428
|
|
|
/** |
429
|
|
|
* By default ID, you can change that |
430
|
|
|
* @param string $primary_key |
431
|
|
|
* @return static |
432
|
|
|
*/ |
433
|
|
|
public function setPrimaryKey($primary_key) |
434
|
|
|
{ |
435
|
|
|
if ($this->dataModel instanceof DataModel) { |
436
|
|
|
throw new DataGridException('Please set datagrid primary key before setting datasource.'); |
437
|
|
|
} |
438
|
|
|
|
439
|
|
|
$this->primary_key = $primary_key; |
440
|
|
|
|
441
|
|
|
return $this; |
442
|
|
|
} |
443
|
|
|
|
444
|
|
|
|
445
|
|
|
/** |
446
|
|
|
* Set Grid data source |
447
|
|
|
* @param DataSource\IDataSource|array|\DibiFluent|Nette\Database\Table\Selection|\Doctrine\ORM\QueryBuilder $source |
448
|
|
|
* @return static |
449
|
|
|
*/ |
450
|
|
|
public function setDataSource($source) |
451
|
|
|
{ |
452
|
|
|
$this->dataModel = new DataModel($source, $this->primary_key); |
453
|
|
|
|
454
|
|
|
return $this; |
455
|
|
|
} |
456
|
|
|
|
457
|
|
|
|
458
|
|
|
/******************************************************************************** |
459
|
|
|
* TEMPLATING * |
460
|
|
|
********************************************************************************/ |
461
|
|
|
|
462
|
|
|
|
463
|
|
|
/** |
464
|
|
|
* Set custom template file to render |
465
|
|
|
* @param string $template_file |
466
|
|
|
* @return static |
467
|
|
|
*/ |
468
|
|
|
public function setTemplateFile($template_file) |
469
|
|
|
{ |
470
|
|
|
$this->template_file = $template_file; |
471
|
|
|
|
472
|
|
|
return $this; |
473
|
|
|
} |
474
|
|
|
|
475
|
|
|
|
476
|
|
|
/** |
477
|
|
|
* Get DataGrid template file |
478
|
|
|
* @return string |
479
|
|
|
* @return static |
480
|
|
|
*/ |
481
|
|
|
public function getTemplateFile() |
482
|
|
|
{ |
483
|
|
|
return $this->template_file ?: $this->getOriginalTemplateFile(); |
484
|
|
|
} |
485
|
|
|
|
486
|
|
|
|
487
|
|
|
/** |
488
|
|
|
* Get DataGrid original template file |
489
|
|
|
* @return string |
490
|
|
|
*/ |
491
|
|
|
public function getOriginalTemplateFile() |
492
|
|
|
{ |
493
|
|
|
return __DIR__.'/templates/datagrid.latte'; |
494
|
|
|
} |
495
|
|
|
|
496
|
|
|
|
497
|
|
|
/** |
498
|
|
|
* Tell datagrid wheteher to use or not happy components |
499
|
|
|
* @param boolean|NULL $use If not given, return value of static::$use_happy_components |
500
|
|
|
* @return void|bool |
501
|
|
|
*/ |
502
|
|
|
public function useHappyComponents($use = NULL) |
503
|
|
|
{ |
504
|
|
|
if (NULL === $use) { |
505
|
|
|
return $this->use_happy_components; |
506
|
|
|
} |
507
|
|
|
|
508
|
|
|
$this->use_happy_components = (bool) $use; |
509
|
|
|
} |
510
|
|
|
|
511
|
|
|
|
512
|
|
|
/******************************************************************************** |
513
|
|
|
* SORTING * |
514
|
|
|
********************************************************************************/ |
515
|
|
|
|
516
|
|
|
|
517
|
|
|
/** |
518
|
|
|
* Set default sorting |
519
|
|
|
* @param array $sort |
520
|
|
|
* @return static |
521
|
|
|
*/ |
522
|
|
|
public function setDefaultSort($sort) |
523
|
|
|
{ |
524
|
|
|
if (is_string($sort)) { |
525
|
|
|
$sort = [$sort => 'ASC']; |
526
|
|
|
} else { |
527
|
|
|
$sort = (array) $sort; |
528
|
|
|
} |
529
|
|
|
|
530
|
|
|
$this->default_sort = $sort; |
531
|
|
|
|
532
|
|
|
return $this; |
533
|
|
|
} |
534
|
|
|
|
535
|
|
|
|
536
|
|
|
/** |
537
|
|
|
* User may set default sorting, apply it |
538
|
|
|
* @return void |
539
|
|
|
*/ |
540
|
|
|
public function findDefaultSort() |
541
|
|
|
{ |
542
|
|
|
if (!empty($this->sort)) { |
543
|
|
|
return; |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
if (!empty($this->default_sort)) { |
547
|
|
|
$this->sort = $this->default_sort; |
548
|
|
|
} |
549
|
|
|
|
550
|
|
|
$this->saveSessionData('_grid_sort', $this->sort); |
551
|
|
|
} |
552
|
|
|
|
553
|
|
|
|
554
|
|
|
/** |
555
|
|
|
* Set grido to be sortable |
556
|
|
|
* @param bool $sortable |
557
|
|
|
* @return static |
558
|
|
|
*/ |
559
|
|
|
public function setSortable($sortable = TRUE) |
560
|
|
|
{ |
561
|
|
|
if ($this->getItemsDetail()) { |
562
|
|
|
throw new DataGridException('You can not use both sortable datagrid and items detail.'); |
563
|
|
|
} |
564
|
|
|
|
565
|
|
|
$this->sortable = (bool) $sortable; |
566
|
|
|
|
567
|
|
|
return $this; |
568
|
|
|
} |
569
|
|
|
|
570
|
|
|
|
571
|
|
|
/** |
572
|
|
|
* Set sortable handle |
573
|
|
|
* @param string $handler |
574
|
|
|
* @return static |
575
|
|
|
*/ |
576
|
|
|
public function setSortableHandler($handler = 'sort!') |
577
|
|
|
{ |
578
|
|
|
$this->sortable_handler = (string) $handler; |
579
|
|
|
|
580
|
|
|
return $this; |
581
|
|
|
} |
582
|
|
|
|
583
|
|
|
|
584
|
|
|
/** |
585
|
|
|
* Tell whether DataGrid is sortable |
586
|
|
|
* @return bool |
587
|
|
|
*/ |
588
|
|
|
public function isSortable() |
589
|
|
|
{ |
590
|
|
|
return $this->sortable; |
591
|
|
|
} |
592
|
|
|
|
593
|
|
|
/** |
594
|
|
|
* Return sortable handle name |
595
|
|
|
* @return string |
596
|
|
|
*/ |
597
|
|
|
public function getSortableHandler() |
598
|
|
|
{ |
599
|
|
|
return $this->sortable_handler; |
600
|
|
|
} |
601
|
|
|
|
602
|
|
|
|
603
|
|
|
/******************************************************************************** |
604
|
|
|
* TREE VIEW * |
605
|
|
|
********************************************************************************/ |
606
|
|
|
|
607
|
|
|
|
608
|
|
|
/** |
609
|
|
|
* Is tree view set? |
610
|
|
|
* @return boolean |
611
|
|
|
*/ |
612
|
|
|
public function isTreeView() |
613
|
|
|
{ |
614
|
|
|
return (bool) $this->tree_view_children_callback; |
615
|
|
|
} |
616
|
|
|
|
617
|
|
|
|
618
|
|
|
/** |
619
|
|
|
* Setting tree view |
620
|
|
|
* @param callable $get_children_callback |
621
|
|
|
* @param string|callable $tree_view_has_children_column |
622
|
|
|
* @return static |
623
|
|
|
*/ |
624
|
|
|
public function setTreeView($get_children_callback, $tree_view_has_children_column = 'has_children') |
625
|
|
|
{ |
626
|
|
|
if (!is_callable($get_children_callback)) { |
627
|
|
|
throw new DataGridException( |
628
|
|
|
'Parameters to method DataGrid::setTreeView must be of type callable' |
629
|
|
|
); |
630
|
|
|
} |
631
|
|
|
|
632
|
|
|
if (is_callable($tree_view_has_children_column)) { |
633
|
|
|
$this->tree_view_has_children_callback = $tree_view_has_children_column; |
634
|
|
|
$tree_view_has_children_column = NULL; |
635
|
|
|
} |
636
|
|
|
|
637
|
|
|
$this->tree_view_children_callback = $get_children_callback; |
638
|
|
|
$this->tree_view_has_children_column = $tree_view_has_children_column; |
639
|
|
|
|
640
|
|
|
/** |
641
|
|
|
* TUrn off pagination |
642
|
|
|
*/ |
643
|
|
|
$this->setPagination(FALSE); |
644
|
|
|
|
645
|
|
|
/** |
646
|
|
|
* Set tree view template file |
647
|
|
|
*/ |
648
|
|
|
if (!$this->template_file) { |
649
|
|
|
$this->setTemplateFile(__DIR__.'/templates/datagrid_tree.latte'); |
650
|
|
|
} |
651
|
|
|
|
652
|
|
|
return $this; |
653
|
|
|
} |
654
|
|
|
|
655
|
|
|
|
656
|
|
|
/** |
657
|
|
|
* Is tree view children callback set? |
658
|
|
|
* @return boolean |
659
|
|
|
*/ |
660
|
|
|
public function hasTreeViewChildrenCallback() |
661
|
|
|
{ |
662
|
|
|
return is_callable($this->tree_view_has_children_callback); |
663
|
|
|
} |
664
|
|
|
|
665
|
|
|
|
666
|
|
|
/** |
667
|
|
|
* @param mixed $item |
668
|
|
|
* @return boolean |
669
|
|
|
*/ |
670
|
|
|
public function treeViewChildrenCallback($item) |
671
|
|
|
{ |
672
|
|
|
return call_user_func($this->tree_view_has_children_callback, $item); |
673
|
|
|
} |
674
|
|
|
|
675
|
|
|
|
676
|
|
|
/******************************************************************************** |
677
|
|
|
* COLUMNS * |
678
|
|
|
********************************************************************************/ |
679
|
|
|
|
680
|
|
|
|
681
|
|
|
/** |
682
|
|
|
* Add text column with no other formating |
683
|
|
|
* @param string $key |
684
|
|
|
* @param string $name |
685
|
|
|
* @param string|null $column |
686
|
|
|
* @return Column\ColumnText |
687
|
|
|
*/ |
688
|
|
|
public function addColumnText($key, $name, $column = NULL) |
689
|
|
|
{ |
690
|
|
|
$this->addColumnCheck($key); |
691
|
|
|
$column = $column ?: $key; |
692
|
|
|
|
693
|
|
|
return $this->addColumn($key, new Column\ColumnText($this, $key, $column, $name)); |
694
|
|
|
} |
695
|
|
|
|
696
|
|
|
|
697
|
|
|
/** |
698
|
|
|
* Add column with link |
699
|
|
|
* @param string $key |
700
|
|
|
* @param string $name |
701
|
|
|
* @param string|null $column |
702
|
|
|
* @return Column\ColumnLink |
703
|
|
|
*/ |
704
|
|
|
public function addColumnLink($key, $name, $href = NULL, $column = NULL, array $params = NULL) |
705
|
|
|
{ |
706
|
|
|
$this->addColumnCheck($key); |
707
|
|
|
$column = $column ?: $key; |
708
|
|
|
$href = $href ?: $key; |
709
|
|
|
|
710
|
|
|
if (NULL === $params) { |
711
|
|
|
$params = [$this->primary_key]; |
712
|
|
|
} |
713
|
|
|
|
714
|
|
|
return $this->addColumn($key, new Column\ColumnLink($this, $key, $column, $name, $href, $params)); |
715
|
|
|
} |
716
|
|
|
|
717
|
|
|
|
718
|
|
|
/** |
719
|
|
|
* Add column with possible number formating |
720
|
|
|
* @param string $key |
721
|
|
|
* @param string $name |
722
|
|
|
* @param string|null $column |
723
|
|
|
* @return Column\ColumnNumber |
724
|
|
|
*/ |
725
|
|
|
public function addColumnNumber($key, $name, $column = NULL) |
726
|
|
|
{ |
727
|
|
|
$this->addColumnCheck($key); |
728
|
|
|
$column = $column ?: $key; |
729
|
|
|
|
730
|
|
|
return $this->addColumn($key, new Column\ColumnNumber($this, $key, $column, $name)); |
731
|
|
|
} |
732
|
|
|
|
733
|
|
|
|
734
|
|
|
/** |
735
|
|
|
* Add column with date formating |
736
|
|
|
* @param string $key |
737
|
|
|
* @param string $name |
738
|
|
|
* @param string|null $column |
739
|
|
|
* @return Column\ColumnDateTime |
740
|
|
|
*/ |
741
|
|
|
public function addColumnDateTime($key, $name, $column = NULL) |
742
|
|
|
{ |
743
|
|
|
$this->addColumnCheck($key); |
744
|
|
|
$column = $column ?: $key; |
745
|
|
|
|
746
|
|
|
return $this->addColumn($key, new Column\ColumnDateTime($this, $key, $column, $name)); |
747
|
|
|
} |
748
|
|
|
|
749
|
|
|
|
750
|
|
|
/** |
751
|
|
|
* Add column status |
752
|
|
|
* @param string $key |
753
|
|
|
* @param string $name |
754
|
|
|
* @param string|null $column |
755
|
|
|
* @return Column\ColumnStatus |
756
|
|
|
*/ |
757
|
|
|
public function addColumnStatus($key, $name, $column = NULL) |
758
|
|
|
{ |
759
|
|
|
$this->addColumnCheck($key); |
760
|
|
|
$column = $column ?: $key; |
761
|
|
|
|
762
|
|
|
return $this->addColumn($key, new Column\ColumnStatus($this, $key, $column, $name)); |
763
|
|
|
} |
764
|
|
|
|
765
|
|
|
|
766
|
|
|
/** |
767
|
|
|
* @param string $key |
768
|
|
|
* @param Column\Column $column |
769
|
|
|
* @return Column\Column |
770
|
|
|
*/ |
771
|
|
|
protected function addColumn($key, Column\Column $column) |
772
|
|
|
{ |
773
|
|
|
$this->onColumnAdd($key, $column); |
|
|
|
|
774
|
|
|
|
775
|
|
|
$this->columns_visibility[$key] = [ |
776
|
|
|
'visible' => TRUE, |
777
|
|
|
'name' => $column->getName() |
778
|
|
|
]; |
779
|
|
|
|
780
|
|
|
return $this->columns[$key] = $column; |
781
|
|
|
} |
782
|
|
|
|
783
|
|
|
|
784
|
|
|
/** |
785
|
|
|
* Return existing column |
786
|
|
|
* @param string $key |
787
|
|
|
* @return Column\Column |
788
|
|
|
* @throws DataGridException |
789
|
|
|
*/ |
790
|
|
|
public function getColumn($key) |
791
|
|
|
{ |
792
|
|
|
if (!isset($this->columns[$key])) { |
793
|
|
|
throw new DataGridException("There is no column at key [$key] defined."); |
794
|
|
|
} |
795
|
|
|
|
796
|
|
|
return $this->columns[$key]; |
797
|
|
|
} |
798
|
|
|
|
799
|
|
|
|
800
|
|
|
/** |
801
|
|
|
* Remove column |
802
|
|
|
* @param string $key |
803
|
|
|
* @return void |
804
|
|
|
*/ |
805
|
|
|
public function removeColumn($key) |
806
|
|
|
{ |
807
|
|
|
unset($this->columns[$key]); |
808
|
|
|
} |
809
|
|
|
|
810
|
|
|
|
811
|
|
|
/** |
812
|
|
|
* Check whether given key already exists in $this->columns |
813
|
|
|
* @param string $key |
814
|
|
|
* @throws DataGridException |
815
|
|
|
*/ |
816
|
|
|
protected function addColumnCheck($key) |
817
|
|
|
{ |
818
|
|
|
if (isset($this->columns[$key])) { |
819
|
|
|
throw new DataGridException("There is already column at key [$key] defined."); |
820
|
|
|
} |
821
|
|
|
} |
822
|
|
|
|
823
|
|
|
|
824
|
|
|
/******************************************************************************** |
825
|
|
|
* ACTIONS * |
826
|
|
|
********************************************************************************/ |
827
|
|
|
|
828
|
|
|
|
829
|
|
|
/** |
830
|
|
|
* Create action |
831
|
|
|
* @param string $key |
832
|
|
|
* @param string $name |
833
|
|
|
* @param string $href |
834
|
|
|
* @param array|null $params |
835
|
|
|
* @return Column\Action |
836
|
|
|
*/ |
837
|
|
|
public function addAction($key, $name, $href = NULL, array $params = NULL) |
838
|
|
|
{ |
839
|
|
|
$this->addActionCheck($key); |
840
|
|
|
$href = $href ?: $key; |
841
|
|
|
|
842
|
|
|
if (NULL === $params) { |
843
|
|
|
$params = [$this->primary_key]; |
844
|
|
|
} |
845
|
|
|
|
846
|
|
|
return $this->actions[$key] = new Column\Action($this, $href, $name, $params); |
847
|
|
|
} |
848
|
|
|
|
849
|
|
|
|
850
|
|
|
/** |
851
|
|
|
* Create action callback |
852
|
|
|
* @param string $key |
853
|
|
|
* @param string $name |
854
|
|
|
* @return Column\Action |
855
|
|
|
*/ |
856
|
|
|
public function addActionCallback($key, $name, $callback = NULL) |
857
|
|
|
{ |
858
|
|
|
$this->addActionCheck($key); |
859
|
|
|
$params = ['__id' => $this->primary_key]; |
860
|
|
|
|
861
|
|
|
$this->actions[$key] = $action = new Column\ActionCallback($this, $key, $name, $params); |
862
|
|
|
|
863
|
|
|
if ($callback) { |
864
|
|
|
if (!is_callable($callback)) { |
865
|
|
|
throw new DataGridException('ActionCallback callback has to be callable.'); |
866
|
|
|
} |
867
|
|
|
|
868
|
|
|
$action->onClick[] = $callback; |
869
|
|
|
} |
870
|
|
|
|
871
|
|
|
return $action; |
872
|
|
|
} |
873
|
|
|
|
874
|
|
|
|
875
|
|
|
/** |
876
|
|
|
* Get existing action |
877
|
|
|
* @param string $key |
878
|
|
|
* @return Column\Action |
879
|
|
|
* @throws DataGridException |
880
|
|
|
*/ |
881
|
|
|
public function getAction($key) |
882
|
|
|
{ |
883
|
|
|
if (!isset($this->actions[$key])) { |
884
|
|
|
throw new DataGridException("There is no action at key [$key] defined."); |
885
|
|
|
} |
886
|
|
|
|
887
|
|
|
return $this->actions[$key]; |
888
|
|
|
} |
889
|
|
|
|
890
|
|
|
|
891
|
|
|
/** |
892
|
|
|
* Remove action |
893
|
|
|
* @param string $key |
894
|
|
|
* @return void |
895
|
|
|
*/ |
896
|
|
|
public function removeAction($key) |
897
|
|
|
{ |
898
|
|
|
unset($this->actions[$key]); |
899
|
|
|
} |
900
|
|
|
|
901
|
|
|
|
902
|
|
|
/** |
903
|
|
|
* Check whether given key already exists in $this->filters |
904
|
|
|
* @param string $key |
905
|
|
|
* @throws DataGridException |
906
|
|
|
*/ |
907
|
|
|
protected function addActionCheck($key) |
908
|
|
|
{ |
909
|
|
|
if (isset($this->actions[$key])) { |
910
|
|
|
throw new DataGridException("There is already action at key [$key] defined."); |
911
|
|
|
} |
912
|
|
|
} |
913
|
|
|
|
914
|
|
|
|
915
|
|
|
/******************************************************************************** |
916
|
|
|
* FILTERS * |
917
|
|
|
********************************************************************************/ |
918
|
|
|
|
919
|
|
|
|
920
|
|
|
/** |
921
|
|
|
* Add filter fot text search |
922
|
|
|
* @param string $key |
923
|
|
|
* @param string $name |
924
|
|
|
* @param array|string $columns |
925
|
|
|
* @return Filter\FilterText |
926
|
|
|
* @throws DataGridException |
927
|
|
|
*/ |
928
|
|
|
public function addFilterText($key, $name, $columns = NULL) |
929
|
|
|
{ |
930
|
|
|
$columns = NULL === $columns ? [$key] : (is_string($columns) ? [$columns] : $columns); |
931
|
|
|
|
932
|
|
|
if (!is_array($columns)) { |
933
|
|
|
throw new DataGridException("Filter Text can except only array or string."); |
934
|
|
|
} |
935
|
|
|
|
936
|
|
|
$this->addFilterCheck($key); |
937
|
|
|
|
938
|
|
|
return $this->filters[$key] = new Filter\FilterText($key, $name, $columns); |
939
|
|
|
} |
940
|
|
|
|
941
|
|
|
|
942
|
|
|
/** |
943
|
|
|
* Add select box filter |
944
|
|
|
* @param string $key |
945
|
|
|
* @param string $name |
946
|
|
|
* @param array $options |
947
|
|
|
* @param string $column |
948
|
|
|
* @return Filter\FilterSelect |
949
|
|
|
* @throws DataGridException |
950
|
|
|
*/ |
951
|
|
View Code Duplication |
public function addFilterSelect($key, $name, array $options, $column = NULL) |
|
|
|
|
952
|
|
|
{ |
953
|
|
|
$column = $column ?: $key; |
954
|
|
|
|
955
|
|
|
if (!is_string($column)) { |
956
|
|
|
throw new DataGridException("Filter Select can only filter in one column."); |
957
|
|
|
} |
958
|
|
|
|
959
|
|
|
$this->addFilterCheck($key); |
960
|
|
|
|
961
|
|
|
return $this->filters[$key] = new Filter\FilterSelect($key, $name, $options, $column); |
962
|
|
|
} |
963
|
|
|
|
964
|
|
|
|
965
|
|
|
/** |
966
|
|
|
* Add multi select box filter |
967
|
|
|
* @param string $key |
968
|
|
|
* @param string $name |
969
|
|
|
* @param array $options |
970
|
|
|
* @param string $column |
971
|
|
|
* @return Filter\FilterSelect |
972
|
|
|
* @throws DataGridException |
973
|
|
|
*/ |
974
|
|
|
public function addFilterMultiSelect($key, $name, array $options, $column = NULL) |
975
|
|
|
{ |
976
|
|
|
$column = $column ?: $key; |
977
|
|
|
|
978
|
|
|
if (!is_string($column)) { |
979
|
|
|
throw new DataGridException("Filter MultiSelect can only filter in one column."); |
980
|
|
|
} |
981
|
|
|
|
982
|
|
|
$this->addFilterCheck($key); |
983
|
|
|
|
984
|
|
|
return $this->filters[$key] = new Filter\FilterMultiSelect($key, $name, $options, $column); |
985
|
|
|
} |
986
|
|
|
|
987
|
|
|
|
988
|
|
|
/** |
989
|
|
|
* Add datepicker filter |
990
|
|
|
* @param string $key |
991
|
|
|
* @param string $name |
992
|
|
|
* @param string $column |
993
|
|
|
* @return Filter\FilterDate |
994
|
|
|
* @throws DataGridException |
995
|
|
|
*/ |
996
|
|
|
public function addFilterDate($key, $name, $column = NULL) |
997
|
|
|
{ |
998
|
|
|
$column = $column ?: $key; |
999
|
|
|
|
1000
|
|
|
if (!is_string($column)) { |
1001
|
|
|
throw new DataGridException("FilterDate can only filter in one column."); |
1002
|
|
|
} |
1003
|
|
|
|
1004
|
|
|
$this->addFilterCheck($key); |
1005
|
|
|
|
1006
|
|
|
return $this->filters[$key] = new Filter\FilterDate($key, $name, $column); |
1007
|
|
|
} |
1008
|
|
|
|
1009
|
|
|
|
1010
|
|
|
/** |
1011
|
|
|
* Add range filter (from - to) |
1012
|
|
|
* @param string $key |
1013
|
|
|
* @param string $name |
1014
|
|
|
* @param string $column |
1015
|
|
|
* @return Filter\FilterRange |
1016
|
|
|
* @throws DataGridException |
1017
|
|
|
*/ |
1018
|
|
View Code Duplication |
public function addFilterRange($key, $name, $column = NULL, $name_second = '-') |
|
|
|
|
1019
|
|
|
{ |
1020
|
|
|
$column = $column ?: $key; |
1021
|
|
|
|
1022
|
|
|
if (!is_string($column)) { |
1023
|
|
|
throw new DataGridException("FilterRange can only filter in one column."); |
1024
|
|
|
} |
1025
|
|
|
|
1026
|
|
|
$this->addFilterCheck($key); |
1027
|
|
|
|
1028
|
|
|
return $this->filters[$key] = new Filter\FilterRange($key, $name, $column, $name_second); |
1029
|
|
|
} |
1030
|
|
|
|
1031
|
|
|
|
1032
|
|
|
/** |
1033
|
|
|
* Add datepicker filter (from - to) |
1034
|
|
|
* @param string $key |
1035
|
|
|
* @param string $name |
1036
|
|
|
* @param string $column |
1037
|
|
|
* @return Filter\FilterDateRange |
1038
|
|
|
* @throws DataGridException |
1039
|
|
|
*/ |
1040
|
|
View Code Duplication |
public function addFilterDateRange($key, $name, $column = NULL, $name_second = '-') |
|
|
|
|
1041
|
|
|
{ |
1042
|
|
|
$column = $column ?: $key; |
1043
|
|
|
|
1044
|
|
|
if (!is_string($column)) { |
1045
|
|
|
throw new DataGridException("FilterDateRange can only filter in one column."); |
1046
|
|
|
} |
1047
|
|
|
|
1048
|
|
|
$this->addFilterCheck($key); |
1049
|
|
|
|
1050
|
|
|
return $this->filters[$key] = new Filter\FilterDateRange($key, $name, $column, $name_second); |
1051
|
|
|
} |
1052
|
|
|
|
1053
|
|
|
|
1054
|
|
|
/** |
1055
|
|
|
* Check whether given key already exists in $this->filters |
1056
|
|
|
* @param string $key |
1057
|
|
|
* @throws DataGridException |
1058
|
|
|
*/ |
1059
|
|
|
protected function addFilterCheck($key) |
1060
|
|
|
{ |
1061
|
|
|
if (isset($this->filters[$key])) { |
1062
|
|
|
throw new DataGridException("There is already action at key [$key] defined."); |
1063
|
|
|
} |
1064
|
|
|
} |
1065
|
|
|
|
1066
|
|
|
|
1067
|
|
|
/** |
1068
|
|
|
* Fill array of Filter\Filter[] with values from $this->filter persistent parameter |
1069
|
|
|
* Fill array of Column\Column[] with values from $this->sort persistent parameter |
1070
|
|
|
* @return Filter\Filter[] $this->filters === Filter\Filter[] |
1071
|
|
|
*/ |
1072
|
|
|
public function assableFilters() |
1073
|
|
|
{ |
1074
|
|
|
foreach ($this->filter as $key => $value) { |
1075
|
|
|
if (!isset($this->filters[$key])) { |
1076
|
|
|
$this->deleteSesssionData($key); |
1077
|
|
|
|
1078
|
|
|
continue; |
1079
|
|
|
} |
1080
|
|
|
|
1081
|
|
|
if (is_array($value) || $value instanceof \Traversable) { |
1082
|
|
|
if (!ArraysHelper::testEmpty($value)) { |
|
|
|
|
1083
|
|
|
$this->filters[$key]->setValue($value); |
1084
|
|
|
} |
1085
|
|
|
} else { |
1086
|
|
|
if ($value !== '' && $value !== NULL) { |
1087
|
|
|
$this->filters[$key]->setValue($value); |
1088
|
|
|
} |
1089
|
|
|
} |
1090
|
|
|
} |
1091
|
|
|
|
1092
|
|
|
foreach ($this->columns as $column) { |
1093
|
|
|
if (isset($this->sort[$column->getSortingColumn()])) { |
1094
|
|
|
$column->setSort($this->sort); |
1095
|
|
|
} |
1096
|
|
|
} |
1097
|
|
|
|
1098
|
|
|
return $this->filters; |
1099
|
|
|
} |
1100
|
|
|
|
1101
|
|
|
|
1102
|
|
|
/** |
1103
|
|
|
* Remove filter |
1104
|
|
|
* @param string $key |
1105
|
|
|
* @return void |
1106
|
|
|
*/ |
1107
|
|
|
public function removeFilter($key) |
1108
|
|
|
{ |
1109
|
|
|
unset($this->filters[$key]); |
1110
|
|
|
} |
1111
|
|
|
|
1112
|
|
|
|
1113
|
|
|
/** |
1114
|
|
|
* Get defined filter |
1115
|
|
|
* @param string $key |
1116
|
|
|
* @return Filter\Filter |
1117
|
|
|
*/ |
1118
|
|
|
public function getFilter($key) |
1119
|
|
|
{ |
1120
|
|
|
if (!isset($this->filters[$key])) { |
1121
|
|
|
throw new DataGridException("Filter [{$key}] is not defined"); |
1122
|
|
|
} |
1123
|
|
|
|
1124
|
|
|
return $this->filters[$key]; |
1125
|
|
|
} |
1126
|
|
|
|
1127
|
|
|
|
1128
|
|
|
/******************************************************************************** |
1129
|
|
|
* FILTERING * |
1130
|
|
|
********************************************************************************/ |
1131
|
|
|
|
1132
|
|
|
|
1133
|
|
|
/** |
1134
|
|
|
* Is filter active? |
1135
|
|
|
* @return boolean |
1136
|
|
|
*/ |
1137
|
|
|
public function isFilterActive() |
1138
|
|
|
{ |
1139
|
|
|
$is_filter = ArraysHelper::testTruthy($this->filter); |
1140
|
|
|
|
1141
|
|
|
return ($is_filter) || $this->force_filter_active; |
1142
|
|
|
} |
1143
|
|
|
|
1144
|
|
|
|
1145
|
|
|
/** |
1146
|
|
|
* Tell that filter is active from whatever reasons |
1147
|
|
|
* return static |
1148
|
|
|
*/ |
1149
|
|
|
public function setFilterActive() |
1150
|
|
|
{ |
1151
|
|
|
$this->force_filter_active = TRUE; |
1152
|
|
|
|
1153
|
|
|
return $this; |
1154
|
|
|
} |
1155
|
|
|
|
1156
|
|
|
|
1157
|
|
|
/** |
1158
|
|
|
* If we want to sent some initial filter |
1159
|
|
|
* @param array $filter |
1160
|
|
|
* @return static |
1161
|
|
|
*/ |
1162
|
|
|
public function setFilter(array $filter) |
1163
|
|
|
{ |
1164
|
|
|
$this->filter = $filter; |
1165
|
|
|
|
1166
|
|
|
return $this; |
1167
|
|
|
} |
1168
|
|
|
|
1169
|
|
|
|
1170
|
|
|
/** |
1171
|
|
|
* FilterAndGroupAction form factory |
1172
|
|
|
* @return Form |
1173
|
|
|
*/ |
1174
|
|
|
public function createComponentFilter() |
1175
|
|
|
{ |
1176
|
|
|
$form = new Form($this, 'filter'); |
1177
|
|
|
|
1178
|
|
|
$form->setMethod('get'); |
1179
|
|
|
|
1180
|
|
|
$form->setTranslator($this->getTranslator()); |
1181
|
|
|
|
1182
|
|
|
/** |
1183
|
|
|
* InlineEdit part |
1184
|
|
|
*/ |
1185
|
|
|
$inline_edit_container = $form->addContainer('inline_edit'); |
1186
|
|
|
|
1187
|
|
View Code Duplication |
if ($this->inlineEdit instanceof InlineEdit) { |
|
|
|
|
1188
|
|
|
$inline_edit_container->addSubmit('submit', 'ublaboo_datagrid.save'); |
1189
|
|
|
$inline_edit_container->addSubmit('cancel', 'ublaboo_datagrid.cancel') |
1190
|
|
|
->setValidationScope(FALSE); |
1191
|
|
|
|
1192
|
|
|
$this->inlineEdit->onControlAdd($inline_edit_container); |
1193
|
|
|
} |
1194
|
|
|
|
1195
|
|
|
/** |
1196
|
|
|
* InlineAdd part |
1197
|
|
|
*/ |
1198
|
|
|
$inline_add_container = $form->addContainer('inline_add'); |
1199
|
|
|
|
1200
|
|
View Code Duplication |
if ($this->inlineAdd instanceof InlineEdit) { |
|
|
|
|
1201
|
|
|
$inline_add_container->addSubmit('submit', 'ublaboo_datagrid.save'); |
1202
|
|
|
$inline_add_container->addSubmit('cancel', 'ublaboo_datagrid.cancel') |
1203
|
|
|
->setValidationScope(FALSE) |
1204
|
|
|
->setAttribute('data-datagrid-cancel-inline-add', TRUE); |
1205
|
|
|
|
1206
|
|
|
$this->inlineAdd->onControlAdd($inline_add_container); |
1207
|
|
|
} |
1208
|
|
|
|
1209
|
|
|
/** |
1210
|
|
|
* ItemDetail form part |
1211
|
|
|
*/ |
1212
|
|
|
$items_detail_form = $this->getItemDetailForm(); |
1213
|
|
|
|
1214
|
|
|
if ($items_detail_form instanceof Nette\Forms\Container) { |
1215
|
|
|
$form['items_detail_form'] = $items_detail_form; |
1216
|
|
|
} |
1217
|
|
|
|
1218
|
|
|
/** |
1219
|
|
|
* Filter part |
1220
|
|
|
*/ |
1221
|
|
|
$filter_container = $form->addContainer('filter'); |
1222
|
|
|
|
1223
|
|
|
foreach ($this->filters as $filter) { |
1224
|
|
|
$filter->addToFormContainer($filter_container); |
1225
|
|
|
} |
1226
|
|
|
|
1227
|
|
|
/** |
1228
|
|
|
* Group action part |
1229
|
|
|
*/ |
1230
|
|
|
$group_action_container = $form->addContainer('group_action'); |
1231
|
|
|
|
1232
|
|
|
if ($this->hasGroupActions()) { |
1233
|
|
|
$this->getGroupActionCollection()->addToFormContainer($group_action_container); |
1234
|
|
|
} |
1235
|
|
|
|
1236
|
|
|
$form->setDefaults(['filter' => $this->filter]); |
1237
|
|
|
|
1238
|
|
|
$form->onSubmit[] = [$this, 'filterSucceeded']; |
1239
|
|
|
|
1240
|
|
|
return $form; |
1241
|
|
|
} |
1242
|
|
|
|
1243
|
|
|
|
1244
|
|
|
/** |
1245
|
|
|
* Set $this->filter values after filter form submitted |
1246
|
|
|
* @param Form $form |
1247
|
|
|
* @return void |
1248
|
|
|
*/ |
1249
|
|
|
public function filterSucceeded(Form $form) |
1250
|
|
|
{ |
1251
|
|
|
if ($this->snippets_set) { |
1252
|
|
|
return; |
1253
|
|
|
} |
1254
|
|
|
|
1255
|
|
|
$values = $form->getValues(); |
1256
|
|
|
|
1257
|
|
|
if ($this->getPresenter()->isAjax()) { |
|
|
|
|
1258
|
|
|
if (isset($form['group_action']['submit']) && $form['group_action']['submit']->isSubmittedBy()) { |
1259
|
|
|
return; |
1260
|
|
|
} |
1261
|
|
|
} |
1262
|
|
|
|
1263
|
|
|
/** |
1264
|
|
|
* Inline edit |
1265
|
|
|
*/ |
1266
|
|
|
$inline_edit = $form['inline_edit']; |
1267
|
|
|
|
1268
|
|
|
if (isset($inline_edit) && isset($inline_edit['submit']) && isset($inline_edit['cancel'])) { |
1269
|
|
|
if ($inline_edit['submit']->isSubmittedBy() || $inline_edit['cancel']->isSubmittedBy()) { |
1270
|
|
|
$id = $form->getHttpData(Form::DATA_LINE, 'inline_edit[_id]'); |
1271
|
|
|
$primary_where_column = $form->getHttpData( |
1272
|
|
|
Form::DATA_LINE, |
1273
|
|
|
'inline_edit[_primary_where_column]' |
1274
|
|
|
); |
1275
|
|
|
|
1276
|
|
View Code Duplication |
if ($inline_edit['submit']->isSubmittedBy()) { |
|
|
|
|
1277
|
|
|
$this->inlineEdit->onSubmit($id, $values->inline_edit); |
1278
|
|
|
|
1279
|
|
|
if ($this->getPresenter()->isAjax()) { |
|
|
|
|
1280
|
|
|
$this->getPresenter()->payload->_datagrid_inline_edited = $id; |
|
|
|
|
1281
|
|
|
} |
1282
|
|
|
} |
1283
|
|
|
|
1284
|
|
|
$this->redrawItem($id, $primary_where_column); |
1285
|
|
|
|
1286
|
|
|
return; |
1287
|
|
|
} |
1288
|
|
|
} |
1289
|
|
|
|
1290
|
|
|
/** |
1291
|
|
|
* Inline add |
1292
|
|
|
*/ |
1293
|
|
|
$inline_add = $form['inline_add']; |
1294
|
|
|
|
1295
|
|
|
if (isset($inline_add) && isset($inline_add['submit']) && isset($inline_add['cancel'])) { |
1296
|
|
|
if ($inline_add['submit']->isSubmittedBy() || $inline_add['cancel']->isSubmittedBy()) { |
1297
|
|
View Code Duplication |
if ($inline_add['submit']->isSubmittedBy()) { |
|
|
|
|
1298
|
|
|
$this->inlineAdd->onSubmit($values->inline_add); |
|
|
|
|
1299
|
|
|
|
1300
|
|
|
if ($this->getPresenter()->isAjax()) { |
|
|
|
|
1301
|
|
|
$this->getPresenter()->payload->_datagrid_inline_added = TRUE; |
|
|
|
|
1302
|
|
|
} |
1303
|
|
|
} |
1304
|
|
|
|
1305
|
|
|
return; |
1306
|
|
|
} |
1307
|
|
|
} |
1308
|
|
|
|
1309
|
|
|
/** |
1310
|
|
|
* Filter itself |
1311
|
|
|
*/ |
1312
|
|
|
$values = $values['filter']; |
1313
|
|
|
|
1314
|
|
|
foreach ($values as $key => $value) { |
1315
|
|
|
/** |
1316
|
|
|
* Session stuff |
1317
|
|
|
*/ |
1318
|
|
|
$this->saveSessionData($key, $value); |
1319
|
|
|
|
1320
|
|
|
/** |
1321
|
|
|
* Other stuff |
1322
|
|
|
*/ |
1323
|
|
|
$this->filter[$key] = $value; |
1324
|
|
|
} |
1325
|
|
|
|
1326
|
|
|
if ($this->getPresenter()->isAjax()) { |
|
|
|
|
1327
|
|
|
$this->getPresenter()->payload->_datagrid_sort = []; |
|
|
|
|
1328
|
|
|
|
1329
|
|
|
foreach ($this->columns as $key => $column) { |
1330
|
|
|
if ($column->isSortable()) { |
1331
|
|
|
$this->getPresenter()->payload->_datagrid_sort[$key] = $this->link('sort!', [ |
|
|
|
|
1332
|
|
|
'sort' => $column->getSortNext() |
1333
|
|
|
]); |
1334
|
|
|
} |
1335
|
|
|
} |
1336
|
|
|
} |
1337
|
|
|
|
1338
|
|
|
$this->reload(); |
1339
|
|
|
} |
1340
|
|
|
|
1341
|
|
|
|
1342
|
|
|
/** |
1343
|
|
|
* Should be datagrid filters rendered separately? |
1344
|
|
|
* @param boolean $out |
1345
|
|
|
* @return static |
1346
|
|
|
*/ |
1347
|
|
|
public function setOuterFilterRendering($out = TRUE) |
1348
|
|
|
{ |
1349
|
|
|
$this->outer_filter_rendering = (bool) $out; |
1350
|
|
|
|
1351
|
|
|
return $this; |
1352
|
|
|
} |
1353
|
|
|
|
1354
|
|
|
|
1355
|
|
|
/** |
1356
|
|
|
* Are datagrid filters rendered separately? |
1357
|
|
|
* @return boolean |
1358
|
|
|
*/ |
1359
|
|
|
public function hasOuterFilterRendering() |
1360
|
|
|
{ |
1361
|
|
|
return $this->outer_filter_rendering; |
1362
|
|
|
} |
1363
|
|
|
|
1364
|
|
|
|
1365
|
|
|
/** |
1366
|
|
|
* Try to restore session stuff |
1367
|
|
|
* @return void |
1368
|
|
|
*/ |
1369
|
|
|
public function findSessionFilters() |
1370
|
|
|
{ |
1371
|
|
|
if ($this->filter || ($this->page != 1) || !empty($this->sort) || $this->per_page) { |
|
|
|
|
1372
|
|
|
return; |
1373
|
|
|
} |
1374
|
|
|
|
1375
|
|
|
if (!$this->remember_state) { |
1376
|
|
|
return; |
1377
|
|
|
} |
1378
|
|
|
|
1379
|
|
|
if ($page = $this->getSessionData('_grid_page')) { |
1380
|
|
|
$this->page = $page; |
1381
|
|
|
} |
1382
|
|
|
|
1383
|
|
|
if ($per_page = $this->getSessionData('_grid_per_page')) { |
1384
|
|
|
$this->per_page = $per_page; |
1385
|
|
|
} |
1386
|
|
|
|
1387
|
|
|
if ($sort = $this->getSessionData('_grid_sort')) { |
1388
|
|
|
$this->sort = $sort; |
|
|
|
|
1389
|
|
|
} |
1390
|
|
|
|
1391
|
|
|
foreach ($this->getSessionData() as $key => $value) { |
1392
|
|
|
$other_session_keys = [ |
1393
|
|
|
'_grid_per_page', |
1394
|
|
|
'_grid_sort', |
1395
|
|
|
'_grid_page', |
1396
|
|
|
'_grid_hidden_columns', |
1397
|
|
|
'_grid_hidden_columns_manipulated' |
1398
|
|
|
]; |
1399
|
|
|
|
1400
|
|
|
if (!in_array($key, $other_session_keys)) { |
1401
|
|
|
$this->filter[$key] = $value; |
1402
|
|
|
} |
1403
|
|
|
} |
1404
|
|
|
} |
1405
|
|
|
|
1406
|
|
|
|
1407
|
|
|
/******************************************************************************** |
1408
|
|
|
* EXPORTS * |
1409
|
|
|
********************************************************************************/ |
1410
|
|
|
|
1411
|
|
|
|
1412
|
|
|
/** |
1413
|
|
|
* Add export of type callback |
1414
|
|
|
* @param string $text |
1415
|
|
|
* @param callable $callback |
1416
|
|
|
* @param boolean $filtered |
1417
|
|
|
* @return Export\Export |
1418
|
|
|
*/ |
1419
|
|
|
public function addExportCallback($text, $callback, $filtered = FALSE) |
1420
|
|
|
{ |
1421
|
|
|
if (!is_callable($callback)) { |
1422
|
|
|
throw new DataGridException("Second parameter of ExportCallback must be callable."); |
1423
|
|
|
} |
1424
|
|
|
|
1425
|
|
|
return $this->addToExports(new Export\Export($text, $callback, $filtered)); |
1426
|
|
|
} |
1427
|
|
|
|
1428
|
|
|
|
1429
|
|
|
/** |
1430
|
|
|
* Add already implemented csv export |
1431
|
|
|
* @param string $text |
1432
|
|
|
* @param string $csv_file_name |
1433
|
|
|
* @param string|null $output_encoding |
1434
|
|
|
* @param string|null $delimiter |
1435
|
|
|
* @return Export\Export |
1436
|
|
|
*/ |
1437
|
|
|
public function addExportCsv($text, $csv_file_name, $output_encoding = NULL, $delimiter = NULL) |
1438
|
|
|
{ |
1439
|
|
|
return $this->addToExports(new Export\ExportCsv( |
1440
|
|
|
$text, |
1441
|
|
|
$csv_file_name, |
1442
|
|
|
FALSE, |
1443
|
|
|
$output_encoding, |
1444
|
|
|
$delimiter |
1445
|
|
|
)); |
1446
|
|
|
} |
1447
|
|
|
|
1448
|
|
|
|
1449
|
|
|
/** |
1450
|
|
|
* Add already implemented csv export, but for filtered data |
1451
|
|
|
* @param string $text |
1452
|
|
|
* @param string $csv_file_name |
1453
|
|
|
* @param string|null $output_encoding |
1454
|
|
|
* @param string|null $delimiter |
1455
|
|
|
* @return Export\Export |
1456
|
|
|
*/ |
1457
|
|
|
public function addExportCsvFiltered($text, $csv_file_name, $output_encoding = NULL, $delimiter = NULL) |
1458
|
|
|
{ |
1459
|
|
|
return $this->addToExports(new Export\ExportCsv( |
1460
|
|
|
$text, |
1461
|
|
|
$csv_file_name, |
1462
|
|
|
TRUE, |
1463
|
|
|
$output_encoding, |
1464
|
|
|
$delimiter |
1465
|
|
|
)); |
1466
|
|
|
} |
1467
|
|
|
|
1468
|
|
|
|
1469
|
|
|
/** |
1470
|
|
|
* Add export to array |
1471
|
|
|
* @param Export\Export $export |
1472
|
|
|
* @return Export\Export |
1473
|
|
|
*/ |
1474
|
|
|
protected function addToExports(Export\Export $export) |
1475
|
|
|
{ |
1476
|
|
|
$id = ($s = sizeof($this->exports)) ? ($s + 1) : 1; |
1477
|
|
|
|
1478
|
|
|
$export->setLink($this->link('export!', ['id' => $id])); |
1479
|
|
|
|
1480
|
|
|
return $this->exports[$id] = $export; |
1481
|
|
|
} |
1482
|
|
|
|
1483
|
|
|
|
1484
|
|
|
public function resetExportsLinks() |
1485
|
|
|
{ |
1486
|
|
|
foreach ($this->exports as $id => $export) { |
1487
|
|
|
$export->setLink($this->link('export!', ['id' => $id])); |
1488
|
|
|
} |
1489
|
|
|
} |
1490
|
|
|
|
1491
|
|
|
|
1492
|
|
|
/******************************************************************************** |
1493
|
|
|
* GROUP ACTIONS * |
1494
|
|
|
********************************************************************************/ |
1495
|
|
|
|
1496
|
|
|
|
1497
|
|
|
/** |
1498
|
|
|
* Alias for add group select action |
1499
|
|
|
* @param string $title |
1500
|
|
|
* @param array $options |
1501
|
|
|
* @return GroupAction\GroupAction |
1502
|
|
|
*/ |
1503
|
|
|
public function addGroupAction($title, $options = []) |
1504
|
|
|
{ |
1505
|
|
|
return $this->getGroupActionCollection()->addGroupSelectAction($title, $options); |
1506
|
|
|
} |
1507
|
|
|
|
1508
|
|
|
/** |
1509
|
|
|
* Add group action (select box) |
1510
|
|
|
* @param string $title |
1511
|
|
|
* @param array $options |
1512
|
|
|
* @return GroupAction\GroupAction |
1513
|
|
|
*/ |
1514
|
|
|
public function addGroupSelectAction($title, $options = []) |
1515
|
|
|
{ |
1516
|
|
|
return $this->getGroupActionCollection()->addGroupSelectAction($title, $options); |
1517
|
|
|
} |
1518
|
|
|
|
1519
|
|
|
/** |
1520
|
|
|
* Add group action (text input) |
1521
|
|
|
* @param string $title |
1522
|
|
|
* @return GroupAction\GroupAction |
1523
|
|
|
*/ |
1524
|
|
|
public function addGroupTextAction($title) |
1525
|
|
|
{ |
1526
|
|
|
return $this->getGroupActionCollection()->addGroupTextAction($title); |
1527
|
|
|
} |
1528
|
|
|
|
1529
|
|
|
/** |
1530
|
|
|
* Get collection of all group actions |
1531
|
|
|
* @return GroupAction\GroupActionCollection |
1532
|
|
|
*/ |
1533
|
|
|
public function getGroupActionCollection() |
1534
|
|
|
{ |
1535
|
|
|
if (!$this->group_action_collection) { |
1536
|
|
|
$this->group_action_collection = new GroupAction\GroupActionCollection(); |
1537
|
|
|
} |
1538
|
|
|
|
1539
|
|
|
return $this->group_action_collection; |
1540
|
|
|
} |
1541
|
|
|
|
1542
|
|
|
|
1543
|
|
|
/** |
1544
|
|
|
* Has datagrid some group actions? |
1545
|
|
|
* @return boolean |
1546
|
|
|
*/ |
1547
|
|
|
public function hasGroupActions() |
1548
|
|
|
{ |
1549
|
|
|
return (bool) $this->group_action_collection; |
1550
|
|
|
} |
1551
|
|
|
|
1552
|
|
|
|
1553
|
|
|
/******************************************************************************** |
1554
|
|
|
* HANDLERS * |
1555
|
|
|
********************************************************************************/ |
1556
|
|
|
|
1557
|
|
|
|
1558
|
|
|
/** |
1559
|
|
|
* Handler for changind page (just refresh site with page as persistent paramter set) |
1560
|
|
|
* @param int $page |
1561
|
|
|
* @return void |
1562
|
|
|
*/ |
1563
|
|
|
public function handlePage($page) |
1564
|
|
|
{ |
1565
|
|
|
/** |
1566
|
|
|
* Session stuff |
1567
|
|
|
*/ |
1568
|
|
|
$this->page = $page; |
1569
|
|
|
$this->saveSessionData('_grid_page', $page); |
1570
|
|
|
|
1571
|
|
|
$this->reload(['table']); |
1572
|
|
|
} |
1573
|
|
|
|
1574
|
|
|
|
1575
|
|
|
/** |
1576
|
|
|
* Handler for sorting |
1577
|
|
|
* @param array $sort |
1578
|
|
|
* @return void |
1579
|
|
|
*/ |
1580
|
|
|
public function handleSort(array $sort) |
1581
|
|
|
{ |
1582
|
|
|
$new_sort = []; |
1583
|
|
|
|
1584
|
|
|
/** |
1585
|
|
|
* Find apropirate column |
1586
|
|
|
*/ |
1587
|
|
|
foreach ($sort as $key => $value) { |
1588
|
|
|
if (empty($this->columns[$key])) { |
1589
|
|
|
throw new DataGridException("Column <$key> not found"); |
1590
|
|
|
} |
1591
|
|
|
|
1592
|
|
|
$column = $this->columns[$key]; |
1593
|
|
|
$new_sort = [$column->getSortingColumn() => $value]; |
1594
|
|
|
|
1595
|
|
|
/** |
1596
|
|
|
* Pagination may be reseted after sorting |
1597
|
|
|
*/ |
1598
|
|
|
if ($column->sortableResetPagination()) { |
1599
|
|
|
$this->page = 1; |
1600
|
|
|
$this->saveSessionData('_grid_page', 1); |
1601
|
|
|
} |
1602
|
|
|
|
1603
|
|
|
/** |
1604
|
|
|
* Custom sorting callback may be applied |
1605
|
|
|
*/ |
1606
|
|
|
if ($column->getSortableCallback()) { |
1607
|
|
|
$this->sort_callback = $column->getSortableCallback(); |
1608
|
|
|
} |
1609
|
|
|
} |
1610
|
|
|
|
1611
|
|
|
/** |
1612
|
|
|
* Session stuff |
1613
|
|
|
*/ |
1614
|
|
|
$this->sort = $new_sort; |
1615
|
|
|
$this->saveSessionData('_grid_sort', $this->sort); |
1616
|
|
|
|
1617
|
|
|
$this->reload(['table']); |
1618
|
|
|
} |
1619
|
|
|
|
1620
|
|
|
|
1621
|
|
|
/** |
1622
|
|
|
* handler for reseting the filter |
1623
|
|
|
* @return void |
1624
|
|
|
*/ |
1625
|
|
|
public function handleResetFilter() |
1626
|
|
|
{ |
1627
|
|
|
/** |
1628
|
|
|
* Session stuff |
1629
|
|
|
*/ |
1630
|
|
|
$this->deleteSesssionData('_grid_page'); |
1631
|
|
|
|
1632
|
|
|
foreach ($this->getSessionData() as $key => $value) { |
1633
|
|
|
if (!in_array($key, ['_grid_per_page', '_grid_sort', '_grid_page'])) { |
1634
|
|
|
$this->deleteSesssionData($key); |
1635
|
|
|
} |
1636
|
|
|
} |
1637
|
|
|
|
1638
|
|
|
$this->filter = []; |
1639
|
|
|
|
1640
|
|
|
$this->reload(['grid']); |
1641
|
|
|
} |
1642
|
|
|
|
1643
|
|
|
|
1644
|
|
|
/** |
1645
|
|
|
* Handler for export |
1646
|
|
|
* @param int $id Key for particular export class in array $this->exports |
1647
|
|
|
* @return void |
1648
|
|
|
*/ |
1649
|
|
|
public function handleExport($id) |
1650
|
|
|
{ |
1651
|
|
|
if (!isset($this->exports[$id])) { |
1652
|
|
|
throw new Nette\Application\ForbiddenRequestException; |
1653
|
|
|
} |
1654
|
|
|
|
1655
|
|
|
if (!empty($this->columns_export_order)) { |
1656
|
|
|
$this->setColumnsOrder($this->columns_export_order); |
1657
|
|
|
} |
1658
|
|
|
|
1659
|
|
|
$export = $this->exports[$id]; |
1660
|
|
|
|
1661
|
|
|
if ($export->isFiltered()) { |
1662
|
|
|
$sort = $this->sort; |
|
|
|
|
1663
|
|
|
$filter = $this->assableFilters(); |
1664
|
|
|
} else { |
1665
|
|
|
$sort = [$this->primary_key => 'ASC']; |
|
|
|
|
1666
|
|
|
$filter = []; |
1667
|
|
|
} |
1668
|
|
|
|
1669
|
|
|
if (NULL === $this->dataModel) { |
1670
|
|
|
throw new DataGridException('You have to set a data source first.'); |
1671
|
|
|
} |
1672
|
|
|
|
1673
|
|
|
$rows = []; |
1674
|
|
|
|
1675
|
|
|
$items = Nette\Utils\Callback::invokeArgs( |
1676
|
|
|
[$this->dataModel, 'filterData'], [ |
1677
|
|
|
NULL, |
1678
|
|
|
new Sorting($this->sort, $this->sort_callback), |
1679
|
|
|
$filter |
1680
|
|
|
] |
1681
|
|
|
); |
1682
|
|
|
|
1683
|
|
|
foreach ($items as $item) { |
1684
|
|
|
$rows[] = new Row($this, $item, $this->getPrimaryKey()); |
1685
|
|
|
} |
1686
|
|
|
|
1687
|
|
|
if ($export instanceof Export\ExportCsv) { |
1688
|
|
|
$export->invoke($rows, $this); |
1689
|
|
|
} else { |
1690
|
|
|
$export->invoke($items, $this); |
1691
|
|
|
} |
1692
|
|
|
|
1693
|
|
|
if ($export->isAjax()) { |
1694
|
|
|
$this->reload(); |
1695
|
|
|
} |
1696
|
|
|
} |
1697
|
|
|
|
1698
|
|
|
|
1699
|
|
|
/** |
1700
|
|
|
* Handler for getting children of parent item (e.g. category) |
1701
|
|
|
* @param int $parent |
1702
|
|
|
* @return void |
1703
|
|
|
*/ |
1704
|
|
View Code Duplication |
public function handleGetChildren($parent) |
|
|
|
|
1705
|
|
|
{ |
1706
|
|
|
$this->setDataSource( |
1707
|
|
|
call_user_func($this->tree_view_children_callback, $parent) |
1708
|
|
|
); |
1709
|
|
|
|
1710
|
|
|
if ($this->getPresenter()->isAjax()) { |
|
|
|
|
1711
|
|
|
$this->getPresenter()->payload->_datagrid_url = $this->refresh_url; |
|
|
|
|
1712
|
|
|
$this->getPresenter()->payload->_datagrid_tree = $parent; |
|
|
|
|
1713
|
|
|
|
1714
|
|
|
$this->redrawControl('items'); |
1715
|
|
|
|
1716
|
|
|
$this->onRedraw(); |
1717
|
|
|
} else { |
1718
|
|
|
$this->getPresenter()->redirect('this'); |
|
|
|
|
1719
|
|
|
} |
1720
|
|
|
} |
1721
|
|
|
|
1722
|
|
|
|
1723
|
|
|
/** |
1724
|
|
|
* Handler for getting item detail |
1725
|
|
|
* @param mixed $id |
1726
|
|
|
* @return void |
1727
|
|
|
*/ |
1728
|
|
View Code Duplication |
public function handleGetItemDetail($id) |
|
|
|
|
1729
|
|
|
{ |
1730
|
|
|
$this->template->add('toggle_detail', $id); |
|
|
|
|
1731
|
|
|
$this->redraw_item = [$this->items_detail->getPrimaryWhereColumn() => $id]; |
1732
|
|
|
|
1733
|
|
|
if ($this->getPresenter()->isAjax()) { |
|
|
|
|
1734
|
|
|
$this->getPresenter()->payload->_datagrid_toggle_detail = $id; |
|
|
|
|
1735
|
|
|
$this->redrawControl('items'); |
1736
|
|
|
|
1737
|
|
|
$this->onRedraw(); |
1738
|
|
|
} else { |
1739
|
|
|
$this->getPresenter()->redirect('this'); |
|
|
|
|
1740
|
|
|
} |
1741
|
|
|
} |
1742
|
|
|
|
1743
|
|
|
|
1744
|
|
|
/** |
1745
|
|
|
* Handler for inline editing |
1746
|
|
|
* @param mixed $id |
1747
|
|
|
* @param mixed $key |
1748
|
|
|
* @return void |
1749
|
|
|
*/ |
1750
|
|
|
public function handleEdit($id, $key) |
1751
|
|
|
{ |
1752
|
|
|
$column = $this->getColumn($key); |
1753
|
|
|
$value = $this->getPresenter()->getRequest()->getPost('value'); |
|
|
|
|
1754
|
|
|
|
1755
|
|
|
call_user_func_array($column->getEditableCallback(), [$id, $value]); |
1756
|
|
|
} |
1757
|
|
|
|
1758
|
|
|
|
1759
|
|
|
/** |
1760
|
|
|
* Redraw $this |
1761
|
|
|
* @return void |
1762
|
|
|
*/ |
1763
|
|
|
public function reload($snippets = []) |
1764
|
|
|
{ |
1765
|
|
|
if ($this->getPresenter()->isAjax()) { |
|
|
|
|
1766
|
|
|
$this->redrawControl('tbody'); |
1767
|
|
|
$this->redrawControl('pagination'); |
1768
|
|
|
|
1769
|
|
|
/** |
1770
|
|
|
* manualy reset exports links... |
1771
|
|
|
*/ |
1772
|
|
|
$this->resetExportsLinks(); |
1773
|
|
|
$this->redrawControl('exports'); |
1774
|
|
|
|
1775
|
|
|
foreach ($snippets as $snippet) { |
1776
|
|
|
$this->redrawControl($snippet); |
1777
|
|
|
} |
1778
|
|
|
|
1779
|
|
|
$this->getPresenter()->payload->_datagrid_url = $this->refresh_url; |
|
|
|
|
1780
|
|
|
|
1781
|
|
|
$this->onRedraw(); |
1782
|
|
|
} else { |
1783
|
|
|
$this->getPresenter()->redirect('this'); |
|
|
|
|
1784
|
|
|
} |
1785
|
|
|
} |
1786
|
|
|
|
1787
|
|
|
|
1788
|
|
|
/** |
1789
|
|
|
* Handler for column status |
1790
|
|
|
* @param string $id |
1791
|
|
|
* @param string $key |
1792
|
|
|
* @param string $value |
1793
|
|
|
* @return void |
1794
|
|
|
*/ |
1795
|
|
|
public function handleChangeStatus($id, $key, $value) |
1796
|
|
|
{ |
1797
|
|
|
if (empty($this->columns[$key])) { |
1798
|
|
|
throw new DataGridException("ColumnStatus[$key] does not exist"); |
1799
|
|
|
} |
1800
|
|
|
|
1801
|
|
|
$this->columns[$key]->onChange($id, $value); |
1802
|
|
|
} |
1803
|
|
|
|
1804
|
|
|
|
1805
|
|
|
/** |
1806
|
|
|
* Redraw just one row via ajax |
1807
|
|
|
* @param int $id |
1808
|
|
|
* @param mixed $primary_where_column |
1809
|
|
|
* @return void |
1810
|
|
|
*/ |
1811
|
|
|
public function redrawItem($id, $primary_where_column = NULL) |
1812
|
|
|
{ |
1813
|
|
|
$this->snippets_set = TRUE; |
1814
|
|
|
|
1815
|
|
|
$this->redraw_item = [($primary_where_column ?: $this->primary_key) => $id]; |
1816
|
|
|
|
1817
|
|
|
$this->redrawControl('items'); |
1818
|
|
|
$this->getPresenter()->payload->_datagrid_url = $this->refresh_url; |
|
|
|
|
1819
|
|
|
|
1820
|
|
|
$this->onRedraw(); |
1821
|
|
|
} |
1822
|
|
|
|
1823
|
|
|
|
1824
|
|
|
/** |
1825
|
|
|
* Tell datagrid to display all columns |
1826
|
|
|
* @return void |
1827
|
|
|
*/ |
1828
|
|
|
public function handleShowAllColumns() |
1829
|
|
|
{ |
1830
|
|
|
$this->deleteSesssionData('_grid_hidden_columns'); |
1831
|
|
|
$this->saveSessionData('_grid_hidden_columns_manipulated', TRUE); |
1832
|
|
|
|
1833
|
|
|
$this->redrawControl(); |
1834
|
|
|
|
1835
|
|
|
$this->onRedraw(); |
1836
|
|
|
} |
1837
|
|
|
|
1838
|
|
|
|
1839
|
|
|
/** |
1840
|
|
|
* Tell datagrid to display default columns |
1841
|
|
|
* @return void |
1842
|
|
|
*/ |
1843
|
|
|
public function handleShowDefaultColumns() |
1844
|
|
|
{ |
1845
|
|
|
$this->deleteSesssionData('_grid_hidden_columns'); |
1846
|
|
|
$this->saveSessionData('_grid_hidden_columns_manipulated', FALSE); |
1847
|
|
|
|
1848
|
|
|
$this->redrawControl(); |
1849
|
|
|
|
1850
|
|
|
$this->onRedraw(); |
1851
|
|
|
} |
1852
|
|
|
|
1853
|
|
|
|
1854
|
|
|
/** |
1855
|
|
|
* Reveal particular column |
1856
|
|
|
* @param string $column |
1857
|
|
|
* @return void |
1858
|
|
|
*/ |
1859
|
|
View Code Duplication |
public function handleShowColumn($column) |
|
|
|
|
1860
|
|
|
{ |
1861
|
|
|
$columns = $this->getSessionData('_grid_hidden_columns'); |
1862
|
|
|
|
1863
|
|
|
if (!empty($columns)) { |
1864
|
|
|
$pos = array_search($column, $columns); |
1865
|
|
|
|
1866
|
|
|
if ($pos !== FALSE) { |
1867
|
|
|
unset($columns[$pos]); |
1868
|
|
|
} |
1869
|
|
|
} |
1870
|
|
|
|
1871
|
|
|
$this->saveSessionData('_grid_hidden_columns', $columns); |
1872
|
|
|
$this->saveSessionData('_grid_hidden_columns_manipulated', TRUE); |
1873
|
|
|
|
1874
|
|
|
$this->redrawControl(); |
1875
|
|
|
|
1876
|
|
|
$this->onRedraw(); |
1877
|
|
|
} |
1878
|
|
|
|
1879
|
|
|
|
1880
|
|
|
/** |
1881
|
|
|
* Notice datagrid to not display particular columns |
1882
|
|
|
* @param string $column |
1883
|
|
|
* @return void |
1884
|
|
|
*/ |
1885
|
|
View Code Duplication |
public function handleHideColumn($column) |
|
|
|
|
1886
|
|
|
{ |
1887
|
|
|
/** |
1888
|
|
|
* Store info about hiding a column to session |
1889
|
|
|
*/ |
1890
|
|
|
$columns = $this->getSessionData('_grid_hidden_columns'); |
1891
|
|
|
|
1892
|
|
|
if (empty($columns)) { |
1893
|
|
|
$columns = [$column]; |
1894
|
|
|
} else if (!in_array($column, $columns)) { |
1895
|
|
|
array_push($columns, $column); |
1896
|
|
|
} |
1897
|
|
|
|
1898
|
|
|
$this->saveSessionData('_grid_hidden_columns', $columns); |
1899
|
|
|
$this->saveSessionData('_grid_hidden_columns_manipulated', TRUE); |
1900
|
|
|
|
1901
|
|
|
$this->redrawControl(); |
1902
|
|
|
|
1903
|
|
|
$this->onRedraw(); |
1904
|
|
|
} |
1905
|
|
|
|
1906
|
|
|
|
1907
|
|
|
public function handleActionCallback($__key, $__id) |
1908
|
|
|
{ |
1909
|
|
|
$action = $this->getAction($__key); |
1910
|
|
|
|
1911
|
|
|
if (!($action instanceof Column\ActionCallback)) { |
1912
|
|
|
throw new DataGridException("Action [$__key] does not exist or is not an callback aciton."); |
1913
|
|
|
} |
1914
|
|
|
|
1915
|
|
|
$action->onClick($__id); |
1916
|
|
|
} |
1917
|
|
|
|
1918
|
|
|
|
1919
|
|
|
/******************************************************************************** |
1920
|
|
|
* PAGINATION * |
1921
|
|
|
********************************************************************************/ |
1922
|
|
|
|
1923
|
|
|
|
1924
|
|
|
/** |
1925
|
|
|
* Set options of select "items_per_page" |
1926
|
|
|
* @param array $items_per_page_list |
1927
|
|
|
* @return static |
1928
|
|
|
*/ |
1929
|
|
|
public function setItemsPerPageList(array $items_per_page_list, $include_all = TRUE) |
1930
|
|
|
{ |
1931
|
|
|
$this->items_per_page_list = $items_per_page_list; |
1932
|
|
|
|
1933
|
|
|
if ($include_all) { |
1934
|
|
|
$this->items_per_page_list[] = 'all'; |
1935
|
|
|
} |
1936
|
|
|
|
1937
|
|
|
return $this; |
1938
|
|
|
} |
1939
|
|
|
|
1940
|
|
|
|
1941
|
|
|
/** |
1942
|
|
|
* Paginator factory |
1943
|
|
|
* @return Components\DataGridPaginator\DataGridPaginator |
1944
|
|
|
*/ |
1945
|
|
|
public function createComponentPaginator() |
1946
|
|
|
{ |
1947
|
|
|
/** |
1948
|
|
|
* Init paginator |
1949
|
|
|
*/ |
1950
|
|
|
$component = new Components\DataGridPaginator\DataGridPaginator( |
1951
|
|
|
$this->getTranslator() |
1952
|
|
|
); |
1953
|
|
|
$paginator = $component->getPaginator(); |
1954
|
|
|
|
1955
|
|
|
$paginator->setPage($this->page); |
1956
|
|
|
$paginator->setItemsPerPage($this->getPerPage()); |
1957
|
|
|
|
1958
|
|
|
return $component; |
1959
|
|
|
} |
1960
|
|
|
|
1961
|
|
|
|
1962
|
|
|
/** |
1963
|
|
|
* PerPage form factory |
1964
|
|
|
* @return Form |
1965
|
|
|
*/ |
1966
|
|
|
public function createComponentPerPage() |
1967
|
|
|
{ |
1968
|
|
|
$form = new Form; |
1969
|
|
|
|
1970
|
|
|
$form->addSelect('per_page', '', $this->getItemsPerPageList()) |
1971
|
|
|
->setValue($this->getPerPage()); |
1972
|
|
|
|
1973
|
|
|
$form->addSubmit('submit', ''); |
1974
|
|
|
|
1975
|
|
|
$saveSessionData = [$this, 'saveSessionData']; |
1976
|
|
|
|
1977
|
|
|
$form->onSuccess[] = function($form, $values) use ($saveSessionData) { |
1978
|
|
|
/** |
1979
|
|
|
* Session stuff |
1980
|
|
|
*/ |
1981
|
|
|
$saveSessionData('_grid_per_page', $values->per_page); |
1982
|
|
|
|
1983
|
|
|
/** |
1984
|
|
|
* Other stuff |
1985
|
|
|
*/ |
1986
|
|
|
$this->per_page = $values->per_page; |
1987
|
|
|
$this->reload(); |
1988
|
|
|
}; |
1989
|
|
|
|
1990
|
|
|
return $form; |
1991
|
|
|
} |
1992
|
|
|
|
1993
|
|
|
|
1994
|
|
|
/** |
1995
|
|
|
* Get parameter per_page |
1996
|
|
|
* @return int |
1997
|
|
|
*/ |
1998
|
|
|
public function getPerPage() |
1999
|
|
|
{ |
2000
|
|
|
$items_per_page_list = $this->getItemsPerPageList(); |
2001
|
|
|
|
2002
|
|
|
$per_page = $this->per_page ?: reset($items_per_page_list); |
2003
|
|
|
|
2004
|
|
|
if ($per_page !== 'all' && !in_array($this->per_page, $items_per_page_list)) { |
2005
|
|
|
$per_page = reset($items_per_page_list); |
2006
|
|
|
} |
2007
|
|
|
|
2008
|
|
|
return $per_page; |
2009
|
|
|
} |
2010
|
|
|
|
2011
|
|
|
|
2012
|
|
|
/** |
2013
|
|
|
* Get associative array of items_per_page_list |
2014
|
|
|
* @return array |
2015
|
|
|
*/ |
2016
|
|
|
public function getItemsPerPageList() |
2017
|
|
|
{ |
2018
|
|
|
if (empty($this->items_per_page_list)) { |
2019
|
|
|
$this->setItemsPerPageList([10, 20, 50], TRUE); |
2020
|
|
|
} |
2021
|
|
|
|
2022
|
|
|
$list = array_flip($this->items_per_page_list); |
2023
|
|
|
|
2024
|
|
|
foreach ($list as $key => $value) { |
2025
|
|
|
$list[$key] = $key; |
2026
|
|
|
} |
2027
|
|
|
|
2028
|
|
|
if (array_key_exists('all', $list)) { |
2029
|
|
|
$list['all'] = $this->getTranslator()->translate('ublaboo_datagrid.all'); |
2030
|
|
|
} |
2031
|
|
|
|
2032
|
|
|
return $list; |
2033
|
|
|
} |
2034
|
|
|
|
2035
|
|
|
|
2036
|
|
|
/** |
2037
|
|
|
* Order Grid to "be paginated" |
2038
|
|
|
* @param bool $do |
2039
|
|
|
* @return static |
2040
|
|
|
*/ |
2041
|
|
|
public function setPagination($do) |
2042
|
|
|
{ |
2043
|
|
|
$this->do_paginate = (bool) $do; |
2044
|
|
|
|
2045
|
|
|
return $this; |
2046
|
|
|
} |
2047
|
|
|
|
2048
|
|
|
|
2049
|
|
|
/** |
2050
|
|
|
* Tell whether Grid is paginated |
2051
|
|
|
* @return bool |
2052
|
|
|
*/ |
2053
|
|
|
public function isPaginated() |
2054
|
|
|
{ |
2055
|
|
|
return $this->do_paginate; |
2056
|
|
|
} |
2057
|
|
|
|
2058
|
|
|
|
2059
|
|
|
/** |
2060
|
|
|
* Return current paginator class |
2061
|
|
|
* @return NULL|Components\DataGridPaginator\DataGridPaginator |
2062
|
|
|
*/ |
2063
|
|
|
public function getPaginator() |
2064
|
|
|
{ |
2065
|
|
|
if ($this->isPaginated() && $this->per_page !== 'all') { |
2066
|
|
|
return $this['paginator']; |
2067
|
|
|
} |
2068
|
|
|
|
2069
|
|
|
return NULL; |
2070
|
|
|
} |
2071
|
|
|
|
2072
|
|
|
|
2073
|
|
|
/******************************************************************************** |
2074
|
|
|
* I18N * |
2075
|
|
|
********************************************************************************/ |
2076
|
|
|
|
2077
|
|
|
|
2078
|
|
|
/** |
2079
|
|
|
* Set datagrid translator |
2080
|
|
|
* @param Nette\Localization\ITranslator $translator |
2081
|
|
|
* @return static |
2082
|
|
|
*/ |
2083
|
|
|
public function setTranslator(Nette\Localization\ITranslator $translator) |
2084
|
|
|
{ |
2085
|
|
|
$this->translator = $translator; |
2086
|
|
|
|
2087
|
|
|
return $this; |
2088
|
|
|
} |
2089
|
|
|
|
2090
|
|
|
|
2091
|
|
|
/** |
2092
|
|
|
* Get translator for datagrid |
2093
|
|
|
* @return Nette\Localization\ITranslator |
2094
|
|
|
*/ |
2095
|
|
|
public function getTranslator() |
2096
|
|
|
{ |
2097
|
|
|
if (!$this->translator) { |
2098
|
|
|
$this->translator = new Localization\SimpleTranslator; |
2099
|
|
|
} |
2100
|
|
|
|
2101
|
|
|
return $this->translator; |
2102
|
|
|
} |
2103
|
|
|
|
2104
|
|
|
|
2105
|
|
|
/******************************************************************************** |
2106
|
|
|
* COLUMNS ORDER * |
2107
|
|
|
********************************************************************************/ |
2108
|
|
|
|
2109
|
|
|
|
2110
|
|
|
/** |
2111
|
|
|
* Set order of datagrid columns |
2112
|
|
|
* @param array $order |
2113
|
|
|
* @return static |
2114
|
|
|
*/ |
2115
|
|
|
public function setColumnsOrder($order) |
2116
|
|
|
{ |
2117
|
|
|
$new_order = []; |
2118
|
|
|
|
2119
|
|
|
foreach ($order as $key) { |
2120
|
|
|
if (isset($this->columns[$key])) { |
2121
|
|
|
$new_order[$key] = $this->columns[$key]; |
2122
|
|
|
} |
2123
|
|
|
} |
2124
|
|
|
|
2125
|
|
|
if (sizeof($new_order) === sizeof($this->columns)) { |
2126
|
|
|
$this->columns = $new_order; |
2127
|
|
|
} else { |
2128
|
|
|
throw new DataGridException('When changing columns order, you have to specify all columns'); |
2129
|
|
|
} |
2130
|
|
|
|
2131
|
|
|
return $this; |
2132
|
|
|
} |
2133
|
|
|
|
2134
|
|
|
|
2135
|
|
|
/** |
2136
|
|
|
* Columns order may be different for export and normal grid |
2137
|
|
|
* @param array $order |
2138
|
|
|
*/ |
2139
|
|
|
public function setColumnsExportOrder($order) |
2140
|
|
|
{ |
2141
|
|
|
$this->columns_export_order = (array) $order; |
2142
|
|
|
} |
2143
|
|
|
|
2144
|
|
|
|
2145
|
|
|
/******************************************************************************** |
2146
|
|
|
* SESSION & URL * |
2147
|
|
|
********************************************************************************/ |
2148
|
|
|
|
2149
|
|
|
|
2150
|
|
|
/** |
2151
|
|
|
* Find some unique session key name |
2152
|
|
|
* @return string |
2153
|
|
|
*/ |
2154
|
|
|
public function getSessionSectionName() |
2155
|
|
|
{ |
2156
|
|
|
return $this->getPresenter()->getName().':'.$this->getUniqueId(); |
2157
|
|
|
} |
2158
|
|
|
|
2159
|
|
|
|
2160
|
|
|
/** |
2161
|
|
|
* Should datagrid remember its filters/pagination/etc using session? |
2162
|
|
|
* @param bool $remember |
2163
|
|
|
* @return static |
2164
|
|
|
*/ |
2165
|
|
|
public function setRememberState($remember = TRUE) |
2166
|
|
|
{ |
2167
|
|
|
$this->remember_state = (bool) $remember; |
2168
|
|
|
|
2169
|
|
|
return $this; |
2170
|
|
|
} |
2171
|
|
|
|
2172
|
|
|
|
2173
|
|
|
/** |
2174
|
|
|
* Should datagrid refresh url using history API? |
2175
|
|
|
* @param bool $refresh |
2176
|
|
|
* @return static |
2177
|
|
|
*/ |
2178
|
|
|
public function setRefreshUrl($refresh = TRUE) |
2179
|
|
|
{ |
2180
|
|
|
$this->refresh_url = (bool) $refresh; |
2181
|
|
|
|
2182
|
|
|
|
2183
|
|
|
return $this; |
2184
|
|
|
} |
2185
|
|
|
|
2186
|
|
|
|
2187
|
|
|
/** |
2188
|
|
|
* Get session data if functionality is enabled |
2189
|
|
|
* @param string $key |
2190
|
|
|
* @return mixed |
2191
|
|
|
*/ |
2192
|
|
|
public function getSessionData($key = NULL, $default_value = NULL) |
2193
|
|
|
{ |
2194
|
|
|
if (!$this->remember_state) { |
2195
|
|
|
return $key ? $default_value : []; |
2196
|
|
|
} |
2197
|
|
|
|
2198
|
|
|
return ($key ? $this->grid_session->{$key} : $this->grid_session) ?: $default_value; |
2199
|
|
|
} |
2200
|
|
|
|
2201
|
|
|
|
2202
|
|
|
/** |
2203
|
|
|
* Save session data - just if it is enabled |
2204
|
|
|
* @param string $key |
2205
|
|
|
* @param mixed $value |
2206
|
|
|
* @return void |
2207
|
|
|
*/ |
2208
|
|
|
public function saveSessionData($key, $value) |
2209
|
|
|
{ |
2210
|
|
|
if ($this->remember_state) { |
2211
|
|
|
$this->grid_session->{$key} = $value; |
2212
|
|
|
} |
2213
|
|
|
} |
2214
|
|
|
|
2215
|
|
|
|
2216
|
|
|
/** |
2217
|
|
|
* Delete session data |
2218
|
|
|
* @return void |
2219
|
|
|
*/ |
2220
|
|
|
public function deleteSesssionData($key) |
2221
|
|
|
{ |
2222
|
|
|
unset($this->grid_session->{$key}); |
2223
|
|
|
} |
2224
|
|
|
|
2225
|
|
|
|
2226
|
|
|
/******************************************************************************** |
2227
|
|
|
* ITEM DETAIL * |
2228
|
|
|
********************************************************************************/ |
2229
|
|
|
|
2230
|
|
|
|
2231
|
|
|
/** |
2232
|
|
|
* Get items detail parameters |
2233
|
|
|
* @return array |
2234
|
|
|
*/ |
2235
|
|
|
public function getItemsDetail() |
2236
|
|
|
{ |
2237
|
|
|
return $this->items_detail; |
2238
|
|
|
} |
2239
|
|
|
|
2240
|
|
|
|
2241
|
|
|
/** |
2242
|
|
|
* Items can have thair detail - toggled |
2243
|
|
|
* @param mixed $detail callable|string|bool |
2244
|
|
|
* @param bool|NULL $primary_where_column |
2245
|
|
|
* @return Column\ItemDetail |
2246
|
|
|
*/ |
2247
|
|
|
public function setItemsDetail($detail = TRUE, $primary_where_column = NULL) |
2248
|
|
|
{ |
2249
|
|
|
if ($this->isSortable()) { |
2250
|
|
|
throw new DataGridException('You can not use both sortable datagrid and items detail.'); |
2251
|
|
|
} |
2252
|
|
|
|
2253
|
|
|
$this->items_detail = new Column\ItemDetail( |
2254
|
|
|
$this, |
2255
|
|
|
$primary_where_column ?: $this->primary_key |
|
|
|
|
2256
|
|
|
); |
2257
|
|
|
|
2258
|
|
|
if (is_string($detail)) { |
2259
|
|
|
/** |
2260
|
|
|
* Item detail will be in separate template |
2261
|
|
|
*/ |
2262
|
|
|
$this->items_detail->setType('template'); |
2263
|
|
|
$this->items_detail->setTemplate($detail); |
2264
|
|
|
|
2265
|
|
|
} else if (is_callable($detail)) { |
2266
|
|
|
/** |
2267
|
|
|
* Item detail will be rendered via custom callback renderer |
2268
|
|
|
*/ |
2269
|
|
|
$this->items_detail->setType('renderer'); |
2270
|
|
|
$this->items_detail->setRenderer($detail); |
2271
|
|
|
|
2272
|
|
|
} else if (TRUE === $detail) { |
2273
|
|
|
/** |
2274
|
|
|
* Item detail will be rendered probably via block #detail |
2275
|
|
|
*/ |
2276
|
|
|
$this->items_detail->setType('block'); |
2277
|
|
|
|
2278
|
|
|
} else { |
2279
|
|
|
throw new DataGridException( |
2280
|
|
|
'::setItemsDetail() can be called either with no parameters or with parameter = template path or callable renderer.' |
2281
|
|
|
); |
2282
|
|
|
} |
2283
|
|
|
|
2284
|
|
|
return $this->items_detail; |
2285
|
|
|
} |
2286
|
|
|
|
2287
|
|
|
|
2288
|
|
|
/** |
2289
|
|
|
* @param callable $callable_set_container |
2290
|
|
|
* @return static |
2291
|
|
|
*/ |
2292
|
|
|
public function setItemsDetailForm(callable $callable_set_container) |
2293
|
|
|
{ |
2294
|
|
|
if ($this->items_detail instanceof Column\ItemDetail) { |
2295
|
|
|
$this->items_detail->setForm( |
2296
|
|
|
new Utils\ItemDetailForm($callable_set_container) |
2297
|
|
|
); |
2298
|
|
|
|
2299
|
|
|
return $this; |
2300
|
|
|
} |
2301
|
|
|
|
2302
|
|
|
throw new DataGridException('Please set the ItemDetail first.'); |
2303
|
|
|
} |
2304
|
|
|
|
2305
|
|
|
|
2306
|
|
|
/** |
2307
|
|
|
* @return Nette\Forms\Container|NULL |
2308
|
|
|
*/ |
2309
|
|
|
public function getItemDetailForm() |
2310
|
|
|
{ |
2311
|
|
|
if ($this->items_detail instanceof Column\ItemDetail) { |
2312
|
|
|
return $this->items_detail->getForm(); |
2313
|
|
|
} |
2314
|
|
|
|
2315
|
|
|
return NULL; |
2316
|
|
|
} |
2317
|
|
|
|
2318
|
|
|
|
2319
|
|
|
/******************************************************************************** |
2320
|
|
|
* ROW PRIVILEGES * |
2321
|
|
|
********************************************************************************/ |
2322
|
|
|
|
2323
|
|
|
|
2324
|
|
|
/** |
2325
|
|
|
* @param callable $condition |
2326
|
|
|
* @return void |
2327
|
|
|
*/ |
2328
|
|
|
public function allowRowsGroupAction(callable $condition) |
2329
|
|
|
{ |
2330
|
|
|
$this->row_conditions['group_action'] = $condition; |
2331
|
|
|
} |
2332
|
|
|
|
2333
|
|
|
|
2334
|
|
|
/** |
2335
|
|
|
* @param string $key |
2336
|
|
|
* @param callable $condition |
2337
|
|
|
* @return void |
2338
|
|
|
*/ |
2339
|
|
|
public function allowRowsAction($key, callable $condition) |
2340
|
|
|
{ |
2341
|
|
|
$this->row_conditions['action'][$key] = $condition; |
2342
|
|
|
} |
2343
|
|
|
|
2344
|
|
|
|
2345
|
|
|
/** |
2346
|
|
|
* @param string $name |
2347
|
|
|
* @param string|null $key |
2348
|
|
|
* @return bool|callable |
2349
|
|
|
*/ |
2350
|
|
|
public function getRowCondition($name, $key = NULL) |
2351
|
|
|
{ |
2352
|
|
|
if (!isset($this->row_conditions[$name])) { |
2353
|
|
|
return FALSE; |
2354
|
|
|
} |
2355
|
|
|
|
2356
|
|
|
$condition = $this->row_conditions[$name]; |
2357
|
|
|
|
2358
|
|
|
if (!$key) { |
|
|
|
|
2359
|
|
|
return $condition; |
2360
|
|
|
} |
2361
|
|
|
|
2362
|
|
|
return isset($condition[$key]) ? $condition[$key] : FALSE; |
2363
|
|
|
} |
2364
|
|
|
|
2365
|
|
|
|
2366
|
|
|
/******************************************************************************** |
2367
|
|
|
* COLUMN CALLBACK * |
2368
|
|
|
********************************************************************************/ |
2369
|
|
|
|
2370
|
|
|
|
2371
|
|
|
/** |
2372
|
|
|
* @param string $key |
2373
|
|
|
* @param callable $callback |
2374
|
|
|
* @return void |
2375
|
|
|
*/ |
2376
|
|
|
public function addColumnCallback($key, callable $callback) |
2377
|
|
|
{ |
2378
|
|
|
$this->column_callbacks[$key] = $callback; |
2379
|
|
|
} |
2380
|
|
|
|
2381
|
|
|
|
2382
|
|
|
/** |
2383
|
|
|
* @param string $key |
2384
|
|
|
* @return callable|null |
2385
|
|
|
*/ |
2386
|
|
|
public function getColumnCallback($key) |
2387
|
|
|
{ |
2388
|
|
|
return empty($this->column_callbacks[$key]) ? NULL : $this->column_callbacks[$key]; |
2389
|
|
|
} |
2390
|
|
|
|
2391
|
|
|
|
2392
|
|
|
/******************************************************************************** |
2393
|
|
|
* INLINE EDIT * |
2394
|
|
|
********************************************************************************/ |
2395
|
|
|
|
2396
|
|
|
|
2397
|
|
|
/** |
2398
|
|
|
* @return InlineEdit |
2399
|
|
|
*/ |
2400
|
|
|
public function addInlineEdit($primary_where_column = NULL) |
2401
|
|
|
{ |
2402
|
|
|
$this->inlineEdit = new InlineEdit($this, $primary_where_column ?: $this->primary_key); |
2403
|
|
|
|
2404
|
|
|
return $this->inlineEdit; |
2405
|
|
|
} |
2406
|
|
|
|
2407
|
|
|
|
2408
|
|
|
/** |
2409
|
|
|
* @return InlineEdit|null |
2410
|
|
|
*/ |
2411
|
|
|
public function getInlineEdit() |
2412
|
|
|
{ |
2413
|
|
|
return $this->inlineEdit; |
2414
|
|
|
} |
2415
|
|
|
|
2416
|
|
|
|
2417
|
|
|
/** |
2418
|
|
|
* @param mixed $id |
2419
|
|
|
* @return void |
2420
|
|
|
*/ |
2421
|
|
|
public function handleInlineEdit($id) |
2422
|
|
|
{ |
2423
|
|
|
if ($this->inlineEdit) { |
2424
|
|
|
$this->inlineEdit->setItemId($id); |
2425
|
|
|
|
2426
|
|
|
$primary_where_column = $this->inlineEdit->getPrimaryWhereColumn(); |
2427
|
|
|
|
2428
|
|
|
$this['filter']['inline_edit']->addHidden('_id', $id); |
2429
|
|
|
$this['filter']['inline_edit']->addHidden('_primary_where_column', $primary_where_column); |
2430
|
|
|
|
2431
|
|
|
$this->redrawItem($id, $primary_where_column); |
2432
|
|
|
} |
2433
|
|
|
} |
2434
|
|
|
|
2435
|
|
|
|
2436
|
|
|
/******************************************************************************** |
2437
|
|
|
* INLINE ADD * |
2438
|
|
|
********************************************************************************/ |
2439
|
|
|
|
2440
|
|
|
|
2441
|
|
|
/** |
2442
|
|
|
* @return InlineEdit |
2443
|
|
|
*/ |
2444
|
|
|
public function addInlineAdd() |
2445
|
|
|
{ |
2446
|
|
|
$this->inlineAdd = new InlineEdit($this); |
2447
|
|
|
|
2448
|
|
|
$this->inlineAdd |
2449
|
|
|
->setIcon('plus') |
2450
|
|
|
->setClass('btn btn-xs btn-default'); |
2451
|
|
|
|
2452
|
|
|
return $this->inlineAdd; |
2453
|
|
|
} |
2454
|
|
|
|
2455
|
|
|
|
2456
|
|
|
/** |
2457
|
|
|
* @return InlineEdit|null |
2458
|
|
|
*/ |
2459
|
|
|
public function getInlineAdd() |
2460
|
|
|
{ |
2461
|
|
|
return $this->inlineAdd; |
2462
|
|
|
} |
2463
|
|
|
|
2464
|
|
|
|
2465
|
|
|
/******************************************************************************** |
2466
|
|
|
* HIDEABLE COLUMNS * |
2467
|
|
|
********************************************************************************/ |
2468
|
|
|
|
2469
|
|
|
|
2470
|
|
|
/** |
2471
|
|
|
* Can datagrid hide colums? |
2472
|
|
|
* @return boolean |
2473
|
|
|
*/ |
2474
|
|
|
public function canHideColumns() |
2475
|
|
|
{ |
2476
|
|
|
return (bool) $this->can_hide_columns; |
2477
|
|
|
} |
2478
|
|
|
|
2479
|
|
|
|
2480
|
|
|
/** |
2481
|
|
|
* Order Grid to set columns hideable. |
2482
|
|
|
* @return static |
2483
|
|
|
*/ |
2484
|
|
|
public function setColumnsHideable() |
2485
|
|
|
{ |
2486
|
|
|
$this->can_hide_columns = TRUE; |
2487
|
|
|
|
2488
|
|
|
return $this; |
2489
|
|
|
} |
2490
|
|
|
|
2491
|
|
|
|
2492
|
|
|
/******************************************************************************** |
2493
|
|
|
* INTERNAL * |
2494
|
|
|
********************************************************************************/ |
2495
|
|
|
|
2496
|
|
|
|
2497
|
|
|
/** |
2498
|
|
|
* Get cont of columns |
2499
|
|
|
* @return int |
2500
|
|
|
*/ |
2501
|
|
|
public function getColumnsCount() |
2502
|
|
|
{ |
2503
|
|
|
$count = sizeof($this->getColumns()); |
2504
|
|
|
|
2505
|
|
|
if (!empty($this->actions) |
2506
|
|
|
|| $this->isSortable() |
2507
|
|
|
|| $this->getItemsDetail() |
2508
|
|
|
|| $this->getInlineEdit() |
2509
|
|
|
|| $this->getInlineAdd()) { |
2510
|
|
|
$count++; |
2511
|
|
|
} |
2512
|
|
|
|
2513
|
|
|
if ($this->hasGroupActions()) { |
2514
|
|
|
$count++; |
2515
|
|
|
} |
2516
|
|
|
|
2517
|
|
|
return $count; |
2518
|
|
|
} |
2519
|
|
|
|
2520
|
|
|
|
2521
|
|
|
/** |
2522
|
|
|
* Get primary key of datagrid data source |
2523
|
|
|
* @return string |
2524
|
|
|
*/ |
2525
|
|
|
public function getPrimaryKey() |
2526
|
|
|
{ |
2527
|
|
|
return $this->primary_key; |
2528
|
|
|
} |
2529
|
|
|
|
2530
|
|
|
|
2531
|
|
|
/** |
2532
|
|
|
* Get set of set columns |
2533
|
|
|
* @return Column\IColumn[] |
2534
|
|
|
*/ |
2535
|
|
|
public function getColumns() |
2536
|
|
|
{ |
2537
|
|
|
if (!$this->getSessionData('_grid_hidden_columns_manipulated', FALSE)) { |
2538
|
|
|
$columns_to_hide = []; |
2539
|
|
|
|
2540
|
|
|
foreach ($this->columns as $key => $column) { |
2541
|
|
|
if ($column->getDefaultHide()) { |
2542
|
|
|
$columns_to_hide[] = $key; |
2543
|
|
|
} |
2544
|
|
|
} |
2545
|
|
|
|
2546
|
|
|
if (!empty($columns_to_hide)) { |
2547
|
|
|
$this->saveSessionData('_grid_hidden_columns', $columns_to_hide); |
2548
|
|
|
$this->saveSessionData('_grid_hidden_columns_manipulated', TRUE); |
2549
|
|
|
} |
2550
|
|
|
} |
2551
|
|
|
|
2552
|
|
|
$hidden_columns = $this->getSessionData('_grid_hidden_columns', []); |
2553
|
|
|
|
2554
|
|
|
foreach ($hidden_columns as $column) { |
2555
|
|
|
if (!empty($this->columns[$column])) { |
2556
|
|
|
$this->columns_visibility[$column] = [ |
2557
|
|
|
'visible' => FALSE, |
2558
|
|
|
'name' => $this->columns[$column]->getName() |
2559
|
|
|
]; |
2560
|
|
|
|
2561
|
|
|
$this->removeColumn($column); |
2562
|
|
|
} |
2563
|
|
|
} |
2564
|
|
|
|
2565
|
|
|
return $this->columns; |
2566
|
|
|
} |
2567
|
|
|
|
2568
|
|
|
|
2569
|
|
|
/** |
2570
|
|
|
* @return PresenterComponent |
2571
|
|
|
*/ |
2572
|
|
|
public function getParent() |
2573
|
|
|
{ |
2574
|
|
|
$parent = parent::getParent(); |
2575
|
|
|
|
2576
|
|
|
if (!($parent instanceof PresenterComponent)) { |
2577
|
|
|
throw new DataGridHasToBeAttachedToPresenterComponentException( |
2578
|
|
|
"DataGrid is attached to: '" . get_class($parent) . "', but instance of PresenterComponent is needed." |
2579
|
|
|
); |
2580
|
|
|
} |
2581
|
|
|
|
2582
|
|
|
return $parent; |
2583
|
|
|
} |
2584
|
|
|
|
2585
|
|
|
} |
2586
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.