Completed
Pull Request — master (#258)
by
unknown
22:19
created

Grid::setDefaultFilter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
ccs 2
cts 2
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
crap 1
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\Paginator;
16
use Grido\Components\Columns\Column;
17
use Grido\Components\Filters\Filter;
18
use Grido\Components\Actions\Action;
19
20
use Symfony\Component\PropertyAccess\PropertyAccessor;
21
22
/**
23
 * Grido - DataGrid for Nette Framework.
24
 *
25
 * @package     Grido
26
 * @author      Petr Bugyík
27
 *
28
 * @property-read int $count
29 1
 * @property-read mixed $data
30
 * @property-read \Nette\Utils\Html $tablePrototype
31
 * @property-read PropertyAccessor $propertyAccessor
32
 * @property-read Customization $customization
33
 * @property-write string $templateFile
34
 * @property bool $rememberState
35
 * @property array $defaultPerPage
36
 * @property array $defaultFilter
37
 * @property array $defaultSort
38
 * @property array $perPageList
39
 * @property \Nette\Localization\ITranslator $translator
40 1
 * @property Paginator $paginator
41
 * @property string $primaryKey
42 1
 * @property string $filterRenderType
43
 * @property DataSources\IDataSource $model
44 1
 * @property callback $rowCallback
45
 * @property bool $strictMode
46 1
 * @method void onRegistered(Grid $grid)
47
 * @method void onRender(Grid $grid)
48
 * @method void onFetchData(Grid $grid)
49
 */
50 1
class Grid extends Components\Container
51 1
{
52
    /***** DEFAULTS ****/
53
    const BUTTONS = 'buttons';
54
55
    const CLIENT_SIDE_OPTIONS = 'grido-options';
56
57
    /** @var int @persistent */
58
    public $page = 1;
59
60
    /** @var int @persistent */
61
    public $perPage;
62
63
    /** @var array @persistent */
64
    public $sort = [];
65
66 1
    /** @var array @persistent */
67
    public $filter = [];
68
69
    /** @var array event on all grid's components registered */
70
    public $onRegistered;
71
72
    /** @var array event on render */
73
    public $onRender;
74
75
    /** @var array event for modifying data */
76
    public $onFetchData;
77
78
    /** @var callback returns tr html element; function($row, Html $tr) */
79
    protected $rowCallback;
80
81
    /** @var \Nette\Utils\Html */
82
    protected $tablePrototype;
83
84
    /** @var bool */
85
    protected $rememberState = FALSE;
86
87
    /** @var string */
88
    protected $rememberStateSectionName;
89
90
    /** @var string */
91
    protected $primaryKey = 'id';
92
93
    /** @var string */
94
    protected $filterRenderType;
95
96
    /** @var array */
97
    protected $perPageList = [10, 20, 30, 50, 100];
98
99
    /** @var int */
100
    protected $defaultPerPage = 20;
101
102
    /** @var array */
103
    protected $defaultFilter = [];
104
105
    /** @var array */
106
    protected $defaultSort = [];
107
108
    /** @var DataSources\IDataSource */
109
    protected $model;
110
111
    /** @var int total count of items */
112
    protected $count;
113
114
    /** @var mixed */
115
    protected $data;
116
117
    /** @var Paginator */
118
    protected $paginator;
119 1
120
    /** @var \Nette\Localization\ITranslator */
121
    protected $translator;
122
123
    /** @var PropertyAccessor */
124
    protected $propertyAccessor;
125
126
    /** @var bool */
127
    protected $strictMode = TRUE;
128
129
    /** @var array */
130
    protected $options = [
131
        self::CLIENT_SIDE_OPTIONS => []
132
    ];
133
134
    /** @var Customization */
135 1
    protected $customization;
136
137
    /**
138
     * Sets a model that implements the interface Grido\DataSources\IDataSource or data-source object.
139
     * @param mixed $model
140
     * @param bool $forceWrapper
141
     * @throws Exception
142
     * @return Grid
143
     */
144
    public function setModel($model, $forceWrapper = FALSE)
145
    {
146 1
        $this->model = $model instanceof DataSources\IDataSource && $forceWrapper === FALSE
147 1
            ? $model
148 1
            : new DataSources\Model($model);
149
150 1
        return $this;
151
    }
152
153 1
    /**
154
     * Sets the default number of items per page.
155
     * @param int $perPage
156
     * @return Grid
157
     */
158
    public function setDefaultPerPage($perPage)
159
    {
160 1
        $perPage = (int) $perPage;
161 1
        $this->defaultPerPage = $perPage;
162
163 1
        if (!in_array($perPage, $this->perPageList)) {
164 1
            $this->perPageList[] = $perPage;
165 1
            sort($this->perPageList);
166 1
        }
167
168 1
        return $this;
169
    }
170
171
    /**
172
     * Sets default filtering.
173
     * @param array $filter
174
     * @return Grid
175
     */
176
    public function setDefaultFilter(array $filter)
177
    {
178 1
        $this->defaultFilter = array_merge($this->defaultFilter, $filter);
179 1
        return $this;
180
    }
181
182
    /**
183
     * Sets default sorting.
184
     * @param array $sort
185
     * @return Grid
186
     * @throws Exception
187 1
     */
188
    public function setDefaultSort(array $sort)
189
    {
190 1
        static $replace = ['asc' => Column::ORDER_ASC, 'desc' => Column::ORDER_DESC];
191
192 1
        foreach ($sort as $column => $dir) {
193 1
            $dir = strtr(strtolower($dir), $replace);
194 1
            if (!in_array($dir, $replace)) {
195 1
                throw new Exception("Dir '$dir' for column '$column' is not allowed.");
196
            }
197
198 1
            $this->defaultSort[$column] = $dir;
199 1
        }
200
201 1
        return $this;
202
    }
203
204
    /**
205
     * Sets items to per-page select.
206
     * @param array $perPageList
207 1
     * @return Grid
208 1
     */
209
    public function setPerPageList(array $perPageList)
210
    {
211 1
        $this->perPageList = $perPageList;
212
213 1
        if ($this->hasFilters(FALSE) || $this->hasOperation(FALSE)) {
214 1
            $this['form']['count']->setItems($this->getItemsForCountSelect());
215 1
        }
216
217 1
        return $this;
218
    }
219
220
    /**
221
     * Sets translator.
222
     * @param \Nette\Localization\ITranslator $translator
223
     * @return Grid
224
     */
225
    public function setTranslator(\Nette\Localization\ITranslator $translator)
226
    {
227 1
        $this->translator = $translator;
228 1
        return $this;
229
    }
230
231
    /**
232
     * Sets type of filter rendering.
233
     * Defaults inner (Filter::RENDER_INNER) if column does not exist then outer filter (Filter::RENDER_OUTER).
234
     * @param string $type
235 1
     * @throws Exception
236
     * @return Grid
237
     */
238
    public function setFilterRenderType($type)
239
    {
240 1
        $type = strtolower($type);
241 1
        if (!in_array($type, [Filter::RENDER_INNER, Filter::RENDER_OUTER])) {
242 1
            throw new Exception('Type must be Filter::RENDER_INNER or Filter::RENDER_OUTER.');
243
        }
244
245 1
        $this->filterRenderType = $type;
246 1
        return $this;
247
    }
248
249
    /**
250
     * Sets custom paginator.
251
     * @param Paginator $paginator
252
     * @return Grid
253
     */
254
    public function setPaginator(Paginator $paginator)
255
    {
256 1
        $this->paginator = $paginator;
257 1
        return $this;
258
    }
259
260
    /**
261
     * Sets grid primary key.
262
     * Defaults is "id".
263
     * @param string $key
264
     * @return Grid
265
     */
266
    public function setPrimaryKey($key)
267
    {
268 1
        $this->primaryKey = $key;
269 1
        return $this;
270
    }
271
272
    /**
273
     * Sets file name of custom template.
274
     * @param string $file
275
     * @return Grid
276
     */
277
    public function setTemplateFile($file)
278
    {
279 1
        $this->onRender[] = function() use ($file) {
280 1
            $this->template->gridoTemplate = $this->getTemplate()->getFile();
0 ignored issues
show
Bug introduced by
Accessing gridoTemplate on the interface Nette\Application\UI\ITemplate suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
281 1
            $this->getTemplate()->setFile($file);
282 1
        };
283 1
284 1
        return $this;
285
    }
286
287
    /**
288
     * Sets saving state to session.
289
     * @param bool $state
290
     * @param string $sectionName
291
     * @return Grid
292
     */
293
    public function setRememberState($state = TRUE, $sectionName = NULL)
294
    {
295 1
        $this->getPresenter(); //component must be attached to presenter
296 1
        $this->getRememberSession(TRUE); //start session if not
297 1
        $this->rememberState = (bool) $state;
298 1
        $this->rememberStateSectionName = $sectionName;
299
300 1
        return $this;
301
    }
302
303
    /**
304
     * Sets callback for customizing tr html object.
305
     * Callback returns tr html element; function($row, Html $tr).
306
     * @param $callback
307
     * @return Grid
308
     */
309
    public function setRowCallback($callback)
310
    {
311 1
        $this->rowCallback = $callback;
312 1
        return $this;
313
    }
314
315
    /**
316
     * Sets client-side options.
317
     * @param array $options
318
     * @return Grid
319
     */
320
    public function setClientSideOptions(array $options)
321
    {
322 1
        $this->options[self::CLIENT_SIDE_OPTIONS] = $options;
323 1
        return $this;
324
    }
325
326
    /**
327
     * Determines whether any user error will cause a notice.
328
     * @param bool $mode
329
     * @return \Grido\Grid
330
     */
331
    public function setStrictMode($mode)
332
    {
333 1
        $this->strictMode = (bool) $mode;
334 1
        return $this;
335
    }
336
337
    /**
338
     * @param \Grido\Customization $customization
339
     */
340
    public function setCustomization(Customization $customization)
341
    {
342 1
        $this->customization = $customization;
343 1
    }
344
345
    /**********************************************************************************************/
346
347
    /**
348
     * Returns total count of data.
349
     * @return int
350
     */
351
    public function getCount()
352
    {
353 1
        if ($this->count === NULL) {
354 1
            $this->count = $this->getModel()->getCount();
355 1
        }
356
357 1
        return $this->count;
358
    }
359
360
    /**
361
     * Returns default per page.
362
     * @return int
363
     */
364
    public function getDefaultPerPage()
365
    {
366 1
        if (!in_array($this->defaultPerPage, $this->perPageList)) {
367 1
            $this->defaultPerPage = $this->perPageList[0];
368 1
        }
369
370 1
        return $this->defaultPerPage;
371
    }
372
373
    /**
374
     * Returns default filter.
375
     * @return array
376
     */
377
    public function getDefaultFilter()
378
    {
379 1
        return $this->defaultFilter;
380
    }
381
382
    /**
383
     * Returns default sort.
384
     * @return array
385
     */
386
    public function getDefaultSort()
387
    {
388 1
        return $this->defaultSort;
389
    }
390
391
    /**
392
     * Returns list of possible items per page.
393
     * @return array
394
     */
395
    public function getPerPageList()
396 1
    {
397 1
        return $this->perPageList;
398
    }
399
400
    /**
401
     * Returns primary key.
402
     * @return string
403
     */
404
    public function getPrimaryKey()
405
    {
406 1
        return $this->primaryKey;
407
    }
408
409
    /**
410
     * Returns remember state.
411
     * @return bool
412
     */
413
    public function getRememberState()
414
    {
415 1
        return $this->rememberState;
416
    }
417
418
    /**
419
     * Returns row callback.
420
     * @return callback
421
     */
422
    public function getRowCallback()
423
    {
424 1
        return $this->rowCallback;
425
    }
426
427
    /**
428
     * Returns items per page.
429
     * @return int
430
     */
431
    public function getPerPage()
432
    {
433 1
        return $this->perPage === NULL
434 1
            ? $this->getDefaultPerPage()
435 1
            : $this->perPage;
436
    }
437
438
    /**
439
     * Returns actual filter values.
440
     * @param string $key
441
     * @return mixed
442
     */
443
    public function getActualFilter($key = NULL)
444
    {
445 1
        $filter = $this->filter ? $this->filter : $this->defaultFilter;
446 1
        return $key !== NULL && isset($filter[$key]) ? $filter[$key] : $filter;
447
    }
448
449
    /**
450
     * Returns fetched data.
451
     * @param bool $applyPaging
452
     * @param bool $useCache
453
     * @param bool $fetch
454
     * @throws Exception
455
     * @return array|DataSources\IDataSource|\Nette\Database\Table\Selection
456
     */
457
    public function getData($applyPaging = TRUE, $useCache = TRUE, $fetch = TRUE)
458
    {
459 1
        if ($this->getModel() === NULL) {
460 1
            throw new Exception('Model cannot be empty, please use method $grid->setModel().');
461
        }
462
463 1
        $data = $this->data;
464 1
        if ($data === NULL || $useCache === FALSE) {
465 1
            $this->applyFiltering();
466 1
            $this->applySorting();
467
468 1
            if ($applyPaging) {
469 1
                $this->applyPaging();
470 1
            }
471
472 1
            if ($fetch === FALSE) {
473 1
                return $this->getModel();
474
            }
475
476 1
            $data = $this->getModel()->getData();
477
478 1
            if ($useCache === TRUE) {
479 1
                $this->data = $data;
480 1
            }
481
482 1
            if ($applyPaging && !empty($data) && !in_array($this->page, range(1, $this->getPaginator()->pageCount))) {
483 1
                $this->__triggerUserNotice("Page is out of range.");
484 1
                $this->page = 1;
485 1
            }
486
487 1
            if (!empty($this->onFetchData)) {
488
                $this->onFetchData($this);
489
            }
490 1
        }
491
492 1
        return $data;
493
    }
494
495
    /**
496
     * Returns translator.
497
     * @return Translations\FileTranslator
498
     */
499
    public function getTranslator()
500
    {
501 1
        if ($this->translator === NULL) {
502 1
            $this->setTranslator(new Translations\FileTranslator);
503 1
        }
504
505 1
        return $this->translator;
506
    }
507
508
    /**
509
     * Returns remember session for set expiration, etc.
510
     * @param bool $forceStart - if TRUE, session will be started if not
511
     * @return \Nette\Http\SessionSection|NULL
512
     */
513
    public function getRememberSession($forceStart = FALSE)
514
    {
515 1
        $presenter = $this->getPresenter();
516 1
        $session = $presenter->getSession();
517
518 1
        if (!$session->isStarted() && $forceStart) {
519 1
            $session->start();
520 1
        }
521
522 1
        return $session->isStarted()
523 1
            ? ($session->getSection($this->rememberStateSectionName ?: ($presenter->name . ':' . $this->getUniqueId())))
0 ignored issues
show
Bug introduced by
Accessing name on the interface Nette\ComponentModel\IComponent suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
524 1
            : NULL;
525
    }
526
527
    /**
528
     * Returns table html element of grid.
529
     * @return \Nette\Utils\Html
530
     */
531
    public function getTablePrototype()
532
    {
533 1
        if ($this->tablePrototype === NULL) {
534 1
            $this->tablePrototype = \Nette\Utils\Html::el('table');
535 1
            $this->tablePrototype->id($this->getName());
536 1
        }
537
538 1
        return $this->tablePrototype;
539
    }
540
541
    /**
542
     * @return string
543
     * @internal
544
     */
545
    public function getFilterRenderType()
546
    {
547 1
        if ($this->filterRenderType !== NULL) {
548 1
            return $this->filterRenderType;
549
        }
550
551 1
        $this->filterRenderType = Filter::RENDER_OUTER;
552 1
        if ($this->hasColumns() && $this->hasFilters() && $this->hasActions()) {
553 1
            $this->filterRenderType = Filter::RENDER_INNER;
554
555 1
            $filters = $this[Filter::ID]->getComponents();
556 1
            foreach ($filters as $filter) {
557 1
                if (!$this[Column::ID]->getComponent($filter->name, FALSE)) {
558 1
                    $this->filterRenderType = Filter::RENDER_OUTER;
559 1
                    break;
560
                }
561 1
            }
562 1
        }
563
564 1
        return $this->filterRenderType;
565
    }
566
567
    /**
568
     * @return DataSources\IDataSource
569
     */
570
    public function getModel()
571
    {
572 1
        return $this->model;
573
    }
574
575
    /**
576
     * @return Paginator
577
     * @internal
578
     */
579
    public function getPaginator()
580
    {
581 1
        if ($this->paginator === NULL) {
582 1
            $this->paginator = new Paginator;
583 1
            $this->paginator->setItemsPerPage($this->getPerPage())
584 1
                ->setGrid($this);
585 1
        }
586
587 1
        return $this->paginator;
588
    }
589
590
    /**
591
     * A simple wrapper around symfony/property-access with Nette Database dot notation support.
592
     * @param array|object $object
593
     * @param string $name
594
     * @return mixed
595
     * @internal
596
     */
597
    public function getProperty($object, $name)
598
    {
599 1
        if ($object instanceof \Nette\Database\Table\IRow && \Nette\Utils\Strings::contains($name, '.')) {
600 1
            $parts = explode('.', $name);
601 1
            foreach ($parts as $item) {
602 1
                if (is_object($object)) {
603 1
                    $object = $object->$item;
604 1
                }
605 1
            }
606
607 1
            return $object;
608
        }
609
610 1
        if (is_array($object)) {
611 1
            $name = "[$name]";
612 1
        }
613
614 1
        if (!$this->getPropertyAccessor()->isReadable($object, $name)) {
615 1
            return null;
616
        } else {
617 1
            return $this->getPropertyAccessor()->getValue($object, $name);
618
        }
619
    }
620
621
    /**
622
     * @return PropertyAccessor
623
     * @internal
624
     */
625
    public function getPropertyAccessor()
626
    {
627 1
        if ($this->propertyAccessor === NULL) {
628 1
            $this->propertyAccessor = new PropertyAccessor(TRUE, TRUE);
629 1
        }
630
631 1
        return $this->propertyAccessor;
632
    }
633
634
    /**
635
     * @param mixed $row item from db
636
     * @return \Nette\Utils\Html
637
     * @internal
638
     */
639
    public function getRowPrototype($row)
640
    {
641
        try {
642 1
            $primaryValue = $this->getProperty($row, $this->getPrimaryKey());
643 1
        } catch (\Exception $e) {
644
            $primaryValue = NULL;
645
        }
646
647 1
        $tr = \Nette\Utils\Html::el('tr');
648 1
        $primaryValue ? $tr->class[] = "grid-row-$primaryValue" : NULL;
649
650 1
        if ($this->rowCallback) {
651 1
            $tr = call_user_func_array($this->rowCallback, [$row, $tr]);
652 1
        }
653
654 1
        return $tr;
655
    }
656
657
    /**
658
     * Returns client-side options.
659
     * @return array
660
     */
661
    public function getClientSideOptions()
662
    {
663 1
        return (array) $this->options[self::CLIENT_SIDE_OPTIONS];
664
    }
665
666
    /**
667
     * @return bool
668
     */
669
    public function isStrictMode()
670
    {
671 1
        return $this->strictMode;
672
    }
673
674
    /**
675
     * @return Customization
676
     */
677
    public function getCustomization()
678
    {
679 1
        if ($this->customization === NULL) {
680 1
            $this->customization = new Customization($this);
681 1
        }
682
683 1
        return $this->customization;
684
    }
685
686
    /**********************************************************************************************/
687
688
    /**
689
     * Loads state informations.
690
     * @param array $params
691
     * @internal
692
     */
693
    public function loadState(array $params)
694
    {
695
        //loads state from session
696 1
        $session = $this->getRememberSession();
697 1
        if ($session && $this->getPresenter()->isSignalReceiver($this)) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Nette\ComponentModel\IComponent as the method isSignalReceiver() does only exist in the following implementations of said interface: KdybyModule\CliPresenter, Nette\Application\UI\Presenter.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
698 1
            $session->remove();
699 1
        } elseif ($session && empty($params) && $session->params) {
700 1
            $params = (array) $session->params;
701 1
        }
702
703 1
        parent::loadState($params);
704 1
    }
705
706
    /**
707
     * Saves state informations for next request.
708
     * @param array $params
709
     * @param \Nette\Application\UI\PresenterComponentReflection $reflection (internal, used by Presenter)
710
     * @internal
711
     */
712
    public function saveState(array &$params, $reflection = NULL)
713
    {
714 1
        !empty($this->onRegistered) && $this->onRegistered($this);
715 1
        return parent::saveState($params, $reflection);
716
    }
717
718
    /**
719
     * Ajax method.
720
     * @internal
721
     */
722
    public function handleRefresh()
723
    {
724
        $this->reload();
725
    }
726
727
    /**
728
     * @param int $page
729
     * @internal
730
     */
731
    public function handlePage($page)
0 ignored issues
show
Unused Code introduced by
The parameter $page is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
732
    {
733 1
        $this->reload();
734
    }
735
736
    /**
737
     * @param array $sort
738
     * @internal
739
     */
740
    public function handleSort(array $sort)
0 ignored issues
show
Unused Code introduced by
The parameter $sort is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
741
    {
742 1
        $this->page = 1;
743 1
        $this->reload();
744
    }
745
746
    /**
747
     * @param \Nette\Forms\Controls\SubmitButton $button
748
     * @internal
749
     */
750
    public function handleFilter(\Nette\Forms\Controls\SubmitButton $button)
751
    {
752 1
        $values = $button->form->values[Filter::ID];
753 1
        $session = $this->rememberState //session filter
754 1
            ? isset($this->getRememberSession(TRUE)->params['filter'])
755 1
                ? $this->getRememberSession(TRUE)->params['filter']
756 1
                : []
757 1
            : [];
758
759 1
        foreach ($values as $name => $value) {
760 1
            if (is_numeric($value) || !empty($value) || isset($this->defaultFilter[$name]) || isset($session[$name])) {
761 1
                $this->filter[$name] = $this->getFilter($name)->changeValue($value);
762 1
            } elseif (isset($this->filter[$name])) {
763
                unset($this->filter[$name]);
764
            }
765 1
        }
766
767 1
        $this->page = 1;
768 1
        $this->reload();
769
    }
770
771
    /**
772
     * @param \Nette\Forms\Controls\SubmitButton $button
773
     * @internal
774
     */
775
    public function handleReset(\Nette\Forms\Controls\SubmitButton $button)
776
    {
777 1
        $this->sort = [];
778 1
        $this->filter = [];
779 1
        $this->perPage = NULL;
780
781 1
        if ($session = $this->getRememberSession()) {
782 1
            $session->remove();
783 1
        }
784
785 1
        $button->form->setValues([Filter::ID => $this->defaultFilter], TRUE);
786
787 1
        $this->page = 1;
788 1
        $this->reload();
789
    }
790
791
    /**
792
     * @param \Nette\Forms\Controls\SubmitButton $button
793
     * @internal
794
     */
795
    public function handlePerPage(\Nette\Forms\Controls\SubmitButton $button)
796
    {
797 1
        $perPage = (int) $button->form['count']->value;
798 1
        $this->perPage = $perPage == $this->defaultPerPage
799 1
            ? NULL
800
            : $perPage;
801
802 1
        $this->page = 1;
803 1
        $this->reload();
804
    }
805
806
    /**
807
     * Refresh wrapper.
808
     * @return void
809
     * @internal
810
     */
811
    public function reload()
812
    {
813 1
        if ($this->presenter->isAjax()) {
814
            $this->presenter->payload->grido = TRUE;
815
            $this->redrawControl();
816
        } else {
817 1
            $this->redirect('this');
818
        }
819
    }
820
821
    /**********************************************************************************************/
822
823
    /**
824
     * @return \Nette\Templating\FileTemplate
825
     * @internal
826
     */
827
    public function createTemplate()
828
    {
829 1
        $template = parent::createTemplate();
830 1
        $template->setFile($this->getCustomization()->getTemplateFiles()[Customization::TEMPLATE_DEFAULT]);
831 1
        $template->registerHelper('translate', [$this->getTranslator(), 'translate']);
832
833 1
        return $template;
834
    }
835
836
    /**
837
     * @internal
838
     * @throws Exception
839
     */
840
    public function render()
841
    {
842 1
        if (!$this->hasColumns()) {
843
            throw new Exception('Grid must have defined a column, please use method $grid->addColumn*().');
844
        }
845
846 1
        $this->saveRememberState();
847 1
        $data = $this->getData();
848
849 1
        if (!empty($this->onRender)) {
850 1
            $this->onRender($this);
851 1
        }
852
853 1
        $this->template->data = $data;
854 1
        $this->template->form = $form = $this['form'];
855 1
        $this->template->paginator = $this->getPaginator();
0 ignored issues
show
Bug introduced by
Accessing paginator on the interface Nette\Application\UI\ITemplate suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
856
857 1
        $this->template->columns = $this->getComponent(Column::ID)->getComponents();
0 ignored issues
show
Bug introduced by
Accessing columns on the interface Nette\Application\UI\ITemplate suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
858 1
        $this->template->actions = $this->hasActions() ? $this->getComponent(Action::ID)->getComponents() : [];
0 ignored issues
show
Bug introduced by
Accessing actions on the interface Nette\Application\UI\ITemplate suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
859 1
        $this->template->formFilters = $this->hasFilters() ? $form->getComponent(Filter::ID)->getComponents() : [];
0 ignored issues
show
Bug introduced by
Accessing formFilters on the interface Nette\Application\UI\ITemplate suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
860 1
        $this->template->customization = $this->getCustomization();
0 ignored issues
show
Bug introduced by
Accessing customization on the interface Nette\Application\UI\ITemplate suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
861
862 1
        $form['count']->setValue($this->getPerPage());
863
864 1
        if ($options = $this->options[self::CLIENT_SIDE_OPTIONS]) {
865 1
            $this->getTablePrototype()->data[self::CLIENT_SIDE_OPTIONS] = json_encode($options);
866 1
        }
867
868 1
        $this->template->render();
869 1
    }
870
871
    protected function saveRememberState()
872
    {
873 1
        if ($this->rememberState) {
874 1
            $session = $this->getRememberSession(TRUE);
875 1
            $params = array_keys($this->getReflection()->getPersistentParams());
876 1
            foreach ($params as $param) {
877 1
                $session->params[$param] = $this->$param;
878 1
            }
879 1
        }
880 1
    }
881
882
    protected function applyFiltering()
883
    {
884 1
        $conditions = $this->__getConditions($this->getActualFilter());
885 1
        $this->getModel()->filter($conditions);
886 1
    }
887
888
    /**
889
     * @param array $filter
890
     * @return array
891
     * @internal
892
     */
893
    public function __getConditions(array $filter)
894
    {
895 1
        $conditions = [];
896 1
        if (!empty($filter)) {
897
            try {
898 1
                $this['form']->setDefaults([Filter::ID => $filter]);
899 1
            } catch (\Nette\InvalidArgumentException $e) {
900
                $this->__triggerUserNotice($e->getMessage());
901
                $filter = [];
902
                if ($session = $this->getRememberSession()) {
903
                    $session->remove();
904
                }
905
            }
906
907 1
            foreach ($filter as $column => $value) {
908 1
                if ($component = $this->getFilter($column, FALSE)) {
909 1
                    if ($condition = $component->__getCondition($value)) {
910 1
                        $conditions[] = $condition;
911 1
                    }
912 1
                } else {
913 1
                    $this->__triggerUserNotice("Filter with name '$column' does not exist.");
914
                }
915 1
            }
916 1
        }
917
918 1
        return $conditions;
919
    }
920
921
    protected function applySorting()
922
    {
923 1
        $sort = [];
924 1
        $this->sort = $this->sort ? $this->sort : $this->defaultSort;
925
926 1
        foreach ($this->sort as $column => $dir) {
927 1
            $component = $this->getColumn($column, FALSE);
928 1
            if (!$component) {
929 1
                if (!isset($this->defaultSort[$column])) {
930 1
                    $this->__triggerUserNotice("Column with name '$column' does not exist.");
931 1
                    break;
932
                }
933
934 1
            } elseif (!$component->isSortable()) {
935 1
                if (isset($this->defaultSort[$column])) {
936 1
                    $component->setSortable();
937 1
                } else {
938 1
                    $this->__triggerUserNotice("Column with name '$column' is not sortable.");
939 1
                    break;
940
                }
941 1
            }
942
943 1
            if (!in_array($dir, [Column::ORDER_ASC, Column::ORDER_DESC])) {
944 1
                if ($dir == '' && isset($this->defaultSort[$column])) {
945
                    unset($this->sort[$column]);
946
                    break;
947
                }
948
949 1
                $this->__triggerUserNotice("Dir '$dir' is not allowed.");
950 1
                break;
951
            }
952
953 1
            $sort[$component ? $component->column : $column] = $dir == Column::ORDER_ASC ? 'ASC' : 'DESC';
0 ignored issues
show
Documentation introduced by
The property $column is declared protected in Grido\Components\Columns\Column. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
954 1
        }
955
956 1
        if (!empty($sort)) {
957 1
            $this->getModel()->sort($sort);
958 1
        }
959 1
    }
960
961
    protected function applyPaging()
962
    {
963 1
        $paginator = $this->getPaginator()
964 1
            ->setItemCount($this->getCount())
965 1
            ->setPage($this->page);
966
967 1
        $perPage = $this->getPerPage();
968 1
        if ($perPage !== NULL && !in_array($perPage, $this->perPageList)) {
969 1
            $this->__triggerUserNotice("The number '$perPage' of items per page is out of range.");
970 1
        }
971
972 1
        $this->getModel()->limit($paginator->getOffset(), $paginator->getLength());
973 1
    }
974
975
    protected function createComponentForm($name)
976
    {
977 1
        $form = new \Nette\Application\UI\Form($this, $name);
978 1
        $form->setTranslator($this->getTranslator());
979 1
        $form->setMethod($form::GET);
980
981 1
        $buttons = $form->addContainer(self::BUTTONS);
982 1
        $buttons->addSubmit('search', 'Grido.Search')
983 1
            ->onClick[] = [$this, 'handleFilter'];
984 1
        $buttons->addSubmit('reset', 'Grido.Reset')
985 1
            ->onClick[] = [$this, 'handleReset'];
986 1
        $buttons->addSubmit('perPage', 'Grido.ItemsPerPage')
987 1
            ->onClick[] = [$this, 'handlePerPage'];
988
989 1
        $form->addSelect('count', 'Count', $this->getItemsForCountSelect())
990 1
            ->setTranslator(NULL)
991 1
            ->controlPrototype->attrs['title'] = $this->getTranslator()->translate('Grido.ItemsPerPage');
992 1
    }
993
994
    /**
995
     * @return array
996
     */
997
    protected function getItemsForCountSelect()
998
    {
999 1
        return array_combine($this->perPageList, $this->perPageList);
1000
    }
1001
1002
    /**
1003
     * @internal
1004
     * @param string $message
1005
     */
1006
    public function __triggerUserNotice($message)
1007
    {
1008 1
        if ($this->getPresenter(FALSE) && $session = $this->getRememberSession()) {
1009 1
            $session->remove();
1010 1
        }
1011
1012 1
        $this->strictMode && trigger_error($message, E_USER_NOTICE);
1013 1
    }
1014
}
1015