Completed
Push — feature/fixes ( d22b4f...d7e727 )
by Martin
46:54 queued 32:48
created

Datagrid::setColumns()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 11
rs 9.4285
cc 2
eloc 6
nc 2
nop 1
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\ServiceManager\ServiceLocatorInterface;
16
use Zend\Session\Container as SessionContainer;
17
use Zend\Stdlib\ResponseInterface;
18
use Zend\View\Model\JsonModel;
19
use Zend\View\Model\ViewModel;
20
use ZfcDatagrid\Column\Style;
21
22
class Datagrid
23
{
24
    /**
25
     *
26
     * @var array
27
     */
28
    protected $options = [];
29
30
    /**
31
     *
32
     * @var SessionContainer
33
     */
34
    protected $session;
35
36
    /**
37
     *
38
     * @var Cache\Storage\StorageInterface
39
     */
40
    protected $cache;
41
42
    /**
43
     *
44
     * @var string
45
     */
46
    protected $cacheId;
47
48
    /**
49
     *
50
     * @var MvcEvent
51
     */
52
    protected $mvcEvent;
53
54
    /**
55
     *
56
     * @var array
57
     */
58
    protected $parameters = [];
59
60
    /**
61
     *
62
     * @var mixed
63
     */
64
    protected $url;
65
66
    /**
67
     *
68
     * @var HttpRequest
69
     */
70
    protected $request;
71
72
    /**
73
     * View or Response
74
     *
75
     * @var \Zend\Http\Response\Stream|\Zend\View\Model\ViewModel
76
     */
77
    protected $response;
78
79
    /**
80
     *
81
     * @var Renderer\AbstractRenderer
82
     */
83
    private $renderer;
84
85
    /**
86
     *
87
     * @var Translator
88
     */
89
    protected $translator;
90
91
    /**
92
     *
93
     * @var string
94
     */
95
    protected $id;
96
97
    /**
98
     * The grid title
99
     *
100
     * @var string
101
     */
102
    protected $title = '';
103
104
    /**
105
     *
106
     * @var DataSource\DataSourceInterface
107
     */
108
    protected $dataSource = null;
109
110
    /**
111
     *
112
     * @var integer
113
     */
114
    protected $defaulItemsPerPage = 25;
115
116
    /**
117
     *
118
     * @var array
119
     */
120
    protected $columns = [];
121
122
    /**
123
     *
124
     * @var Style\AbstractStyle[]
125
     */
126
    protected $rowStyles = [];
127
128
    /**
129
     *
130
     * @var Column\Action\AbstractAction
131
     */
132
    protected $rowClickAction;
133
134
    /**
135
     *
136
     * @var Action\Mass
137
     */
138
    protected $massActions = [];
139
140
    /**
141
     * The prepared data
142
     *
143
     * @var array
144
     */
145
    protected $preparedData = [];
146
147
    /**
148
     *
149
     * @var array
150
     */
151
    protected $isUserFilterEnabled = true;
152
153
    /**
154
     *
155
     * @var Paginator
156
     */
157
    protected $paginator = null;
158
159
    /**
160
     *
161
     * @var array
162
     */
163
    protected $exportRenderers;
164
165
    /**
166
     * @var string|null
167
     */
168
    protected $toolbarTemplate;
169
170
    /**
171
     *
172
     * @var array
173
     */
174
    protected $toolbarTemplateVariables = [];
175
176
    /**
177
     *
178
     * @var ViewModel
179
     */
180
    protected $viewModel;
181
182
    /**
183
     *
184
     * @var boolean
185
     */
186
    protected $isInit = false;
187
188
    /**
189
     *
190
     * @var boolean
191
     */
192
    protected $isDataLoaded = false;
193
194
    /**
195
     *
196
     * @var boolean
197
     */
198
    protected $isRendered = false;
199
200
    /**
201
     *
202
     * @var string
203
     */
204
    protected $forceRenderer;
205
206
    /**
207
     *
208
     * @var Renderer\AbstractRenderer
209
     */
210
    private $rendererService;
211
212
    /**
213
     * @var array
214
     */
215
    private $specialMethods = [
216
        'filterSelectOptions',
217
        'rendererParameter',
218
        'replaceValues',
219
        'select',
220
        'sortDefault',
221
    ];
222
223
    /**
224
     * @var ServiceLocatorInterface
225
     */
226
    protected $serviceLocator = null;
227
228
    /**
229
     * Init method is called automatically with the service creation
230
     */
231
    public function init()
232
    {
233
        if ($this->getCache() === null) {
234
            $options = $this->getOptions();
235
            $this->setCache(Cache\StorageFactory::factory($options['cache']));
236
        }
237
238
        $this->isInit = true;
239
    }
240
241
    /**
242
     *
243
     * @return boolean
244
     */
245
    public function isInit()
246
    {
247
        return (bool) $this->isInit;
248
    }
249
250
    /**
251
     * Set the options from config
252
     *
253
     * @param array $config
254
     */
255
    public function setOptions(array $config)
256
    {
257
        $this->options = $config;
258
    }
259
260
    /**
261
     * Get the config options
262
     *
263
     * @return array
264
     */
265
    public function getOptions()
266
    {
267
        return $this->options;
268
    }
269
270
    /**
271
     * Set the grid id
272
     *
273
     * @param string $id
274
     */
275
    public function setId($id = null)
276
    {
277
        if ($id !== null) {
278
            $id = preg_replace("/[^a-z0-9_\\\d]/i", '_', $id);
279
280
            $this->id = (string) $id;
281
        }
282
    }
283
284
    /**
285
     * Get the grid id
286
     *
287
     * @return string
288
     */
289
    public function getId()
290
    {
291
        if (null === $this->id) {
292
            $this->id = 'defaultGrid';
293
        }
294
295
        return $this->id;
296
    }
297
298
    /**
299
     * Set the session
300
     *
301
     * @param \Zend\Session\Container $session
302
     */
303
    public function setSession(SessionContainer $session)
304
    {
305
        $this->session = $session;
306
    }
307
308
    /**
309
     * Get session container
310
     *
311
     * Instantiate session container if none currently exists
312
     *
313
     * @return SessionContainer
314
     */
315
    public function getSession()
316
    {
317
        if (null === $this->session) {
318
            // Using fully qualified name, to ensure polyfill class alias is used
319
            $this->session = new SessionContainer($this->getId());
320
        }
321
322
        return $this->session;
323
    }
324
325
    /**
326
     * @param Cache\Storage\StorageInterface $cache
327
     */
328
    public function setCache(Cache\Storage\StorageInterface $cache)
329
    {
330
        $this->cache = $cache;
331
    }
332
333
    /**
334
     *
335
     * @return Cache\Storage\StorageInterface
336
     */
337
    public function getCache()
338
    {
339
        return $this->cache;
340
    }
341
342
    /**
343
     * Set the cache id
344
     *
345
     * @param string $id
346
     */
347
    public function setCacheId($id)
348
    {
349
        $this->cacheId = (string) $id;
350
    }
351
352
    /**
353
     * Get the cache id
354
     *
355
     * @return string
356
     */
357
    public function getCacheId()
358
    {
359
        if (null === $this->cacheId) {
360
            $this->cacheId = md5($this->getSession()
361
                ->getManager()
362
                ->getId() . '_' . $this->getId());
363
        }
364
365
        return $this->cacheId;
366
    }
367
368
    /**
369
     * @param MvcEvent $mvcEvent
370
     */
371
    public function setMvcEvent(MvcEvent $mvcEvent)
372
    {
373
        $this->mvcEvent = $mvcEvent;
374
        $this->request  = $mvcEvent->getRequest();
375
    }
376
377
    /**
378
     *
379
     * @return MvcEvent
380
     */
381
    public function getMvcEvent()
382
    {
383
        return $this->mvcEvent;
384
    }
385
386
    /**
387
     *
388
     * @return HttpRequest
389
     */
390
    public function getRequest()
391
    {
392
        return $this->request;
393
    }
394
395
    /**
396
     * Set the translator
397
     *
398
     * @param  Translator                $translator
399
     * @throws \InvalidArgumentException
400
     */
401 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...
402
    {
403
        if (! $translator instanceof Translator && ! $translator instanceof \Zend\I18n\Translator\TranslatorInterface) {
404
            throw new \InvalidArgumentException('Translator must be an instanceof "Zend\I18n\Translator\Translator" or "Zend\I18n\Translator\TranslatorInterface"');
405
        }
406
407
        $this->translator = $translator;
408
    }
409
410
    /**
411
     *
412
     * @return Translator
413
     */
414
    public function getTranslator()
415
    {
416
        return $this->translator;
417
    }
418
419
    /**
420
     *
421
     * @return boolean
422
     */
423
    public function hasTranslator()
424
    {
425
        if ($this->translator !== null) {
426
            return true;
427
        }
428
429
        return false;
430
    }
431
432
    /**
433
     * Set the data source
434
     *
435
     * @param  mixed      $data
436
     * @throws \Exception
437
     */
438
    public function setDataSource($data)
439
    {
440
        if ($data instanceof DataSource\DataSourceInterface) {
441
            $this->dataSource = $data;
442
        } elseif (is_array($data)) {
443
            $this->dataSource = new DataSource\PhpArray($data);
444
        } elseif ($data instanceof QueryBuilder) {
445
            $this->dataSource = new DataSource\Doctrine2($data);
446
        } elseif ($data instanceof ZendSelect) {
447
            $args = func_get_args();
448
            if (count($args) === 1 || (! $args[1] instanceof \Zend\Db\Adapter\Adapter && ! $args[1] instanceof \Zend\Db\Sql\Sql)) {
449
                throw new \InvalidArgumentException('For "Zend\Db\Sql\Select" also a "Zend\Db\Adapter\Sql" or "Zend\Db\Sql\Sql" is needed.');
450
            }
451
            $this->dataSource = new DataSource\ZendSelect($data);
452
            $this->dataSource->setAdapter($args[1]);
453
        } elseif ($data instanceof Collection) {
454
            $args = func_get_args();
455
            if (count($args) === 1 || ! $args[1] instanceof \Doctrine\ORM\EntityManager) {
456
                throw new \InvalidArgumentException('If providing a Collection, also the Doctrine\ORM\EntityManager is needed as a second parameter');
457
            }
458
            $this->dataSource = new DataSource\Doctrine2Collection($data);
459
            $this->dataSource->setEntityManager($args[1]);
460
        } else {
461
            throw new \InvalidArgumentException('$data must implement the interface ZfcDatagrid\DataSource\DataSourceInterface');
462
        }
463
    }
464
465
    /**
466
     *
467
     * @return \ZfcDatagrid\DataSource\DataSourceInterface
468
     */
469
    public function getDataSource()
470
    {
471
        return $this->dataSource;
472
    }
473
474
    /**
475
     * Datasource defined?
476
     *
477
     * @return boolean
478
     */
479
    public function hasDataSource()
480
    {
481
        if ($this->dataSource !== null) {
482
            return true;
483
        }
484
485
        return false;
486
    }
487
488
    /**
489
     * Set default items per page (-1 for unlimited)
490
     *
491
     * @param integer $count
492
     */
493
    public function setDefaultItemsPerPage($count = 25)
494
    {
495
        $this->defaulItemsPerPage = (int) $count;
496
    }
497
498
    /**
499
     *
500
     * @return integer
501
     */
502
    public function getDefaultItemsPerPage()
503
    {
504
        return (int) $this->defaulItemsPerPage;
505
    }
506
507
    /**
508
     * Set the title
509
     *
510
     * @param string $title
511
     */
512
    public function setTitle($title)
513
    {
514
        $this->title = (string) $title;
515
    }
516
517
    /**
518
     *
519
     * @return string
520
     */
521
    public function getTitle()
522
    {
523
        return $this->title;
524
    }
525
526
    /**
527
     * Add a external parameter
528
     *
529
     * @param string $name
530
     * @param mixed  $value
531
     */
532
    public function addParameter($name, $value)
533
    {
534
        $this->parameters[$name] = $value;
535
    }
536
537
    /**
538
     * These parameters are handled to the view + over all grid actions
539
     *
540
     * @param array $parameters
541
     */
542
    public function setParameters(array $parameters)
543
    {
544
        $this->parameters = $parameters;
545
    }
546
547
    /**
548
     *
549
     * @return array
550
     */
551
    public function getParameters()
552
    {
553
        return $this->parameters;
554
    }
555
556
    /**
557
     * Has parameters?
558
     *
559
     * @return boolean
560
     */
561
    public function hasParameters()
562
    {
563
        return (bool) $this->getParameters();
564
    }
565
566
    /**
567
     * Set the base url
568
     *
569
     * @param string $url
570
     */
571
    public function setUrl($url)
572
    {
573
        $this->url = $url;
574
    }
575
576
    /**
577
     *
578
     * @return string
579
     */
580
    public function getUrl()
581
    {
582
        return $this->url;
583
    }
584
585
    /**
586
     * Set the export renderers (overwrite the config)
587
     *
588
     * @param array $renderers
589
     */
590
    public function setExportRenderers(array $renderers = [])
591
    {
592
        $this->exportRenderers = $renderers;
593
    }
594
595
    /**
596
     * Get the export renderers
597
     *
598
     * @return array
599
     */
600
    public function getExportRenderers()
601
    {
602
        if (null === $this->exportRenderers) {
603
            $options               = $this->getOptions();
604
            $this->exportRenderers = $options['settings']['export']['formats'];
605
        }
606
607
        return $this->exportRenderers;
608
    }
609
610
    /**
611
     * Create a column from array instanceof
612
     *
613
     * @param array $config
614
     *
615
     * @return Column\AbstractColumn
616
     */
617
    private function createColumn($config)
618
    {
619
        if ($config instanceof Column\AbstractColumn) {
620
            return $config;
621
        }
622
623
        if (! is_array($config) && ! $config instanceof Column\AbstractColumn) {
624
            throw new \InvalidArgumentException('createColumn() supports only a config array or instanceof Column\AbstractColumn as a parameter');
625
        }
626
627
        $colType = isset($config['colType']) ? $config['colType'] : 'Select';
628
        if (class_exists($colType, true)) {
629
            $class = $colType;
630
        } elseif (class_exists('ZfcDatagrid\\Column\\' . $colType, true)) {
631
            $class = 'ZfcDatagrid\\Column\\' . $colType;
632
        } else {
633
            throw new \InvalidArgumentException(sprintf('Column type: "%s" not found!', $colType));
634
        }
635
636
        if ('ZfcDatagrid\\Column\\Select' == $class) {
637
            if (! isset($config['select']['column'])) {
638
                throw new \InvalidArgumentException('For "ZfcDatagrid\Column\Select" the option select[column] must be defined!');
639
            }
640
            $table = isset($config['select']['table']) ? $config['select']['table'] : null;
641
642
            $instance = new $class($config['select']['column'], $table);
643
        } else {
644
            $instance = new $class();
645
        }
646
647
        foreach ($config as $key => $value) {
648
            $method = 'set' . ucfirst($key);
649
            if (method_exists($instance, $method)) {
650
                if (in_array($key, $this->specialMethods)) {
651
                    if (! is_array($value)) {
652
                        $value = [
653
                            $value,
654
                        ];
655
                    }
656
                    call_user_func_array([
657
                        $instance,
658
                        $method,
659
                    ], $value);
660
                } else {
661
                    call_user_func([
662
                        $instance,
663
                        $method,
664
                    ], $value);
665
                }
666
            }
667
        }
668
669
        return $instance;
670
    }
671
672
    /**
673
     * Set multiple columns by array (willoverwrite all existing)
674
     *
675
     * @param array $columns
676
     */
677
    public function setColumns(array $columns)
678
    {
679
        $useColumns = [];
680
681
        foreach ($columns as $col) {
682
            $col                             = $this->createColumn($col);
683
            $useColumns[$col->getUniqueId()] = $col;
684
        }
685
686
        $this->columns = $useColumns;
687
    }
688
689
    /**
690
     * Add a column by array config or instanceof Column\AbstractColumn
691
     *
692
     * @param array|Column\AbstractColumn $col
693
     */
694
    public function addColumn($col)
695
    {
696
        $col                                = $this->createColumn($col);
0 ignored issues
show
Bug introduced by
It seems like $col defined by $this->createColumn($col) on line 696 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...
697
        $this->columns[$col->getUniqueId()] = $col;
698
    }
699
700
    /**
701
     *
702
     * @return \ZfcDatagrid\Column\AbstractColumn[]
703
     */
704
    public function getColumns()
705
    {
706
        return $this->columns;
707
    }
708
709
    /**
710
     *
711
     * @param  string                $id
712
     * @return Column\AbstractColumn null
713
     */
714
    public function getColumnByUniqueId($id)
715
    {
716
        if (isset($this->columns[$id])) {
717
            return $this->columns[$id];
718
        }
719
720
        return;
721
    }
722
723
    /**
724
     *
725
     * @param Style\AbstractStyle $style
726
     */
727
    public function addRowStyle(Style\AbstractStyle $style)
728
    {
729
        $this->rowStyles[] = $style;
730
    }
731
732
    /**
733
     *
734
     * @return Style\AbstractStyle[]
735
     */
736
    public function getRowStyles()
737
    {
738
        return $this->rowStyles;
739
    }
740
741
    /**
742
     *
743
     * @return boolean
744
     */
745
    public function hasRowStyles()
746
    {
747
        return (bool) $this->rowStyles;
748
    }
749
750
    /**
751
     * If disabled, the toolbar filter will not be shown to the user
752
     *
753
     * @param boolean $mode
754
     */
755
    public function setUserFilterDisabled($mode = true)
756
    {
757
        $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...
758
    }
759
760
    /**
761
     *
762
     * @return boolean
763
     */
764
    public function isUserFilterEnabled()
765
    {
766
        return (bool) $this->isUserFilterEnabled;
767
    }
768
769
    /**
770
     * Set the row click action - identity will be automatically appended!
771
     *
772
     * @param Column\Action\AbstractAction $action
773
     */
774
    public function setRowClickAction(Column\Action\AbstractAction $action)
775
    {
776
        $this->rowClickAction = $action;
777
    }
778
779
    /**
780
     *
781
     * @return null Column\Action\AbstractAction
782
     */
783
    public function getRowClickAction()
784
    {
785
        return $this->rowClickAction;
786
    }
787
788
    /**
789
     *
790
     * @return boolean
791
     */
792
    public function hasRowClickAction()
793
    {
794
        if (is_object($this->rowClickAction)) {
795
            return true;
796
        }
797
798
        return false;
799
    }
800
801
    /**
802
     * Add a mass action
803
     *
804
     * @param Action\Mass $action
805
     */
806
    public function addMassAction(Action\Mass $action)
807
    {
808
        $this->massActions[] = $action;
809
    }
810
811
    /**
812
     *
813
     * @return Action\Mass[]
814
     */
815
    public function getMassActions()
816
    {
817
        return $this->massActions;
818
    }
819
820
    /**
821
     *
822
     * @return boolean
823
     */
824
    public function hasMassAction()
825
    {
826
        return (bool) $this->massActions;
827
    }
828
829
    /**
830
     * Overwrite the render
831
     * F.x.
832
     * if you want to directly render a PDF
833
     *
834
     * @param string $name
835
     */
836
    public function setRendererName($name = null)
837
    {
838
        $this->forceRenderer = $name;
839
    }
840
841
    /**
842
     * Get the current renderer name
843
     *
844
     * @return string
845
     */
846
    public function getRendererName()
847
    {
848
        $options       = $this->getOptions();
849
        $parameterName = $options['generalParameterNames']['rendererType'];
850
851
        if ($this->forceRenderer !== null) {
852
            // A special renderer was given -> use is
853
            $rendererName = $this->forceRenderer;
854
        } else {
855
            // DEFAULT
856
            if ($this->getRequest() instanceof ConsoleRequest) {
857
                $rendererName = $options['settings']['default']['renderer']['console'];
858
            } else {
859
                $rendererName = $options['settings']['default']['renderer']['http'];
860
            }
861
        }
862
863
        // From request
864
        if ($this->getRequest() instanceof HttpRequest && $this->getRequest()->getQuery($parameterName) != '') {
865
            $rendererName = $this->getRequest()->getQuery($parameterName);
866
        }
867
868
        return $rendererName;
869
    }
870
871
    /**
872
     * Return the current renderer
873
     *
874
     * @throws \Exception
875
     * @return \ZfcDatagrid\Renderer\AbstractRenderer
876
     */
877
    public function getRenderer()
878
    {
879
        if (null === $this->renderer) {
880
            if (!isset($this->rendererService)) {
881
                $rendererName = 'zfcDatagrid.renderer.' . $this->getRendererName();
882
                $service      = $this->getServiceLocator()->has($rendererName);
0 ignored issues
show
Unused Code introduced by
$service is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
883
884
                if ($this->getServiceLocator()->has($rendererName) !== true) {
885
                    throw new \Exception(sprintf('Renderer service was not found, please register it: "zfcDatagrid.renderer.%s"', $this->getRendererName()));
886
                }
887
888
                $this->rendererService = $this->getServiceLocator()->get($rendererName);
889
            }
890
891
            $renderer = $this->rendererService;
892
            if (! $renderer instanceof Renderer\AbstractRenderer) {
893
                throw new \Exception('Renderer service must be an instanceof "ZfcDatagrid\Renderer\AbstractRenderer"');
894
            }
895
896
            $renderer->setOptions($this->getOptions());
897
            $renderer->setMvcEvent($this->getMvcEvent());
898
            if ($this->getToolbarTemplate() !== null) {
899
                $renderer->setToolbarTemplate($this->getToolbarTemplate());
900
            }
901
            $renderer->setToolbarTemplateVariables($this->getToolbarTemplateVariables());
902
            $renderer->setViewModel($this->getViewModel());
903
            if ($this->hasTranslator()) {
904
                $renderer->setTranslator($this->getTranslator());
905
            }
906
            $renderer->setTitle($this->getTitle());
907
            $renderer->setColumns($this->getColumns());
908
            $renderer->setRowStyles($this->getRowStyles());
909
            $renderer->setCache($this->getCache());
910
            $renderer->setCacheId($this->getCacheId());
911
912
            $this->renderer = $renderer;
913
        }
914
915
        return $this->renderer;
916
    }
917
918
    /**
919
     *
920
     * @return boolean
921
     */
922
    public function isDataLoaded()
923
    {
924
        return (bool) $this->isDataLoaded;
925
    }
926
927
    /**
928
     * Load the data
929
     */
930
    public function loadData()
931
    {
932
        if (true === $this->isDataLoaded) {
933
            return true;
934
        }
935
936
        if ($this->isInit() !== true) {
937
            throw new \Exception('The init() method has to be called, before you can call loadData()!');
938
        }
939
940
        if ($this->hasDataSource() === false) {
941
            throw new \Exception('No datasource defined! Please call "setDataSource()" first"');
942
        }
943
944
        /**
945
         * Apply cache
946
         */
947
        $renderer = $this->getRenderer();
948
949
        /**
950
         * Step 1) Apply needed columns + filters + sort
951
         * - from Request (HTML View) -> and save in cache for export
952
         * - or from cache (Export PDF / Excel) -> same view like HTML (without LIMIT/Pagination)
953
         */
954
        {
955
            /**
956
             * Step 1.1) Only select needed columns (performance)
957
             */
958
            $this->getDataSource()->setColumns($this->getColumns());
959
960
            /**
961
             * Step 1.2) Sorting
962
             */
963
            foreach ($renderer->getSortConditions() as $condition) {
964
                $this->getDataSource()->addSortCondition($condition['column'], $condition['sortDirection']);
965
            }
966
967
            /**
968
             * Step 1.3) Filtering
969
             */
970
            foreach ($renderer->getFilters() as $filter) {
971
                $this->getDataSource()->addFilter($filter);
972
            }
973
        }
974
975
        /*
976
         * Step 2) Load the data (Paginator)
977
         */
978
        {
979
            $this->getDataSource()->execute();
980
            $paginatorAdapter = $this->getDataSource()->getPaginatorAdapter();
981
982
            \Zend\Paginator\Paginator::setDefaultScrollingStyle('Sliding');
983
984
            $this->paginator = new Paginator($paginatorAdapter);
985
            $this->paginator->setCurrentPageNumber($renderer->getCurrentPageNumber());
986
            $this->paginator->setItemCountPerPage($renderer->getItemsPerPage($this->getDefaultItemsPerPage()));
987
988
            /* @var $currentItems \ArrayIterator */
989
            $data = $this->paginator->getCurrentItems();
990
            if (! is_array($data)) {
991
                if ($data instanceof \Zend\Db\ResultSet\ResultSet) {
992
                    $data = $data->toArray();
993
                } elseif ($data instanceof ArrayIterator) {
994
                    $data = $data->getArrayCopy();
995
                } else {
996
                    if (is_object($data)) {
997
                        $add = get_class($data);
998
                    } else {
999
                        $add = '[no object]';
1000
                    }
1001
                    throw new \Exception(
1002
                        sprintf('The paginator returned an unknown result: %s (allowed: \ArrayIterator or a plain php array)', $add)
1003
                    );
1004
                }
1005
            }
1006
        }
1007
1008
        /*
1009
         * check if the export is enabled
1010
         * Save cache
1011
         */
1012
        if ($this->getOptions()['settings']['export']['enabled'] && $renderer->isExport() === false) {
1013
            $cacheData = [
1014
                'sortConditions' => $renderer->getSortConditions(),
1015
                'filters'        => $renderer->getFilters(),
1016
                'currentPage'    => $this->getPaginator()->getCurrentPageNumber(),
1017
            ];
1018
            $success = $this->getCache()->setItem($this->getCacheId(), $cacheData);
1019
            if ($success !== true) {
1020
                /** @var \Zend\Cache\Storage\Adapter\FilesystemOptions $options */
1021
                $options = $this->getCache()->getOptions();
1022
                throw new \Exception(
1023
                    sprintf(
1024
                        'Could not save the datagrid cache. Does the directory "%s" exists and is writeable? CacheId: %s',
1025
                        $options->getCacheDir(),
1026
                        $this->getCacheId()
1027
                    )
1028
                );
1029
            }
1030
        }
1031
1032
        /*
1033
         * Step 3) Format the data - Translate - Replace - Date / time / datetime - Numbers - ...
1034
         */
1035
        $prepareData = new PrepareData($data, $this->getColumns());
1036
        $prepareData->setRendererName($this->getRendererName());
1037
        if ($this->hasTranslator()) {
1038
            $prepareData->setTranslator($this->getTranslator());
1039
        }
1040
        $prepareData->prepare();
1041
        $this->preparedData = $prepareData->getData();
1042
1043
        $this->isDataLoaded = true;
1044
    }
1045
1046
    /**
1047
     * Render the grid
1048
     */
1049
    public function render()
1050
    {
1051
        if ($this->isDataLoaded() === false) {
1052
            $this->loadData();
1053
        }
1054
1055
        /**
1056
         * Step 4) Render the data to the defined output format (HTML, PDF...)
1057
         * - Styling the values based on column (and value)
1058
         */
1059
        $renderer = $this->getRenderer();
1060
        $renderer->setTitle($this->getTitle());
1061
        $renderer->setPaginator($this->getPaginator());
1062
        $renderer->setData($this->getPreparedData());
1063
        $renderer->prepareViewModel($this);
1064
1065
        $this->response = $renderer->execute();
1066
1067
        $this->isRendered = true;
1068
    }
1069
1070
    /**
1071
     * Is already rendered?
1072
     *
1073
     * @return boolean
1074
     */
1075
    public function isRendered()
1076
    {
1077
        return (bool) $this->isRendered;
1078
    }
1079
1080
    /**
1081
     *
1082
     * @throws \Exception
1083
     * @return Paginator
1084
     */
1085
    public function getPaginator()
1086
    {
1087
        if (null === $this->paginator) {
1088
            throw new \Exception('Paginator is only available after calling "loadData()"');
1089
        }
1090
1091
        return $this->paginator;
1092
    }
1093
1094
    /**
1095
     *
1096
     * @return array
1097
     */
1098
    private function getPreparedData()
1099
    {
1100
        return $this->preparedData;
1101
    }
1102
1103
    /**
1104
     * Set the toolbar view template
1105
     *
1106
     * @param string $name
1107
     */
1108
    public function setToolbarTemplate($name)
1109
    {
1110
        $this->toolbarTemplate = (string) $name;
1111
    }
1112
1113
    /**
1114
     * Get the toolbar template name
1115
     * Return null if nothing custom set
1116
     *
1117
     * @return string|null
1118
     */
1119
    public function getToolbarTemplate()
1120
    {
1121
        return $this->toolbarTemplate;
1122
    }
1123
1124
    /**
1125
     * Set the toolbar view template variables
1126
     *
1127
     * @param array $variables
1128
     */
1129
    public function setToolbarTemplateVariables(array $variables)
1130
    {
1131
        $this->toolbarTemplateVariables = $variables;
1132
    }
1133
1134
    /**
1135
     * Get the toolbar template variables
1136
     *
1137
     * @return array
1138
     */
1139
    public function getToolbarTemplateVariables()
1140
    {
1141
        return $this->toolbarTemplateVariables;
1142
    }
1143
1144
    /**
1145
     * Set a custom ViewModel...generally NOT necessary!
1146
     *
1147
     * @param  ViewModel  $viewModel
1148
     * @throws \Exception
1149
     */
1150
    public function setViewModel(ViewModel $viewModel)
1151
    {
1152
        if ($this->viewModel !== null) {
1153
            throw new \Exception('A viewModel is already set. Did you already called $grid->render() or $grid->getViewModel() before?');
1154
        }
1155
1156
        $this->viewModel = $viewModel;
1157
    }
1158
1159
    /**
1160
     *
1161
     * @return ViewModel
1162
     */
1163
    public function getViewModel()
1164
    {
1165
        if (null === $this->viewModel) {
1166
            $this->viewModel = new ViewModel();
1167
        }
1168
1169
        return $this->viewModel;
1170
    }
1171
1172
    /**
1173
     *
1174
     * @return \Zend\Stdlib\ResponseInterface|\Zend\Http\Response\Stream|\Zend\View\Model\ViewModel
1175
     */
1176
    public function getResponse()
1177
    {
1178
        if (! $this->isRendered()) {
1179
            $this->render();
1180
        }
1181
1182
        return $this->response;
1183
    }
1184
1185
    /**
1186
     * Is this a HTML "init" response?
1187
     * YES: loading the HTML for the grid
1188
     * NO: AJAX loading OR it's an export
1189
     *
1190
     * @return boolean
1191
     */
1192
    public function isHtmlInitReponse()
1193
    {
1194
        if (! $this->getResponse() instanceof JsonModel && ! $this->getResponse() instanceof ResponseInterface) {
1195
            return true;
1196
        }
1197
1198
        return false;
1199
    }
1200
1201
    /**
1202
     * @param  Renderer\AbstractRenderer $rendererService
1203
     * @return self
1204
     */
1205
    public function setRendererService(Renderer\AbstractRenderer $rendererService)
1206
    {
1207
        $this->rendererService = $rendererService;
1208
1209
        return $this;
1210
    }
1211
1212
    /**
1213
     * Set service locator
1214
     *
1215
     * @param  ContainerInterface $serviceLocator
1216
     * @return mixed
1217
     */
1218
    public function setServiceLocator(ContainerInterface $serviceLocator)
1219
    {
1220
        $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...
1221
1222
        return $this;
1223
    }
1224
1225
    /**
1226
     * Get service locator
1227
     *
1228
     * @return ContainerInterface
1229
     */
1230
    public function getServiceLocator()
1231
    {
1232
        return $this->serviceLocator;
1233
    }
1234
}
1235