Completed
Pull Request — master (#360)
by Anton
05:20
created

Grid::getController()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * Bluz Framework Component
4
 *
5
 * @copyright Bluz PHP Team
6
 * @link https://github.com/bluzphp/framework
7
 */
8
9
/**
10
 * @namespace
11
 */
12
namespace Bluz\Grid;
13
14
use Bluz\Common\Helper;
15
use Bluz\Common\Options;
16
use Bluz\Proxy\Request;
17
use Bluz\Proxy\Router;
18
19
/**
20
 * Grid
21
 *
22
 * @package  Bluz\Grid
23
 * @author   Anton Shevchuk
24
 * @link     https://github.com/bluzphp/framework/wiki/Grid
25
 *
26
 * @method string filter($column, $filter, $value, $reset = true)
27
 * @method string first()
28
 * @method string last()
29
 * @method string limit($limit = 25)
30
 * @method string next()
31
 * @method string order($column, $order = null, $defaultOrder = Grid::ORDER_ASC, $reset = true)
32
 * @method string page($page = 1)
33
 * @method string pages()
34
 * @method string prev()
35
 * @method string reset()
36
 * @method string total()
37
 */
38
abstract class Grid
39
{
40
    use Options;
41
    use Helper;
42
43
    const ORDER_ASC = 'asc';
44
    const ORDER_DESC = 'desc';
45
46
    const FILTER_LIKE = 'like'; // like
47
    const FILTER_ENUM = 'enum'; // one from .., .., ..
48
    const FILTER_NUM = 'num'; // ==, !=, >, >=, <, <=
49
50
    const FILTER_EQ = 'eq'; // equal to ..
51
    const FILTER_NE = 'ne'; // not equal to ..
52
    const FILTER_GT = 'gt'; // greater than ..
53
    const FILTER_GE = 'ge'; // greater than .. or equal
54
    const FILTER_LT = 'lt'; // less than ..
55
    const FILTER_LE = 'le'; // less than .. or equal
56
57
    /**
58
     * @var Source\AbstractSource instance of Source
59
     */
60
    protected $adapter;
61
62
    /**
63
     * @var Data instance of Data
64
     */
65
    protected $data;
66
67
    /**
68
     * @var string unique identification of grid
69
     */
70
    protected $uid;
71
72
    /**
73
     * @var string unique prefix of grid
74
     */
75
    protected $prefix;
76
77
    /**
78
     * @var string location of Grid
79
     */
80
    protected $module;
81
82
    /**
83
     * @var string location of Grid
84
     */
85
    protected $controller;
86
87
    /**
88
     * @var array custom array params
89
     */
90
    protected $params = array();
91
92
    /**
93
     * @var integer start from first page
94
     */
95
    protected $page = 1;
96
97
    /**
98
     * @var integer limit per page
99
     */
100
    protected $limit = 25;
101
102
    /**
103
     * @var integer default value of page limit
104
     * @see Grid::$limit
105
     */
106
    protected $defaultLimit = 25;
107
108
    /**
109
     * List of orders
110
     *
111
     * Example
112
     *     'first' => 'ASC',
113
     *     'last' => 'ASC'
114
     *
115
     * @var array
116
     */
117
    protected $orders = array();
118
119
    /**
120
     * @var array default order
121
     * @see Grid::$orders
122
     */
123
    protected $defaultOrder;
124
125
    /**
126
     * @var array list of allow orders
127
     * @see Grid::$orders
128
     */
129
    protected $allowOrders = array();
130
131
    /**
132
     * @var array list of filters
133
     */
134
    protected $filters = array();
135
136
    /**
137
     * List of allow filters
138
     *
139
     * Example
140
     *     ['id', 'status' => ['active', 'disable']]
141
     *
142
     * @var array
143
     * @see Grid::$filters
144
     */
145
    protected $allowFilters = array();
146
147
    /**
148
     * List of aliases for columns in DB
149
     *
150
     * @var array
151
     */
152
    protected $aliases = array();
153
154
    /**
155
     * Grid constructor
156
     *
157
     * @param array $options
158
     */
159 33
    public function __construct($options = null)
160
    {
161 33
        if ($options) {
162
            $this->setOptions($options);
163
        }
164
165 33
        if ($this->uid) {
166 33
            $this->prefix = $this->getUid() . '-';
167
        } else {
168
            $this->prefix = '';
169
        }
170
171 33
        $this->init();
172
173 33
        $this->processRequest();
174
175
        // initial default helper path
176 33
        $this->addHelperPath(dirname(__FILE__) . '/Helper/');
177 33
    }
178
179
    /**
180
     * Initialize Grid
181
     *
182
     * @return Grid
183
     */
184
    abstract public function init();
185
186
    /**
187
     * Set source adapter
188
     *
189
     * @param Source\AbstractSource $adapter
190
     * @return void
191
     */
192 33
    public function setAdapter(Source\AbstractSource $adapter)
193
    {
194 33
        $this->adapter = $adapter;
195 33
    }
196
197
    /**
198
     * Get source adapter
199
     *
200
     * @return Source\AbstractSource
201
     * @throws GridException
202
     */
203 15
    public function getAdapter()
204
    {
205 15
        if (null == $this->adapter) {
206
            throw new GridException('Grid adapter is not initialized');
207
        }
208 15
        return $this->adapter;
209
    }
210
211
    /**
212
     * Get unique Grid Id
213
     *
214
     * @return string
215
     */
216 33
    public function getUid()
217
    {
218 33
        return $this->uid;
219
    }
220
221
    /**
222
     * Get prefix
223
     *
224
     * @return string
225
     */
226 1
    public function getPrefix()
227
    {
228 1
        return $this->prefix;
229
    }
230
231
    /**
232
     * Set module
233
     *
234
     * @param string $module
235
     * @return void
236
     */
237 1
    public function setModule($module)
238
    {
239 1
        $this->module = $module;
240 1
    }
241
242
    /**
243
     * Get module
244
     *
245
     * @return string
246
     */
247 11
    public function getModule()
248
    {
249 11
        return $this->module;
250
    }
251
252
    /**
253
     * Set controller
254
     *
255
     * @param  string $controller
256
     * @return void
257
     */
258 1
    public function setController($controller)
259
    {
260 1
        $this->controller = $controller;
261 1
    }
262
263
    /**
264
     * Get controller
265
     *
266
     * @return string
267
     */
268 11
    public function getController()
269
    {
270 11
        return $this->controller;
271
    }
272
273
    /**
274
     * Process request
275
     *
276
     * Example of request url
277
     * - http://domain.com/pages/grid/
278
     * - http://domain.com/pages/grid/page/2/
279
     * - http://domain.com/pages/grid/page/2/order-alias/desc/
280
     * - http://domain.com/pages/grid/page/2/order-created/desc/order-alias/asc/
281
     *
282
     * with prefix for support more than one grid on page
283
     * - http://domain.com/users/grid/users-page/2/users-order-created/desc/
284
     * - http://domain.com/users/grid/users-page/2/users-filter-status/active/
285
     *
286
     * hash support
287
     * - http://domain.com/pages/grid/#/page/2/order-created/desc/order-alias/asc/
288
     *
289
     * @return Grid
290
     */
291 33
    public function processRequest()
292
    {
293 33
        $this->module = Request::getModule();
294 33
        $this->controller = Request::getController();
295
296 33
        $page = Request::getParam($this->prefix . 'page', 1);
297 33
        $this->setPage($page);
298
299 33
        $limit = Request::getParam($this->prefix . 'limit', $this->limit);
300 33
        $this->setLimit($limit);
301
302 33
        foreach ($this->allowOrders as $column) {
303 33
            $order = Request::getParam($this->prefix . 'order-' . $column);
304 33
            if ($order) {
305 33
                $this->addOrder($column, $order);
306
            }
307
        }
308 33
        foreach ($this->allowFilters as $column) {
309 33
            $filter = Request::getParam($this->prefix . 'filter-' . $column);
310
311 33
            if ($filter) {
312 1
                if (strpos($filter, '-')) {
313 1
                    $filter = trim($filter, ' -');
314
315 1
                    while ($pos = strpos($filter, '-')) {
316 1
                        $filterType = substr($filter, 0, $pos);
317 1
                        $filter = substr($filter, $pos + 1);
318
319 1
                        if (strpos($filter, '-')) {
320
                            $filterValue = substr($filter, 0, strpos($filter, '-'));
321
                            $filter = substr($filter, strpos($filter, '-') + 1);
322
                        } else {
323 1
                            $filterValue = $filter;
324
                        }
325
326 1
                        $this->addFilter($column, $filterType, $filterValue);
327
                    }
328
329
                } else {
330 33
                    $this->addFilter($column, self::FILTER_EQ, $filter);
331
                }
332
            }
333
        }
334 33
        return $this;
335
    }
336
337
    /**
338
     * Process source
339
     *
340
     * @return self
341
     * @throws GridException
342
     */
343 15
    public function processSource()
344
    {
345 15
        if (null === $this->adapter) {
346
            throw new GridException("Grid Adapter is not initiated, please update method init() and try again");
347
        }
348
349
        try {
350 15
            $this->data = $this->getAdapter()->process($this->getSettings());
351
        } catch (\Exception $e) {
352
            throw new GridException("Grid Adapter can't process request: ". $e->getMessage());
353
        }
354
355 15
        return $this;
356
    }
357
358
    /**
359
     * Get data
360
     *
361
     * @return Data
362
     */
363 15
    public function getData()
364
    {
365 15
        if (!$this->data) {
366 15
            $this->processSource();
367
        }
368 15
        return $this->data;
369
    }
370
371
    /**
372
     * Get settings
373
     *
374
     * @return array
375
     */
376 15
    public function getSettings()
377
    {
378 15
        $settings = array();
379 15
        $settings['page'] = $this->getPage();
380 15
        $settings['limit'] = $this->getLimit();
381 15
        $settings['orders'] = $this->getOrders();
382 15
        $settings['filters'] = $this->getFilters();
383 15
        return $settings;
384
    }
385
386
    /**
387
     * Setup params
388
     *
389
     * @param  $params
390
     * @return void
391
     */
392
    public function setParams($params)
393
    {
394
        $this->params = $params;
395
    }
396
397
    /**
398
     * Return params prepared for url builder
399
     *
400
     * @param  array $rewrite
401
     * @return array
402
     */
403 11
    public function getParams(array $rewrite = [])
404
    {
405 11
        $params = $this->params;
406
407
        // change page
408 11
        if (isset($rewrite['page']) && $rewrite['page'] > 1) {
409 4
            $params[$this->prefix . 'page'] = $rewrite['page'];
410
        }
411
412
        // change limit
413 11
        if (isset($rewrite['limit'])) {
414 1
            if ($rewrite['limit'] != $this->defaultLimit) {
415 1
                $params[$this->prefix . 'limit'] = ($rewrite['limit'] != $this->limit)
416 1
                    ? $rewrite['limit'] : $this->limit;
417
            }
418
        } else {
419 10
            if ($this->limit != $this->defaultLimit) {
420
                $params[$this->prefix . 'limit'] = $this->limit;
421
            }
422
        }
423
424
        // change orders
425 11
        if (isset($rewrite['orders'])) {
426 2
            $orders = $rewrite['orders'];
427
        } else {
428 9
            $orders = $this->getOrders();
429
        }
430
431 11
        foreach ($orders as $column => $order) {
432 2
            $params[$this->prefix . 'order-' . $column] = $order;
433
        }
434
435
        // change filters
436 11
        if (isset($rewrite['filters'])) {
437 1
            $filters = $rewrite['filters'];
438
        } else {
439 10
            $filters = $this->getFilters();
440
        }
441 11
        foreach ($filters as $column => $columnFilters) {
442 1
            $columnFilter = [];
443 1
            foreach ($columnFilters as $filterName => $filterValue) {
444 1
                if ($filterName == self::FILTER_EQ) {
445
                    $columnFilter[] = $filterValue;
446
                } else {
447 1
                    $columnFilter[] = $filterName . '-' . $filterValue;
448
                }
449
            }
450 1
            $params[$this->prefix . 'filter-' . $column] = join('-', $columnFilter);
451
        }
452
453 11
        return $params;
454
    }
455
456
    /**
457
     * Get Url
458
     *
459
     * @param  array $params
460
     * @return string
461
     */
462 11
    public function getUrl($params)
463
    {
464
        // prepare params
465 11
        $params = $this->getParams($params);
466
467
        // retrieve URL
468 11
        return Router::getUrl(
469 11
            $this->getModule(),
470 11
            $this->getController(),
471
            $params
472
        );
473
    }
474
475
    /**
476
     * Set allow orders
477
     *
478
     * @param  string[] $orders
479
     * @return void
480
     */
481 33
    public function setAllowOrders(array $orders = [])
482
    {
483 33
        $this->allowOrders = $orders;
484 33
    }
485
486
    /**
487
     * Get allow orders
488
     *
489
     * @return array
490
     */
491 2
    public function getAllowOrders()
492
    {
493 2
        return $this->allowOrders;
494
    }
495
496
    /**
497
     * Add order rule
498
     *
499
     * @param  string $column
500
     * @param  string $order
501
     * @return void
502
     * @throws GridException
503
     */
504 8
    public function addOrder($column, $order = Grid::ORDER_ASC)
505
    {
506 8
        if (!in_array($column, $this->allowOrders)) {
507 1
            throw new GridException('Wrong column order');
508
        }
509
510 7
        if (strtolower($order) != Grid::ORDER_ASC
511 7
            && strtolower($order) != Grid::ORDER_DESC
512
        ) {
513 1
            throw new GridException('Order for column "' . $column . '" is incorrect');
514
        }
515 6
        $column = $this->applyAlias($column);
516
517 6
        $this->orders[$column] = $order;
518 6
    }
519
520
    /**
521
     * Add order rules
522
     *
523
     * @param  array $orders
524
     * @return void
525
     */
526 1
    public function addOrders(array $orders)
527
    {
528 1
        foreach ($orders as $column => $order) {
529 1
            $this->addOrder($column, $order);
530
        }
531 1
    }
532
533
    /**
534
     * Set order
535
     *
536
     * @param  string $column
537
     * @param  string $order  ASC or DESC
538
     * @return void
539
     */
540 6
    public function setOrder($column, $order = Grid::ORDER_ASC)
541
    {
542 6
        $this->orders = [];
543 6
        $this->addOrder($column, $order);
544 4
    }
545
546
    /**
547
     * Set orders
548
     *
549
     * @param  array $orders
550
     * @return void
551
     */
552 1
    public function setOrders(array $orders)
553
    {
554 1
        $this->orders = [];
555 1
        $this->addOrders($orders);
556 1
    }
557
558
    /**
559
     * Get orders
560
     *
561
     * @return array
562
     */
563 24
    public function getOrders()
564
    {
565 24
        $default = $this->getDefaultOrder();
566
567
        // remove default order when another one is set
568 24
        if (is_array($default)
569 24
            && count($this->orders) > 1
570 24
            && isset($this->orders[key($default)])
571 24
            && $this->orders[key($default)] == reset($default)
572
        ) {
573
            unset($this->orders[key($default)]);
574
        }
575
576 24
        return $this->orders;
577
    }
578
579
    /**
580
     * Set allowed filters
581
     *
582
     * @param  string[] $filters
583
     * @return void
584
     */
585 33
    public function setAllowFilters(array $filters = array())
586
    {
587 33
        $this->allowFilters = $filters;
588 33
    }
589
590
    /**
591
     * Get allow filters
592
     *
593
     * @return array
594
     */
595 3
    public function getAllowFilters()
596
    {
597 3
        return $this->allowFilters;
598
    }
599
600
    /**
601
     * Check filter
602
     *
603
     * @param  string $filter
604
     * @return bool
605
     */
606 10
    public function checkFilter($filter)
607
    {
608 10
        if ($filter == self::FILTER_EQ ||
609 9
            $filter == self::FILTER_NE ||
610 6
            $filter == self::FILTER_GT ||
611 6
            $filter == self::FILTER_GE ||
612 6
            $filter == self::FILTER_LT ||
613 6
            $filter == self::FILTER_LE ||
614 5
            $filter == self::FILTER_NUM ||
615 5
            $filter == self::FILTER_ENUM ||
616 10
            $filter == self::FILTER_LIKE
617
        ) {
618 8
            return true;
619
        }
620 2
        return false;
621
    }
622
623
    /**
624
     * Add filter
625
     *
626
     * @param  string $column
627
     * @param  string $filter
628
     * @param  string $value
629
     * @return void
630
     * @throws GridException
631
     */
632 10
    public function addFilter($column, $filter, $value)
633
    {
634 10
        if (!in_array($column, $this->allowFilters) &&
635 10
            !array_key_exists($column, $this->allowFilters)
636
        ) {
637 1
            throw new GridException('Wrong column name for filter');
638
        }
639
640 9
        $filter = strtolower($filter);
641
642 9
        if (!$this->checkFilter($filter)) {
643 1
            throw new GridException('Wrong filter name');
644
        }
645
646 8
        $column = $this->applyAlias($column);
647
        
648 8
        if (!isset($this->filters[$column])) {
649 8
            $this->filters[$column] = [];
650
        }
651 8
        $this->filters[$column][$filter] = $value;
652 8
    }
653
654
655
    /**
656
     * Get filter
657
     *
658
     * @param  string $column
659
     * @param  string $filter
660
     * @return mixed
661
     */
662
    public function getFilter($column, $filter = null)
663
    {
664
        if (isset($this->filters[$column])) {
665
            if ($filter) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $filter of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
666
                if (isset($this->filters[$column][$filter])) {
667
                    return $this->filters[$column][$filter];
668
                } else {
669
                    return null;
670
                }
671
            } else {
672
                return $this->filters[$column];
673
            }
674
        } else {
675
            return null;
676
        }
677
    }
678
679
    /**
680
     * Get filters
681
     *
682
     * @return array
683
     */
684 23
    public function getFilters()
685
    {
686 23
        return $this->filters;
687
    }
688
689
    /**
690
     * Add alias
691
     *
692
     * @param  string $key
693
     * @param  string $value
694
     * @return void
695
     */
696
    public function addAlias($key, $value)
697
    {
698
        $this->aliases[$key] = $value;
699
    }
700
701
    /**
702
     * Set aliases
703
     *
704
     * @param array $aliases
705
     * @return void
706
     */
707
    public function setAliases($aliases)
708
    {
709
        $this->aliases = $aliases;
710
    }
711
712
    /**
713
     * Apply Alias
714
     *
715
     * @param  string $key
716
     * @return string
717
     */
718 11
    protected function applyAlias($key)
719
    {
720 11
        return isset($this->aliases[$key])?$this->aliases[$key]:$key;
721
    }
722
723
    /**
724
     * Set page
725
     *
726
     * @param  integer $page
727
     * @return void
728
     * @throws GridException
729
     */
730 33
    public function setPage($page = 1)
731
    {
732 33
        if ($page < 1) {
733 1
            throw new GridException('Wrong page number, should be greater than zero');
734
        }
735 33
        $this->page = (int)$page;
736 33
    }
737
738
    /**
739
     * Get page
740
     *
741
     * @return integer
742
     */
743 17
    public function getPage()
744
    {
745 17
        return $this->page;
746
    }
747
748
    /**
749
     * Set limit per page
750
     *
751
     * @param  integer $limit
752
     * @return void
753
     * @throws GridException
754
     */
755 33
    public function setLimit($limit)
756
    {
757 33
        if ($limit < 1) {
758 1
            throw new GridException('Wrong limit value, should be greater than zero');
759
        }
760 33
        $this->limit = (int)$limit;
761 33
    }
762
763
    /**
764
     * Get limit per page
765
     *
766
     * @return integer
767
     */
768 16
    public function getLimit()
769
    {
770 16
        return $this->limit;
771
    }
772
773
    /**
774
     * Set default limit
775
     *
776
     * @param  integer $limit
777
     * @return void
778
     * @throws GridException
779
     */
780 33
    public function setDefaultLimit($limit)
781
    {
782 33
        if ($limit < 1) {
783 1
            throw new GridException('Wrong default limit value, should be greater than zero');
784
        }
785 33
        $this->setLimit($limit);
786
787 33
        $this->defaultLimit = (int)$limit;
788 33
    }
789
790
    /**
791
     * Get default limit
792
     *
793
     * @return integer
794
     */
795 1
    public function getDefaultLimit()
796
    {
797 1
        return $this->defaultLimit;
798
    }
799
800
    /**
801
     * Set default order
802
     *
803
     * @param  string $column
804
     * @param  string $order ASC or DESC
805
     * @return void
806
     * @throws GridException
807
     */
808 5
    public function setDefaultOrder($column, $order = Grid::ORDER_ASC)
809
    {
810 5
        $this->setOrder($column, $order);
811
812 3
        $this->defaultOrder = array($column => $order);
813 3
    }
814
815
    /**
816
     * Get default order
817
     *
818
     * @return array
819
     */
820 23
    public function getDefaultOrder()
821
    {
822 23
        return $this->defaultOrder;
823
    }
824
}
825