Completed
Pull Request — master (#240)
by Tomáš
06:38
created

Grid   F

Complexity

Total Complexity 156

Size/Duplication

Total Lines 982
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 22

Test Coverage

Coverage 74.01%

Importance

Changes 23
Bugs 1 Features 5
Metric Value
wmc 156
c 23
b 1
f 5
lcom 1
cbo 22
dl 0
loc 982
ccs 262
cts 354
cp 0.7401
rs 1.263

58 Methods

Rating   Name   Duplication   Size   Complexity  
A setModel() 0 8 3
A setDefaultPerPage() 0 12 2
A setDefaultFilter() 0 5 1
A setDefaultSort() 0 15 3
A setPerPageList() 0 10 3
A setTranslator() 0 5 1
A setFilterRenderType() 0 10 2
A setPaginator() 0 5 1
A setPrimaryKey() 0 5 1
A setTemplateFile() 0 9 1
A setRememberState() 0 11 2
A setRowCallback() 0 5 1
A setClientSideOptions() 0 5 1
A setStrictMode() 0 5 1
A setCustomization() 0 4 1
A getCount() 0 8 2
A getDefaultPerPage() 0 8 2
A getDefaultFilter() 0 4 1
A getDefaultSort() 0 4 1
A getPerPageList() 0 4 1
A getPrimaryKey() 0 4 1
A getRememberState() 0 4 1
A getRowCallback() 0 4 1
A getPerPage() 0 6 2
A getActualFilter() 0 5 4
C getData() 0 37 11
A getTranslator() 0 8 2
B getRememberSession() 0 13 5
A getTablePrototype() 0 9 2
B getFilterRenderType() 0 21 7
A getModel() 0 4 1
A getPaginator() 0 10 2
B getProperty() 0 19 6
A getPropertyAccessor() 0 8 2
A getRowPrototype() 0 17 4
A getClientSideOptions() 0 4 1
A isStrictMode() 0 4 1
A getCustomization() 0 8 2
B loadState() 0 12 6
A saveState() 0 5 2
A handleRefresh() 0 4 1
A handlePage() 0 4 1
A handleSort() 0 5 1
B handleFilter() 0 20 9
A handleReset() 0 15 2
A handlePerPage() 0 10 2
A reload() 0 9 2
A createTemplate() 0 8 1
C render() 0 31 7
A attached() 0 10 3
A saveRememberState() 0 10 3
A applyFiltering() 0 5 1
C __getConditions() 0 27 7
C applySorting() 0 39 13
A applyPaging() 0 13 3
A createComponentForm() 0 18 1
A getItemsForCountSelect() 0 4 1
A __triggerUserNotice() 0 8 4

How to fix   Complexity   

Complex Class

Complex classes like Grid often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Grid, and based on these observations, apply Extract Interface, too.

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
    /** @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 1
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
     * Sets a model that implements the interface Grido\DataSources\IDataSource or data-source object.
140
     * @param mixed $model
141
     * @param bool $forceWrapper
142 1
     * @throws Exception
143
     * @return Grid
144
     */
145
    public function setModel($model, $forceWrapper = FALSE)
146
    {
147 1
        $this->model = $model instanceof DataSources\IDataSource && $forceWrapper === FALSE
148 1
            ? $model
149 1
            : new DataSources\Model($model);
150 1
151 1
        return $this;
152
    }
153
154
    /**
155
     * Sets the default number of items per page.
156
     * @param int $perPage
157
     * @return Grid
158
     */
159
    public function setDefaultPerPage($perPage)
160 1
    {
161 1
        $perPage = (int) $perPage;
162 1
        $this->defaultPerPage = $perPage;
163
164 1
        if (!in_array($perPage, $this->perPageList)) {
165 1
            $this->perPageList[] = $perPage;
166 1
            sort($this->perPageList);
167 1
        }
168 1
169 1
        return $this;
170
    }
171
172
    /**
173
     * Sets default filtering.
174
     * @param array $filter
175
     * @return Grid
176
     */
177
    public function setDefaultFilter(array $filter)
178
    {
179 1
        $this->defaultFilter = array_merge($this->defaultFilter, $filter);
180 1
        return $this;
181
    }
182
183
    /**
184
     * Sets default sorting.
185
     * @param array $sort
186
     * @return Grid
187 1
     * @throws Exception
188
     */
189
    public function setDefaultSort(array $sort)
190
    {
191 1
        static $replace = ['asc' => Column::ORDER_ASC, 'desc' => Column::ORDER_DESC];
192
193 1
        foreach ($sort as $column => $dir) {
194 1
            $dir = strtr(strtolower($dir), $replace);
195 1
            if (!in_array($dir, $replace)) {
196 1
                throw new Exception("Dir '$dir' for column '$column' is not allowed.");
197
            }
198
199 1
            $this->defaultSort[$column] = $dir;
200 1
        }
201
202 1
        return $this;
203
    }
204
205
    /**
206
     * Sets items to per-page select.
207
     * @param array $perPageList
208 1
     * @return Grid
209
     */
210
    public function setPerPageList(array $perPageList)
211
    {
212 1
        $this->perPageList = $perPageList;
213
214 1
        if ($this->hasFilters(FALSE) || $this->hasOperation(FALSE)) {
215 1
            $this['form']['count']->setItems($this->getItemsForCountSelect());
216 1
        }
217
218 1
        return $this;
219
    }
220 1
221
    /**
222
     * Sets translator.
223
     * @param \Nette\Localization\ITranslator $translator
224
     * @return Grid
225
     */
226
    public function setTranslator(\Nette\Localization\ITranslator $translator)
227
    {
228 1
        $this->translator = $translator;
229 1
        return $this;
230
    }
231
232
    /**
233
     * Sets type of filter rendering.
234
     * Defaults inner (Filter::RENDER_INNER) if column does not exist then outer filter (Filter::RENDER_OUTER).
235
     * @param string $type
236 1
     * @throws Exception
237
     * @return Grid
238
     */
239
    public function setFilterRenderType($type)
240
    {
241 1
        $type = strtolower($type);
242 1
        if (!in_array($type, [Filter::RENDER_INNER, Filter::RENDER_OUTER])) {
243 1
            throw new Exception('Type must be Filter::RENDER_INNER or Filter::RENDER_OUTER.');
244
        }
245
246 1
        $this->filterRenderType = $type;
247 1
        return $this;
248
    }
249
250
    /**
251
     * Sets custom paginator.
252
     * @param Paginator $paginator
253
     * @return Grid
254
     */
255
    public function setPaginator(Paginator $paginator)
256
    {
257 1
        $this->paginator = $paginator;
258 1
        return $this;
259
    }
260
261
    /**
262
     * Sets grid primary key.
263
     * Defaults is "id".
264
     * @param string $key
265
     * @return Grid
266
     */
267
    public function setPrimaryKey($key)
268
    {
269 1
        $this->primaryKey = $key;
270 1
        return $this;
271
    }
272
273
    /**
274
     * Sets file name of custom template.
275
     * @param string $file
276
     * @return Grid
277
     */
278
    public function setTemplateFile($file)
279
    {
280 1
        $this->onRender[] = function() use ($file) {
281 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...
282 1
            $this->getTemplate()->setFile($file);
283 1
        };
284
285 1
        return $this;
286
    }
287
288
    /**
289
     * Sets saving state to session.
290
     * @param bool $state
291
     * @param string $sectionName
292
     * @return Grid
293
     */
294
    public function setRememberState($state = TRUE, $sectionName = NULL)
295
    {
296 1
        $this->rememberState = (bool) $state;
297 1
        $this->rememberStateSectionName = $sectionName;
298
299 1
        if ($this->lookup('Nette\Application\UI\Presenter', FALSE)) {
300 1
            $this->getRememberSession(TRUE); //start session if not
301 1
        }
302
303 1
        return $this;
304
    }
305
306
    /**
307
     * Sets callback for customizing tr html object.
308
     * Callback returns tr html element; function($row, Html $tr).
309
     * @param $callback
310
     * @return Grid
311
     */
312
    public function setRowCallback($callback)
313
    {
314 1
        $this->rowCallback = $callback;
315 1
        return $this;
316
    }
317
318
    /**
319
     * Sets client-side options.
320
     * @param array $options
321
     * @return Grid
322
     */
323
    public function setClientSideOptions(array $options)
324
    {
325 1
        $this->options[self::CLIENT_SIDE_OPTIONS] = $options;
326 1
        return $this;
327
    }
328
329
    /**
330
     * Determines whether any user error will cause a notice.
331
     * @param bool $mode
332
     * @return \Grido\Grid
333
     */
334
    public function setStrictMode($mode)
335
    {
336 1
        $this->strictMode = (bool) $mode;
337 1
        return $this;
338
    }
339
340
    /**
341
     * @param \Grido\Customization $customization
342
     */
343
    public function setCustomization(Customization $customization)
344
    {
345
        $this->customization = $customization;
346
    }
347
348
    /**********************************************************************************************/
349
350
    /**
351
     * Returns total count of data.
352
     * @return int
353
     */
354
    public function getCount()
355
    {
356 1
        if ($this->count === NULL) {
357 1
            $this->count = $this->getModel()->getCount();
358 1
        }
359
360 1
        return $this->count;
361
    }
362
363
    /**
364
     * Returns default per page.
365
     * @return int
366 1
     */
367
    public function getDefaultPerPage()
368
    {
369 1
        if (!in_array($this->defaultPerPage, $this->perPageList)) {
370
            $this->defaultPerPage = $this->perPageList[0];
371
        }
372
373 1
        return $this->defaultPerPage;
374
    }
375
376
    /**
377
     * Returns default filter.
378
     * @return array
379
     */
380
    public function getDefaultFilter()
381
    {
382 1
        return $this->defaultFilter;
383
    }
384
385
    /**
386
     * Returns default sort.
387
     * @return array
388
     */
389
    public function getDefaultSort()
390
    {
391 1
        return $this->defaultSort;
392
    }
393
394
    /**
395
     * Returns list of possible items per page.
396 1
     * @return array
397
     */
398
    public function getPerPageList()
399
    {
400 1
        return $this->perPageList;
401
    }
402
403
    /**
404
     * Returns primary key.
405
     * @return string
406
     */
407
    public function getPrimaryKey()
408
    {
409 1
        return $this->primaryKey;
410
    }
411
412
    /**
413
     * Returns remember state.
414
     * @return bool
415
     */
416
    public function getRememberState()
417
    {
418 1
        return $this->rememberState;
419
    }
420
421
    /**
422
     * Returns row callback.
423
     * @return callback
424
     */
425
    public function getRowCallback()
426
    {
427 1
        return $this->rowCallback;
428
    }
429
430
    /**
431
     * Returns items per page.
432
     * @return int
433
     */
434 1
    public function getPerPage()
435
    {
436 1
        return $this->perPage === NULL
437 1
            ? $this->getDefaultPerPage()
438 1
            : $this->perPage;
439
    }
440
441
    /**
442
     * Returns actual filter values.
443
     * @param string $key
444
     * @return mixed
445
     */
446
    public function getActualFilter($key = NULL)
447
    {
448 1
        $filter = $this->filter ? $this->filter : $this->defaultFilter;
449 1
        return $key !== NULL && isset($filter[$key]) ? $filter[$key] : $filter;
450
    }
451
452
    /**
453
     * Returns fetched data.
454
     * @param bool $applyPaging
455
     * @param bool $useCache
456
     * @param bool $fetch
457
     * @throws Exception
458
     * @return array|DataSources\IDataSource|\Nette\Database\Table\Selection
459
     */
460
    public function getData($applyPaging = TRUE, $useCache = TRUE, $fetch = TRUE)
461
    {
462 1
        if ($this->getModel() === NULL) {
463 1
            throw new Exception('Model cannot be empty, please use method $grid->setModel().');
464
        }
465
466 1
        $data = $this->data;
467 1
        if ($data === NULL || $useCache === FALSE) {
468 1
            $this->applyFiltering();
469 1
            $this->applySorting();
470
471 1
            if ($applyPaging) {
472 1
                $this->applyPaging();
473 1
            }
474
475 1
            if ($fetch === FALSE) {
476 1
                return $this->getModel();
477
            }
478
479 1
            $data = $this->getModel()->getData();
480
481 1
            if ($useCache === TRUE) {
482 1
                $this->data = $data;
483 1
            }
484
485 1
            if ($applyPaging && !empty($data) && !in_array($this->page, range(1, $this->getPaginator()->pageCount))) {
486
                $this->__triggerUserNotice("Page is out of range.");
487
                $this->page = 1;
488
            }
489
490 1
            if (!empty($this->onFetchData)) {
491
                $this->onFetchData($this);
492
            }
493 1
        }
494
495 1
        return $data;
496
    }
497
498
    /**
499
     * Returns translator.
500
     * @return Translations\FileTranslator
501
     */
502
    public function getTranslator()
503
    {
504 1
        if ($this->translator === NULL) {
505 1
            $this->setTranslator(new Translations\FileTranslator);
506 1
        }
507
508 1
        return $this->translator;
509
    }
510
511
    /**
512
     * Returns remember session for set expiration, etc.
513
     * @param bool $forceStart - if TRUE, session will be started if not
514
     * @return \Nette\Http\SessionSection|NULL
515
     */
516
    public function getRememberSession($forceStart = FALSE)
517
    {
518 1
        $presenter = $this->getPresenter();
519 1
        $session = $presenter->getSession();
520
521 1
        if (!$session->isStarted() && $forceStart) {
522 1
            $session->start();
523 1
        }
524
525 1
        return $session->isStarted()
526 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...
527 1
            : NULL;
528
    }
529
530
    /**
531
     * Returns table html element of grid.
532
     * @return \Nette\Utils\Html
533
     */
534
    public function getTablePrototype()
535
    {
536 1
        if ($this->tablePrototype === NULL) {
537 1
            $this->tablePrototype = \Nette\Utils\Html::el('table');
538 1
            $this->tablePrototype->id($this->getName());
539 1
        }
540
541 1
        return $this->tablePrototype;
542
    }
543
544
    /**
545
     * @return string
546
     * @internal
547
     */
548
    public function getFilterRenderType()
549
    {
550 1
        if ($this->filterRenderType !== NULL) {
551 1
            return $this->filterRenderType;
552
        }
553
554 1
        $this->filterRenderType = Filter::RENDER_OUTER;
555 1
        if ($this->hasColumns() && $this->hasFilters() && $this->hasActions()) {
556 1
            $this->filterRenderType = Filter::RENDER_INNER;
557
558 1
            $filters = $this[Filter::ID]->getComponents();
559 1
            foreach ($filters as $filter) {
560 1
                if (!$this[Column::ID]->getComponent($filter->name, FALSE)) {
561
                    $this->filterRenderType = Filter::RENDER_OUTER;
562
                    break;
563
                }
564 1
            }
565 1
        }
566
567 1
        return $this->filterRenderType;
568
    }
569
570
    /**
571
     * @return DataSources\IDataSource
572
     */
573
    public function getModel()
574
    {
575 1
        return $this->model;
576
    }
577
578
    /**
579
     * @return Paginator
580
     * @internal
581
     */
582
    public function getPaginator()
583
    {
584 1
        if ($this->paginator === NULL) {
585 1
            $this->paginator = new Paginator;
586 1
            $this->paginator->setItemsPerPage($this->getPerPage())
587 1
                ->setGrid($this);
588 1
        }
589
590 1
        return $this->paginator;
591
    }
592
593
    /**
594
     * A simple wrapper around symfony/property-access with Nette Database dot notation support.
595
     * @param array|object $object
596
     * @param string $name
597
     * @return mixed
598
     * @internal
599
     */
600
    public function getProperty($object, $name)
601
    {
602 1
        if ($object instanceof \Nette\Database\Table\IRow && \Nette\Utils\Strings::contains($name, '.')) {
603
            $parts = explode('.', $name);
604
            foreach ($parts as $item) {
605
                if (is_object($object)) {
606
                    $object = $object->$item;
607
                }
608
            }
609
610
            return $object;
611
        }
612
613 1
        if (is_array($object)) {
614 1
            $name = "[$name]";
615 1
        }
616
617 1
        return $this->getPropertyAccessor()->getValue($object, $name);
618
    }
619
620
    /**
621
     * @return PropertyAccessor
622
     * @internal
623
     */
624
    public function getPropertyAccessor()
625
    {
626 1
        if ($this->propertyAccessor === NULL) {
627 1
            $this->propertyAccessor = new PropertyAccessor(TRUE, TRUE);
628 1
        }
629
630 1
        return $this->propertyAccessor;
631
    }
632
633
    /**
634
     * @param mixed $row item from db
635
     * @return \Nette\Utils\Html
636
     * @internal
637
     */
638
    public function getRowPrototype($row)
639
    {
640
        try {
641 1
            $primaryValue = $this->getProperty($row, $this->getPrimaryKey());
642 1
        } catch (\Exception $e) {
643
            $primaryValue = NULL;
644
        }
645
646 1
        $tr = \Nette\Utils\Html::el('tr');
647 1
        $primaryValue ? $tr->class[] = "grid-row-$primaryValue" : NULL;
648
649 1
        if ($this->rowCallback) {
650 1
            $tr = call_user_func_array($this->rowCallback, [$row, $tr]);
651 1
        }
652
653 1
        return $tr;
654
    }
655
656
    /**
657
     * Returns client-side options.
658
     * @return array
659
     */
660
    public function getClientSideOptions()
661
    {
662 1
        return (array) $this->options[self::CLIENT_SIDE_OPTIONS];
663
    }
664
665
    /**
666
     * @return bool
667
     */
668
    public function isStrictMode()
669
    {
670
        return $this->strictMode;
671
    }
672
673
    /**
674
     * @return Customization
675
     */
676
    public function getCustomization()
677
    {
678 1
        if ($this->customization === NULL) {
679 1
            $this->customization = new Customization($this);
680 1
        }
681
682 1
        return $this->customization;
683
    }
684
685
    /**********************************************************************************************/
686
687
    /**
688
     * Loads state informations.
689
     * @param array $params
690
     * @internal
691
     */
692
    public function loadState(array $params)
693
    {
694
        //loads state from session
695 1
        $session = $this->getRememberSession();
696 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...
697
            $session->remove();
698 1
        } elseif ($session && empty($params) && $session->params) {
699
            $params = (array) $session->params;
700
        }
701
702 1
        parent::loadState($params);
703 1
    }
