Completed
Push — master ( 254f36...db5e86 )
by Petr
05:30
created

Grid::__construct()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 4
cts 4
cp 1
rs 9.9332
c 0
b 0
f 0
cc 3
nc 3
nop 0
crap 3
1
<?php
2
3
/**
4
 * This file is part of the Grido (http://grido.bugyik.cz)
5
 *
6
 * Copyright (c) 2011 Petr Bugyík (http://petr.bugyik.cz)
7
 *
8
 * For the full copyright and license information, please view
9
 * the file LICENSE.md that was distributed with this source code.
10
 */
11
12
namespace Grido;
13
14
use Grido\Exception;
15
use Grido\Components\Button;
16
use Grido\Components\Paginator;
17
use Grido\Components\Columns\Column;
18
use Grido\Components\Filters\Filter;
19
use Grido\Components\Actions\Action;
20
21
use Symfony\Component\PropertyAccess\PropertyAccessor;
22
23
/**
24
 * Grido - DataGrid for Nette Framework.
25
 *
26
 * @package     Grido
27
 * @author      Petr Bugyík
28
 *
29 1
 * @property-read int $count
30
 * @property-read mixed $data
31
 * @property-read \Nette\Utils\Html $tablePrototype
32
 * @property-read PropertyAccessor $propertyAccessor
33
 * @property-read Customization $customization
34
 * @property-write string $templateFile
35
 * @property bool $rememberState
36
 * @property array $defaultPerPage
37
 * @property array $defaultFilter
38
 * @property array $defaultSort
39
 * @property array $perPageList
40 1
 * @property \Nette\Localization\ITranslator $translator
41
 * @property Paginator $paginator
42 1
 * @property string $primaryKey
43
 * @property string $filterRenderType
44 1
 * @property DataSources\IDataSource $model
45
 * @property callback $rowCallback
46 1
 * @property bool $strictMode
47
 * @method void onRegistered(Grid $grid)
48
 * @method void onRender(Grid $grid)
49
 * @method void onFetchData(Grid $grid)
50 1
 */
