Completed
Pull Request — master (#270)
by
unknown
12:35
created

Datagrid::getColumns()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace ZfcDatagrid;
4
5
use ArrayIterator;
6
use Doctrine\Common\Collections\Collection;
7
use Doctrine\ORM\QueryBuilder;
8
use Interop\Container\ContainerInterface;
9
use Zend\Cache;
10
use Zend\Console\Request as ConsoleRequest;
11
use Zend\Db\Sql\Select as ZendSelect;
12
use Zend\Http\PhpEnvironment\Request as HttpRequest;
13
use Zend\I18n\Translator\Translator;
14
use Zend\Mvc\MvcEvent;
15
use Zend\Paginator\Paginator;
16
use Zend\Router\RouteStackInterface;
17
use Zend\ServiceManager\ServiceLocatorInterface;
18
use Zend\Session\Container as SessionContainer;
19
use Zend\Stdlib\ResponseInterface;
20
use Zend\View\Model\JsonModel;
21
use Zend\View\Model\ViewModel;
22
use ZfcDatagrid\Column\Style;
23
24
class Datagrid
25
{
26
    /**
27
     * @var array
28
     */
29
    protected $options = [];
30
31
    /**
32
     * @var SessionContainer
33
     */
34
    protected $session;
35
36
    /**
37
     * @var Cache\Storage\StorageInterface
38
     */
39
    protected $cache;
40
41
    /**
42
     * @var string
43
     */
44
    protected $cacheId;
45
46
    /**
47
     * @var MvcEvent
48
     */
49
    protected $mvcEvent;
50
51
    /**
52
     * @var array
53
     */
54
    protected $parameters = [];
55
56
    /**
57
     * @var mixed
58
     */
59
    protected $url;
60
61
    /**
62
     * @var HttpRequest
63
     */
64
    protected $request;
65
66
    /**
67
     * View or Response.
68
     *
69
     * @var \Zend\Http\Response\Stream|\Zend\View\Model\ViewModel
70
     */
71
    protected $response;
72
73
    /**
74
     * @var Renderer\AbstractRenderer
75
     */
76
    private $renderer;
77
78
    /**
79
     * @var Translator
80
     */
81
    protected $translator;
82
83
    /**
84
     * @var RouteStackInterface
85
     */
86
    protected $router;
87
88
    /**
89
     * @var string
90
     */
91
    protected $id;
92
93
    /**
94
     * The grid title.
95
     *
96
     * @var string
97
     */
98
    protected $title = '';
99
100
    /**
101
     * @var DataSource\DataSourceInterface
102
     */
103
    protected $dataSource = null;
104
105
    /**
106
     * @var int
107
     */
108
    protected $defaulItemsPerPage = 25;
109
110
    /**
111
     * @var array
112
     */
113
    protected $columns = [];
114
115
    /**
116
     * @var Style\AbstractStyle[]
117
     */
118
    protected $rowStyles = [];
119
120
    /**
121
     * @var Column\Action\AbstractAction
122
     */
123
    protected $rowClickAction;
124
125
    /**
126
     * @var Action\Mass
127
     */
128
    protected $massActions = [];
129
130
    /**
131
     * The prepared data.
132
     *
133
     * @var array
134
     */
135
    protected $preparedData = [];
136
137
    /**
138
     * @var array
139
     */
140
    protected $isUserFilterEnabled = true;
141
142
    /**
143
     * @var Paginator
144
     */
145
    protected $paginator = null;
146
147
    /**
148
     * @var array
149
     */
150
    protected $exportRenderers;
151
152
    /**
153
     * @var string|null
154
     */
155
    protected $toolbarTemplate;
156
157
    /**
158
     * @var array
159
     */
160
    protected $toolbarTemplateVariables = [];
161
162
    /**
163
     * @var ViewModel
164
     */
165
    protected $viewModel;
166
167
    /**
168
     * @var bool
169
     */
170
    protected $isInit = false;
171
172
    /**
173
     * @var bool
174
     */
175
    protected $isDataLoaded = false;
176
177
    /**
178
     * @var bool
179
     */
180
    protected $isRendered = false;
181
182
    /**
183
     * @var string
184
     */
185
    protected $forceRenderer;
186
187
    /**
188
     * @var Renderer\AbstractRenderer
189
     */
190
    private $rendererService;
191
192
    /**
193
     * @var array
194
     */
195
    private $specialMethods = [
196
        'filterSelectOptions',
197
        'rendererParameter',
198
        'replaceValues',
199
        'select',
200
        'sortDefault',
201
    ];
202
203
    /**
204
     * @var ServiceLocatorInterface
205
     */
206
    protected $serviceLocator = null;
207
208
    /**
209
     * Init method is called automatically with the service creation.
210
     */
211
    public function init()
212
    {
213
        if ($this->getCache() === null) {
214
            $options = $this->getOptions();
215
            $this->setCache(Cache\StorageFactory::factory($options['cache']));
216
        }
217
218
        $this->isInit = true;
219
    }
220
221
    /**
222
     * @return bool
223
     */
224
    public function isInit()
225
    {
226
        return (bool) $this->isInit;
227
    }
228
229
    /**
230
     * Set the options from config.
231
     *
232
     * @param array $config
233
     */
234
    public function setOptions(array $config)
235
    {
236
        $this->options = $config;
237
    }
238
239
    /**
240
     * Get the config options.
241
     *
242
     * @return array
243
     */
244
    public function getOptions()
245
    {
246
        return $this->options;
247
    }
248
249
    /**
250
     * Set the grid id.
251
     *
252
     * @param string $id
253
     */
254
    public function setId($id = null)
255
    {
256
        if ($id !== null) {
257
            $id = preg_replace("/[^a-z0-9_\\\d]/i", '_', $id);
258
259
            $this->id = (string) $id;
260
        }
261
    }
262
263
    /**
264
     * Get the grid id.
265
     *
266
     * @return string
267
     */
268
    public function getId()
269
    {
270
        if (null === $this->id) {
271
            $this->id = 'defaultGrid';
272
        }
273
274
        return $this->id;
275
    }
276
277
    /**
278
     * Set the session.
279
     *
280
     * @param \Zend\Session\Container $session
281
     */
282
    public function setSession(SessionContainer $session)
283
    {
284
        $this->session = $session;
285
    }
286
287
    /**
288
     * Get session container.
289
     *
290
     * Instantiate session container if none currently exists
291
     *
292
     * @return SessionContainer
293
     */
294
    public function getSession()
295
    {
296
        if (null === $this->session) {
297
            // Using fully qualified name, to ensure polyfill class alias is used
298
            $this->session = new SessionContainer($this->getId());
299
        }
300
301
        return $this->session;
302
    }
303
304
    /**
305
     * @param Cache\Storage\StorageInterface $cache
306
     */
307
    public function setCache(Cache\Storage\StorageInterface $cache)
308
    {
309
        $this->cache = $cache;
310
    }
311
312
    /**
313
     * @return Cache\Storage\StorageInterface
314
     */
315
    public function getCache()
316
    {
317
        return $this->cache;
318
    }
319
320
    /**
321
     * Set the cache id.
322
     *
323
     * @param string $id
324
     */
325
    public function setCacheId($id)
326
    {
327
        $this->cacheId = (string) $id;
328
    }
329
330
    /**
331
     * Get the cache id.
332
     *
333
     * @return string
334
     */
335
    public function getCacheId()
336
    {
337
        if (null === $this->cacheId) {
338
            $this->cacheId = md5($this->getSession()
339
                ->getManager()
340
                ->getId().'_'.$this->getId());
341
        }
342
343
        return $this->cacheId;
344
    }
345
346
    /**
347
     * @param MvcEvent $mvcEvent
348
     */
349
    public function setMvcEvent(MvcEvent $mvcEvent)
350
    {
351
        $this->mvcEvent = $mvcEvent;
352
        $this->request = $mvcEvent->getRequest();
353
    }
354
355
    /**
356
     * @return MvcEvent
357
     */
358
    public function getMvcEvent()
359
    {
360
        return $this->mvcEvent;
361
    }
362
363
    /**
364
     * @return HttpRequest
365
     */
366
    public function getRequest()
367
    {
368
        return $this->request;
369
    }
370
371
    /**
372
     * Set the translator.
373
     *
374
     * @param Translator $translator
375
     *
376
     * @throws \InvalidArgumentException
377
     */
378 View Code Duplication
    public function setTranslator($translator = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
379
    {
380
        if (!$translator instanceof Translator && !$translator instanceof \Zend\I18n\Translator\TranslatorInterface) {
381
            throw new \InvalidArgumentException('Translator must be an instanceof "Zend\I18n\Translator\Translator" or "Zend\I18n\Translator\TranslatorInterface"');
382
        }
383
384
        $this->translator = $translator;
385
    }
386
387
    /**
388
     * @return Translator
389
     */
390
    public function getTranslator()
391
    {
392
        return $this->translator;
393
    }
394
395
    /**
396
     * @return bool
397
     */
398
    public function hasTranslator()
399
    {
400
        if ($this->translator !== null) {
401
            return true;
402
        }
403
404
        return false;
405
    }
406
407
    /**
408
     * @param \Zend\Router\RouteStackInterface $router
409
     */
410
    public function setRouter( RouteStackInterface $router )
411
    {
412
        $this->router = $router;
413
    }
414
415
    /**
416
     * @return RouteStackInterface
417
     */
418
    public function getRouter()
419
    {
420
        return $this->router;
421
    }
422
423
    /**
424
     * @return bool
425
     */
426
    public function hasRouter()
427
    {
428
        return !is_null($this->router);
429
    }
430
431
    /**
432
     * Set the data source.
433
     *
434
     * @param mixed $data
435
     *
436
     * @throws \Exception
437
     */
438
    public function setDataSource($data)
439
    {
440
        if ($data instanceof DataSource\DataSourceInterface) {
441
            $this->dataSource = $data;
442
        } elseif (is_array($data)) {
443
            $this->dataSource = new DataSource\PhpArray($data);
444
        } elseif ($data instanceof QueryBuilder) {
445
            $this->dataSource = new DataSource\Doctrine2($data);
446
        } elseif ($data instanceof ZendSelect) {
447
            $args = func_get_args();
448
            if (count($args) === 1 || (!$args[1] instanceof \Zend\Db\Adapter\Adapter && !$args[1] instanceof \Zend\Db\Sql\Sql)) {
449
                throw new \InvalidArgumentException('For "Zend\Db\Sql\Select" also a "Zend\Db\Adapter\Sql" or "Zend\Db\Sql\Sql" is needed.');
450
            }
451
            $this->dataSource = new DataSource\ZendSelect($data);
452
            $this->dataSource->setAdapter($args[1]);
453
        } elseif ($data instanceof Collection) {
454
            $args = func_get_args();
455
            if (count($args) === 1 || !$args[1] instanceof \Doctrine\ORM\EntityManager) {
456
                throw new \InvalidArgumentException('If providing a Collection, also the Doctrine\ORM\EntityManager is needed as a second parameter');
457
            }
458
            $this->dataSource = new DataSource\Doctrine2Collection($data);
459
            $this->dataSource->setEntityManager($args[1]);
460
        } else {
461
            throw new \InvalidArgumentException('$data must implement the interface ZfcDatagrid\DataSource\DataSourceInterface');
462
        }
463
    }
464
465
    /**
466
     * @return \ZfcDatagrid\DataSource\DataSourceInterface
467
     */
468
    public function getDataSource()
469
    {
470
        return $this->dataSource;
471
    }
472
473
    /**
474
     * Datasource defined?
475
     *
476
     * @return bool
477
     */
478
    public function hasDataSource()
479
    {
480
        if ($this->dataSource !== null) {
481
            return true;
482
        }
483
484
        return false;
485
    }
486
487
    /**
488
     * Set default items per page (-1 for unlimited).
489
     *
490
     * @param int $count
491
     */
492
    public function setDefaultItemsPerPage($count = 25)
493
    {
494
        $this->defaulItemsPerPage = (int) $count;
495
    }
496
497
    /**
498
     * @return int
499
     */
500
    public function getDefaultItemsPerPage()
501
    {
502
        return (int) $this->defaulItemsPerPage;
503
    }
504
505
    /**
506
     * Set the title.
507
     *
508
     * @param string $title
509
     */
510
    public function setTitle($title)
511
    {
512
        $this->title = (string) $title;
513
    }
514
515
    /**
516
     * @return string
517
     */
518
    public function getTitle()
519
    {
520
        return $this->title;
521
    }
522
523
    /**
524
     * Add a external parameter.
525
     *
526
     * @param string $name
527
     * @param mixed  $value
528
     */
529
    public function addParameter($name, $value)
530
    {
531
        $this->parameters[$name] = $value;
532
    }
533
534
    /**
535
     * These parameters are handled to the view + over all grid actions.
536
     *
537
     * @param array $parameters
538
     */
539
    public function setParameters(array $parameters)
540
    {
541
        $this->parameters = $parameters;
542
    }
543
544
    /**
545
     * @return array
546
     */
547
    public function getParameters()
548
    {
549
        return $this->parameters;
550
    }
551
552
    /**
553
     * Has parameters?
554
     *
555
     * @return bool
556
     */
557
    public function hasParameters()
558
    {
559
        return (bool) $this->getParameters();
560
    }
561
562
    /**
563
     * Set the base url.
564
     *
565
     * @param string $url
566
     */
567
    public function setUrl($url)
568
    {
569
        $this->url = $url;
570
    }
571
572
    /**
573
     * @return string
574
     */
575
    public function getUrl()
576
    {
577
        return $this->url;
578
    }
579
580
    /**
581
     * Set the export renderers (overwrite the config).
582
     *
583
     * @param array $renderers
584
     */
585
    public function setExportRenderers(array $renderers = [])
586
    {
587
        $this->exportRenderers = $renderers;
588
    }
589
590
    /**
591
     * Get the export renderers.
592
     *
593
     * @return array
594
     */
595
    public function getExportRenderers()
596
    {
597
        if (null === $this->exportRenderers) {
598
            $options = $this->getOptions();
599
            $this->exportRenderers = $options['settings']['export']['formats'];
600
        }
601
602
        return $this->exportRenderers;
603
    }
604
605
    /**
606
     * Create a column from array instanceof.
607
     *
608
     * @param array $config
609
     *
610
     * @return Column\AbstractColumn
611
     */
612
    private function createColumn($config)
613
    {
614
        if ($config instanceof Column\AbstractColumn) {
615
            return $config;
616
        }
617
618
        if (!is_array($config) && !$config instanceof Column\AbstractColumn) {
619
            throw new \InvalidArgumentException('createColumn() supports only a config array or instanceof Column\AbstractColumn as a parameter');
620
        }
621
622
        $colType = isset($config['colType']) ? $config['colType'] : 'Select';
623
        if (class_exists($colType, true)) {
624
            $class = $colType;
625
        } elseif (class_exists('ZfcDatagrid\\Column\\'.$colType, true)) {
626
            $class = 'ZfcDatagrid\\Column\\'.$colType;
627
        } else {
628
            throw new \InvalidArgumentException(sprintf('Column type: "%s" not found!', $colType));
629
        }
630
631
        if ('ZfcDatagrid\\Column\\Select' == $class) {
632
            if (!isset($config['select']['column'])) {
633
                throw new \InvalidArgumentException('For "ZfcDatagrid\Column\Select" the option select[column] must be defined!');
634
            }
635
            $table = isset($config['select']['table']) ? $config['select']['table'] : null;
636
637
            $instance = new $class($config['select']['column'], $table);
638
        } else {
639
            $instance = new $class();
640
        }
641
642
        foreach ($config as $key => $value) {
643
            $method = 'set'.ucfirst($key);
644
            if (method_exists($instance, $method)) {
645
                if (in_array($key, $this->specialMethods)) {
646
                    if (!is_array($value)) {
647
                        $value = [
648
                            $value,
649
                        ];
650
                    }
651
                    call_user_func_array([
652
                        $instance,
653
                        $method,
654
                    ], $value);
655
                } else {
656
                    call_user_func([
657
                        $instance,
658
                        $method,
659
                    ], $value);
660
                }
661
            }
662
        }
663
664
        return $instance;
665
    }
666
667
    /**
668
     * Set multiple columns by array (willoverwrite all existing).
669
     *
670
     * @param array $columns
671
     */
672
    public function setColumns(array $columns)
673
    {
674
        $useColumns = [];
675
676
        foreach ($columns as $col) {
677
            $col = $this->createColumn($col);
678
            $useColumns[$col->getUniqueId()] = $col;
679
        }
680
681
        $this->columns = $useColumns;
682
    }
683
684
    /**
685
     * Add a column by array config or instanceof Column\AbstractColumn.
686
     *
687
     * @param array|Column\AbstractColumn $col
688
     */
689
    public function addColumn($col)
690
    {
691
        $col = $this->createColumn($col);
0 ignored issues
show
Bug introduced by
It seems like $col defined by $this->createColumn($col) on line 691 can also be of type object<ZfcDatagrid\Column\AbstractColumn>; however, ZfcDatagrid\Datagrid::createColumn() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
692
        $this->columns[$col->getUniqueId()] = $col;
693
    }
694
695
    /**
696
     * @return \ZfcDatagrid\Column\AbstractColumn[]
697
     */
698
    public function getColumns()
699
    {
700
        return $this->columns;
701
    }
702
703
    /**
704
     * @param string $id
705
     *
706
     * @return Column\AbstractColumn null
707
     */
708
    public function getColumnByUniqueId($id)
709
    {
710
        if (isset($this->columns[$id])) {
711
            return $this->columns[$id];
712
        }
713
714
        return;
715
    }
716
717
    /**
718
     * @param Style\AbstractStyle $style
719
     */
720
    public function addRowStyle(Style\AbstractStyle $style)
721
    {
722
        $this->rowStyles[] = $style;
723
    }
724
725
    /**
726
     * @return Style\AbstractStyle[]
727
     */
728
    public function getRowStyles()
729
    {
730
        return $this->rowStyles;
731
    }
732
733
    /**
734
     * @return bool
735
     */
736
    public function hasRowStyles()
737
    {
738
        return (bool) $this->rowStyles;
739
    }
740
741
    /**
742
     * If disabled, the toolbar filter will not be shown to the user.
743
     *
744
     * @param bool $mode
745
     */
746
    public function setUserFilterDisabled($mode = true)
747
    {
748
        $this->isUserFilterEnabled = (bool) !$mode;
0 ignored issues
show
Documentation Bug introduced by
It seems like (bool) (!$mode) of type boolean is incompatible with the declared type array of property $isUserFilterEnabled.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
749
    }
750
751
    /**
752
     * @return bool
753
     */
754
    public function isUserFilterEnabled()
755
    {
756
        return (bool) $this->isUserFilterEnabled;
757
    }
758
759
    /**
760
     * Set the row click action - identity will be automatically appended!
761
     *
762
     * @param Column\Action\AbstractAction $action
763
     */
764
    public function setRowClickAction(Column\Action\AbstractAction $action)
765
    {
766
        $this->rowClickAction = $action;
767
    }
768
769
    public function getRowClickAction()
770
    {
771
        return $this->rowClickAction;
772
    }
773
774
    /**
775
     * @return bool
776
     */
777
    public function hasRowClickAction()
778
    {
779
        if (is_object($this->rowClickAction)) {
780
            return true;
781
        }
782
783
        return false;
784
    }
785
786
    /**
787
     * Add a mass action.
788
     *
789
     * @param Action\Mass $action
790
     */
791
    public function addMassAction(Action\Mass $action)
792
    {
793
        $this->massActions[] = $action;
794
    }
795
796
    /**
797
     * @return Action\Mass[]
798
     */
799
    public function getMassActions()
800
    {
801
        return $this->massActions;
802
    }
803
804
    /**
805
     * @return bool
806
     */
807
    public function hasMassAction()
808
    {
809
        return (bool) $this->massActions;
810
    }
811
812
    /**
813
     * Overwrite the render
814
     * F.x.
815
     * if you want to directly render a PDF.
816
     *
817
     * @param string $name
818
     */
819
    public function setRendererName($name = null)
820
    {
821
        $this->forceRenderer = $name;
822
    }
823
824
    /**
825
     * Get the current renderer name.
826
     *
827
     * @return string
828
     */
829
    public function getRendererName()
830
    {
831
        $options = $this->getOptions();
832
        $parameterName = $options['generalParameterNames']['rendererType'];
833
834
        if ($this->forceRenderer !== null) {
835
            // A special renderer was given -> use is
836
            $rendererName = $this->forceRenderer;
837
        } else {
838
            // DEFAULT
839
            if ($this->getRequest() instanceof ConsoleRequest) {
840
                $rendererName = $options['settings']['default']['renderer']['console'];
841
            } else {
842
                $rendererName = $options['settings']['default']['renderer']['http'];
843
            }
844
        }
845
846
        // From request
847
        if ($this->getRequest() instanceof HttpRequest && $this->getRequest()->getQuery($parameterName) != '') {
848
            $rendererName = $this->getRequest()->getQuery($parameterName);
849
        }
850
851
        return $rendererName;
852
    }
853
854
    /**
855
     * Return the current renderer.
856
     *
857
     * @throws \Exception
858
     *
859
     * @return \ZfcDatagrid\Renderer\AbstractRenderer
860
     */
861
    public function getRenderer()
862
    {
863
        if (null === $this->renderer) {
864
            if (isset($this->rendererService)) {
865
                $renderer = $this->rendererService;
866
                if (!$renderer instanceof Renderer\AbstractRenderer) {
867
                    throw new \Exception('Renderer service must implement "ZfcDatagrid\Renderer\AbstractRenderer"');
868
                }
869
                $renderer->setOptions($this->getOptions());
870
                $renderer->setMvcEvent($this->getMvcEvent());
871
                if ($this->getToolbarTemplate() !== null) {
872
                    $renderer->setToolbarTemplate($this->getToolbarTemplate());
873
                }
874
                $renderer->setToolbarTemplateVariables($this->getToolbarTemplateVariables());
875
                $renderer->setViewModel($this->getViewModel());
876
                if ($this->hasTranslator()) {
877
                    $renderer->setTranslator($this->getTranslator());
878
                }
879
                $renderer->setTitle($this->getTitle());
880
                $renderer->setColumns($this->getColumns());
881
                $renderer->setRowStyles($this->getRowStyles());
882
                $renderer->setCache($this->getCache());
883
                $renderer->setCacheId($this->getCacheId());
884
885
                $this->renderer = $renderer;
886
            } else {
887
                throw new \Exception(sprintf('Renderer service was not found, please register it: "zfcDatagrid.renderer.%s"', $this->getRendererName()));
888
            }
889
        }
890
891
        return $this->renderer;
892
    }
893
894
    /**
895
     * @return bool
896
     */
897
    public function isDataLoaded()
898
    {
899
        return (bool) $this->isDataLoaded;
900
    }
901
902
    /**
903
     * Load the data.
904
     */
905
    public function loadData()
906
    {
907
        if (true === $this->isDataLoaded) {
908
            return true;
909
        }
910
911
        if ($this->isInit() !== true) {
912
            throw new \Exception('The init() method has to be called, before you can call loadData()!');
913
        }
914
915
        if ($this->hasDataSource() === false) {
916
            throw new \Exception('No datasource defined! Please call "setDataSource()" first"');
917
        }
918
919
        /**
920
         * Apply cache.
921
         */
922
        $renderer = $this->getRenderer();
923
924
        /*
925
         * Step 1) Apply needed columns + filters + sort
926
         * - from Request (HTML View) -> and save in cache for export
927
         * - or from cache (Export PDF / Excel) -> same view like HTML (without LIMIT/Pagination)
928
         */
929
        {
930
            /*
931
             * Step 1.1) Only select needed columns (performance)
932
             */
933
            $this->getDataSource()->setColumns($this->getColumns());
934
935
            /*
936
             * Step 1.2) Sorting
937
             */
938
            foreach ($renderer->getSortConditions() as $condition) {
939
                $this->getDataSource()->addSortCondition($condition['column'], $condition['sortDirection']);
940
            }
941
942
            /*
943
             * Step 1.3) Filtering
944
             */
945
            foreach ($renderer->getFilters() as $filter) {
946
                $this->getDataSource()->addFilter($filter);
947
            }
948
        }
949
950
        /*
951
         * Step 2) Load the data (Paginator)
952
         */
953
        {
954
            $this->getDataSource()->execute();
955
            $paginatorAdapter = $this->getDataSource()->getPaginatorAdapter();
956
957
            \Zend\Paginator\Paginator::setDefaultScrollingStyle('Sliding');
958
959
            $this->paginator = new Paginator($paginatorAdapter);
960
            $this->paginator->setCurrentPageNumber($renderer->getCurrentPageNumber());
961
            $this->paginator->setItemCountPerPage($renderer->getItemsPerPage($this->getDefaultItemsPerPage()));
962
963
            /* @var $currentItems \ArrayIterator */
964
            $data = $this->paginator->getCurrentItems();
965
            if (!is_array($data)) {
966
                if ($data instanceof \Zend\Db\ResultSet\ResultSet) {
967
                    $data = $data->toArray();
968
                } elseif ($data instanceof ArrayIterator) {
969
                    $data = $data->getArrayCopy();
970
                } else {
971
                    if (is_object($data)) {
972
                        $add = get_class($data);
973
                    } else {
974
                        $add = '[no object]';
975
                    }
976
                    throw new \Exception(
977
                        sprintf('The paginator returned an unknown result: %s (allowed: \ArrayIterator or a plain php array)', $add)
978
                    );
979
                }
980
            }
981
        }
982
983
        /*
984
         * check if the export is enabled
985
         * Save cache
986
         */
987
        if ($this->getOptions()['settings']['export']['enabled'] && $renderer->isExport() === false) {
988
            $cacheData = [
989
                'sortConditions' => $renderer->getSortConditions(),
990
                'filters' => $renderer->getFilters(),
991
                'currentPage' => $this->getPaginator()->getCurrentPageNumber(),
992
            ];
993
            $success = $this->getCache()->setItem($this->getCacheId(), $cacheData);
994
            if ($success !== true) {
995
                /** @var \Zend\Cache\Storage\Adapter\FilesystemOptions $options */
996
                $options = $this->getCache()->getOptions();
997
                throw new \Exception(
998
                    sprintf(
999
                        'Could not save the datagrid cache. Does the directory "%s" exists and is writeable? CacheId: %s',
1000
                        $options->getCacheDir(),
1001
                        $this->getCacheId()
1002
                    )
1003
                );
1004
            }
1005
        }
1006
1007
        /*
1008
         * Step 3) Format the data - Translate - Replace - Date / time / datetime - Numbers - ...
1009
         */
1010
        $prepareData = new PrepareData($data, $this->getColumns());
1011
        if ($this->getRouter() instanceof RouteStackInterface) {
1012
            $prepareData->setRouter($this->getRouter());
1013
        }
1014
1015
        $prepareData->setRendererName($this->getRendererName());
1016
        if ($this->hasTranslator()) {
1017
            $prepareData->setTranslator($this->getTranslator());
1018
        }
1019
        $prepareData->prepare();
1020
        $this->preparedData = $prepareData->getData();
1021
1022
        $this->isDataLoaded = true;
1023
    }
1024
1025
    /**
1026
     * Render the grid.
1027
     */
1028
    public function render()
1029
    {
1030
        if ($this->isDataLoaded() === false) {
1031
            $this->loadData();
1032
        }
1033
1034
        /**
1035
         * Step 4) Render the data to the defined output format (HTML, PDF...)
1036
         * - Styling the values based on column (and value).
1037
         */
1038
        $renderer = $this->getRenderer();
1039
        $renderer->setTitle($this->getTitle());
1040
        $renderer->setPaginator($this->getPaginator());
1041
        $renderer->setData($this->getPreparedData());
1042
        $renderer->prepareViewModel($this);
1043
1044
        $this->response = $renderer->execute();
1045
1046
        $this->isRendered = true;
1047
    }
1048
1049
    /**
1050
     * Is already rendered?
1051
     *
1052
     * @return bool
1053
     */
1054
    public function isRendered()
1055
    {
1056
        return (bool) $this->isRendered;
1057
    }
1058
1059
    /**
1060
     * @throws \Exception
1061
     *
1062
     * @return Paginator
1063
     */
1064
    public function getPaginator()
1065
    {
1066
        if (null === $this->paginator) {
1067
            throw new \Exception('Paginator is only available after calling "loadData()"');
1068
        }
1069
1070
        return $this->paginator;
1071
    }
1072
1073
    /**
1074
     * @return array
1075
     */
1076
    private function getPreparedData()
1077
    {
1078
        return $this->preparedData;
1079
    }
1080
1081
    /**
1082
     * Set the toolbar view template.
1083
     *
1084
     * @param string $name
1085
     */
1086
    public function setToolbarTemplate($name)
1087
    {
1088
        $this->toolbarTemplate = (string) $name;
1089
    }
1090
1091
    /**
1092
     * Get the toolbar template name
1093
     * Return null if nothing custom set.
1094
     *
1095
     * @return string|null
1096
     */
1097
    public function getToolbarTemplate()
1098
    {
1099
        return $this->toolbarTemplate;
1100
    }
1101
1102
    /**
1103
     * Set the toolbar view template variables.
1104
     *
1105
     * @param array $variables
1106
     */
1107
    public function setToolbarTemplateVariables(array $variables)
1108
    {
1109
        $this->toolbarTemplateVariables = $variables;
1110
    }
1111
1112
    /**
1113
     * Get the toolbar template variables.
1114
     *
1115
     * @return array
1116
     */
1117
    public function getToolbarTemplateVariables()
1118
    {
1119
        return $this->toolbarTemplateVariables;
1120
    }
1121
1122
    /**
1123
     * Set a custom ViewModel...generally NOT necessary!
1124
     *
1125
     * @param ViewModel $viewModel
1126
     *
1127
     * @throws \Exception
1128
     */
1129
    public function setViewModel(ViewModel $viewModel)
1130
    {
1131
        if ($this->viewModel !== null) {
1132
            throw new \Exception('A viewModel is already set. Did you already called $grid->render() or $grid->getViewModel() before?');
1133
        }
1134
1135
        $this->viewModel = $viewModel;
1136
    }
1137
1138
    /**
1139
     * @return ViewModel
1140
     */
1141
    public function getViewModel()
1142
    {
1143
        if (null === $this->viewModel) {
1144
            $this->viewModel = new ViewModel();
1145
        }
1146
1147
        return $this->viewModel;
1148
    }
1149
1150
    /**
1151
     * @return \Zend\Stdlib\ResponseInterface|\Zend\Http\Response\Stream|\Zend\View\Model\ViewModel
1152
     */
1153
    public function getResponse()
1154
    {
1155
        if (!$this->isRendered()) {
1156
            $this->render();
1157
        }
1158
1159
        return $this->response;
1160
    }
1161
1162
    /**
1163
     * Is this a HTML "init" response?
1164
     * YES: loading the HTML for the grid
1165
     * NO: AJAX loading OR it's an export.
1166
     *
1167
     * @return bool
1168
     */
1169
    public function isHtmlInitReponse()
1170
    {
1171
        if (!$this->getResponse() instanceof JsonModel && !$this->getResponse() instanceof ResponseInterface) {
1172
            return true;
1173
        }
1174
1175
        return false;
1176
    }
1177
1178
    /**
1179
     * @param Renderer\AbstractRenderer $rendererService
1180
     *
1181
     * @return self
1182
     */
1183
    public function setRendererService(Renderer\AbstractRenderer $rendererService)
1184
    {
1185
        $this->rendererService = $rendererService;
1186
1187
        return $this;
1188
    }
1189
1190
    /**
1191
     * Set service locator.
1192
     *
1193
     * @param ContainerInterface $serviceLocator
1194
     *
1195
     * @return mixed
1196
     */
1197
    public function setServiceLocator(ContainerInterface $serviceLocator)
1198
    {
1199
        $this->serviceLocator = $serviceLocator;
0 ignored issues
show
Documentation Bug introduced by
$serviceLocator is of type object<Interop\Container\ContainerInterface>, but the property $serviceLocator was declared to be of type object<Zend\ServiceManag...erviceLocatorInterface>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
1200
1201
        return $this;
1202
    }
1203
1204
    /**
1205
     * Get service locator.
1206
     *
1207
     * @return ContainerInterface
1208
     */
1209
    public function getServiceLocator()
1210
    {
1211
        return $this->serviceLocator;
1212
    }
1213
}
1214