Completed
Push — master ( c4bcc6...c033be )
by Michael
04:57
created

CustomOrderTrait::setColumn()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 3
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace Blasttech\EloquentRelatedPlus;
4
5
use DB;
6
use Illuminate\Database\Eloquent\Builder;
7
use Illuminate\Database\Eloquent\Model;
8
use InvalidArgumentException;
9
10
/**
11
 * Trait RelatedPlusTrait
12
 *
13
 * @property array order_fields
14
 * @property array order_defaults
15
 * @property array order_relations
16
 * @property array order_with
17
 * @property array search_fields
18
 * @property string connection
19
 */
20
trait CustomOrderTrait
21
{
22
    use HelperMethodTrait, RelatedPlusTrait;
23
24
    /**
25
     * Check $order_fields and $order_defaults are set
26
     *
27
     * @param string $orderField
28
     * @param string $direction
29
     * @return bool
30
     */
31
    private function hasOrderFieldsAndDefaults($orderField, $direction)
32
    {
33
        return $this->hasOrderFields() && $this->hasOrderDefaults($orderField, $direction);
34
    }
35
36
    /**
37
     * Check $this->order_fields set correctly
38
     *
39
     * @return bool
40
     */
41
    private function hasOrderFields()
42
    {
43
        if (!isset($this->order_fields) || !is_array($this->order_fields)) {
44
            throw new InvalidArgumentException(get_class($this) . ' order fields not set correctly.');
45
        } else {
46
            return true;
47
        }
48
    }
49
50
    /**
51
     * Check order defaults set correctly
52
     *
53
     * @param string $orderField
54
     * @param string $direction
55
     * @return bool
56
     */
57
    private function hasOrderDefaults($orderField, $direction)
58
    {
59
        if (($orderField === '' || $direction === '')
60
            && (!isset($this->order_defaults) || !is_array($this->order_defaults))) {
61
            throw new InvalidArgumentException(get_class($this) . ' order defaults not set and not overriden.');
62
        } else {
63
            return true;
64
        }
65
    }
66
67
    /**
68
     * Check if column being sorted by is from a related model
69
     *
70
     * @param Builder $query
71
     * @param string $column
72
     * @param string $direction
73
     * @return Builder
74
     */
75
    public function scopeOrderByCheckModel(Builder $query, $column, $direction)
76
    {
77
        /** @var Model $query */
78
        $query->orderBy(DB::raw($column), $direction);
79
80
        $periodPos = strpos($column, '.');
81
        if (isset($this->order_relations) && ($periodPos !== false || isset($this->order_relations[$column]))) {
82
            $table = ($periodPos !== false ? substr($column, 0, $periodPos) : $column);
83
            $query = $this->joinRelatedTable($query, $table);
84
        }
85
86
        return $query;
87
    }
88
89
    /**
90
     * Set the model order
91
     *
92
     * @param Builder $query
93
     * @param string $column
94
     * @param string $direction
95
     * @return Builder
96
     */
97
    public function scopeSetCustomOrder(Builder $query, $column, $direction)
98
    {
99
        if (isset($this->order_defaults)) {
100
            $column = $this->setColumn($column);
101
            $direction = $this->setDirection($direction);
102
        }
103
104
        return $this->setOrder($query, $column, $direction);
105
    }
106
107
    /**
108
     * Override column if provided column not valid
109
     *
110
     * @param string $column
111
     * @return string
112
     */
113
    private function setColumn($column)
114
    {
115
        // If $column not in order_fields list, use default
116
        if ($column == '' || !isset($this->order_fields[$column])) {
117
            $column = $this->order_defaults['field'];
118
        }
119
120
        return $column;
121
    }
122
123
    /**
124
     * Override direction if provided direction not valid
125
     *
126
     * @param string $direction
127
     * @return string
128
     */
129
    private function setDirection($direction)
130
    {
131
        // If $direction not asc or desc, use default
132
        if ($direction == '' || !in_array(strtoupper($direction), ['ASC', 'DESC'])) {
133
            $direction = $this->order_defaults['dir'];
134
        }
135
136
        return $direction;
137
    }
138
139
    /**
140
     * Set order based on order_fields
141
     *
142
     * @param Builder $query
143
     * @param string $column
144
     * @param string $direction
145
     * @return Builder
146
     */
147
    private function setOrder($query, $column, $direction)
148
    {
149
        if (!is_array($this->order_fields[$column])) {
150
            $query->orderByCheckModel($this->order_fields[$column], $direction);
151
        } else {
152
            foreach ($this->order_fields[$column] as $dbField) {
153
                $query->orderByCheckModel($dbField, $direction);
154
            }
155
        }
156
157
        return $query;
158
    }
159
160
    /**
161
     * Join a related table if not already joined
162
     *
163
     * @param Builder $query
164
     * @param string $table
165
     * @return Builder
166
     */
167
    private function joinRelatedTable($query, $table)
168
    {
169
        if (isset($this->order_relations[$table]) &&
170
            !$this->hasJoin($query, $table, $this->order_relations[$table])) {
171
            $columnRelations = $this->order_relations[$table];
172
173
            $query->modelJoin(
174
                $columnRelations,
175
                '=',
176
                'left',
177
                false,
178
                false
179
            );
180
        }
181
182
        return $query;
183
    }
184
}
185