Completed
Branch develop (f7dc53)
by Anton
05:49
created

JoinsTrait::whereWrapper()   B

Complexity

Conditions 6
Paths 1

Size

Total Lines 27
Code Lines 12

Duplication

Lines 27
Ratio 100 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 27
loc 27
rs 8.439
cc 6
eloc 12
nc 1
nop 0
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
namespace Spiral\Database\Builders\Traits;
9
10
use Spiral\Database\Entities\QueryBuilder;
11
use Spiral\Database\Exceptions\BuilderException;
12
use Spiral\Database\Injections\Expression;
13
use Spiral\Database\Injections\FragmentInterface;
14
use Spiral\Database\Injections\Parameter;
15
use Spiral\Database\Injections\ParameterInterface;
16
17
/**
18
 * Provides ability to generate QueryCompiler JOIN tokens including ON conditions and table/column
19
 * aliases.
20
 *
21
 * Simple joins (ON userID = users.id):
22
 * $select->join('LEFT', 'info', 'userID', 'users.id');
23
 * $select->leftJoin('info', 'userID', '=', 'users.id');
24
 * $select->rightJoin('info', ['userID' => 'users.id']);
25
 *
26
 * More complex ON conditions:
27
 * $select->leftJoin('info', function($select) {
28
 *      $select->on('userID', 'users.id')->orOn('userID', 'users.masterID');
29
 * });
30
 *
31
 * To specify on conditions outside join method use "on" methods.
32
 * $select->leftJoin('info')->on('userID', '=', 'users.id');
33
 *
34
 * On methods will only support conditions based on outer table columns. You can not use parametric
35
 * values here, use "on where" conditions instead.
36
 * $select->leftJoin('info')->on('userID', '=', 'users.id')->onWhere('value', 100);
37
 *
38
 * Arguments and syntax in "on" and "onWhere" conditions is identical to "where" method defined in
39
 * AbstractWhere.
40
 * Attention, "on" and "onWhere" conditions will be applied to last registered join only!
41
 *
42
 * You can also use table aliases and use them in conditions after:
43
 * $select->join('LEFT', 'info as i')->on('i.userID', 'users.id');
44
 * $select->join('LEFT', 'info as i', function($select) {
45
 *      $select->on('i.userID', 'users.id')->orOn('i.userID', 'users.masterID');
46
 * });
47
 *
48
 * @see AbstractWhere
49
 */