51
class Grid extends Components\Container
52 1
{
53
    /***** DEFAULTS ****/
54
    const BUTTONS = 'buttons';
55
56
    const CLIENT_SIDE_OPTIONS = 'grido-options';
57
58
    /** @var int @persistent */
59
    public $page = 1;
60
61
    /** @var int @persistent */
62
    public $perPage;
63
64
    /** @var array @persistent */
65
    public $sort = [];
66
67 1
    /** @var array @persistent */
68
    public $filter = [];
69
70
    /** @var array event on all grid's components registered */
71
    public $onRegistered;
72
73
    /** @var array event on render */
74
    public $onRender;
75
76
    /** @var array event for modifying data */
77
    public $onFetchData;
78
79
    /** @var callback returns tr html element; function($row, Html $tr) */
80
    protected $rowCallback;
81
82
    /** @var \Nette\Utils\Html */
83
    protected $tablePrototype;
84
85
    /** @var bool */
86
    protected $rememberState = FALSE;
87
88
    /** @var string */
89
    protected $rememberStateSectionName;
90
91
    /** @var string */
92
    protected $primaryKey = 'id';
93
94
    /** @var string */
95
    protected $filterRenderType;
96
97
    /** @var array */
98
    protected $perPageList = [10, 20, 30, 50, 100];
99
100
    /** @var int */
101
    protected $defaultPerPage = 20;
102
103
    /** @var array */
104
    protected $defaultFilter = [];
105
106
    /** @var array */
107
    protected $defaultSort = [];
108
109
    /** @var DataSources\IDataSource */
110
    protected $model;
111
112
    /** @var int total count of items */
113
    protected $count;
114
115
    /** @var mixed */
116
    protected $data;
117
118
    /** @var Paginator */
119
    protected $paginator;
120
121
    /** @var \Nette\Localization\ITranslator */
122
    protected $translator;
123
124
    /** @var PropertyAccessor */
125
    protected $propertyAccessor;
126
127
    /** @var bool */
128
    protected $strictMode = TRUE;
129
130
    /** @var array */
131
    protected $options = [
132
        self::CLIENT_SIDE_OPTIONS => []
133
    ];
134
135
    /** @var Customization */
136
    protected $customization;
137
138
    /**
139
     * Grid constructor.
140
     */
141
    public function __construct()
142
    {
143
        parent::__construct();
144
        list($parent, $name) = func_get_args() + [NULL, NULL];
145
        if ($parent !== NULL) {
146
            $parent->addComponent($this, $name);
147 1
        } elseif (is_string($name)) {
148 1
            $this->name = $name;
149 1
        }
150 1
    }
151 1
152
    /**
153
     * Sets a model that implements the interface Grido\DataSources\IDataSource or data-source object.
154
     * @param mixed $model
155
     * @param bool $forceWrapper
156
     * @throws Exception
157
     * @return Grid
158
     */
159
    public function setModel($model, $forceWrapper = FALSE)
160 1
    {
161 1
        $this->model = $model instanceof DataSources\IDataSource && $forceWrapper === FALSE
162 1
            ? $model
163
            : new DataSources\Model($model);
164 1
165 1
        return $this;
166 1
    }
167 1
168 1
    /**
169 1
     * Sets the default number of items per page.
170
     * @param int $perPage
171
     * @return Grid
172
     */
173
    public function setDefaultPerPage($perPage)
174
    {
175
        $perPage = (int) $perPage;
176
        $this->defaultPerPage = $perPage;
177
178
        if (!in_array($perPage, $this->perPageList)) {
179 1
            $this->perPageList[] = $perPage;
180 1
            sort($this->perPageList);
181
        }
182
183
        return $this;
184
    }
185
186
    /**
187 1
     * Sets default filtering.
188
     * @param array $filter
189
     * @return Grid
190
     */
191 1
    public function setDefaultFilter(array $filter)
192
    {
193 1
        $this->defaultFilter = array_merge($this->defaultFilter, $filter);
194 1
        return $this;
195 1
    }
196 1
197
    /**
198
     * Sets default sorting.
199 1
     * @param array $sort
200 1
     * @return Grid
201
     * @throws Exception
202 1
     */
203 1
    public function setDefaultSort(array $sort)
204
    {
205
        static $replace = ['asc' => Column::ORDER_ASC, 'desc' => Column::ORDER_DESC];
206
207
        foreach ($sort as $column => $dir) {
208 1
            $dir = strtr(strtolower($dir), $replace);
209
            if (!in_array($dir, $replace)) {
210
                throw new Exception("Dir '$dir' for column '$column' is not allowed.");
211
            }
212 1
213
            $this->defaultSort[$column] = $dir;
214 1
        }
215 1
216 1
        return $this;
217
    }
218 1
219
    /**
220 1
     * Sets items to per-page select.
221
     * @param array $perPageList
222
     * @return Grid
223
     */
224
    public function setPerPageList(array $perPageList)
225
    {
226
        $this->perPageList = $perPageList;
227
228 1
        if ($this->hasFilters(FALSE) || $this->hasOperation(FALSE)) {
229 1
            $this['form']['count']->setItems($this->getItemsForCountSelect());
230
        }
231
232
        return $this;
233
    }
234
235
    /**
236 1
     * Sets translator.
237
     * @param \Nette\Localization\ITranslator $translator
238
     * @return Grid
239
     */
240
    public function setTranslator(\Nette\Localization\ITranslator $translator)
241 1
    {
242 1
        $this->translator = $translator;
243 1
        return $this;
244
    }
245
246 1
    /**
247 1
     * Sets type of filter rendering.
248
     * Defaults inner (Filter::RENDER_INNER) if column does not exist then outer filter (Filter::RENDER_OUTER).
249
     * @param string $type
250
     * @throws Exception
251
     * @return Grid
252
     */
253
    public function setFilterRenderType($type)
254
    {
255
        $type = strtolower($type);
256
        if (!in_array($type, [Filter::RENDER_INNER, Filter::RENDER_OUTER])) {
257 1
            throw new Exception('Type must be Filter::RENDER_INNER or Filter::RENDER_OUTER.');
258 1
        }
259
260
        $this->filterRenderType = $type;
261
        return $this;
262
    }
263
264
    /**
265
     * Sets custom paginator.
266
     * @param Paginator $paginator
267
     * @return Grid
268
     */
269 1
    public function setPaginator(Paginator $paginator)
270 1
    {
271
        $this->paginator = $paginator;
272
        return $this;
273
    }
274
275 1
    /**
276
     * Sets grid primary key.
277
     * Defaults is "id".
278
     * @param string $key
279
     * @return Grid
280 1
     */
281 1
    public function setPrimaryKey($key)
282 1
    {
283 1
        $this->primaryKey = $key;
284
        return $this;
285 1
    }
286
287
    /**
288
     * Sets file name of custom template.
289
     * @param string $file
290
     * @return Grid
291
     */
292
    public function setTemplateFile($file)
293
    {
294
        $this->onRender[] = function() use ($file) {
295
            $this->getTemplate()->add('gridoTemplate', $this->getTemplate()->getFile());
296 1
            $this->getTemplate()->setFile($file);
297 1
        };
298 1
299 1
        return $this;
300
    }
301 1
302
    /**
303
     * Sets saving state to session.
304
     * @param bool $state
305
     * @param string $sectionName
306
     * @return Grid
307
     */
308
    public function setRememberState($state = TRUE, $sectionName = NULL)
309
    {
310
        $this->getPresenter(); //component must be attached to presenter
311
        $this->getRememberSession(TRUE); //start session if not
312 1
        $this->rememberState = (bool) $state;
313 1
        $this->rememberStateSectionName = $sectionName;
314
315
        return $this;
316
    }
317
318
    /**
319
     * Sets callback for customizing tr html object.
320
     * Callback returns tr html element; function($row, Html $tr).
321
     * @param $callback
322
     * @return Grid
323 1
     */
324 1
    public function setRowCallback($callback)
325
    {
326
        $this->rowCallback = $callback;
327
        return $this;
328
    }
329
330
    /**
331
     * Sets client-side options.
332
     * @param array $options
333
     * @return Grid
334 1
     */
335 1
    public function setClientSideOptions(array $options)
336
    {
337
        $this->options[self::CLIENT_SIDE_OPTIONS] = $options;
338
        return $this;
339
    }
340
341
    /**
342
     * Determines whether any user error will cause a notice.
343 1
     * @param bool $mode
344 1
     * @return \Grido\Grid
345
     */
346
    public function setStrictMode($mode)
347
    {
348
        $this->strictMode = (bool) $mode;
349
        return $this;
350
    }
351
352
    /**
353
     * @param \Grido\Customization $customization
354 1
     */
355 1
    public function setCustomization(Customization $customization)
356 1
    {
357
        $this->customization = $customization;
358 1
    }
359
360
    /**********************************************************************************************/
361
362
    /**
363
     * Returns total count of data.
364
     * @return int
365
     */
366
    public function getCount()
367 1
    {
368 1
        if ($this->count === NULL) {
369 1
            $this->count = $this->getModel()->getCount();
370
        }
371 1
372
        return $this->count;
373
    }
374
375
    /**
376
     * Returns default per page.
377
     * @return int
378
     */
379
    public function getDefaultPerPage()
380 1
    {
381
        if (!in_array($this->defaultPerPage, $this->perPageList)) {
382
            $this->defaultPerPage = $this->perPageList[0];
383
        }
384
385
        return $this->defaultPerPage;
386
    }
387
388
    /**
389 1
     * Returns default filter.
390
     * @return array
391 1
     */
392
    public function getDefaultFilter()
393
    {
394
        return $this->defaultFilter;
395
    }
396
397
    /**
398 1
     * Returns default sort.
399
     * @return array
400
     */
401
    public function getDefaultSort()
402
    {
403
        return $this->defaultSort;
404
    }
405
406
    /**
407 1
     * Returns list of possible items per page.
408
     * @return array
409
     */
410
    public function getPerPageList()
411
    {
412
        return $this->perPageList;
413
    }
414
415
    /**
416 1
     * Returns primary key.
417
     * @return string
418
     */
419 1
    public function getPrimaryKey()
420
    {
421
        return $this->primaryKey;
422
    }
423
424
    /**
425 1
     * Returns remember state.
426
     * @return bool
427
     */
428
    public function getRememberState()
429
    {
430
        return $this->rememberState;
431
    }
432
433
    /**
434 1
     * Returns row callback.
435 1
     * @return callback
436 1
     */
437
    public function getRowCallback()
438
    {
439
        return $this->rowCallback;
440
    }
441
442
    /**
443
     * Returns items per page.
444
     * @return int
445
     */
446 1
    public function getPerPage()
447 1
    {
448
        return $this->perPage === NULL
449
            ? $this->getDefaultPerPage()
450
            : $this->perPage;
451
    }
452
453
    /**
454
     * Returns actual filter values.
455
     * @param string $key
456
     * @return mixed
457
     */
458
    public function getActualFilter($key = NULL)
459
    {
460 1
        $filter = $this->filter ? $this->filter : $this->defaultFilter;
461 1
        return $key !== NULL && isset($filter[$key]) ? $filter[$key] : $filter;
462
    }
463
464 1
    /**
465 1
     * Returns fetched data.
466 1
     * @param bool $applyPaging
467 1
     * @param bool $useCache
468
     * @param bool $fetch
469 1
     * @throws Exception
470 1
     * @return array|DataSources\IDataSource|\Nette\Database\Table\Selection
471 1
     */
472
    public function getData($applyPaging = TRUE, $useCache = TRUE, $fetch = TRUE)
473 1
    {
474 1
        if ($this->getModel() === NULL) {
475
            throw new Exception('Model cannot be empty, please use method $grid->setModel().');
476
        }
477 1
478
        $data = $this->data;
479 1
        if ($data === NULL || $useCache === FALSE) {
480 1
            $this->applyFiltering();
481 1
            $this->applySorting();
482
483 1
            if ($applyPaging) {
484 1
                $this->applyPaging();
485 1
            }
486 1
487
            if ($fetch === FALSE) {
488 1
                return $this->getModel();
489
            }
490
491 1
            $data = $this->getModel()->getData();
492
493 1
            if ($useCache === TRUE) {
494
                $this->data = $data;
495
            }
496
497
            if ($applyPaging && !empty($data) && !in_array($this->page, range(1, $this->getPaginator()->pageCount))) {
498
                $this->__triggerUserNotice("Page is out of range.");
499
                $this->page = 1;
500
            }
501
502 1
            if (!empty($this->onFetchData)) {
503 1
                $this->onFetchData($this);
504 1
            }
505
        }
506 1
507
        return $data;
508
    }
509
510
    /**
511
     * Returns translator.
512
     * @return Translations\FileTranslator
513
     */
514
    public function getTranslator()
515
    {
516 1
        if ($this->translator === NULL) {
517 1
            $this->setTranslator(new Translations\FileTranslator);
518
        }
519 1
520 1
        return $this->translator;
521 1
    }
522
523 1
    /**
524 1
     * Returns remember session for set expiration, etc.
525 1
     * @param bool $forceStart - if TRUE, session will be started if not
526
     * @return \Nette\Http\SessionSection|NULL
527
     */
528
    public function getRememberSession($forceStart = FALSE)
529
    {
530
        $presenter = $this->getPresenter();
531
        $session = $presenter->getSession();
532
533
        if (!$session->isStarted() && $forceStart) {
534 1
            $session->start();
535 1
        }
536 1
537 1
        return $session->isStarted()
538
            ? ($session->getSection($this->rememberStateSectionName ?: ($presenter->name . ':' . $this->getUniqueId())))
539 1
            : NULL;
540
    }
541
542
    /**
543
     * Returns table html element of grid.
544
     * @return \Nette\Utils\Html
545
     */
546
    public function getTablePrototype()
547
    {
548 1
        if ($this->tablePrototype === NULL) {
549 1
            $this->tablePrototype = \Nette\Utils\Html::el('table');
550
            $this->tablePrototype->id($this->getName());
551
        }
552 1
553 1
        return $this->tablePrototype;
554 1
    }
555
556 1
    /**
557 1
     * @return string
558 1
     * @internal
559 1
     */
560 1
    public function getFilterRenderType()
561
    {
562 1
        if ($this->filterRenderType !== NULL) {
563 1
            return $this->filterRenderType;
564
        }
565 1
566
        $this->filterRenderType = Filter::RENDER_OUTER;
567
        if ($this->hasColumns() && $this->hasFilters() && $this->hasActions()) {
568
            $this->filterRenderType = Filter::RENDER_INNER;
569
570
            $filters = $this[Filter::ID]->getComponents();
571
            foreach ($filters as $filter) {
572
                if (!$this[Column::ID]->getComponent($filter->name, FALSE)) {
573 1
                    $this->filterRenderType = Filter::RENDER_OUTER;
574
                    break;
575
                }
576
            }
577
        }
578
579
        return $this->filterRenderType;
580
    }
581
582 1
    /**
583 1
     * @return DataSources\IDataSource
584 1
     */
585 1
    public function getModel()
586 1
    {
587
        return $this->model;
588 1
    }
589
590
    /**
591
     * @return Paginator
592
     * @internal
593
     */
594
    public function getPaginator()
595
    {
596
        if ($this->paginator === NULL) {
597
            $this->paginator = new Paginator;
598
            $this->paginator->setItemsPerPage($this->getPerPage())
599
                ->setGrid($this);
600 1
        }
601 1
602 1
        return $this->paginator;
603 1
    }
604 1
605 1
    /**
606 1
     * A simple wrapper around symfony/property-access with Nette Database dot notation support.
607
     * @param array|object $object
608 1
     * @param string $name
609
     * @return mixed
610
     * @internal
611 1
     */
612 1
    public function getProperty($object, $name)
613 1
    {
614
        if ($object instanceof \Nette\Database\Table\IRow && \Nette\Utils\Strings::contains($name, '.')) {
0 ignored issues
show
Bug introduced by
The class Nette\Database\Table\IRow does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
615 1
            $parts = explode('.', $name);
616
            foreach ($parts as $item) {
617
                if (is_object($object)) {
618
                    $object = $object->$item;
619
                }
620
            }
621
622
            return $object;
623
        }
624 1
625 1
        if (is_array($object)) {
626 1
            $name = "[$name]";
627
        }
628 1
629
        return $this->getPropertyAccessor()->getValue($object, $name);
630
    }
631
632
    /**
633
     * @return PropertyAccessor
634
     * @internal
635
     */
636
    public function getPropertyAccessor()
637
    {
638
        if ($this->propertyAccessor === NULL) {
639 1
            $this->propertyAccessor = new PropertyAccessor(TRUE, TRUE);
640 1
        }
641 1
642
        return $this->propertyAccessor;
643
    }
644 1
645 1
    /**
646
     * @param mixed $row item from db
647 1
     * @return \Nette\Utils\Html
648 1
     * @internal
649 1
     */
650
    public function getRowPrototype($row)
651 1
    {
652
        try {
653
            $primaryValue = $this->getProperty($row, $this->getPrimaryKey());
654
        } catch (\Exception $e) {
655
            $primaryValue = NULL;
656
        }
657
658
        $tr = \Nette\Utils\Html::el('tr');
659
        $primaryValue ? $tr->class[] = "grid-row-$primaryValue" : NULL;
660 1
661
        if ($this->rowCallback) {
662
            $tr = call_user_func_array($this->rowCallback, [$row, $tr]);
663
        }
664
665
        return $tr;
666
    }
667
668 1
    /**
669
     * Returns client-side options.
670
     * @return array
671
     */
672
    public function getClientSideOptions()
673
    {
674
        return (array) $this->options[self::CLIENT_SIDE_OPTIONS];
675
    }
676 1
677 1
    /**
678 1
     * @return bool
679
     */
680 1
    public function isStrictMode()
681
    {
682
        return $this->strictMode;
683
    }
684
685
    /**
686
     * @return Customization
687
     */
688
    public function getCustomization()
689
    {
690
        if ($this->customization === NULL) {
691
            $this->customization = new Customization($this);
692
        }
693 1
694 1
        return $this->customization;
695 1
    }
696 1
697 1
    /**********************************************************************************************/
698 1
699
    /**
700 1
     * Loads state informations.
701 1
     * @param array $params
702
     * @internal
703
     */
704
    public function loadState(array $params)
705
    {
706
        //loads state from session
707
        $session = $this->getRememberSession();
708
        if ($session && $this->getPresenter()->isSignalReceiver($this)) {
709
            $session->remove();
710
        } elseif ($session && empty($params) && $session->params) {
711 1
            $params = (array) $session->params;
712 1
        }
713
714
        parent::loadState($params);
715
    }
716
717
    /**
718
     * Saves state informations for next request.
719
     * @param array $params
720
     * @param \Nette\Application\UI\PresenterComponentReflection $reflection (internal, used by Presenter)
721
     * @internal
722
     */
723
    public function saveState(array &$params, $reflection = NULL)
724
    {
725
        !empty($this->onRegistered) && $this->onRegistered($this);
726
        return parent::saveState($params, $reflection);
727
    }
728
729
    /**
730 1
     * Ajax method.
731
     * @internal
732
     */
733
    public function handleRefresh()
734
    {
735
        $this->reload();
736
    }
737
738
    /**
739 1
     * @param int $page
740 1
     * @internal
741
     */
742
    public function handlePage($page)
743
    {
744
        $this->reload();
745
    }
746
747
    /**
748
     * @param array $sort
749 1
     * @internal
750 1
     */
751 1
    public function handleSort(array $sort)
752 1
    {
753 1
        $this->page = 1;
754 1
        $this->reload();
755
    }
756 1
757 1
    /**
758 1
     * @param \Nette\Forms\Controls\SubmitButton $button
759 1
     * @internal
760
     */
761
    public function handleFilter(\Nette\Forms\Controls\SubmitButton $button)
762 1
    {
763
        $values = $button->form->values[Filter::ID];
764 1
        $session = $this->rememberState //session filter
765 1
            ? isset($this->getRememberSession(TRUE)->params['filter'])
766
                ? $this->getRememberSession(TRUE)->params['filter']
767
                : []
768
            : [];
769
770
        foreach ($values as $name => $value) {
771
            if (is_numeric($value) || !empty($value) || isset($this->defaultFilter[$name]) || isset($session[$name])) {
772
                $this->filter[$name] = $this->getFilter($name)->changeValue($value);
773
            } elseif (isset($this->filter[$name])) {
774 1
                unset($this->filter[$name]);
775 1
            }
776 1
        }
777
778 1
        $this->page = 1;
779 1
        $this->reload();
780 1
    }
781
782 1
    /**
783
     * @param \Nette\Forms\Controls\SubmitButton $button
784 1
     * @internal
785 1
     */
786
    public function handleReset(\Nette\Forms\Controls\SubmitButton $button)
787
    {
788
        $this->sort = [];
789
        $this->filter = [];
790
        $this->perPage = NULL;
791
792
        if ($session = $this->getRememberSession()) {
793
            $session->remove();
794 1
        }
795 1
796 1
        $button->form->setValues([Filter::ID => $this->defaultFilter], TRUE);
797
798
        $this->page = 1;
799 1
        $this->reload();
800 1
    }
801
802
    /**
803
     * @param \Nette\Forms\Controls\SubmitButton $button
804
     * @internal
805
     */
806
    public function handlePerPage(\Nette\Forms\Controls\SubmitButton $button)
807
    {
808
        $perPage = (int) $button->form['count']->value;
809
        $this->perPage = $perPage == $this->defaultPerPage
810 1
            ? NULL
811
            : $perPage;
812
813
        $this->page = 1;
814 1
        $this->reload();
815
    }
816
817
    /**
818
     * Refresh wrapper.
819
     * @return void
820
     * @internal
821
     */
822
    public function reload()
823
    {
824
        if ($this->presenter->isAjax()) {
825
            $this->presenter->payload->grido = TRUE;
826 1
            $this->redrawControl();
827 1
        } else {
828 1
            $this->redirect('this');
829
        }
830 1
    }
831
832
    /**********************************************************************************************/
833
834
    /**
835
     * @return \Nette\Templating\FileTemplate
836
     * @internal
837
     */
838
    public function createTemplate()
839 1
    {
840
        $template = parent::createTemplate();
841
        $template->setFile($this->getCustomization()->getTemplateFiles()[Customization::TEMPLATE_DEFAULT]);
842
        $template->getLatte()->addFilter('translate', [$this->getTranslator(), 'translate']);
843 1
844 1
        return $template;
845
    }
846 1
847 1
    /**
848 1
     * @internal
849
     * @throws Exception
850 1
     */
851
    public function render()
852 1
    {
853 1
        if (!$this->hasColumns()) {
854 1
            throw new Exception('Grid must have defined a column, please use method $grid->addColumn*().');
855 1
        }
856 1
857 1
        $this->saveRememberState();
858 1
        $data = $this->getData();
859 1
860 1
        if (!empty($this->onRender)) {
861
            $this->onRender($this);
862 1
        }
863 1
864 1
        $form = $this['form'];
865 1
866
        $this->getTemplate()->add('data', $data);
867 1
        $this->getTemplate()->add('form', $form);
868 1
        $this->getTemplate()->add('paginator', $this->getPaginator());
869 1
        $this->getTemplate()->add('customization', $this->getCustomization());
870 1
        $this->getTemplate()->add('columns', $this->getComponent(Column::ID)->getComponents());
871
        $this->getTemplate()->add('actions', $this->hasActions()
872 1
            ? $this->getComponent(Action::ID)->getComponents()
873
            : []
874 1
        );
875 1
876 1
        $this->getTemplate()->add('buttons', $this->hasButtons()
877
            ? $this->getComponent(Button::ID)->getComponents()
878 1
            : []
879 1
        );
880
881
        $this->getTemplate()->add('formFilters', $this->hasFilters()
882
            ? $form->getComponent(Filter::ID)->getComponents()
883 1
            : []
884 1
        );
885 1
886 1
        $form['count']->setValue($this->getPerPage());
887 1
888 1
        if ($options = $this->options[self::CLIENT_SIDE_OPTIONS]) {
889 1
            $this->getTablePrototype()->setAttribute('data-' . self::CLIENT_SIDE_OPTIONS, json_encode($options));
890 1
        }
891
892
        $this->getTemplate()->render();
893
    }
894 1
895 1
    protected function saveRememberState()
896 1
    {
897
        if ($this->rememberState) {
898
            $session = $this->getRememberSession(TRUE);
899
            $params = array_keys($this->getReflection()->getPersistentParams());
900
            foreach ($params as $param) {
901
                $session->params[$param] = $this->$param;
902
            }
903
        }
904
    }
905 1
906 1
    protected function applyFiltering()
907
    {
908 1
        $conditions = $this->__getConditions($this->getActualFilter());
909 1
        $this->getModel()->filter($conditions);
910
    }
911
912
    /**
913
     * @param array $filter
914
     * @return array
915
     * @internal
916
     */
917 1
    public function __getConditions(array $filter)
918 1
    {
919 1
        $conditions = [];
920 1
        if (!empty($filter)) {
921 1
            try {
922 1
                $this['form']->setDefaults([Filter::ID => $filter]);
923 1
            } catch (\Nette\InvalidArgumentException $e) {
0 ignored issues
show
Bug introduced by
The class Nette\InvalidArgumentException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
924
                $this->__triggerUserNotice($e->getMessage());
925 1
                $filter = [];
926 1
                if ($session = $this->getRememberSession()) {
927
                    $session->remove();
928 1
                }
929
            }
930
931
            foreach ($filter as $column => $value) {
932
                if ($component = $this->getFilter($column, FALSE)) {
933 1
                    if ($condition = $component->__getCondition($value)) {
934 1
                        $conditions[] = $condition;
935
                    }
936 1
                } else {
937 1
                    $this->__triggerUserNotice("Filter with name '$column' does not exist.");
938 1
                }
939 1
            }
940 1
        }
941 1
942
        return $conditions;
943
    }
944 1
945 1
    protected function applySorting()
946 1
    {
947 1
        $sort = [];
948 1
        $this->sort = $this->sort ? $this->sort : $this->defaultSort;
949 1
950
        foreach ($this->sort as $column => $dir) {
951 1
            $component = $this->getColumn($column, FALSE);
952
            if (!$component) {
953 1
                if (!isset($this->defaultSort[$column])) {
954 1
                    $this->__triggerUserNotice("Column with name '$column' does not exist.");
955
                    break;
956
                }
957
958
            } elseif (!$component->isSortable()) {
959 1
                if (isset($this->defaultSort[$column])) {
960 1
                    $component->setSortable();
961
                } else {
962
                    $this->__triggerUserNotice("Column with name '$column' is not sortable.");
963 1
                    break;
964 1
                }
965
            }
966 1
967 1
            if (!in_array($dir, [Column::ORDER_ASC, Column::ORDER_DESC])) {
968 1
                if ($dir == '' && isset($this->defaultSort[$column])) {
969 1
                    unset($this->sort[$column]);
970
                    break;
971
                }
972
973 1
                $this->__triggerUserNotice("Dir '$dir' is not allowed.");
974 1
                break;
975 1
            }
976
977 1
            $sort[$component ? $component->column : $column] = $dir == Column::ORDER_ASC ? 'ASC' : 'DESC';
978 1
        }
979 1
980 1
        if (!empty($sort)) {
981
            $this->getModel()->sort($sort);
982 1
        }
983 1
    }
984
985
    protected function applyPaging()
986
    {
987 1
        $paginator = $this->getPaginator()
988 1
            ->setItemCount($this->getCount())
989 1
            ->setPage($this->page);
990
991 1
        $perPage = $this->getPerPage();
992 1
        if ($perPage !== NULL && !in_array($perPage, $this->perPageList)) {
993 1
            $this->__triggerUserNotice("The number '$perPage' of items per page is out of range.");
994 1
        }
995 1
996 1
        $this->getModel()->limit($paginator->getOffset(), $paginator->getLength());
997 1
    }
998
999 1
    protected function createComponentForm($name)
1000 1
    {
1001 1
        $form = new \Nette\Application\UI\Form($this, $name);
1002 1
        $form->setTranslator($this->getTranslator());
1003
        $form->setMethod($form::GET);
1004
1005
        $buttons = $form->addContainer(self::BUTTONS);
1006
        $buttons->addSubmit('search', 'Grido.Search')
1007
            ->onClick[] = [$this, 'handleFilter'];
1008
        $buttons->addSubmit('reset', 'Grido.Reset')
1009 1
            ->onClick[] = [$this, 'handleReset'];
1010
        $buttons->addSubmit('perPage', 'Grido.ItemsPerPage')
1011
            ->onClick[] = [$this, 'handlePerPage'];
1012
1013
        $form->addSelect('count', 'Count', $this->getItemsForCountSelect())
1014
            ->setTranslator(NULL)
1015
            ->controlPrototype->attrs['title'] = $this->getTranslator()->translate('Grido.ItemsPerPage');
1016
    }
1017
1018 1
    /**
1019 1
     * @return array
1020 1
     */
1021
    protected function getItemsForCountSelect()
1022 1
    {
1023 1
        return array_combine($this->perPageList, $this->perPageList);
1024
    }
1025 1
1026
    /**
1027
     * @internal
1028
     * @param string $message
1029
     */
1030
    public function __triggerUserNotice($message)
1031
    {
1032
        if ($this->getPresenter(FALSE) && $session = $this->getRememberSession()) {
1033
            $session->remove();
1034
        }
1035
1036
        $this->strictMode && trigger_error($message, E_USER_NOTICE);
1037
    }
1038
}
1039