Completed
Push — feature/mvc ( d2c4d4 )
by Martin
46:58 queued 31:56
created

Datagrid::addMassAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

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