704
705
    /**
706
     * Saves state informations for next request.
707
     * @param array $params
708
     * @param \Nette\Application\UI\PresenterComponentReflection $reflection (internal, used by Presenter)
709
     * @internal
710
     */
711
    public function saveState(array &$params, $reflection = NULL)
712
    {
713 1
        !empty($this->onRegistered) && $this->onRegistered($this);
714 1
        return parent::saveState($params, $reflection);
715
    }
716
717
    /**
718
     * Ajax method.
719
     * @internal
720
     */
721
    public function handleRefresh()
722
    {
723
        $this->reload();
724
    }
725
726
    /**
727
     * @param int $page
728
     * @internal
729
     */
730
    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...
731
    {
732
        $this->reload();
733
    }
734
735
    /**
736
     * @param array $sort
737
     * @internal
738
     */
739
    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...
740
    {
741
        $this->page = 1;
742
        $this->reload();
743
    }
744
745
    /**
746
     * @param \Nette\Forms\Controls\SubmitButton $button
747
     * @internal
748
     */
749
    public function handleFilter(\Nette\Forms\Controls\SubmitButton $button)
750
    {
751
        $values = $button->form->values[Filter::ID];
752
        $session = $this->rememberState //session filter
753
            ? isset($this->getRememberSession(TRUE)->params['filter'])
754
                ? $this->getRememberSession(TRUE)->params['filter']
755
                : []
756
            : [];
757
758
        foreach ($values as $name => $value) {
759
            if (is_numeric($value) || !empty($value) || isset($this->defaultFilter[$name]) || isset($session[$name])) {
760
                $this->filter[$name] = $this->getFilter($name)->changeValue($value);
761
            } elseif (isset($this->filter[$name])) {
762
                unset($this->filter[$name]);
763
            }
764
        }
765
766
        $this->page = 1;
767
        $this->reload();
768
    }
