Datagrid   F
last analyzed

Complexity

Total Complexity 134

Size/Duplication

Total Lines 1157
Duplicated Lines 0.69 %

Coupling/Cohesion

Components 5
Dependencies 16

Importance

Changes 0
Metric Value
wmc 134
lcom 5
cbo 16
dl 8
loc 1157
rs 0.6314
c 0
b 0
f 0

69 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 9 2
A isInit() 0 4 1
A setOptions() 0 4 1
A getOptions() 0 4 1
A setId() 0 8 2
A getId() 0 8 2
A setSession() 0 4 1
A getSession() 0 9 2
A setCache() 0 4 1
A getCache() 0 4 1
A setCacheId() 0 4 1
A getCacheId() 0 10 2
A setMvcEvent() 0 5 1
A getMvcEvent() 0 4 1
A getRequest() 0 4 1
A setTranslator() 8 8 3
A getTranslator() 0 4 1
A hasTranslator() 0 8 2
C setDataSource() 0 26 11
A getDataSource() 0 4 1
A hasDataSource() 0 8 2
A setDefaultItemsPerPage() 0 4 1
A getDefaultItemsPerPage() 0 4 1
A setTitle() 0 4 1
A getTitle() 0 4 1
A addParameter() 0 4 1
A setParameters() 0 4 1
A getParameters() 0 4 1
A hasParameters() 0 4 1
A setUrl() 0 4 1
A getUrl() 0 4 1
A setExportRenderers() 0 4 1
A getExportRenderers() 0 9 2
C createColumn() 0 54 14
A setColumns() 0 11 2
A addColumn() 0 5 1
A getColumns() 0 4 1
A getColumnByUniqueId() 0 8 2
A addRowStyle() 0 4 1
A getRowStyles() 0 4 1
A hasRowStyles() 0 4 1
A setUserFilterDisabled() 0 4 1
A isUserFilterEnabled() 0 4 1
A setRowClickAction() 0 4 1
A getRowClickAction() 0 4 1
A hasRowClickAction() 0 8 2
A addMassAction() 0 4 1
A getMassActions() 0 4 1
A hasMassAction() 0 4 1
A setRendererName() 0 4 1
B getRendererName() 0 24 5
B getRenderer() 0 32 6
A isDataLoaded() 0 4 1
D loadData() 0 115 14
A render() 0 20 2
A isRendered() 0 4 1
A getPaginator() 0 8 2
A getPreparedData() 0 4 1
A setToolbarTemplate() 0 4 1
A getToolbarTemplate() 0 4 1
A setToolbarTemplateVariables() 0 4 1
A getToolbarTemplateVariables() 0 4 1
A setViewModel() 0 8 2
A getViewModel() 0 8 2
A getResponse() 0 8 2
A isHtmlInitReponse() 0 8 3
A setRendererService() 0 6 1
A setServiceLocator() 0 6 1
A getServiceLocator() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Datagrid often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Datagrid, and based on these observations, apply Extract Interface, too.

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