Completed
Pull Request — master (#271)
by Martin
11:36
created

Datagrid::getMvcEvent()   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
namespace ZfcDatagrid;
3
4
use ArrayIterator;
5
use Doctrine\Common\Collections\Collection;
6
use Doctrine\ORM\QueryBuilder;
7
use Interop\Container\ContainerInterface;
8
use Zend\Cache;
9
use Zend\Console\Request as ConsoleRequest;
10
use Zend\Db\Sql\Select as ZendSelect;
11
use Zend\Http\PhpEnvironment\Request as HttpRequest;
12
use Zend\I18n\Translator\Translator;
13
use Zend\Mvc\MvcEvent;
14
use Zend\Paginator\Paginator;
15
use Zend\Router\RouteStackInterface;
16
use Zend\ServiceManager\ServiceLocatorInterface;
17
use Zend\Session\Container as SessionContainer;
18
use Zend\Stdlib\ResponseInterface;
19
use Zend\View\Model\JsonModel;
20
use Zend\View\Model\ViewModel;
21
use ZfcDatagrid\Column\Style;
22
23
class Datagrid
24
{
25
    /**
26
     * @var array
27
     */
28
    protected $options = [];
29
30
    /**
31
     * @var SessionContainer
32
     */
33
    protected $session;
34
35
    /**
36
     * @var Cache\Storage\StorageInterface
37
     */
38
    protected $cache;
39
40
    /**
41
     * @var string
42
     */
43
    protected $cacheId;
44
45
    /**
46
     * @var MvcEvent
47
     */
48
    protected $mvcEvent;
49
50
    /**
51
     * @var array
52
     */
53
    protected $parameters = [];
54
55
    /**
56
     * @var mixed
57
     */
58
    protected $url;
59
60
    /**
61
     * @var HttpRequest
62
     */
63
    protected $request;
64
65
    /**
66
     * View or Response.
67
     *
68
     * @var \Zend\Http\Response\Stream|\Zend\View\Model\ViewModel
69
     */
70
    protected $response;
71
72
    /**
73
     * @var Renderer\AbstractRenderer
74
     */
75
    private $renderer;
76
77
    /**
78
     * @var Translator
79
     */
80
    protected $translator;
81
82
    /**
83
     * @var RouteStackInterface
84
     */
85
    protected $router;
86
87
    /**
88
     * @var string
89
     */
90
    protected $id;
91
92
    /**
93
     * The grid title.
94
     *
95
     * @var string
96
     */
97
    protected $title = '';
98
99
    /**
100
     * @var DataSource\DataSourceInterface
101
     */
102
    protected $dataSource = null;
103
104
    /**
105
     * @var int
106
     */
107
    protected $defaulItemsPerPage = 25;
108
109
    /**
110
     * @var array
111
     */
112
    protected $columns = [];
113
114
    /**
115
     * @var Style\AbstractStyle[]
116
     */
117
    protected $rowStyles = [];
118
119
    /**
120
     * @var Column\Action\AbstractAction
121
     */
122
    protected $rowClickAction;
123
124
    /**
125
     * @var Action\Mass
126
     */
127
    protected $massActions = [];
128
129
    /**
130
     * The prepared data.
131
     *
132
     * @var array
133
     */
134
    protected $preparedData = [];
135
136
    /**
137
     * @var array
138
     */
139
    protected $isUserFilterEnabled = true;
140
141
    /**
142
     * @var Paginator
143
     */
144
    protected $paginator = null;
145
146
    /**
147
     * @var array
148
     */
149
    protected $exportRenderers;
150
151
    /**
152
     * @var string|null
153
     */
154
    protected $toolbarTemplate;
155
156
    /**
157
     * @var array
158
     */
159
    protected $toolbarTemplateVariables = [];
160
161
    /**
162
     * @var ViewModel
163
     */
164
    protected $viewModel;
165
166
    /**
167
     * @var bool
168
     */
169
    protected $isInit = false;
170
171
    /**
172
     * @var bool
173
     */
174
    protected $isDataLoaded = false;
175
176
    /**
177
     * @var bool
178
     */
179
    protected $isRendered = false;
180
181
    /**
182
     * @var string
183
     */
184
    protected $forceRenderer;
185
186
    /**
187
     * @var Renderer\AbstractRenderer
188
     */
189
    private $rendererService;
190
191
    /**
192
     * @var array
193
     */
194
    private $specialMethods = [
195
        'filterSelectOptions',
196
        'rendererParameter',
197
        'replaceValues',
198
        'select',
199
        'sortDefault',
200
    ];
201
202
    /**
203
     * @var ServiceLocatorInterface
204
     */
205
    protected $serviceLocator = null;
206
207
    /**
208
     * Init method is called automatically with the service creation.
209
     */
210
    public function init()
211
    {
212
        if ($this->getCache() === null) {
213
            $options = $this->getOptions();
214
            $this->setCache(Cache\StorageFactory::factory($options['cache']));
215
        }
216
217
        $this->isInit = true;
218
    }
219
220
    /**
221
     * @return bool
222
     */
223
    public function isInit()
224
    {
225
        return (bool) $this->isInit;
226
    }
227
228
    /**
229
     * Set the options from config.
230
     *
231
     * @param array $config
232
     */
233
    public function setOptions(array $config)
234
    {
235
        $this->options = $config;
236
    }
237
238
    /**
239
     * Get the config options.
240
     *
241
     * @return array
242
     */
243
    public function getOptions()
244
    {
245
        return $this->options;
246
    }
247
248
    /**
249
     * Set the grid id.
250
     *
251
     * @param string $id
252
     */
253
    public function setId($id = null)
254
    {
255
        if ($id !== null) {
256
            $id = preg_replace("/[^a-z0-9_\\\d]/i", '_', $id);
257
258
            $this->id = (string) $id;
259
        }
260
    }
261
262
    /**
263
     * Get the grid id.
264
     *
265
     * @return string
266
     */
267
    public function getId()
268
    {
269
        if (null === $this->id) {
270
            $this->id = 'defaultGrid';
271
        }
272
273
        return $this->id;
274
    }
275
276
    /**
277
     * Set the session.
278
     *
279
     * @param \Zend\Session\Container $session
280
     */
281
    public function setSession(SessionContainer $session)
282
    {
283
        $this->session = $session;
284
    }
285
286
    /**
287
     * Get session container.
288
     *
289
     * Instantiate session container if none currently exists
290
     *
291
     * @return SessionContainer
292
     */
293
    public function getSession()
294
    {
295
        if (null === $this->session) {
296
            // Using fully qualified name, to ensure polyfill class alias is used
297
            $this->session = new SessionContainer($this->getId());
298
        }
299
300
        return $this->session;
301
    }
302
303
    /**
304
     * @param Cache\Storage\StorageInterface $cache
305
     */
306
    public function setCache(Cache\Storage\StorageInterface $cache)
307
    {
308
        $this->cache = $cache;
309
    }
310
311
    /**
312
     * @return Cache\Storage\StorageInterface
313
     */
314
    public function getCache()
315
    {
316
        return $this->cache;
317
    }
318
319
    /**
320
     * Set the cache id.
321
     *
322
     * @param string $id
323
     */
324
    public function setCacheId($id)
325
    {
326
        $this->cacheId = (string) $id;
327
    }
328
329
    /**
330
     * Get the cache id.
331
     *
332
     * @return string
333
     */
334
    public function getCacheId()
335
    {
336
        if (null === $this->cacheId) {
337
            $this->cacheId = md5($this->getSession()
338
                ->getManager()
339
                ->getId() . '_' . $this->getId());
340
        }
341
342
        return $this->cacheId;
343
    }
344
345
    /**
346
     * @param MvcEvent $mvcEvent
347
     */
348
    public function setMvcEvent(MvcEvent $mvcEvent)
349
    {
350
        $this->mvcEvent = $mvcEvent;
351
        $this->request  = $mvcEvent->getRequest();
352
    }
353
354
    /**
355
     * @return MvcEvent
356
     */
357
    public function getMvcEvent()
358
    {
359
        return $this->mvcEvent;
360
    }
361
362
    /**
363
     * @return HttpRequest
364
     */
365
    public function getRequest()
366
    {
367
        return $this->request;
368
    }
369
370
    /**
371
     * Set the translator.
372
     *
373
     * @param Translator $translator
374
     *
375
     * @throws \InvalidArgumentException
376
     */
377 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...
378
    {
379
        if (!$translator instanceof Translator && !$translator instanceof \Zend\I18n\Translator\TranslatorInterface) {
380
            throw new \InvalidArgumentException('Translator must be an instanceof "Zend\I18n\Translator\Translator" or "Zend\I18n\Translator\TranslatorInterface"');
381
        }
382
383
        $this->translator = $translator;
384
    }
385
386
    /**
387
     * @return Translator
388
     */
389
    public function getTranslator()
390
    {
391
        return $this->translator;
392
    }
393
394
    /**
395
     * @return bool
396
     */
397
    public function hasTranslator()
398
    {
399
        if ($this->translator !== null) {
400
            return true;
401
        }
402
403
        return false;
404
    }
405
406
    /**
407
     * @param \Zend\Router\RouteStackInterface $router
408
     */
409
    public function setRouter(RouteStackInterface $router)
410
    {
411
        $this->router = $router;
412
    }
413
414
    /**
415
     * @return RouteStackInterface
416
     */
417
    public function getRouter()
418
    {
419
        return $this->router;
420
    }
421
422
    /**
423
     * @return bool
424
     */
425
    public function hasRouter()
426
    {
427
        return !is_null($this->router);
428
    }
429
430
    /**
431
     * Set the data source.
432
     *
433
     * @param mixed $data
434
     *
435
     * @throws \Exception
436
     */
437
    public function setDataSource($data)
438
    {
439
        if ($data instanceof DataSource\DataSourceInterface) {
440
            $this->dataSource = $data;
441
        } elseif (is_array($data)) {
442
            $this->dataSource = new DataSource\PhpArray($data);
443
        } elseif ($data instanceof QueryBuilder) {
444
            $this->dataSource = new DataSource\Doctrine2($data);
445
        } elseif ($data instanceof ZendSelect) {
446
            $args = func_get_args();
447
            if (count($args) === 1 || (!$args[1] instanceof \Zend\Db\Adapter\Adapter && !$args[1] instanceof \Zend\Db\Sql\Sql)) {
448
                throw new \InvalidArgumentException('For "Zend\Db\Sql\Select" also a "Zend\Db\Adapter\Sql" or "Zend\Db\Sql\Sql" is needed.');
449
            }
450
            $this->dataSource = new DataSource\ZendSelect($data);
451
            $this->dataSource->setAdapter($args[1]);
452
        } elseif ($data instanceof Collection) {
453
            $args = func_get_args();
454
            if (count($args) === 1 || !$args[1] instanceof \Doctrine\ORM\EntityManager) {
455
                throw new \InvalidArgumentException('If providing a Collection, also the Doctrine\ORM\EntityManager is needed as a second parameter');
456
            }
457
            $this->dataSource = new DataSource\Doctrine2Collection($data);
458
            $this->dataSource->setEntityManager($args[1]);
459
        } else {
460
            throw new \InvalidArgumentException('$data must implement the interface ZfcDatagrid\DataSource\DataSourceInterface');
461
        }
462
    }
463
464
    /**
465
     * @return \ZfcDatagrid\DataSource\DataSourceInterface
466
     */
467
    public function getDataSource()
468
    {
469
        return $this->dataSource;
470
    }
471
472
    /**
473
     * Datasource defined?
474
     *
475
     * @return bool
476
     */
477
    public function hasDataSource()
478
    {
479
        if ($this->dataSource !== null) {
480
            return true;
481
        }
482
483
        return false;
484
    }
485
486
    /**
487
     * Set default items per page (-1 for unlimited).
488
     *
489
     * @param int $count
490
     */
491
    public function setDefaultItemsPerPage($count = 25)
492
    {
493
        $this->defaulItemsPerPage = (int) $count;
494
    }
495
496
    /**
497
     * @return int
498
     */
499
    public function getDefaultItemsPerPage()
500
    {
501
        return (int) $this->defaulItemsPerPage;
502
    }
503
504
    /**
505
     * Set the title.
506
     *
507
     * @param string $title
508
     */
509
    public function setTitle($title)
510
    {
511
        $this->title = (string) $title;
512
    }
513
514
    /**
515
     * @return string
516
     */
517
    public function getTitle()
518
    {
519
        return $this->title;
520
    }
521
522
    /**
523
     * Add a external parameter.
524
     *
525
     * @param string $name
526
     * @param mixed  $value
527
     */
528
    public function addParameter($name, $value)
529
    {
530
        $this->parameters[$name] = $value;
531
    }
532
533
    /**
534
     * These parameters are handled to the view + over all grid actions.
535
     *
536
     * @param array $parameters
537
     */
538
    public function setParameters(array $parameters)
539
    {
540
        $this->parameters = $parameters;
541
    }
542
543
    /**
544
     * @return array
545
     */
546
    public function getParameters()
547
    {
548
        return $this->parameters;
549
    }
550
551
    /**
552
     * Has parameters?
553
     *
554
     * @return bool
555
     */
556
    public function hasParameters()
557
    {
558
        return (bool) $this->getParameters();
559
    }
560
561
    /**
562
     * Set the base url.
563
     *
564
     * @param string $url
565
     */
566
    public function setUrl($url)
567
    {
568
        $this->url = $url;
569
    }
570
571
    /**
572
     * @return string
573
     */
574
    public function getUrl()
575
    {
576
        return $this->url;
577
    }
578
579
    /**
580
     * Set the export renderers (overwrite the config).
581
     *
582
     * @param array $renderers
583
     */
584
    public function setExportRenderers(array $renderers = [])
585
    {
586
        $this->exportRenderers = $renderers;
587
    }
588
589
    /**
590
     * Get the export renderers.
591
     *
592
     * @return array
593
     */
594
    public function getExportRenderers()
595
    {
596
        if (null === $this->exportRenderers) {
597
            $options               = $this->getOptions();
598
            $this->exportRenderers = $options['settings']['export']['formats'];
599
        }
600
601
        return $this->exportRenderers;
602
    }
603
604
    /**
605
     * Create a column from array instanceof.
606
     *
607
     * @param array $config
608
     *
609
     * @return Column\AbstractColumn
610
     */
611
    private function createColumn($config)
612
    {
613
        if ($config instanceof Column\AbstractColumn) {
614
            return $config;
615
        }
616
617
        if (!is_array($config) && !$config instanceof Column\AbstractColumn) {
618
            throw new \InvalidArgumentException('createColumn() supports only a config array or instanceof Column\AbstractColumn as a parameter');
619
        }
620
621
        $colType = isset($config['colType']) ? $config['colType'] : 'Select';
622
        if (class_exists($colType, true)) {
623
            $class = $colType;
624
        } elseif (class_exists('ZfcDatagrid\\Column\\' . $colType, true)) {
625
            $class = 'ZfcDatagrid\\Column\\' . $colType;
626
        } else {
627
            throw new \InvalidArgumentException(sprintf('Column type: "%s" not found!', $colType));
628
        }
629
630
        if ('ZfcDatagrid\\Column\\Select' == $class) {
631
            if (!isset($config['select']['column'])) {
632
                throw new \InvalidArgumentException('For "ZfcDatagrid\Column\Select" the option select[column] must be defined!');
633
            }
634
            $table = isset($config['select']['table']) ? $config['select']['table'] : null;
635
636
            $instance = new $class($config['select']['column'], $table);
637
        } else {
638
            $instance = new $class();
639
        }
640
641
        foreach ($config as $key => $value) {
642
            $method = 'set' . ucfirst($key);
643
            if (method_exists($instance, $method)) {
644
                if (in_array($key, $this->specialMethods)) {
645
                    if (!is_array($value)) {
646
                        $value = [
647
                            $value,
648
                        ];
649
                    }
650
                    call_user_func_array([
651
                        $instance,
652
                        $method,
653
                    ], $value);
654
                } else {
655
                    call_user_func([
656
                        $instance,
657
                        $method,
658
                    ], $value);
659
                }
660
            }
661
        }
662
663
        return $instance;
664
    }
665
666
    /**
667
     * Set multiple columns by array (willoverwrite all existing).
668
     *
669
     * @param array $columns
670
     */
671
    public function setColumns(array $columns)
672
    {
673
        $useColumns = [];
674
675
        foreach ($columns as $col) {
676
            $col                             = $this->createColumn($col);
677
            $useColumns[$col->getUniqueId()] = $col;
678
        }
679
680
        $this->columns = $useColumns;
681
    }
682
683
    /**
684
     * Add a column by array config or instanceof Column\AbstractColumn.
685
     *
686
     * @param array|Column\AbstractColumn $col
687
     */
688
    public function addColumn($col)
689
    {
690
        $col                                = $this->createColumn($col);
0 ignored issues
show
Bug introduced by
It seems like $col defined by $this->createColumn($col) on line 690 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...
691
        $this->columns[$col->getUniqueId()] = $col;
692
    }
693
694
    /**
695
     * @return \ZfcDatagrid\Column\AbstractColumn[]
696
     */
697
    public function getColumns()
698
    {
699
        return $this->columns;
700
    }
701
702
    /**
703
     * @param string $id
704
     *
705
     * @return Column\AbstractColumn null
706
     */
707
    public function getColumnByUniqueId($id)
708
    {
709
        if (isset($this->columns[$id])) {
710
            return $this->columns[$id];
711
        }
712
713
        return;
714
    }
715
716
    /**
717
     * @param Style\AbstractStyle $style
718
     */
719
    public function addRowStyle(Style\AbstractStyle $style)
720
    {
721
        $this->rowStyles[] = $style;
722
    }
723
724
    /**
725
     * @return Style\AbstractStyle[]
726
     */
727
    public function getRowStyles()
728
    {
729
        return $this->rowStyles;
730
    }
731
732
    /**
733
     * @return bool
734
     */
735
    public function hasRowStyles()
736
    {
737
        return (bool) $this->rowStyles;
738
    }
739
740
    /**
741
     * If disabled, the toolbar filter will not be shown to the user.
742
     *
743
     * @param bool $mode
744
     */
745
    public function setUserFilterDisabled($mode = true)
746
    {
747
        $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...
748
    }
749
750
    /**
751
     * @return bool
752
     */
753
    public function isUserFilterEnabled()
754
    {
755
        return (bool) $this->isUserFilterEnabled;
756
    }
757
758
    /**
759
     * Set the row click action - identity will be automatically appended!
760
     *
761
     * @param Column\Action\AbstractAction $action
762
     */
763
    public function setRowClickAction(Column\Action\AbstractAction $action)
764
    {
765
        $this->rowClickAction = $action;
766
    }
767
768
    public function getRowClickAction()
769
    {
770
        return $this->rowClickAction;
771
    }
772
773
    /**
774
     * @return bool
775
     */
776
    public function hasRowClickAction()
777
    {
778
        if (is_object($this->rowClickAction)) {
779
            return true;
780
        }
781
782
        return false;
783
    }
784
785
    /**
786
     * Add a mass action.
787
     *
788
     * @param Action\Mass $action
789
     */
790
    public function addMassAction(Action\Mass $action)
791
    {
792
        $this->massActions[] = $action;
793
    }
794
795
    /**
796
     * @return Action\Mass[]
797
     */
798
    public function getMassActions()
799
    {
800
        return $this->massActions;
801
    }
802
803
    /**
804
     * @return bool
805
     */
806
    public function hasMassAction()
807
    {
808
        return (bool) $this->massActions;
809
    }
810
811
    /**
812
     * Overwrite the render
813
     * F.x.
814
     * if you want to directly render a PDF.
815
     *
816
     * @param string $name
817
     */
818
    public function setRendererName($name = null)
819
    {
820
        $this->forceRenderer = $name;
821
    }
822
823
    /**
824
     * Get the current renderer name.
825
     *
826
     * @return string
827
     */
828
    public function getRendererName()
829
    {
830
        $options       = $this->getOptions();
831
        $parameterName = $options['generalParameterNames']['rendererType'];
832
833
        if ($this->forceRenderer !== null) {
834
            // A special renderer was given -> use is
835
            $rendererName = $this->forceRenderer;
836
        } else {
837
            // DEFAULT
838
            if ($this->getRequest() instanceof ConsoleRequest) {
839
                $rendererName = $options['settings']['default']['renderer']['console'];
840
            } else {
841
                $rendererName = $options['settings']['default']['renderer']['http'];
842
            }
843
        }
844
845
        // From request
846
        if ($this->getRequest() instanceof HttpRequest && $this->getRequest()->getQuery($parameterName) != '') {
847
            $rendererName = $this->getRequest()->getQuery($parameterName);
848
        }
849
850
        return $rendererName;
851
    }
852
853
    /**
854
     * Return the current renderer.
855
     *
856
     * @throws \Exception
857
     *
858
     * @return \ZfcDatagrid\Renderer\AbstractRenderer
859
     */
860
    public function getRenderer()
861
    {
862
        if (null === $this->renderer) {
863
            if (isset($this->rendererService)) {
864
                $renderer = $this->rendererService;
865
                if (!$renderer instanceof Renderer\AbstractRenderer) {
866
                    throw new \Exception('Renderer service must implement "ZfcDatagrid\Renderer\AbstractRenderer"');
867
                }
868
                $renderer->setOptions($this->getOptions());
869
                $renderer->setMvcEvent($this->getMvcEvent());
870
                if ($this->getToolbarTemplate() !== null) {
871
                    $renderer->setToolbarTemplate($this->getToolbarTemplate());
872
                }
873
                $renderer->setToolbarTemplateVariables($this->getToolbarTemplateVariables());
874
                $renderer->setViewModel($this->getViewModel());
875
                if ($this->hasTranslator()) {
876
                    $renderer->setTranslator($this->getTranslator());
877
                }
878
                $renderer->setTitle($this->getTitle());
879
                $renderer->setColumns($this->getColumns());
880
                $renderer->setRowStyles($this->getRowStyles());
881
                $renderer->setCache($this->getCache());
882
                $renderer->setCacheId($this->getCacheId());
883
884
                $this->renderer = $renderer;
885
            } else {
886
                throw new \Exception(sprintf('Renderer service was not found, please register it: "zfcDatagrid.renderer.%s"', $this->getRendererName()));
887
            }
888
        }
889
890
        return $this->renderer;
891
    }
892
893
    /**
894
     * @return bool
895
     */
896
    public function isDataLoaded()
897
    {
898
        return (bool) $this->isDataLoaded;
899
    }
900
901
    /**
902
     * Load the data.
903
     */
904
    public function loadData()
905
    {
906
        if (true === $this->isDataLoaded) {
907
            return true;
908
        }
909
910
        if ($this->isInit() !== true) {
911
            throw new \Exception('The init() method has to be called, before you can call loadData()!');
912
        }
913
914
        if ($this->hasDataSource() === false) {
915
            throw new \Exception('No datasource defined! Please call "setDataSource()" first"');
916
        }
917
918
        /**
919
         * Apply cache.
920
         */
921
        $renderer = $this->getRenderer();
922
923
        /*
924
         * Step 1) Apply needed columns + filters + sort
925
         * - from Request (HTML View) -> and save in cache for export
926
         * - or from cache (Export PDF / Excel) -> same view like HTML (without LIMIT/Pagination)
927
         */
928
        {
929
            /*
930
             * Step 1.1) Only select needed columns (performance)
931
             */
932
            $this->getDataSource()->setColumns($this->getColumns());
933
934
            /*
935
             * Step 1.2) Sorting
936
             */
937
            foreach ($renderer->getSortConditions() as $condition) {
938
                $this->getDataSource()->addSortCondition($condition['column'], $condition['sortDirection']);
939
            }
940
941
            /*
942
             * Step 1.3) Filtering
943
             */
944
            foreach ($renderer->getFilters() as $filter) {
945
                $this->getDataSource()->addFilter($filter);
946
            }
947
        }
948
949
        /*
950
         * Step 2) Load the data (Paginator)
951
         */
952
        {
953
            $this->getDataSource()->execute();
954
            $paginatorAdapter = $this->getDataSource()->getPaginatorAdapter();
955
956
            \Zend\Paginator\Paginator::setDefaultScrollingStyle('Sliding');
957
958
            $this->paginator = new Paginator($paginatorAdapter);
959
            $this->paginator->setCurrentPageNumber($renderer->getCurrentPageNumber());
960
            $this->paginator->setItemCountPerPage($renderer->getItemsPerPage($this->getDefaultItemsPerPage()));
961
962
            /* @var $currentItems \ArrayIterator */
963
            $data = $this->paginator->getCurrentItems();
964
            if (!is_array($data)) {
965
                if ($data instanceof \Zend\Db\ResultSet\ResultSet) {
966
                    $data = $data->toArray();
967
                } elseif ($data instanceof ArrayIterator) {
968
                    $data = $data->getArrayCopy();
969
                } else {
970
                    if (is_object($data)) {
971
                        $add = get_class($data);
972
                    } else {
973
                        $add = '[no object]';
974
                    }
975
                    throw new \Exception(
976
                        sprintf('The paginator returned an unknown result: %s (allowed: \ArrayIterator or a plain php array)', $add)
977
                    );
978
                }
979
            }
980
        }
981
982
        /*
983
         * check if the export is enabled
984
         * Save cache
985
         */
986
        if ($this->getOptions()['settings']['export']['enabled'] && $renderer->isExport() === false) {
987
            $cacheData = [
988
                'sortConditions' => $renderer->getSortConditions(),
989
                'filters'        => $renderer->getFilters(),
990
                'currentPage'    => $this->getPaginator()->getCurrentPageNumber(),
991
            ];
992
            $success = $this->getCache()->setItem($this->getCacheId(), $cacheData);
993
            if ($success !== true) {
994
                /** @var \Zend\Cache\Storage\Adapter\FilesystemOptions $options */
995
                $options = $this->getCache()->getOptions();
996
                throw new \Exception(
997
                    sprintf(
998
                        'Could not save the datagrid cache. Does the directory "%s" exists and is writeable? CacheId: %s',
999
                        $options->getCacheDir(),
1000
                        $this->getCacheId()
1001
                    )
1002
                );
1003
            }
1004
        }
1005
1006
        /*
1007
         * Step 3) Format the data - Translate - Replace - Date / time / datetime - Numbers - ...
1008
         */
1009
        $prepareData = new PrepareData($data, $this->getColumns());
1010
        if ($this->getRouter() instanceof RouteStackInterface) {
1011
            $prepareData->setRouter($this->getRouter());
1012
        }
1013
1014
        $prepareData->setRendererName($this->getRendererName());
1015
        if ($this->hasTranslator()) {
1016
            $prepareData->setTranslator($this->getTranslator());
1017
        }
1018
        $prepareData->prepare();
1019
        $this->preparedData = $prepareData->getData();
1020
1021
        $this->isDataLoaded = true;
1022
    }
1023
1024
    /**
1025
     * Render the grid.
1026
     */
1027
    public function render()
1028
    {
1029
        if ($this->isDataLoaded() === false) {
1030
            $this->loadData();
1031
        }
1032
1033
        /**
1034
         * Step 4) Render the data to the defined output format (HTML, PDF...)
1035
         * - Styling the values based on column (and value).
1036
         */
1037
        $renderer = $this->getRenderer();
1038
        $renderer->setTitle($this->getTitle());
1039
        $renderer->setPaginator($this->getPaginator());
1040
        $renderer->setData($this->getPreparedData());
1041
        $renderer->prepareViewModel($this);
1042
1043
        $this->response = $renderer->execute();
1044
1045
        $this->isRendered = true;
1046
    }
1047
1048
    /**
1049
     * Is already rendered?
1050
     *
1051
     * @return bool
1052
     */
1053
    public function isRendered()
1054
    {
1055
        return (bool) $this->isRendered;
1056
    }
1057
1058
    /**
1059
     * @throws \Exception
1060
     *
1061
     * @return Paginator
1062
     */
1063
    public function getPaginator()
1064
    {
1065
        if (null === $this->paginator) {
1066
            throw new \Exception('Paginator is only available after calling "loadData()"');
1067
        }
1068
1069
        return $this->paginator;
1070
    }
1071
1072
    /**
1073
     * @return array
1074
     */
1075
    private function getPreparedData()
1076
    {
1077
        return $this->preparedData;
1078
    }
1079
1080
    /**
1081
     * Set the toolbar view template.
1082
     *
1083
     * @param string $name
1084
     */
1085
    public function setToolbarTemplate($name)
1086
    {
1087
        $this->toolbarTemplate = (string) $name;
1088
    }
1089
1090
    /**
1091
     * Get the toolbar template name
1092
     * Return null if nothing custom set.
1093
     *
1094
     * @return string|null
1095
     */
1096
    public function getToolbarTemplate()
1097
    {
1098
        return $this->toolbarTemplate;
1099
    }
1100
1101
    /**
1102
     * Set the toolbar view template variables.
1103
     *
1104
     * @param array $variables
1105
     */
1106
    public function setToolbarTemplateVariables(array $variables)
1107
    {
1108
        $this->toolbarTemplateVariables = $variables;
1109
    }
1110
1111
    /**
1112
     * Get the toolbar template variables.
1113
     *
1114
     * @return array
1115
     */
1116
    public function getToolbarTemplateVariables()
1117
    {
1118
        return $this->toolbarTemplateVariables;
1119
    }
1120
1121
    /**
1122
     * Set a custom ViewModel...generally NOT necessary!
1123
     *
1124
     * @param ViewModel $viewModel
1125
     *
1126
     * @throws \Exception
1127
     */
1128
    public function setViewModel(ViewModel $viewModel)
1129
    {
1130
        if ($this->viewModel !== null) {
1131
            throw new \Exception('A viewModel is already set. Did you already called $grid->render() or $grid->getViewModel() before?');
1132
        }
1133
1134
        $this->viewModel = $viewModel;
1135
    }
1136
1137
    /**
1138
     * @return ViewModel
1139
     */
1140
    public function getViewModel()
1141
    {
1142
        if (null === $this->viewModel) {
1143
            $this->viewModel = new ViewModel();
1144
        }
1145
1146
        return $this->viewModel;
1147
    }
1148
1149
    /**
1150
     * @return \Zend\Stdlib\ResponseInterface|\Zend\Http\Response\Stream|\Zend\View\Model\ViewModel
1151
     */
1152
    public function getResponse()
1153
    {
1154
        if (!$this->isRendered()) {
1155
            $this->render();
1156
        }
1157
1158
        return $this->response;
1159
    }
1160
1161
    /**
1162
     * Is this a HTML "init" response?
1163
     * YES: loading the HTML for the grid
1164
     * NO: AJAX loading OR it's an export.
1165
     *
1166
     * @return bool
1167
     */
1168
    public function isHtmlInitReponse()
1169
    {
1170
        if (!$this->getResponse() instanceof JsonModel && !$this->getResponse() instanceof ResponseInterface) {
1171
            return true;
1172
        }
1173
1174
        return false;
1175
    }
1176
1177
    /**
1178
     * @param Renderer\AbstractRenderer $rendererService
1179
     *
1180
     * @return self
1181
     */
1182
    public function setRendererService(Renderer\AbstractRenderer $rendererService)
1183
    {
1184
        $this->rendererService = $rendererService;
1185
1186
        return $this;
1187
    }
1188
1189
    /**
1190
     * Set service locator.
1191
     *
1192
     * @param ContainerInterface $serviceLocator
1193
     *
1194
     * @return mixed
1195
     */
1196
    public function setServiceLocator(ContainerInterface $serviceLocator)
1197
    {
1198
        $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...
1199
1200
        return $this;
1201
    }
1202
1203
    /**
1204
     * Get service locator.
1205
     *
1206
     * @return ContainerInterface
1207
     */
1208
    public function getServiceLocator()
1209
    {
1210
        return $this->serviceLocator;
1211
    }
1212
}
1213