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

DatabaseOrder::sql()   C

Complexity

Conditions 8
Paths 8

Size

Total Lines 28
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 15
nc 8
nop 0
dl 0
loc 28
rs 5.3846
c 1
b 0
f 0
1
<?php
2
3
namespace Charcoal\Source\Database;
4
5
use UnexpectedValueException;
6
7
// From 'charcoal-core'
8
use Charcoal\Source\Database\DatabaseExpressionInterface;
9
use Charcoal\Source\DatabaseSource;
10
use Charcoal\Source\Order;
11
12
/**
13
 * SQL Order Expression
14
 *
15
 * Priority of SQL resolution if the expression is "active":
16
 * 1. Random — If "mode" is set to "rand".
17
 * 2. Custom — If "condition" is defined or "mode" set to "custom".
18
 * 3. Values — If "property" and "values" are defined or "mode" set to "values".
19
 * 4. Direction — If "property" is defined.
20
 */
21
class DatabaseOrder extends Order implements
22
    DatabaseExpressionInterface
23
{
24
    /**
25
     * The table related to the field identifier.
26
     *
27
     * @var string
28
     */
29
    protected $table = DatabaseSource::DEFAULT_TABLE_ALIAS;
30
31
    /**
32
     * Retrieve the default values for sorting.
33
     *
34
     * @return array
35
     */
36
    public function defaultData()
37
    {
38
        $defaults = parent::defaultData();
39
        $defaults['table'] = DatabaseSource::DEFAULT_TABLE_ALIAS;
40
41
        return $defaults;
42
    }
43
44
    /**
45
     * Converts the order into a SQL expression for the ORDER BY clause.
46
     *
47
     * @return string A SQL string fragment.
48
     */
49
    public function sql()
50
    {
51
        if ($this->active()) {
52
            switch ($this->mode()) {
53
                case self::MODE_RANDOM:
54
                    return $this->byRandom();
55
56
                case self::MODE_CUSTOM:
57
                    return $this->byCondition();
58
59
                case self::MODE_VALUES:
60
                    return $this->byValues();
61
            }
62
63
            if ($this->hasCondition()) {
64
                return $this->byCondition();
65
            }
66
67
            if ($this->hasValues()) {
68
                return $this->byValues();
69
            }
70
71
            if ($this->hasProperty()) {
72
                return $this->byProperty();
73
            }
74
        }
75
76
        return '';
77
    }
78
79
    /**
80
     * Retrieve the ORDER BY clause for the {@see self::MODE_RANDOM} mode.
81
     *
82
     * @return string
83
     */
84
    protected function byRandom()
85
    {
86
        return 'RAND()';
87
    }
88
89
    /**
90
     * Generate the ORDER BY clause(s) for the direction mode.
91
     *
92
     * @throws UnexpectedValueException If any required property is empty.
93
     * @return string
94
     */
95
    protected function byProperty()
96
    {
97
        $fields = $this->fieldIdentifiers();
98
        if (empty($fields)) {
99
            throw new UnexpectedValueException(
100
                'Property is required.'
101
            );
102
        }
103
104
        $dir = $this->direction();
105
        $dir = $dir === null ? '' : ' '.$dir;
106
107
        return implode($dir.', ', $fields).$dir;
108
    }
109
110
    /**
111
     * Retrieve the ORDER BY clause for the {@see self::MODE_CUSTOM} mode.
112
     *
113
     * @throws UnexpectedValueException If the custom clause is empty.
114
     * @return string
115
     */
116
    protected function byCondition()
117
    {
118
        if (!$this->hasCondition()) {
119
            throw new UnexpectedValueException(
120
                'Custom expression can not be empty.'
121
            );
122
        }
123
124
        return $this->condition();
125
    }
126
127
    /**
128
     * Retrieve the ORDER BY clause for the {@see self::MODE_VALUES} mode.
129
     *
130
     * @throws UnexpectedValueException If any required property or values is empty.
131
     * @return string
132
     */
133
    protected function byValues()
134
    {
135
        $fields = $this->fieldIdentifiers();
136
        if (empty($fields)) {
137
            throw new UnexpectedValueException(
138
                'Property is required.'
139
            );
140
        }
141
142
        $values = $this->prepareValues($this->values());
143
        if (empty($values)) {
144
            throw new UnexpectedValueException(
145
                'Values can not be empty.'
146
            );
147
        }
148
149
        $dir = $this->direction();
150
        $dir = $dir === null ? '' : ' '.$dir;
151
152
        $values  = implode(',', $values);
153
        $clauses = [];
154
        foreach ($fields as $fieldName) {
155
            $clauses[] = sprintf('FIELD(%1$s, %2$s)', $fieldName, $values).$dir;
156
        }
157
158
        return implode(', ', $clauses);
159
    }
160
161
    /**
162
     * Parse the given values for SQL.
163
     *
164
     * @param  mixed $values The value to be normalized.
165
     * @return array Returns a collection of parsed values.
166
     */
167
    public function prepareValues($values)
168
    {
169
        if (empty($values)) {
170
            return [];
171
        }
172
173
        if (!is_array($values)) {
174
            $values = (array)$values;
175
        }
176
177
        $values = array_filter($values, 'is_scalar');
178
        $values = array_map('self::quoteValue', $values);
179
180
        return $values;
181
    }
182
}
183