1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Phossa Project |
4
|
|
|
* |
5
|
|
|
* PHP version 5.4 |
6
|
|
|
* |
7
|
|
|
* @category Library |
8
|
|
|
* @package Phossa2\Query |
9
|
|
|
* @copyright Copyright (c) 2016 phossa.com |
10
|
|
|
* @license http://mit-license.org/ MIT License |
11
|
|
|
* @link http://www.phossa.com/ |
12
|
|
|
*/ |
13
|
|
|
/*# declare(strict_types=1); */ |
14
|
|
|
|
15
|
|
|
namespace Phossa2\Query\Traits\Clause; |
16
|
|
|
|
17
|
|
|
use Phossa2\Query\Interfaces\StatementInterface; |
18
|
|
|
use Phossa2\Query\Interfaces\ExpressionInterface; |
19
|
|
|
use Phossa2\Query\Interfaces\Clause\JoinInterface; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* JoinTrait |
23
|
|
|
* |
24
|
|
|
* Implementation of JoinInterface |
25
|
|
|
* |
26
|
|
|
* @package Phossa2\Query |
27
|
|
|
* @author Hong Zhang <[email protected]> |
28
|
|
|
* @see JoinInterface |
29
|
|
|
* @version 2.0.0 |
30
|
|
|
* @since 2.0.0 added |
31
|
|
|
*/ |
32
|
|
|
trait JoinTrait |
33
|
|
|
{ |
34
|
|
|
use AbstractTrait; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* {@inheritDoc} |
38
|
|
|
*/ |
39
|
|
|
public function join($secondTable, $onClause = '') |
40
|
|
|
{ |
41
|
|
|
return $this->realJoin('INNER JOIN', $secondTable, $onClause); |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* {@inheritDoc} |
46
|
|
|
*/ |
47
|
|
|
public function leftJoin($secondTable, $onClause = '') |
48
|
|
|
{ |
49
|
|
|
return $this->realJoin('LEFT JOIN', $secondTable, $onClause); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* {@inheritDoc} |
54
|
|
|
*/ |
55
|
|
|
public function leftOuterJoin($secondTable, $onClause = '') |
56
|
|
|
{ |
57
|
|
|
return $this->realJoin('LEFT OUTER JOIN', $secondTable, $onClause); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* {@inheritDoc} |
62
|
|
|
*/ |
63
|
|
|
public function rightJoin($secondTable, $onClause = '') |
64
|
|
|
{ |
65
|
|
|
return $this->realJoin('RIGHT JOIN', $secondTable, $onClause); |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* {@inheritDoc} |
70
|
|
|
*/ |
71
|
|
|
public function rightOuterJoin($secondTable, $onClause = '') |
72
|
|
|
{ |
73
|
|
|
return $this->realJoin('RIGHT OUTER JOIN', $secondTable, $onClause); |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* {@inheritDoc} |
78
|
|
|
*/ |
79
|
|
|
public function outerJoin($secondTable, $onClause = '') |
80
|
|
|
{ |
81
|
|
|
return $this->realJoin('OUTER JOIN', $secondTable, $onClause); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* {@inheritDoc} |
86
|
|
|
*/ |
87
|
|
|
public function crossJoin($secondTable, $onClause = '') |
88
|
|
|
{ |
89
|
|
|
return $this->realJoin('CROSS JOIN', $secondTable, $onClause); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* {@inheritDoc} |
94
|
|
|
*/ |
95
|
|
|
public function joinRaw( |
96
|
|
|
/*# string */ $joinType, |
97
|
|
|
/*# string */ $rawString, |
98
|
|
|
array $params = [] |
99
|
|
|
) { |
100
|
|
|
|
101
|
|
|
$rawString = $this->positionedParam($rawString, $params); |
102
|
|
|
return $this->realJoin(strtoupper($joinType), $rawString, '', true); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* The real join |
107
|
|
|
* |
108
|
|
|
* @param string $joinType |
109
|
|
|
* @param string|string[]|SelectStatementInterface $secondTable |
110
|
|
|
* @param string|string[]|ExpressionInterface $onClause |
111
|
|
|
* @param bool $rawMode |
112
|
|
|
* @return $this |
113
|
|
|
* @access protected |
114
|
|
|
*/ |
115
|
|
|
protected function realJoin( |
116
|
|
|
/*# string */ $joinType, |
117
|
|
|
$secondTable, |
118
|
|
|
$onClause = '', |
119
|
|
|
/*# bool */ $rawMode = false |
120
|
|
|
) { |
121
|
|
|
$alias = 0; // no alias |
122
|
|
|
list($secondTable, $alias) = $this->fixJoinTable($secondTable); |
123
|
|
|
|
124
|
|
|
if ($rawMode || '' === $onClause || $this->isRaw($onClause, false)) { |
125
|
|
|
$rawMode = true; |
126
|
|
|
} else { |
127
|
|
|
$onClause = $this->fixOnClause($onClause); |
128
|
|
|
} |
129
|
|
|
$clause = &$this->getClause('JOIN'); |
130
|
|
|
$clause[] = [$rawMode, $joinType, $secondTable, $alias, $onClause]; |
131
|
|
|
return $this; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Fix join table |
136
|
|
|
* |
137
|
|
|
* @param string|string[]|SelectStatementInterface $table |
138
|
|
|
* @return array [table, alias] |
139
|
|
|
* @access protected |
140
|
|
|
*/ |
141
|
|
|
protected function fixJoinTable($table) |
142
|
|
|
{ |
143
|
|
|
if (is_array($table)) { |
144
|
|
|
return $table; |
145
|
|
|
} elseif (is_object($table) && $table instanceof StatementInterface) { |
146
|
|
|
return [$table, uniqid()]; |
147
|
|
|
} else { |
148
|
|
|
return [$table, 0]; // alias set 0 |
149
|
|
|
} |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* Fix 'ON' clause |
154
|
|
|
* |
155
|
|
|
* @param mixed $onClause |
156
|
|
|
* @return array|ExpressionInterface |
157
|
|
|
* @access protected |
158
|
|
|
*/ |
159
|
|
|
protected function fixOnClause($onClause) |
160
|
|
|
{ |
161
|
|
|
if (is_string($onClause)) { |
162
|
|
|
return [$onClause, '=', $onClause]; |
163
|
|
|
} elseif (is_array($onClause) && !isset($onClause[2])) { |
164
|
|
|
return [$onClause[0], '=', $onClause[1]]; |
165
|
|
|
} else { |
166
|
|
|
return $onClause; |
167
|
|
|
} |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* Build join |
172
|
|
|
* |
173
|
|
|
* @param string $prefix |
174
|
|
|
* @param array $settings |
175
|
|
|
* @return string |
176
|
|
|
* @access protected |
177
|
|
|
*/ |
178
|
|
View Code Duplication |
protected function buildJoin( |
|
|
|
|
179
|
|
|
/*# string */ $prefix, |
|
|
|
|
180
|
|
|
array $settings |
181
|
|
|
)/*# : string */ { |
182
|
|
|
$string = ''; |
183
|
|
|
$clause = &$this->getClause('JOIN'); |
184
|
|
|
foreach ($clause as $cls) { |
185
|
|
|
$result = []; |
186
|
|
|
$prefix = $cls[1]; // join type |
187
|
|
|
$result[] = $this->buildJoinTable($cls, $settings); // join table |
188
|
|
|
if (!empty($cls[4])) { |
189
|
|
|
$result[] = $this->buildJoinOn($cls, $settings); |
190
|
|
|
} |
191
|
|
|
$string .= $this->joinClause($prefix, '', $result, $settings); |
192
|
|
|
} |
193
|
|
|
return $string; |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* Build TABLE part |
198
|
|
|
* |
199
|
|
|
* @param array $cls |
200
|
|
|
* @param array $settings |
201
|
|
|
* @return string |
202
|
|
|
* @access protected |
203
|
|
|
*/ |
204
|
|
|
protected function buildJoinTable(array $cls, array $settings)/*# : string */ |
205
|
|
|
{ |
206
|
|
|
$table = $cls[2]; |
207
|
|
|
$alias = $cls[3]; |
208
|
|
|
return $this->quoteItem($table, $settings) . $this->quoteAlias($alias, $settings); |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Build ON part |
213
|
|
|
* |
214
|
|
|
* @param array $cls |
215
|
|
|
* @param array $settings |
216
|
|
|
* @return string |
217
|
|
|
* @access protected |
218
|
|
|
*/ |
219
|
|
|
protected function buildJoinOn(array $cls, array $settings)/*# : string */ |
220
|
|
|
{ |
221
|
|
|
$res = ['ON']; |
222
|
|
|
$on = $cls[4]; |
223
|
|
|
if (is_string($on)) { // ON string |
224
|
|
|
$res[] = $on; |
225
|
|
|
} elseif (is_object($on)) { // ON is an object |
226
|
|
|
$res[] = $this->quoteItem($on, $settings); |
227
|
|
|
} else { // common on |
228
|
|
|
$res[] = $this->quote( // left |
229
|
|
|
$this->getFirstTableAlias($on[0]) . $on[0], |
230
|
|
|
$settings |
231
|
|
|
); |
232
|
|
|
$res[] = $on[1]; // operator |
233
|
|
|
$res[] = $this->quote( // right |
234
|
|
|
$this->getSecondTableAlias($cls, $on[2]) . $on[2], |
235
|
|
|
$settings |
236
|
|
|
); |
237
|
|
|
} |
238
|
|
|
return join(' ', $res); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Get first table alias |
243
|
|
|
* |
244
|
|
|
* @param string $left left part of eq |
245
|
|
|
* @return string |
246
|
|
|
* @access protected |
247
|
|
|
*/ |
248
|
|
|
protected function getFirstTableAlias( |
249
|
|
|
/*# string */ $left |
250
|
|
|
)/*# : string */ { |
251
|
|
|
if (false !== strpos($left, '.')) { // alias exists |
252
|
|
|
return ''; |
253
|
|
|
} else { // prepend first table alias |
254
|
|
|
$tables = &$this->getClause('TABLE'); |
255
|
|
|
reset($tables); |
256
|
|
|
$alias = key($tables); |
257
|
|
|
return (is_int($alias) ? $tables[$alias][0] : $alias) . '.'; |
258
|
|
|
} |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
/** |
262
|
|
|
* Get second table alias |
263
|
|
|
* |
264
|
|
|
* @param array $cls |
265
|
|
|
* @param string $right right part of eq |
266
|
|
|
* @return string |
267
|
|
|
* @access protected |
268
|
|
|
*/ |
269
|
|
|
protected function getSecondTableAlias( |
270
|
|
|
array $cls, |
271
|
|
|
/*# string */ $right |
272
|
|
|
)/*# : string */ { |
273
|
|
|
if (false !== strpos($right, '.')) { |
274
|
|
|
return ''; |
275
|
|
|
} else { |
276
|
|
|
$alias = $cls[3]; |
277
|
|
|
if (!is_string($alias)) { |
278
|
|
|
$alias = $cls[2]; |
279
|
|
|
} |
280
|
|
|
return $alias . '.'; |
281
|
|
|
} |
282
|
|
|
} |
283
|
|
|
} |
284
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.