Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * Builds a query.
19
 *
20
 * @package    block_dash
21
 * @copyright  2019 bdecent gmbh <https://bdecent.de>
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
namespace block_dash\local\dash_framework\query_builder;
26
 
27
use block_dash\local\dash_framework\query_builder\exception\invalid_operator_exception;
28
use block_dash\local\dash_framework\query_builder\exception\invalid_where_clause_exception;
29
use coding_exception;
30
use dml_exception;
31
 
32
/**
33
 * Builds a query.
34
 *
35
 * @package block_dash
36
 */
37
class where {
38
 
39
    /**
40
     * @var int Unique counter for param/placeholder names.
41
     */
42
    public static $paramcounter = 0;
43
 
44
    /**
45
     * Sql equal sign.
46
     */
47
    const OPERATOR_EQUAL = '=';
48
    /**
49
     * SQL not equal.
50
     */
51
    const OPERATOR_NOT_EQUAL = '!=';
52
    /**
53
     * SQL IN operator.
54
     */
55
    const OPERATOR_IN = 'in';
56
    /**
57
     * SQL IN query.
58
     */
59
    const OPERATOR_IN_QUERY = 'in_query';
60
 
61
    /**
62
     * SQL grader than.
63
     */
64
    const OPERATOR_GREATERTHAN = '>';
65
 
66
    /**
67
     * SQL greater than or equal.
68
     */
69
    const OPERATOR_GREATERTHAN_EQUAL = '>=';
70
 
71
    /**
72
     * SQL less than.
73
     */
74
    const OPERATOR_LESSTHAN = '<';
75
 
76
    /**
77
     * SQL less than or equal.
78
     */
79
    const OPERATOR_LESSTHAN_EQUAL = '<=';
80
 
81
    /**
82
     * SQL Like query.
83
     */
84
    const OPERATOR_LIKE = 'like';
85
 
86
    /**
87
     * SQL Not like query.
88
     */
89
    const OPERATOR_NOT_LIKE = 'not_like';
90
 
91
    /**
92
     * SQL Not IN.
93
     */
94
    const OPERATOR_NOT_IN = 'not_in';
95
 
96
    /**
97
     * SQL Not IN query.
98
     */
99
    const OPERATOR_NOT_IN_QUERY = 'not_in_query';
100
 
101
    /**
102
     * SQL conjection of OR.
103
     */
104
    const CONJUNCTIVE_OPERATOR_OR = 'OR';
105
 
106
    /**
107
     * SQL conjection of AND.
108
     */
109
    const CONJUNCTIVE_OPERATOR_AND = 'AND';
110
 
111
    /**
112
     * @var string Field or subquery.
113
     */
114
    private $selector;
115
 
116
    /**
117
     * @var array
118
     */
119
    private $values;
120
 
121
    /**
122
     * @var string See self::OPERATION_*
123
     */
124
    private $operator;
125
 
126
    /**
127
     * @var string
128
     */
129
    private $query;
130
 
131
    /**
132
     * @var array
133
     */
134
    private $queryparams;
135
 
136
    /**
137
     * Conjunctive operator.
138
     *
139
     * @var string
140
     */
141
    private $conjunctive;
142
 
143
    /**
144
     * Create new where condition.
145
     *
146
     * @param string $selector
147
     * @param array $values
148
     * @param string $operator
149
     * @param string $conjunctive
150
     */
151
    public function __construct(string $selector, array $values, string $operator = self::OPERATOR_EQUAL,
152
        string $conjunctive = self::CONJUNCTIVE_OPERATOR_AND) {
153
        $this->selector = $selector;
154
        $this->values = array_values($values);
155
        $this->operator = $operator;
156
        $this->conjunctive = $conjunctive;
157
    }
158
 
159
    /**
160
     * Set sql query to build.
161
     *
162
     * @param string $query
163
     * @param array $params
164
     */
165
    public function set_query(string $query, array $params = []) {
166
        $this->query = $query;
167
        $this->queryparams = $params;
168
        $this->operator = self::OPERATOR_IN_QUERY;
169
    }
170
 
171
    /**
172
     * Conjunctive operator for this where clasuse with previous.
173
     *
174
     * @return string
175
     */
176
    public function get_conjunctive_operator() {
177
        return $this->conjunctive ?: self::CONJUNCTIVE_OPERATOR_AND;
178
    }
179
 
180
    /**
181
     * Get sql query and parameters with processed operators.
182
     *
183
     * @return array<string, array>
184
     * @throws invalid_operator_exception
185
     * @throws invalid_where_clause_exception
186
     * @throws dml_exception|coding_exception
187
     */
188
    public function get_sql_and_params(): array {
189
        global $DB;
190
 
191
        $sql = '';
192
        // Named parameters.
193
        $params = [];
194
 
195
        // First ensure this where clause is valid.
196
        switch ($this->operator) {
197
            case self::OPERATOR_EQUAL:
198
            case self::OPERATOR_IN:
199
                if (empty($this->values)) {
200
                    throw new invalid_where_clause_exception();
201
                }
202
                break;
203
        }
204
 
205
        // Build SQL and params.
206
        switch ($this->operator) {
207
            case self::OPERATOR_EQUAL:
208
            case self::OPERATOR_NOT_EQUAL:
209
            case self::OPERATOR_GREATERTHAN:
210
            case self::OPERATOR_LESSTHAN:
211
            case self::OPERATOR_GREATERTHAN_EQUAL:
212
            case self::OPERATOR_LESSTHAN_EQUAL:
213
                $placeholder = self::get_param_name();
214
                $sql = sprintf('%s %s :%s', $this->selector, $this->operator, $placeholder);
215
                $params[$placeholder] = $this->values[0];
216
                break;
217
            case self::OPERATOR_IN:
218
                // At this point we are guaranteed at least one value being applied.
219
                [$psql, $pparams] = $DB->get_in_or_equal($this->values, SQL_PARAMS_NAMED, 'p');
220
                $sql = sprintf('%s %s', $this->selector, $psql);
221
                $params = array_merge($params, $pparams);
222
                break;
223
            case self::OPERATOR_NOT_IN:
224
                // At this point we are guaranteed at least one value being applied.
225
                [$psql, $pparams] = $DB->get_in_or_equal($this->values, SQL_PARAMS_NAMED, 'p', false);
226
                $sql = sprintf('%s %s', $this->selector, $psql);
227
                $params = array_merge($params, $pparams);
228
                break;
229
            case self::OPERATOR_IN_QUERY:
230
                $sql = sprintf('%s IN (%s)', $this->selector, $this->query);
231
                $params = array_merge($params, $this->queryparams);
232
                break;
233
            case self::OPERATOR_NOT_IN_QUERY:
234
                $sql = sprintf('%s NOT IN (%s)', $this->selector, $this->query);
235
                $params = array_merge($params, $this->queryparams);
236
                break;
237
            case self::OPERATOR_LIKE:
238
                $placeholder = self::get_param_name();
239
                $sql = $DB->sql_like($this->selector, ':'.$placeholder);
240
                $params[$placeholder] = isset($this->values[0]) ? '%'.$this->values[0].'%' : '';
241
                break;
242
            case self::OPERATOR_NOT_LIKE:
243
                $placeholder = self::get_param_name();
244
                $sql = $DB->sql_like($this->selector, ':'.$placeholder, true, true, true);
245
                $params[$placeholder] = isset($this->values[0]) ? '%'.$DB->sql_like_escape($this->values[0]).'%' : '';
246
                break;
247
            default:
248
                throw new invalid_operator_exception('', ['operator' => $this->operator]);
249
        }
250
 
251
        return [$sql, $params];
252
    }
253
 
254
    /**
255
     * Get unique parameter name.
256
     *
257
     * @param string $prefix
258
     * @return string
259
     */
260
    public static function get_param_name(string $prefix = 'p_'): string {
261
        return $prefix . self::$paramcounter++;
262
    }
263
}