769
770
    /**
771
     * @param \Nette\Forms\Controls\SubmitButton $button
772
     * @internal
773
     */
774
    public function handleReset(\Nette\Forms\Controls\SubmitButton $button)
775
    {
776
        $this->sort = [];
777
        $this->filter = [];
778
        $this->perPage = NULL;
779
780
        if ($session = $this->getRememberSession()) {
781
            $session->remove();
782
        }
783
784
        $button->form->setValues([Filter::ID => $this->defaultFilter], TRUE);
785
786
        $this->page = 1;
787
        $this->reload();
788
    }
789
790
    /**
791
     * @param \Nette\Forms\Controls\SubmitButton $button
792
     * @internal
793
     */
794
    public function handlePerPage(\Nette\Forms\Controls\SubmitButton $button)
795
    {
796
        $perPage = (int) $button->form['count']->value;
797
        $this->perPage = $perPage == $this->defaultPerPage
798
            ? NULL
799
            : $perPage;
800
801
        $this->page = 1;
802
        $this->reload();
803
    }
804
805
    /**
806
     * Refresh wrapper.
807
     * @return void
808
     * @internal
809
     */
810
    public function reload()
811
    {
812
        if ($this->presenter->isAjax()) {
813
            $this->presenter->payload->grido = TRUE;
814
            $this->redrawControl();
815
        } else {
816
            $this->redirect('this');
817
        }
818
    }
