Passed
Push — master ( 2da942...d633d7 )
by Paul
15:03 queued 05:40
created

Sql::normalizeAndClauses()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 11
dl 0
loc 16
ccs 12
cts 12
cp 1
rs 9.9
c 1
b 0
f 0
cc 4
nc 6
nop 1
crap 4
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Database;
4
5
use GeminiLabs\SiteReviews\Database;
6
use GeminiLabs\SiteReviews\Helper;
7
use GeminiLabs\SiteReviews\Helpers\Arr;
8
use GeminiLabs\SiteReviews\Helpers\Cast;
9
use GeminiLabs\SiteReviews\Helpers\Str;
10
11
trait Sql
12
{
13
    /**
14
     * @var array
15
     */
16
    public $args;
17
18
    /**
19
     * @var \wpdb
20
     */
21
    public $db;
22
23
    /**
24
     * @param string $clause
25
     * @return array
26
     */
27 8
    public function clauses($clause, array $values = [])
28
    {
29 8
        $prefix = Str::restrictTo('and,join', $clause);
30 8
        foreach ($this->args as $key => $value) {
31 8
            $method = Helper::buildMethodName($key, 'clause-'.$prefix);
32 8
            if (!method_exists($this, $method) || Helper::isEmpty($value)) {
33 8
                continue;
34
            }
35 8
            if ($statement = call_user_func([$this, $method])) {
36 8
                $values[$key] = $statement;
37
            }
38
        }
39 8
        return $values;
40
    }
41
42
    /**
43
     * @return string
44
     */
45 14
    public function escFieldsForInsert(array $fields)
46
    {
47 14
        return sprintf('(`%s`)', implode('`,`', $fields));
48
    }
49
50
    /**
51
     * @return string
52
     */
53 21
    public function escValuesForInsert(array $values)
54
    {
55 21
        $values = array_values(array_map('esc_sql', $values));
56 21
        return sprintf("('%s')", implode("','", $values));
57
    }
58
59
    /**
60
     * @param string $statement
61
     * @return string
62
     */
63 22
    public function sql($statement)
64
    {
65 22
        $handle = $this->sqlHandle();
66 22
        $statement = glsr()->filterString('database/sql/'.$handle, $statement);
67 22
        glsr()->action('database/sql/'.$handle, $statement);
68 22
        glsr()->action('database/sql', $statement, $handle);
69 22
        return $statement;
70
    }
71
72
    /**
73
     * @return string
74
     */
75 7
    public function sqlJoin()
76
    {
77 7
        $join = $this->clauses('join');
78 7
        $join = glsr()->filterArrayUnique('query/sql/join', $join, $this->sqlHandle(), $this);
79 7
        return implode(' ', $join);
80
    }
81
82
    /**
83
     * @return string
84
     */
85 1
    public function sqlLimit()
86
    {
87 1
        $limit = Helper::ifTrue($this->args['per_page'] > 0,
88 1
            $this->db->prepare('LIMIT %d', $this->args['per_page'])
89
        );
90 1
        return glsr()->filterString('query/sql/limit', $limit, $this->sqlHandle(), $this);
91
    }
92
93
    /**
94
     * @return string
95
     */
96 1
    public function sqlOffset()
97
    {
98 1
        $offsetBy = (($this->args['page'] - 1) * $this->args['per_page']) + $this->args['offset'];
99 1
        $offset = Helper::ifTrue($offsetBy > 0,
100 1
            $this->db->prepare('OFFSET %d', $offsetBy)
101
        );
102 1
        return glsr()->filterString('query/sql/offset', $offset, $this->sqlHandle(), $this);
103
    }
104
105
    /**
106
     * @return string|void
107
     */
108 1
    public function sqlOrderBy()
109
    {
110
        $values = [
111 1
            'random' => 'RAND()',
112
        ];
113 1
        $order = $this->args['order'];
114 1
        $orderby = $this->args['orderby'];
115 1
        $orderedby = [];
116 1
        if (Str::startsWith(['p.', 'r.'], $orderby)) {
117 1
            $orderedby[] = "r.is_pinned {$order}";
118 1
            $orderedby[] = "{$orderby} {$order}";
119
        } elseif (array_key_exists($orderby, $values)) {
120
            $orderedby[] = $values[$orderby];
121
        }
122 1
        $orderedby = glsr()->filterArrayUnique('query/sql/order-by', $orderedby, $this->sqlHandle(), $this);
123 1
        if (!empty($orderedby)) {
124 1
            return 'ORDER BY '.implode(', ', $orderedby);
125
        }
126
    }
127
128
    /**
129
     * @return string
130
     */
131 7
    public function sqlWhere()
132
    {
133 7
        $and = $this->clauses('and');
134 7
        $and = glsr()->filterArrayUnique('query/sql/and', $and, $this->sqlHandle(), $this);
135 7
        $and = $this->normalizeAndClauses($and);
136 7
        return 'WHERE 1=1 '.implode(' ', $and);
137
    }
138
139
    /**
140
     * @return string
141
     */
142 23
    public function table($table)
143
    {
144 23
        return glsr(SqlSchema::class)->table($table);
145
    }
146
147
    /**
148
     * @return string
149
     */
150 2
    protected function clauseAndAssignedPosts()
151
    {
152 2
        $postIds = implode(',', $this->args['assigned_posts']);
153 2
        return sprintf('(apt.post_id IN (%s) AND apt.is_published = 1)', $postIds);
154
    }
155
156
    /**
157
     * @return string
158
     */
159 2
    protected function clauseAndAssignedTerms()
160
    {
161 2
        $termIds = implode(',', $this->args['assigned_terms']);
162 2
        return sprintf('(att.term_id IN (%s))', $termIds);
163
    }
164
165
    /**
166
     * @return string
167
     */
168 2
    protected function clauseAndAssignedUsers()
169
    {
170 2
        $userIds = implode(',', $this->args['assigned_users']);
171 2
        return sprintf('(aut.user_id IN (%s))', $userIds);
172
    }
173
174
    /**
175
     * @return string
176
     */
177 7
    protected function clauseAndDate()
178
    {
179 7
        $clauses = [];
180 7
        $date = $this->args['date'];
181 7
        if (!empty($date['after'])) {
182
            $clauses[] = $this->db->prepare("(p.post_date >{$date['inclusive']} %s)", $date['after']);
183
        }
184 7
        if (!empty($date['before'])) {
185
            $clauses[] = $this->db->prepare("(p.post_date <{$date['inclusive']} %s)", $date['before']);
186
        }
187 7
        if (!empty($date['year'])) {
188
            $clauses[] = $this->db->prepare('(YEAR(p.post_date) = %d AND MONTH(p.post_date) = %d AND DAYOFMONTH(p.post_date) = %d)',
189
                $date['year'], $date['month'], $date['day']
190
            );
191
        }
192 7
        if ($clauses = implode(' AND ', $clauses)) {
193
            return sprintf('AND (%s)', $clauses);
194
        }
195 7
        return '';
196
    }
197
198
    /**
199
     * @return string
200
     */
201 1
    protected function clauseAndEmail()
202
    {
203 1
        return $this->db->prepare('AND r.email = %s', $this->args['email']);
204
    }
205
206
    /**
207
     * @return string
208
     */
209 1
    protected function clauseAndIpAddress()
210
    {
211 1
        return $this->db->prepare('AND r.ip_address = %s', $this->args['ip_address']);
212
    }
213
214
    /**
215
     * @return string
216
     */
217
    protected function clauseAndPostIn()
218
    {
219
        return $this->db->prepare('AND r.review_id IN (%s)', implode(',', $this->args['post__in']));
220
    }
221
222
    /**
223
     * @return string
224
     */
225
    protected function clauseAndPostNotIn()
226
    {
227
        return $this->db->prepare('AND r.review_id NOT IN (%s)', implode(',', $this->args['post__not_in']));
228
    }
229
230
    /**
231
     * @return string
232
     */
233 7
    protected function clauseAndRating()
234
    {
235 7
        return Helper::ifTrue($this->args['rating'] > 0,
236 7
            $this->db->prepare('AND r.rating > %d', --$this->args['rating'])
237
        );
238
    }
239
240
    /**
241
     * @return string
242
     */
243 13
    protected function clauseAndStatus()
244
    {
245 13
        return $this->db->prepare('AND r.is_approved = %d', $this->args['status']);
246
    }
247
248
    /**
249
     * @return string
250
     */
251
    protected function clauseAndTerms()
252
    {
253
        return Helper::ifTrue(glsr(Database::class)->version('1.1'),
254
            $this->db->prepare('AND r.terms = %d', Cast::toBool($this->args['terms']))
255
        );
256
    }
257
258
    /**
259
     * @return string
260
     */
261 7
    protected function clauseAndType()
262
    {
263 7
        return $this->db->prepare('AND r.type = %s', $this->args['type']);
264
    }
265
266
    /**
267
     * @return string
268
     */
269 1
    protected function clauseAndUserIn()
270
    {
271 1
        return $this->db->prepare('AND p.post_author IN (%s)', implode(',', $this->args['user__in']));
272
    }
273
274
    /**
275
     * @return string
276
     */
277
    protected function clauseAndUserNotIn()
278
    {
279
        return $this->db->prepare('AND p.post_author NOT IN (%s)', implode(',', $this->args['user__not_in']));
280
    }
281
282
    /**
283
     * @return string
284
     */
285 3
    protected function clauseJoinAssignedPosts()
286
    {
287 3
        return "INNER JOIN {$this->table('assigned_posts')} AS apt ON r.ID = apt.rating_id";
288
    }
289
290
    /**
291
     * @return string
292
     */
293 3
    protected function clauseJoinAssignedTerms()
294
    {
295 3
        return "INNER JOIN {$this->table('assigned_terms')} AS att ON r.ID = att.rating_id";
296
    }
297
298
    /**
299
     * @return string
300
     */
301 3
    protected function clauseJoinAssignedUsers()
302
    {
303 3
        return "INNER JOIN {$this->table('assigned_users')} AS aut ON r.ID = aut.rating_id";
304
    }
305
306
    /**
307
     * @return string
308
     */
309 8
    protected function clauseJoinDate()
310
    {
311 8
        return Helper::ifTrue(!empty(array_filter($this->args['date'])),
312 8
            "INNER JOIN {$this->db->posts} AS p ON r.review_id = p.ID"
313
        );
314
    }
315
316
    /**
317
     * @return string
318
     */
319 1
    protected function clauseJoinUserIn()
320
    {
321 1
        return "INNER JOIN {$this->db->posts} AS p ON r.review_id = p.ID";
322
    }
323
324
    /**
325
     * @return string
326
     */
327
    protected function clauseJoinUserNotIn()
328
    {
329
        return "INNER JOIN {$this->db->posts} AS p ON r.review_id = p.ID";
330
    }
331
332
    /**
333
     * @return string
334
     */
335 2
    protected function clauseJoinOrderBy()
336
    {
337 2
        return Helper::ifTrue(Str::startsWith('p.', $this->args['orderby']),
338 2
            "INNER JOIN {$this->db->posts} AS p ON r.review_id = p.ID"
339
        );
340
    }
341
342
    /**
343
     * @return array
344
     */
345 7
    protected function normalizeAndClauses(array $and)
346
    {
347 7
        $clauses = [];
348 7
        foreach ($and as $key => $value) {
349 7
            if (Str::startsWith('assigned_', $key)) {
350 6
                $clauses[] = $value;
351 6
                unset($and[$key]);
352
            }
353
        }
354 7
        $operator = glsr()->filterString('query/sql/clause/operator', 'OR', $clauses, $this->args);
355 7
        $operator = strtoupper($operator);
356 7
        $operator = Helper::ifTrue(in_array($operator, ['AND', 'OR']), $operator, 'OR');
357 7
        if ($clauses = implode(" {$operator} ", $clauses)) {
358 6
            $and['assigned'] = "AND ($clauses)";
359
        }
360 7
        return $and;
361
    }
362
363
    /**
364
     * @param int $depth
365
     * @return string
366
     */
367 22
    protected function sqlHandle($depth = 2)
368
    {
369 22
        return Str::dashCase(Arr::get((new \Exception())->getTrace(), $depth.'.function'));
370
    }
371
}
372