1
|
|
|
<?php |
2
|
|
|
namespace PhpBoot\DB\rules\select; |
3
|
|
|
use PhpBoot\DB\Context; |
4
|
|
|
use PhpBoot\DB\rules\basic\BasicRule; |
5
|
|
|
use PhpBoot\DB\impls\ExecImpl; |
6
|
|
|
use PhpBoot\DB\impls\SelectImpl; |
7
|
|
|
use PhpBoot\DB\impls\FromImpl; |
8
|
|
|
use PhpBoot\DB\impls\JoinImpl; |
9
|
|
|
use PhpBoot\DB\impls\JoinOnImpl; |
10
|
|
|
use PhpBoot\DB\impls\WhereImpl; |
11
|
|
|
use PhpBoot\DB\impls\GroupByImpl; |
12
|
|
|
use PhpBoot\DB\impls\OrderByImpl; |
13
|
|
|
use PhpBoot\DB\impls\LimitImpl; |
14
|
|
|
use PhpBoot\DB\impls\ForUpdateOfImpl; |
15
|
|
|
use PhpBoot\DB\impls\ForUpdateImpl; |
16
|
|
|
use PhpBoot\DB\rules\basic\ScopedQuery; |
17
|
|
|
|
18
|
|
|
require_once dirname(__DIR__).'/impls.php'; |
19
|
|
|
require_once __DIR__.'/basic.php'; |
20
|
|
|
|
21
|
|
|
class SelectRule extends BasicRule |
22
|
|
|
{ |
23
|
|
|
/** |
24
|
|
|
* select('column0, column1') => "SELECT column0, column1" |
25
|
|
|
* select('column0', 'column1') => "SELECT column0, column1" |
26
|
|
|
* @param string $columns |
27
|
|
|
* @return \PhpBoot\DB\rules\select\FromRule |
28
|
|
|
*/ |
29
|
28 |
|
public function select($columns) { |
30
|
28 |
|
SelectImpl::select($this->context, $columns); |
31
|
28 |
|
return new FromRule($this->context); |
32
|
|
|
} |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
class GetRule extends BasicRule |
36
|
|
|
{ |
37
|
|
|
/** |
38
|
|
|
* Execute sql and get responses |
39
|
|
|
* @param string|false $asDict |
40
|
|
|
* @return array |
41
|
|
|
*/ |
42
|
27 |
|
public function get($asDict=false) { |
43
|
27 |
|
return ExecImpl::get($this->context, $asDict); |
|
|
|
|
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* @return int|false |
48
|
|
|
*/ |
49
|
|
|
public function count() { |
50
|
|
|
return ExecImpl::count($this->context); |
51
|
|
|
} |
52
|
|
|
/** |
53
|
|
|
* Execute sql and get one response |
54
|
|
|
* @return null |
55
|
|
|
*/ |
56
|
1 |
|
public function getFirst(){ |
57
|
1 |
|
$res = ExecImpl::get($this->context); |
58
|
1 |
|
if(count($res)){ |
59
|
1 |
|
return $res[0]; |
60
|
|
|
} |
61
|
|
|
return null; |
62
|
|
|
} |
63
|
|
|
} |
64
|
|
|
class FromRule extends GetRule |
65
|
|
|
{ |
66
|
|
|
/** |
67
|
|
|
* from('table') => "FROM table" |
68
|
|
|
* @param string $table |
69
|
|
|
* @return \PhpBoot\DB\rules\select\JoinRule |
70
|
|
|
*/ |
71
|
27 |
|
public function from($table, $as=null){ |
72
|
27 |
|
FromImpl::from($this->context, $table,$as); |
73
|
27 |
|
return new JoinRule($this->context); |
74
|
|
|
} |
75
|
|
|
} |
76
|
|
|
class ForUpdateOfRule extends GetRule |
77
|
|
|
{ |
78
|
|
|
/** |
79
|
|
|
* forUpdate()->of('column') => 'FOR UPDATE OF column' |
80
|
|
|
* @param string $column |
81
|
|
|
* @return \PhpBoot\DB\rules\select\GetRule |
82
|
|
|
*/ |
83
|
1 |
|
public function of($column){ |
84
|
1 |
|
ForUpdateOfImpl::of($this->context, $column); |
85
|
1 |
|
return new GetRule($this->context); |
86
|
|
|
} |
87
|
|
|
} |
88
|
|
|
class ForUpdateRule extends GetRule |
89
|
|
|
{ |
90
|
|
|
/** |
91
|
|
|
* forUpdate() => 'FOR UPDATE' |
92
|
|
|
* @return \PhpBoot\DB\rules\select\ForUpdateOfRule |
93
|
|
|
*/ |
94
|
2 |
|
public function forUpdate(){ |
95
|
2 |
|
ForUpdateImpl::forUpdate($this->context); |
96
|
2 |
|
return new ForUpdateOfRule($this->context); |
97
|
|
|
} |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
class LimitRule extends ForUpdateRule |
101
|
|
|
{ |
102
|
|
|
/** |
103
|
|
|
* limit(0,1) => "LIMIT 0,1" |
104
|
|
|
* @param int $start |
105
|
|
|
* @param int $size |
106
|
|
|
* @return \PhpBoot\DB\rules\select\ForUpdateRule |
107
|
|
|
*/ |
108
|
1 |
|
public function limit($start, $size) { |
109
|
1 |
|
LimitImpl::limitWithOffset($this->context, $start, $size); |
110
|
1 |
|
return new ForUpdateRule($this->context); |
111
|
|
|
} |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
class OrderByRule extends LimitRule |
115
|
|
|
{ |
116
|
27 |
|
public function __construct($context){ |
117
|
27 |
|
parent::__construct($context); |
118
|
27 |
|
$this->order = new OrderByImpl(); |
119
|
27 |
|
} |
120
|
|
|
/** |
121
|
|
|
* orderBy('column') => "ORDER BY column" |
122
|
|
|
* orderBy('column', Sql::ORDER_BY_ASC) => "ORDER BY column ASC" |
123
|
|
|
* orderBy('column0')->orderBy('column1') => "ORDER BY column0, column1" |
124
|
|
|
* |
125
|
|
|
* orderBy(['column0', 'column1'=>Sql::ORDER_BY_ASC]) => "ORDER BY column0,column1 ASC" |
126
|
|
|
* |
127
|
|
|
* @param string $column |
128
|
|
|
* @param string $order Sql::ORDER_BY_ASC or Sql::ORDER_BY_DESC |
129
|
|
|
* @return \PhpBoot\DB\rules\select\OrderByRule |
130
|
|
|
*/ |
131
|
3 |
|
public function orderBy($column, $order=null) { |
132
|
3 |
|
$this->order->orderBy($this->context, $column, $order); |
133
|
3 |
|
return $this; |
134
|
|
|
} |
135
|
|
|
// /** |
136
|
|
|
// * orderByArgs(['column0', 'column1'=>Sql::ORDER_BY_ASC]) => "ORDER BY column0,column1 ASC" |
137
|
|
|
// * @param array $args |
138
|
|
|
// * @return \PhpBoot\DB\rules\select\OrderByRule |
139
|
|
|
// */ |
140
|
|
|
// public function orderByArgs($args) { |
141
|
|
|
// $this->order->orderByArgs($this->context, $args); |
142
|
|
|
// return $this; |
143
|
|
|
// } |
144
|
|
|
/** |
145
|
|
|
* @var OrderByImpl |
146
|
|
|
*/ |
147
|
|
|
private $order; |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
class HavingRule extends OrderByRule |
151
|
|
|
{ |
152
|
5 |
|
public function __construct(Context $context, $isTheFirst = true) |
153
|
|
|
{ |
154
|
5 |
|
parent::__construct($context); |
155
|
5 |
|
$this->isTheFirst = $isTheFirst; |
156
|
5 |
|
} |
157
|
|
|
/** |
158
|
|
|
* |
159
|
|
|
* having('SUM(a)=?', 1) => "HAVING SUM(a)=1" |
160
|
|
|
* having('a>?', Sql::raw('now()')) => "HAVING a>now()" |
161
|
|
|
* having('a IN (?)', [1, 2]) => "HAVING a IN (1,2)" |
162
|
|
|
* |
163
|
|
|
* having([ |
164
|
|
|
* 'a'=>1, |
165
|
|
|
* 'b'=>['IN'=>[1,2]] |
166
|
|
|
* 'c'=>['BETWEEN'=>[1,2]] |
167
|
|
|
* 'd'=>['<>'=>1] |
168
|
|
|
* ]) |
169
|
|
|
* |
170
|
|
|
* => |
171
|
|
|
* "HAVING a=1 AND b IN(1,2) AND c BETWEEN 1 AND 2 AND d<>1" |
172
|
|
|
* |
173
|
|
|
* @param string|array|callable $expr |
174
|
|
|
* @param string $_ |
175
|
|
|
* @return \PhpBoot\DB\rules\select\HavingRule |
176
|
|
|
*/ |
177
|
4 |
|
public function having($expr, $_=null) { |
|
|
|
|
178
|
4 |
|
if(is_callable($expr)){ |
179
|
|
|
$callback = function ($context)use($expr){ |
180
|
1 |
|
$rule = new ScopedQuery($context); |
181
|
1 |
|
$expr($rule); |
182
|
1 |
|
}; |
183
|
1 |
|
$expr = $callback; |
184
|
1 |
|
} |
185
|
4 |
|
if($this->isTheFirst){ |
186
|
4 |
|
WhereImpl::where($this->context, 'HAVING', $expr, array_slice(func_get_args(), 1)); |
187
|
4 |
|
}else{ |
188
|
2 |
|
WhereImpl::where($this->context, 'AND', $expr, array_slice(func_get_args(), 1)); |
189
|
|
|
} |
190
|
|
|
|
191
|
4 |
|
return new HavingRule($this->context, false); |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
/** |
195
|
|
|
* |
196
|
|
|
* orHaving('SUM(a)=?', 1) => "OR SUM(a)=1" |
197
|
|
|
* orHaving('a>?', Sql::raw('now()')) => "OR a>now()" |
198
|
|
|
* orHaving('a IN (?)', [1, 2]) => "OR a IN (1,2)" |
199
|
|
|
* |
200
|
|
|
* orHaving([ |
201
|
|
|
* 'a'=>1, |
202
|
|
|
* 'b'=>['IN'=>[1,2]] |
203
|
|
|
* 'c'=>['BETWEEN'=>[1,2]] |
204
|
|
|
* 'd'=>['<>'=>1] |
205
|
|
|
* ]) |
206
|
|
|
* |
207
|
|
|
* => |
208
|
|
|
* "OR (a=1 AND b IN(1,2) AND c BETWEEN 1 AND 2 AND d<>1)" |
209
|
|
|
* |
210
|
|
|
* @param string|array|callable $expr |
211
|
|
|
* @param string $_ |
212
|
|
|
* @return \PhpBoot\DB\rules\select\HavingRule |
213
|
|
|
*/ |
214
|
1 |
|
public function orHaving($expr, $_=null) { |
|
|
|
|
215
|
1 |
|
if(is_callable($expr)){ |
216
|
|
|
$callback = function ($context)use($expr){ |
217
|
|
|
$rule = new ScopedQuery($context); |
218
|
|
|
$expr($rule); |
219
|
|
|
}; |
220
|
|
|
$expr = $callback; |
221
|
|
|
} |
222
|
1 |
|
WhereImpl::where($this->context, 'OR', $expr, array_slice(func_get_args(), 1)); |
223
|
1 |
|
return new HavingRule($this->context, false); |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
private $isTheFirst; |
227
|
|
|
} |
228
|
|
|
class GroupByRule extends OrderByRule |
229
|
|
|
{ |
230
|
|
|
/** |
231
|
|
|
* groupBy('column') => "GROUP BY column" |
232
|
|
|
* @param string $column |
233
|
|
|
* @return \PhpBoot\DB\rules\select\HavingRule |
234
|
|
|
*/ |
235
|
5 |
|
public function groupBy($column) { |
236
|
5 |
|
GroupByImpl::groupBy($this->context, $column); |
237
|
5 |
|
return new HavingRule($this->context); |
238
|
|
|
} |
239
|
|
|
} |
240
|
|
|
|
241
|
|
View Code Duplication |
class WhereRule extends GroupByRule |
|
|
|
|
242
|
|
|
{ |
243
|
27 |
|
public function __construct(Context $context, $isTheFirst = true) |
244
|
|
|
{ |
245
|
27 |
|
parent::__construct($context); |
246
|
27 |
|
$this->isTheFirst = $isTheFirst; |
247
|
27 |
|
} |
248
|
|
|
|
249
|
|
|
/** |
250
|
|
|
* where('a=?', 1) => "WHERE a=1" |
251
|
|
|
* where('a=?', Sql::raw('now()')) => "WHERE a=now()" |
252
|
|
|
* where('a IN (?)', [1, 2]) => "WHERE a IN (1,2)" |
253
|
|
|
* where([ |
254
|
|
|
* 'a'=>1, |
255
|
|
|
* 'b'=>['IN'=>[1,2]] |
256
|
|
|
* 'c'=>['BETWEEN'=>[1,2]] |
257
|
|
|
* 'd'=>['<>'=>1] |
258
|
|
|
* ]) |
259
|
|
|
* => |
260
|
|
|
* "WHERE a=1 AND b IN(1,2) AND c BETWEEN 1 AND 2 AND d<>1" |
261
|
|
|
* |
262
|
|
|
* @param string|array|callable $conditions |
263
|
|
|
* @param mixed $_ |
264
|
|
|
* @return \PhpBoot\DB\rules\select\NextWhereRule |
265
|
|
|
*/ |
266
|
12 |
|
public function where($conditions=null, $_=null) { |
|
|
|
|
267
|
12 |
|
if(is_callable($conditions)){ |
268
|
1 |
|
$callback = function ($context)use($conditions){ |
269
|
1 |
|
$rule = new ScopedQuery($context); |
270
|
1 |
|
$conditions($rule); |
271
|
1 |
|
}; |
272
|
1 |
|
$conditions = $callback; |
273
|
1 |
|
} |
274
|
12 |
|
if($this->isTheFirst){ |
275
|
12 |
|
WhereImpl::where($this->context, 'WHERE' ,$conditions, array_slice(func_get_args(), 1)); |
276
|
12 |
|
}else{ |
277
|
2 |
|
WhereImpl::where($this->context, 'AND', $conditions, array_slice(func_get_args(), 1)); |
278
|
|
|
} |
279
|
12 |
|
return new NextWhereRule($this->context, false); |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
protected $isTheFirst; |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
|
286
|
|
View Code Duplication |
class NextWhereRule extends WhereRule |
|
|
|
|
287
|
|
|
{ |
288
|
|
|
/** |
289
|
|
|
* orWhere('a=?', 1) => "OR a=1" |
290
|
|
|
* orWhere('a=?', Sql::raw('now()')) => "OR a=now()" |
291
|
|
|
* orWhere('a IN (?)', [1, 2]) => "OR a IN (1,2)" |
292
|
|
|
* orWhere([ |
293
|
|
|
* 'a'=>1, |
294
|
|
|
* 'b'=>['IN'=>[1,2]] |
295
|
|
|
* 'c'=>['BETWEEN'=>[1,2]] |
296
|
|
|
* 'd'=>['<>'=>1] |
297
|
|
|
* ]) |
298
|
|
|
* => |
299
|
|
|
* "OR (a=1 AND b IN(1,2) AND c BETWEEN 1 AND 2 AND d<>1)" |
300
|
|
|
* |
301
|
|
|
* @param string|array|callable $conditions |
302
|
|
|
* @param mixed $_ |
303
|
|
|
* @return \PhpBoot\DB\rules\select\NextWhereRule |
304
|
|
|
* |
305
|
|
|
* @TODO orWhere 只能跟在 Where 后 |
306
|
|
|
*/ |
307
|
1 |
|
public function orWhere($conditions=null, $_=null) { |
|
|
|
|
308
|
1 |
|
if(is_callable($conditions)){ |
309
|
|
|
$callback = function ($context)use($conditions){ |
310
|
|
|
$rule = new ScopedQuery($context); |
311
|
|
|
$conditions($rule); |
312
|
|
|
}; |
313
|
|
|
$conditions = $callback; |
314
|
|
|
} |
315
|
1 |
|
WhereImpl::where($this->context, 'OR', $conditions, array_slice(func_get_args(), 1)); |
316
|
1 |
|
return new NextWhereRule($this->context, false); |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
class JoinRule extends WhereRule |
322
|
|
|
{ |
323
|
|
|
/** |
324
|
|
|
* join('table1')->on('table0.id=table1.id') => "JOIN table1 ON table0.id=table1.id" |
325
|
|
|
* @param string $table |
326
|
|
|
* @return \PhpBoot\DB\rules\select\JoinOnRule |
327
|
|
|
*/ |
328
|
2 |
|
public function join($table){ |
329
|
2 |
|
JoinImpl::join($this->context,null, $table); |
330
|
2 |
|
return new JoinOnRule($this->context); |
331
|
|
|
} |
332
|
|
|
/** |
333
|
|
|
* leftJoin('table1')->on('table0.id=table1.id') => "LEFT JOIN table1 ON table0.id=table1.id" |
334
|
|
|
* @param string $table |
335
|
|
|
* @return \PhpBoot\DB\rules\select\JoinOnRule |
336
|
|
|
*/ |
337
|
1 |
|
public function leftJoin($table){ |
338
|
1 |
|
JoinImpl::join($this->context,'LEFT', $table); |
339
|
1 |
|
return new JoinOnRule($this->context); |
340
|
|
|
} |
341
|
|
|
/** |
342
|
|
|
* rightJoin('table1')->on('table0.id=table1.id') => "RIGHT JOIN table1 ON table0.id=table1.id" |
343
|
|
|
* @param string $table |
344
|
|
|
* @return \PhpBoot\DB\rules\select\JoinOnRule |
345
|
|
|
*/ |
346
|
1 |
|
public function rightJoin($table) { |
347
|
1 |
|
JoinImpl::join($this->context,'RIGHT', $table); |
348
|
1 |
|
return new JoinOnRule($this->context); |
349
|
|
|
} |
350
|
|
|
/** |
351
|
|
|
* innerJoin('table1')->on('table0.id=table1.id') => "INNER JOIN table1 ON table0.id=table1.id" |
352
|
|
|
* @param string $table |
353
|
|
|
* @return \PhpBoot\DB\rules\select\JoinOnRule |
354
|
|
|
*/ |
355
|
1 |
|
public function innerJoin($table) { |
356
|
1 |
|
JoinImpl::join($this->context,'INNER', $table); |
357
|
1 |
|
return new JoinOnRule($this->context); |
358
|
|
|
} |
359
|
|
|
} |
360
|
|
|
|
361
|
|
|
class JoinOnRule extends BasicRule |
362
|
|
|
{ |
363
|
|
|
/** |
364
|
|
|
* join('table1')->on('table0.id=table1.id') => "JOIN table1 ON table0.id=table1.id" |
365
|
|
|
* @param string $condition |
366
|
|
|
* @return \PhpBoot\DB\rules\select\JoinRule |
367
|
|
|
*/ |
368
|
5 |
|
public function on($condition){ |
369
|
5 |
|
JoinOnImpl::on($this->context, $condition); |
370
|
5 |
|
return new JoinRule($this->context); |
371
|
|
|
} |
372
|
|
|
} |
373
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.