50
trait JoinsTrait
51
{
52
    /**
53
     * Name/id of last join, every ON and ON WHERE call will be associated with this join.
54
     *
55
     * @var string
56
     */
57
    private $activeJoin = null;
58
59
    /**
60
     * Set of join tokens with on and on where conditions associated, must be supported by
61
     * QueryCompilers.
62
     *
63
     * @var array
64
     */
65
    protected $joinTokens = [];
66
67
    /**
68
     * Parameters collected while generating ON WHERE tokens, must be in a same order as parameters
69
     * in resulted query. Parameters declared in ON methods will be converted into expressions and
70
     * will not be aggregated.
71
     *
72
     * @see AbstractWhere
73
     * @var array
74
     */
75
    protected $onParameters = [];
76
77
    /**
78
     * Register new JOIN with specified type with set of on conditions (linking one table to
79
     * another, no parametric on conditions allowed here).
80
     *
81
     * @param string $type  Join type. Allowed values, LEFT, RIGHT, INNER and etc.
82
     * @param string $table Joined table name (without prefix), may include AS statement.
83
     * @param mixed  $on    Simplified on definition linking table names (no parameters allowed) or
84
     *                      closure.
85
     * @return $this
86
     * @throws BuilderException
87
     */
88
    public function join($type, $table, $on = null)
0 ignored issues
show
Unused Code introduced by
The parameter $on is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
89
    {
90
        $this->joinTokens[$this->activeJoin = $table] = ['type' => strtoupper($type), 'on' => []];
91
92
        return call_user_func_array([$this, 'on'], array_slice(func_get_args(), 2));
93
    }
94
95
    /**
96
     * Register new INNER JOIN with set of on conditions (linking one table to another, no
97
     * parametric on conditions allowed here).
98
     *
99
     * @link http://www.w3schools.com/sql/sql_join_inner.asp
100
     * @see  join()
101
     * @param string $table Joined table name (without prefix), may include AS statement.
102
     * @param mixed  $on    Simplified on definition linking table names (no parameters allowed) or
103
     *                      closure.
104
     * @return $this
105
     * @throws BuilderException
106
     */
107
    public function innerJoin($table, $on = null)
0 ignored issues
show
Unused Code introduced by
The parameter $on is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
108
    {
109
        $this->joinTokens[$this->activeJoin = $table] = ['type' => 'INNER', 'on' => []];
110
111
        return call_user_func_array([$this, 'on'], array_slice(func_get_args(), 1));
112
    }
113
114
    /**
115
     * Register new RIGHT JOIN with set of on conditions (linking one table to another, no
116
     * parametric on conditions allowed here).
117
     *
118
     * @link http://www.w3schools.com/sql/sql_join_right.asp
119
     * @see  join()
120
     * @param string $table Joined table name (without prefix), may include AS statement.
121
     * @param mixed  $on    Simplified on definition linking table names (no parameters allowed) or
122
     *                      closure.
123
     * @return $this
124
     * @throws BuilderException
125
     */
126
    public function rightJoin($table, $on = null)
0 ignored issues
show
Unused Code introduced by
The parameter $on is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
127
    {
128
        $this->joinTokens[$this->activeJoin = $table] = ['type' => 'RIGHT', 'on' => []];
129
130
        return call_user_func_array([$this, 'on'], array_slice(func_get_args(), 1));
131
    }
132
133
    /**
134
     * Register new LEFT JOIN with set of on conditions (linking one table to another, no parametric
135
     * on conditions allowed here).
136
     *
137
     * @link http://www.w3schools.com/sql/sql_join_left.asp
138
     * @see  join()
139
     * @param string $table Joined table name (without prefix), may include AS statement.
140
     * @param mixed  $on    Simplified on definition linking table names (no parameters allowed) or
141
     *                      closure.
142
     * @return $this
143
     * @throws BuilderException
144
     */
145
    public function leftJoin($table, $on = null)
0 ignored issues
show
Unused Code introduced by
The parameter $on is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
146
    {
147
        $this->joinTokens[$this->activeJoin = $table] = ['type' => 'LEFT', 'on' => []];
148
149
        return call_user_func_array([$this, 'on'], array_slice(func_get_args(), 1));
150
    }
151
152
    /**
153
     * Register new FULL JOIN with set of on conditions (linking one table to another, no parametric
154
     * on conditions allowed here).
155
     *
156
     * @link http://www.w3schools.com/sql/sql_join_full.asp
157
     * @see  join()
158
     * @param string $table Joined table name (without prefix), may include AS statement.
159
     * @param mixed  $on    Simplified on definition linking table names (no parameters allowed) or
160
     *                      closure.
161
     * @return $this
162
     * @throws BuilderException
163
     */
164
    public function fullJoin($table, $on = null)
0 ignored issues
show
Unused Code introduced by
The parameter $on is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
165
    {
166
        $this->joinTokens[$this->activeJoin = $table] = ['type' => 'FULL', 'on' => []];
167
168
        return call_user_func_array([$this, 'on'], array_slice(func_get_args(), 1));
169
    }
170
171
    /**
172
     * Simple ON condition with various set of arguments. Can only be used to link column values
173
     * together, no parametric values allowed.
174
     *
175
     * @param mixed $joined   Joined column name or expression.
176
     * @param mixed $operator Foreign column name, if operator specified.
177
     * @param mixed $outer    Foreign column name.
178
     * @return $this
179
     * @throws BuilderException
180
     */
181 View Code Duplication
    public function on($joined = null, $operator = null, $outer = null)
0 ignored issues
show
Unused Code introduced by
The parameter $joined is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $outer is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
182
    {
183
        $this->whereToken(
184
            'AND', func_get_args(), $this->joinTokens[$this->activeJoin]['on'],
185
            $this->onWrapper()
186
        );
187
188
        return $this;
189
    }
190
191
    /**
192
     * Simple AND ON condition with various set of arguments. Can only be used to link column values
193
     * together, no parametric values allowed.
194
     *
195
     * @param mixed $joined   Joined column name or expression.
196
     * @param mixed $operator Foreign column name, if operator specified.
197
     * @param mixed $outer    Foreign column name.
198
     * @return $this
199
     * @throws BuilderException
200
     */
201 View Code Duplication
    public function andOn($joined = null, $operator = null, $outer = null)
0 ignored issues
show
Unused Code introduced by
The parameter $joined is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $outer is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
202
    {
203
        $this->whereToken(
204
            'AND', func_get_args(), $this->joinTokens[$this->activeJoin]['on'],
205
            $this->onWrapper()
206
        );
207
208
        return $this;
209
    }
210
211
    /**
212
     * Simple OR ON condition with various set of arguments. Can only be used to link column values
213
     * together, no parametric values allowed.
214
     *
215
     * @param mixed $joined   Joined column name or expression.
216
     * @param mixed $operator Foreign column name, if operator specified.
217
     * @param mixed $outer    Foreign column name.
218
     * @return $this
219
     * @throws BuilderException
220
     */
221 View Code Duplication
    public function orOn($joined = null, $operator = null, $outer = null)
0 ignored issues
show
Unused Code introduced by
The parameter $joined is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $operator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $outer is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
222
    {
223
        $this->whereToken(
224
            'AND', func_get_args(), $this->joinTokens[$this->activeJoin]['on'], $this->onWrapper()
225
        );
226
227
        return $this;
228
    }
229
230
    /**
231
     * Simple ON WHERE condition with various set of arguments. You can use parametric values in
232
     * such methods.
233
     *
234
     * @see AbstractWhere
235
     * @param string|mixed $joined   Joined column or expression.
236
     * @param mixed        $variousA Operator or value.
237
     * @param mixed        $variousB Value, if operator specified.
238
     * @param mixed        $variousC Required only in between statements.
239
     * @return $this
240
     * @throws BuilderException
241
     */
242 View Code Duplication
    public function onWhere($joined, $variousA = null, $variousB = null, $variousC = null)
0 ignored issues
show
Unused Code introduced by
The parameter $joined is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $variousA is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $variousB is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $variousC is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
243
    {
244
        $this->whereToken(
245
            'AND', func_get_args(), $this->joinTokens[$this->activeJoin]['on'],
246
            $this->whereWrapper()
247
        );
248
249
        return $this;
250
    }
251
252
    /**
253
     * Simple AND ON WHERE condition with various set of arguments. You can use parametric values in
254
     * such methods.
255
     *
256
     * @see AbstractWhere
257
     * @param string|mixed $joined   Joined column or expression.
258
     * @param mixed        $variousA Operator or value.
259
     * @param mixed        $variousB Value, if operator specified.
260
     * @param mixed        $variousC Required only in between statements.
261
     * @return $this
262
     * @throws BuilderException
263
     */
264 View Code Duplication
    public function andOnWhere($joined, $variousA = null, $variousB = null, $variousC = null)
0 ignored issues
show
Unused Code introduced by
The parameter $joined is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $variousA is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $variousB is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $variousC is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
265
    {
266
        $this->whereToken(
267
            'AND', func_get_args(), $this->joinTokens[$this->activeJoin]['on'],
268
            $this->whereWrapper()
269
        );
270
271
        return $this;
272
    }
273
274
    /**
275
     * Simple OR ON WHERE condition with various set of arguments. You can use parametric values in
276
     * such methods.
277
     *
278
     * @see AbstractWhere
279
     * @param string|mixed $joined   Joined column or expression.
280
     * @param mixed        $variousA Operator or value.
281
     * @param mixed        $variousB Value, if operator specified.
282
     * @param mixed        $variousC Required only in between statements.
283
     * @return $this
284
     * @throws BuilderException
285
     */
286 View Code Duplication
    public function orOnWhere($joined, $variousA = null, $variousB = null, $variousC = null)
0 ignored issues
show
Unused Code introduced by
The parameter $joined is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $variousA is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $variousB is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $variousC is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
287
    {
288
        $this->whereToken(
289
            'AND', func_get_args(), $this->joinTokens[$this->activeJoin]['on'],
290
            $this->whereWrapper()
291
        );
292
293
        return $this;
294
    }
295
296
    /**
297
     * Convert various amount of where function arguments into valid where token.
298
     *
299
     * @see AbstractWhere
300
     * @param string        $joiner     Boolean joiner (AND | OR).
301
     * @param array         $parameters Set of parameters collected from where functions.
302
     * @param array         $tokens     Array to aggregate compiled tokens. Reference.
303
     * @param \Closure|null $wrapper    Callback or closure used to wrap/collect every potential
304
     *                                  parameter.
305
     * @throws BuilderException
306
     */
307
    abstract protected function whereToken(
308
        $joiner,
309
        array $parameters,
310
        &$tokens = [],
311
        callable $wrapper
312
    );
313
314
    /**
315
     * Convert parameters used in JOIN ON statements into sql expressions.
316
     *
317
     * @return \Closure
318
     */
319
    private function onWrapper()
320
    {
321
        return function ($parameter) {
322
            if ($parameter instanceof FragmentInterface) {
323
                return $parameter;
324
            }
325
326
            return new Expression($parameter);
327
        };
328
    }
329
330
    /**
331
     * Applied to every potential parameter while ON WHERE tokens generation.
332
     *
333
     * @return \Closure
334
     */
335 View Code Duplication
    private function whereWrapper()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
336
    {
337
        return function ($parameter) {
338
            if ($parameter instanceof FragmentInterface) {
339
                //We are only not creating bindings for plan fragments
340
                if (!$parameter instanceof ParameterInterface && !$parameter instanceof QueryBuilder) {
341
                    return $parameter;
342
                }
343
344
                return $parameter;
345
            }
346
347
            if (is_array($parameter)) {
348
                throw new BuilderException("Arrays must be wrapped with Parameter instance.");
349
            }
350
351
            //Wrapping all values with ParameterInterface
352
            if (!$parameter instanceof ParameterInterface) {
353
                $parameter = new Parameter($parameter, Parameter::DETECT_TYPE);
354
            };
355
356
            //Let's store to sent to driver when needed
357
            $this->onParameters[] = $parameter;
358
359
            return $parameter;
360
        };
361
    }
362
}