819
820
    /**********************************************************************************************/
821
822
    /**
823
     * @return \Nette\Templating\FileTemplate
824
     * @internal
825
     */
826
    public function createTemplate()
827
    {
828 1
        $template = parent::createTemplate();
829 1
        $template->setFile($this->getCustomization()->getTemplateFiles()[Customization::TEMPLATE_DEFAULT]);
830 1
        $template->registerHelper('translate', [$this->getTranslator(), 'translate']);
831
832 1
        return $template;
833
    }
834
835
    /**
836
     * @internal
837
     * @throws Exception
838
     */
839
    public function render()
840
    {
841 1
        if (!$this->hasColumns()) {
842
            throw new Exception('Grid must have defined a column, please use method $grid->addColumn*().');
843
        }
844
845 1
        $this->saveRememberState();
846 1
        $data = $this->getData();
847
848 1
        if (!empty($this->onRender)) {
849 1
            $this->onRender($this);
850 1
        }
851
852 1
        $this->template->data = $data;
853 1
        $this->template->form = $form = $this['form'];
854 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...
855
856 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...
Bug introduced by
It seems like you code against a concrete implementation and not the interface Nette\ComponentModel\IComponent as the method getComponents() does only exist in the following implementations of said interface: Grido\Components\Actions\Action, Grido\Components\Actions\Event, Grido\Components\Actions\Href, Grido\Components\Button, Grido\Components\Columns\Column, Grido\Components\Columns\Date, Grido\Components\Columns\Editable, Grido\Components\Columns\Email, Grido\Components\Columns\Link, Grido\Components\Columns\Number, Grido\Components\Columns\Text, Grido\Components\Component, Grido\Components\Container, Grido\Components\Export, Grido\Components\Filters\Check, Grido\Components\Filters\Custom, Grido\Components\Filters\Date, Grido\Components\Filters\DateRange, Grido\Components\Filters\Filter, Grido\Components\Filters\Number, Grido\Components\Filters\Select, Grido\Components\Filters\Text, Grido\Components\Operation, Grido\Grid, KdybyModule\CliPresenter, Nette\Application\UI\Control, Nette\Application\UI\Form, Nette\Application\UI\Multiplier, Nette\Application\UI\Presenter, Nette\Application\UI\PresenterComponent, Nette\ComponentModel\Container, Nette\Forms\Container, Nette\Forms\Form.

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...
857 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...
Bug introduced by
It seems like you code against a concrete implementation and not the interface Nette\ComponentModel\IComponent as the method getComponents() does only exist in the following implementations of said interface: Grido\Components\Actions\Action, Grido\Components\Actions\Event, Grido\Components\Actions\Href, Grido\Components\Button, Grido\Components\Columns\Column, Grido\Components\Columns\Date, Grido\Components\Columns\Editable, Grido\Components\Columns\Email, Grido\Components\Columns\Link, Grido\Components\Columns\Number, Grido\Components\Columns\Text, Grido\Components\Component, Grido\Components\Container, Grido\Components\Export, Grido\Components\Filters\Check, Grido\Components\Filters\Custom, Grido\Components\Filters\Date, Grido\Components\Filters\DateRange, Grido\Components\Filters\Filter, Grido\Components\Filters\Number, Grido\Components\Filters\Select, Grido\Components\Filters\Text, Grido\Components\Operation, Grido\Grid, KdybyModule\CliPresenter, Nette\Application\UI\Control, Nette\Application\UI\Form, Nette\Application\UI\Multiplier, Nette\Application\UI\Presenter, Nette\Application\UI\PresenterComponent, Nette\ComponentModel\Container, Nette\Forms\Container, Nette\Forms\Form.

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...
858 1
        $this->template->buttons = $this->hasButtons() ? $this->getComponent(Button::ID)->getComponents() : [];
0 ignored issues
show
Bug introduced by
Accessing buttons 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...
Bug introduced by
It seems like you code against a concrete implementation and not the interface Nette\ComponentModel\IComponent as the method getComponents() does only exist in the following implementations of said interface: Grido\Components\Actions\Action, Grido\Components\Actions\Event, Grido\Components\Actions\Href, Grido\Components\Button, Grido\Components\Columns\Column, Grido\Components\Columns\Date, Grido\Components\Columns\Editable, Grido\Components\Columns\Email, Grido\Components\Columns\Link, Grido\Components\Columns\Number, Grido\Components\Columns\Text, Grido\Components\Component, Grido\Components\Container, Grido\Components\Export, Grido\Components\Filters\Check, Grido\Components\Filters\Custom, Grido\Components\Filters\Date, Grido\Components\Filters\DateRange, Grido\Components\Filters\Filter, Grido\Components\Filters\Number, Grido\Components\Filters\Select, Grido\Components\Filters\Text, Grido\Components\Operation, Grido\Grid, KdybyModule\CliPresenter, Nette\Application\UI\Control, Nette\Application\UI\Form, Nette\Application\UI\Multiplier, Nette\Application\UI\Presenter, Nette\Application\UI\PresenterComponent, Nette\ComponentModel\Container, Nette\Forms\Container, Nette\Forms\Form.

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...
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
    /**
872
     * This method will be called when the component (or component's parent)
873
     * becomes attached to a monitored object. Do not call this method yourself.
874
     * @param  Nette\ComponentModel\IComponent
875
     * @return void
876
     * @internal
877
     */
878
    protected function attached($presenter)
879
    {
880 1
        parent::attached($presenter);
881
882 1
        if ($presenter instanceof \Nette\Application\UI\Presenter) {
883 1
            if ($this->rememberState) {
884 1
                $this->getRememberSession(TRUE); //start session if not
885 1
            }
886 1
        }
887 1
    }
888
889
    protected function saveRememberState()
890
    {
891 1
        if ($this->rememberState) {
892
            $session = $this->getRememberSession(TRUE);
893
            $params = array_keys($this->getReflection()->getPersistentParams());
894
            foreach ($params as $param) {
895
                $session->params[$param] = $this->$param;
896
            }
897
        }
898 1
    }
899
900
    protected function applyFiltering()
901
    {
902 1
        $conditions = $this->__getConditions($this->getActualFilter());
903 1
        $this->getModel()->filter($conditions);
904 1
    }
905
906
    /**
907
     * @param array $filter
908
     * @return array
909
     * @internal
910
     */
911
    public function __getConditions(array $filter)
912
    {
913 1
        $conditions = [];
914 1
        if (!empty($filter)) {
915
            try {
916 1
                $this['form']->setDefaults([Filter::ID => $filter]);
917 1
            } catch (\Nette\InvalidArgumentException $e) {
918
                $this->__triggerUserNotice($e->getMessage());
919
                $filter = [];
920
                if ($session = $this->getRememberSession()) {
921
                    $session->remove();
922
                }
923
            }
924
925 1
            foreach ($filter as $column => $value) {
926 1
                if ($component = $this->getFilter($column, FALSE)) {
927 1
                    if ($condition = $component->__getCondition($value)) {
928 1
                        $conditions[] = $condition;
929 1
                    }
930 1
                } else {
931 1
                    $this->__triggerUserNotice("Filter with name '$column' does not exist.");
932
                }
933 1
            }
934 1
        }
935
936 1
        return $conditions;
937
    }
938
939
    protected function applySorting()
940
    {
941 1
        $sort = [];
942 1
        $this->sort = $this->sort ? $this->sort : $this->defaultSort;
943
944 1
        foreach ($this->sort as $column => $dir) {
945 1
            $component = $this->getColumn($column, FALSE);
946 1
            if (!$component) {
947 1
                if (!isset($this->defaultSort[$column])) {
948
                    $this->__triggerUserNotice("Column with name '$column' does not exist.");
949
                    break;
950
                }
951
952 1
            } elseif (!$component->isSortable()) {
953 1
                if (isset($this->defaultSort[$column])) {
954 1
                    $component->setSortable();
955 1
                } else {
956
                    $this->__triggerUserNotice("Column with name '$column' is not sortable.");
957
                    break;
958
                }
959 1
            }
960
961 1
            if (!in_array($dir, [Column::ORDER_ASC, Column::ORDER_DESC])) {
962
                if ($dir == '' && isset($this->defaultSort[$column])) {
963
                    unset($this->sort[$column]);
964
                    break;
965
                }
966
967
                $this->__triggerUserNotice("Dir '$dir' is not allowed.");
968
                break;
969
            }
970
971 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...
972 1
        }
973
974 1
        if (!empty($sort)) {
975 1
            $this->getModel()->sort($sort);
976 1
        }
977 1
    }
978
979
    protected function applyPaging()
980
    {
981 1
        $paginator = $this->getPaginator()
982 1
            ->setItemCount($this->getCount())
983 1
            ->setPage($this->page);
984
985 1
        $perPage = $this->getPerPage();
986 1
        if ($perPage !== NULL && !in_array($perPage, $this->perPageList)) {
987 1
            $this->__triggerUserNotice("The number '$perPage' of items per page is out of range.");
988 1
        }
989
990 1
        $this->getModel()->limit($paginator->getOffset(), $paginator->getLength());
991 1
    }
992
993
    protected function createComponentForm($name)
994
    {
995 1
        $form = new \Nette\Application\UI\Form($this, $name);
996 1
        $form->setTranslator($this->getTranslator());
997 1
        $form->setMethod($form::GET);
998
999 1
        $buttons = $form->addContainer(self::BUTTONS);
1000 1
        $buttons->addSubmit('search', 'Grido.Search')
1001 1
            ->onClick[] = [$this, 'handleFilter'];
1002 1
        $buttons->addSubmit('reset', 'Grido.Reset')
1003 1
            ->onClick[] = [$this, 'handleReset'];
1004 1
        $buttons->addSubmit('perPage', 'Grido.ItemsPerPage')
1005 1
            ->onClick[] = [$this, 'handlePerPage'];
1006
1007 1
        $form->addSelect('count', 'Count', $this->getItemsForCountSelect())
1008 1
            ->setTranslator(NULL)
1009 1
            ->controlPrototype->attrs['title'] = $this->getTranslator()->translate('Grido.ItemsPerPage');
1010 1
    }
1011
1012
    /**
1013
     * @return array
1014
     */
1015
    protected function getItemsForCountSelect()
1016
    {
1017 1
        return array_combine($this->perPageList, $this->perPageList);
1018
    }
1019
1020
    /**
1021
     * @internal
1022
     * @param string $message
1023
     */
1024
    public function __triggerUserNotice($message)
1025
    {
1026 1
        if ($this->getPresenter(FALSE) && $session = $this->getRememberSession()) {
1027
            $session->remove();
1028
        }
1029
1030 1
        $this->strictMode && trigger_error($message, E_USER_NOTICE);
1031 1
    }
1032
}
1033