Passed
Branch master (018ba4)
by Mathieu
06:43
created

Order::setData()   F

Complexity

Conditions 12
Paths 576

Size

Total Lines 59
Code Lines 31

Duplication

Lines 20
Ratio 33.9 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 12
eloc 31
nc 576
nop 1
dl 20
loc 59
rs 3.5932
c 1
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Charcoal\Source;
4
5
use InvalidArgumentException;
6
7
// From 'charcoal-core'
8
use Charcoal\Source\Expression;
9
use Charcoal\Source\ExpressionFieldTrait;
10
use Charcoal\Source\OrderInterface;
11
12
/**
13
 * Order Expression
14
 *
15
 * For sorting the results of a query.
16
 *
17
 * Possible sorting modes:
18
 * 1. Custom — Sort results by a custom expression.
19
 *    - Requirement: "condition"
20
 * 2. Values — Sort results against a defined order.
21
 *    - Requirements: "values", "property"
22
 *    - Complementary: "direction" (useful for sorting unlisted results)
23
 * 3. Direction — Sort results in ascending or descending order.
24
 *    - Requirements: "property"
25
 *    - Complementary: "direction" (ascending, by default)
26
 */
27
class Order extends Expression implements
28
    OrderInterface
29
{
30
    use ExpressionFieldTrait;
31
32
    const MODE_ASC    = 'asc';
33
    const MODE_DESC   = 'desc';
34
    const MODE_RANDOM = 'rand';
35
    const MODE_VALUES = 'values';
36
    const MODE_CUSTOM = 'custom';
37
38
    /**
39
     * The sort mode.
40
     *
41
     * @var string|null
42
     */
43
    protected $mode;
44
45
    /**
46
     * The values to sort against when {@see self::$mode} is {@see self::MODE_VALUES}.
47
     *
48
     * @var array|null
49
     */
50
    protected $values;
51
52
    /**
53
     * The direction of sorting.
54
     *
55
     * @var string|null
56
     */
57
    protected $direction;
58
59
    /**
60
     * Set the order clause data.
61
     *
62
     * @param  array<string,mixed> $data The expression data;
63
     *     as an associative array.
64
     * @return self
65
     */
66
    public function setData(array $data)
67
    {
68
        parent::setData($data);
69
70
        /** @deprecated */
71 View Code Duplication
        if (isset($data['string'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
72
            trigger_error(
73
                sprintf(
74
                    'Sort expression option "string" is deprecated in favour of "condition": %s',
75
                    $data['string']
76
                ),
77
                E_USER_DEPRECATED
78
            );
79
            $this->setCondition($data['string']);
80
        }
81
82
        /** @deprecated */
83 View Code Duplication
        if (isset($data['table_name'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
84
            trigger_error(
85
                sprintf(
86
                    'Sort expression option "table_name" is deprecated in favour of "table": %s',
87
                    $data['table_name']
88
                ),
89
                E_USER_DEPRECATED
90
            );
91
            $this->setTable($data['table_name']);
92
        }
93
94
        if (isset($data['table'])) {
95
            $this->setTable($data['table']);
96
        }
97
98
        if (isset($data['property'])) {
99
            $this->setProperty($data['property']);
100
        }
101
102
        if (isset($data['direction'])) {
103
            $this->setDirection($data['direction']);
104
        }
105
106
        if (isset($data['mode'])) {
107
            $this->setMode($data['mode']);
108
        }
109
110
        if (isset($data['values'])) {
111
            $this->setValues($data['values']);
112
113
            if (!isset($data['mode'])) {
114
                $this->setMode(self::MODE_VALUES);
115
            }
116
        }
117
118
        if (isset($data['condition']) || isset($data['string'])) {
119
            if (!isset($data['mode'])) {
120
                $this->setMode(self::MODE_CUSTOM);
121
            }
122
        }
123
124
        return $this;
125
    }
126
127
    /**
128
     * Retrieve the default values for sorting.
129
     *
130
     * @return array<string,mixed> An associative array.
131
     */
132
    public function defaultData()
133
    {
134
        return [
135
            'property'  => null,
136
            'table'     => null,
137
            'direction' => null,
138
            'mode'      => null,
139
            'values'    => null,
140
            'condition' => null,
141
            'active'    => true,
142
            'name'      => null,
143
        ];
144
    }
145
146
    /**
147
     * Retrieve the order clause structure.
148
     *
149
     * @return array<string,mixed> An associative array.
150
     */
151
    public function data()
152
    {
153
        return [
154
            'property'  => $this->property(),
155
            'table'     => $this->table(),
156
            'direction' => $this->direction(),
157
            'mode'      => $this->mode(),
158
            'values'    => $this->values(),
159
            'condition' => $this->condition(),
160
            'active'    => $this->active(),
161
            'name'      => $this->name(),
162
        ];
163
    }
164
165
    /**
166
     * Set the, pre-defined, sorting mode.
167
     *
168
     * @param  string|null $mode The sorting mode.
169
     * @throws InvalidArgumentException If the mode is not a string or invalid.
170
     * @return self
171
     */
172
    public function setMode($mode)
173
    {
174
        if ($mode === null) {
175
            $this->mode = $mode;
176
            return $this;
177
        }
178
179
        if (!is_string($mode)) {
180
            throw new InvalidArgumentException(
181
                'Order Mode must be a string.'
182
            );
183
        }
184
185
        $mode  = strtolower($mode);
186
        $valid = $this->validModes();
187
        if (!in_array($mode, $valid)) {
188
            throw new InvalidArgumentException(sprintf(
189
                'Invalid Order Mode. Must be one of "%s"',
190
                implode('", "', $valid)
191
            ));
192
        }
193
194
        if (in_array($mode, [ self::MODE_ASC, self::MODE_DESC ])) {
195
            $this->setDirection($mode);
196
        }
197
198
        $this->mode = $mode;
199
        return $this;
200
    }
201
202
    /**
203
     * Retrieve the sorting mode.
204
     *
205
     * @return string|null
206
     */
207
    public function mode()
208
    {
209
        return $this->mode;
210
    }
211
212
    /**
213
     * Set the sorting direction.
214
     *
215
     * @param  string|null $direction The direction to sort on.
216
     * @throws InvalidArgumentException If the direction is not a string.
217
     * @return self
218
     */
219 View Code Duplication
    public function setDirection($direction)
220
    {
221
        if ($direction === null) {
222
            $this->direction = $direction;
223
            return $this;
224
        }
225
226
        if (!is_string($direction)) {
227
            throw new InvalidArgumentException(
228
                'Direction must be a string.'
229
            );
230
        }
231
232
        $this->direction = strtolower($direction) === 'asc' ? 'ASC' : 'DESC';
233
        return $this;
234
    }
235
236
    /**
237
     * Retrieve the sorting direction.
238
     *
239
     * @return string|null
240
     */
241
    public function direction()
242
    {
243
        return $this->direction;
244
    }
245
246
    /**
247
     * Set the values to sort against.
248
     *
249
     * Note: Values are ignored if the mode is not {@see self::MODE_VALUES}.
250
     *
251
     * @throws InvalidArgumentException If the parameter is not an array or a string.
252
     * @param  string|array|null $values A list of field values.
253
     *     If the $values parameter:
254
     *     - is a string, the string will be split by ",".
255
     *     - is an array, the values will be used as is.
256
     *     - any other data type throws an exception.
257
     * @return self
258
     */
259
    public function setValues($values)
260
    {
261
        if ($values === null) {
262
            $this->values = $values;
263
            return $this;
264
        }
265
266
        if (is_string($values)) {
267
            if ($values === '') {
268
                throw new InvalidArgumentException(
269
                    'String values can not be empty.'
270
                );
271
            }
272
273
            $values = array_map('trim', explode(',', $values));
274
        }
275
276
        if (is_array($values)) {
277
            if (empty($values)) {
278
                throw new InvalidArgumentException(
279
                    'Array values can not be empty.'
280
                );
281
            }
282
283
            $this->values = $values;
284
            return $this;
285
        }
286
287
        throw new InvalidArgumentException(sprintf(
288
            'Order Values must be an array or comma-delimited string, received %s',
289
            is_object($values) ? get_class($values) : gettype($values)
290
        ));
291
    }
292
293
    /**
294
     * Determine if the Order expression has values.
295
     *
296
     * @return boolean
297
     */
298
    public function hasValues()
299
    {
300
        return !empty($this->values);
301
    }
302
303
    /**
304
     * Retrieve the values to sort against.
305
     *
306
     * @return array|null A list of field values or NULL if no values were assigned.
307
     */
308
    public function values()
309
    {
310
        return $this->values;
311
    }
312
313
    /**
314
     * Retrieve the supported sorting modes.
315
     *
316
     * @return array
317
     */
318
    protected function validModes()
319
    {
320
        return [
321
            self::MODE_DESC,
322
            self::MODE_ASC,
323
            self::MODE_RANDOM,
324
            self::MODE_VALUES,
325
            self::MODE_CUSTOM
326
        ];
327
    }
328
}
329