Completed
Pull Request — master (#230)
by Oliver
20:19 queued 05:21
created

Datagrid::setRendererService()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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