Sortable::setSortablePayload()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 2
1
<?php
2
3
namespace Thinktomorrow\Repo;
4
5
use Illuminate\Support\Facades\Input;
6
7
trait Sortable
8
{
9
10
    /**
11
     * Url query parameter key for sorting
12
     *
13
     * @var string
14
     */
15
    private $sortableKey = 'sort';
16
17
    /**
18
     * Delimiter of chained sort string,
19
     * e.g. ?sort=foo|bar
20
     *
21
     * @var string
22
     */
23
    private $sortDelimiter = '|';
24
25
    /**
26
     * Collection of allowed keys to sort on
27
     *
28
     * @var array
29
     */
30
    private $sortableWhitelist;
31
32
    /**
33
     * Key that should be used to sort the current Query
34
     *
35
     * @var array
36
     */
37
    private $sortablePayload;
38
39
    /**
40
     * Enable sort
41
     *
42
     * @param array $sortableWhitelist - whitelist of sortable parameters
43
     * @param array $forcedPayload - enforce these sorters
44
     * @param array $defaultPayload - default sorting if no sorting is passed
45
     * @return $this
46
     */
47
    public function sort($sortableWhitelist = null, $forcedPayload = [], $defaultPayload = [])
48
    {
49
        $this->sortableWhitelist = $this->convertToCleanArray($sortableWhitelist);
50
51
        $this->sortablePayload = $this->setSortablePayload($forcedPayload, $defaultPayload);
52
53
        $this->handleSortablePayload();
54
55
        return $this;
56
    }
57
58
    /**
59
     * Get our current sorters
60
     *
61
     * Sorters        custom sorting payload which has priority
62
     * uriSorters    By default the sorters provided via uri payload are used
63
     * defaults    if none are given, a default sorter can be activated
64
     *
65
     * @param  array $forcedPayload
66
     * @param array $defaultPayload
67
     * @return array
68
     */
69
    protected function setSortablePayload($forcedPayload = [], $defaultPayload = [])
70
    {
71
        if (count($forced = $this->convertToCleanArray($forcedPayload)) > 0) {
72
            return $forced;
73
        }
74
75
        if (count($uri_sorters = $this->convertToCleanArray(Input::get($this->sortableKey))) > 0) {
76
            return $uri_sorters;
77
        }
78
79
        return $this->convertToCleanArray($defaultPayload);
80
    }
81
82
    /**
83
     * Process the sorting payload
84
     *
85
     * If the url query contains the sort key, the belonging values are taken into account for sorting.
86
     * multiple values are separated by a comma.
87
     * Default is Ascending sort, a minus before a value depicts a descending direction
88
     *
89
     * @return    void
90
     */
91
    protected function handleSortablePayload()
92
    {
93
        if (empty($this->sortableWhitelist) || empty($this->sortablePayload)) {
94
            return;
95
        }
96
97
        foreach ($this->sortablePayload as $sorter) {
98
            list($sorter, $order) = $this->getSorterAndOrderFromQueryString($sorter);
99
100
            if (false !== ($key = array_search($sorter, $this->sortableWhitelist))) {
101
                $this->addSortQuery($key, $sorter, $order);
102
            }
103
        }
104
    }
105
106
    /**
107
     * @param $key
108
     * @param $sorter
109
     * @param $order
110
     */
111
    protected function addSortQuery($key, $sorter, $order)
112
    {
113
        $sortable = $this->sortableWhitelist[$key];
114
115
        if (method_exists($this, 'sortBy' . ucfirst($sortable))) {
116
            call_user_func_array(array($this, 'sortBy' . ucfirst($sortable)), array($sorter, $order));
117
        } else {
118
            $this->model = $this->model->orderBy($sortable, $order);
0 ignored issues
show
Bug introduced by
The property model does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
119
        }
120
    }
121
122
    /**
123
     * @param $sorter
124
     * @return array
125
     */
126
    protected function getSorterAndOrderFromQueryString($sorter)
127
    {
128
        if (0 === strpos($sorter, '-')) {
129
            return array(substr($sorter, 1), 'DESC');
130
        }
131
132
        return array($sorter, 'ASC');
133
    }
134
135
    private function convertToCleanArray($values)
136
    {
137
        $values = (array)$values;
138
139
        // Remove empty values for our value array
140
        $values = array_filter($values, function ($v) {
141
            return ($v);
142
        });
143
144
        // Key pointers must stay nicely indexed so rebase the keys
145
        $values = array_values($values);
146
147
        foreach ($values as $k => $v) {
148
            if (false !== strpos($v, $this->sortDelimiter)) {
149
                $split_values = explode($this->sortDelimiter, $v);
150
151
                // Inject the delimited values into the main array
152
                array_splice($values, $k, 1, $split_values);
153
            }
154
        }
155
156
        return array_values($values);
157
    }
158
}
159