Issues (21)

src/Query/Expression.php (3 issues)

1
<?php
2
3
/**
4
 * Platine Database
5
 *
6
 * Platine Database is the abstraction layer using PDO with support of query and schema builder
7
 *
8
 * This content is released under the MIT License (MIT)
9
 *
10
 * Copyright (c) 2020 Platine Database
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a copy
13
 * of this software and associated documentation files (the "Software"), to deal
14
 * in the Software without restriction, including without limitation the rights
15
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
 * copies of the Software, and to permit persons to whom the Software is
17
 * furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included in all
20
 * copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
 * SOFTWARE.
29
 */
30
31
/**
32
 *  @file Expression.php
33
 *
34
 *  The Expression class
35
 *
36
 *  @package    Platine\Database\Query
37
 *  @author Platine Developers Team
38
 *  @copyright  Copyright (c) 2020
39
 *  @license    http://opensource.org/licenses/MIT  MIT License
40
 *  @link   https://www.platine-php.com
41
 *  @version 1.0.0
42
 *  @filesource
43
 */
44
45
declare(strict_types=1);
46
47
namespace Platine\Database\Query;
48
49
use Closure;
50
51
/**
52
 * @class Expression
53
 * @package Platine\Database\Query
54
 */
55
class Expression
56
{
57
    /**
58
     * The list of expression
59
     * @var array<int, array<string, mixed>>
60
     */
61
    protected array $expressions = [];
62
63
    /**
64
     * @return array<int, array<string, mixed>>
65
     */
66
    public function getExpressions(): array
67
    {
68
        return $this->expressions;
69
    }
70
71
    /**
72
     * @param mixed $value
73
     * @return $this
74
     */
75
    public function column(mixed $value): self
76
    {
77
        return $this->addExpression('column', $value);
78
    }
79
80
    /**
81
     * @param mixed $value
82
     * @return $this
83
     */
84
    public function op(mixed $value): self
85
    {
86
        return $this->addExpression('op', $value);
87
    }
88
89
    /**
90
     * @param mixed $value
91
     * @return $this
92
     */
93
    public function value(mixed $value): self
94
    {
95
        return $this->addExpression('value', $value);
96
    }
97
98
    /**
99
     * @param Closure $closure
100
     * @return $this
101
     */
102
    public function group(Closure $closure): self
103
    {
104
        $expression = new Expression();
105
        $closure($expression);
106
107
        return $this->addExpression('group', $expression);
108
    }
109
110
    /**
111
     * @param string|array<string> $tables
112
     * @return SelectStatement
113
     */
114
    public function from(string|array $tables): SelectStatement
115
    {
116
        $subQuery = new SubQuery();
117
        $this->addExpression('subquery', $subQuery);
118
119
        return $subQuery->from($tables);
120
    }
121
122
    /**
123
     * @param string|array<int, mixed>|Expression|Closure $column
124
     * @param bool $distinct
125
     * @return $this
126
     */
127
    public function count(
128
        string|array|Expression|Closure $column = '*',
129
        bool $distinct = false
130
    ): self {
131
        if (!is_array($column)) {
132
            $column = [$column];
133
        }
134
135
        return $this->addFunction(
136
            'aggregateFunction',
137
            'COUNT',
138
            $column,
139
            ['distinct' => $distinct || count($column) > 1]
140
        );
141
    }
142
143
    /**
144
     * @param string|Expression|Closure $column
145
     * @param bool $distinct
146
     * @return $this
147
     */
148
    public function sum(string|Expression|Closure $column, bool $distinct = false): self
149
    {
150
        return $this->addFunction(
151
            'aggregateFunction',
152
            'SUM',
153
            $column,
154
            ['distinct' => $distinct]
155
        );
156
    }
157
158
    /**
159
     * @param string|Expression|Closure $column
160
     * @param bool $distinct
161
     * @return $this
162
     */
163
    public function avg(string|Expression|Closure $column, bool $distinct = false): self
164
    {
165
        return $this->addFunction(
166
            'aggregateFunction',
167
            'AVG',
168
            $column,
169
            ['distinct' => $distinct]
170
        );
171
    }
172
173
    /**
174
     * @param string|Expression|Closure $column
175
     * @param bool $distinct
176
     * @return $this
177
     */
178
    public function min(string|Expression|Closure $column, bool $distinct = false): self
179
    {
180
        return $this->addFunction(
181
            'aggregateFunction',
182
            'MIN',
183
            $column,
184
            ['distinct' => $distinct]
185
        );
186
    }
187
188
    /**
189
     * @param string|Expression|Closure $column
190
     * @param bool $distinct
191
     * @return $this
192
     */
193
    public function max(string|Expression|Closure $column, bool $distinct = false): self
194
    {
195
        return $this->addFunction(
196
            'aggregateFunction',
197
            'MAX',
198
            $column,
199
            ['distinct' => $distinct]
200
        );
201
    }
202
203
    /**
204
     * @param Closure $closure
205
     * @return self
206
     */
207
    public static function fromClosure(Closure $closure): self
208
    {
209
        $expression = new Expression();
210
        $closure($expression);
211
212
        return $expression;
213
    }
214
215
    /**
216
     * @param string $type
217
     * @param mixed $value
218
     *
219
     * @return $this
220
     */
221
    protected function addExpression(string $type, mixed $value): self
222
    {
223
        $this->expressions[] = [
224
            'type' => $type,
225
            'value' => $value
226
        ];
227
228
        return $this;
229
    }
230
231
    /**
232
     * @param string $type
233
     * @param string $name
234
     * @param string|Closure|array<int, mixed>|Expression $column
235
     * @param array<string, bool> $arguments
236
     * @return $this
237
     */
238
    protected function addFunction(
239
        string $type,
240
        string $name,
241
        string|Closure|array|Expression $column,
242
        array $arguments = []
243
    ): self {
244
        if ($column instanceof Closure) {
0 ignored issues
show
$column is never a sub-type of Closure.
Loading history...
245
            /** @var Expression $column */
246
            $column = static::fromClosure($column);
247
        } elseif (is_array($column)) {
0 ignored issues
show
The condition is_array($column) is always true.
Loading history...
248
            foreach ($column as &$col) {
249
                if ($col instanceof Closure) {
250
                    /** @var Expression $col */
251
                    $col = static::fromClosure($col);
0 ignored issues
show
$col of type Platine\Database\Query\Expression is incompatible with the type Closure expected by parameter $closure of Platine\Database\Query\Expression::fromClosure(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

251
                    $col = static::fromClosure(/** @scrutinizer ignore-type */ $col);
Loading history...
252
                }
253
            }
254
        }
255
256
        $func = array_merge(
257
            [
258
                'type' => $type,
259
                'name' => $name,
260
                'column' => $column
261
            ],
262
            $arguments
263
        );
264
265
        return $this->addExpression('function', $func);
266
    }
267
}
268