Completed
Push — master ( 38d909...e2a527 )
by Hong
05:34
created

JoinTrait::rightJoin()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
rs 10
cc 1
eloc 2
nc 1
nop 3
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\Clause\JoinInterface;
18
use Phossa2\Query\Interfaces\ExpressionInterface;
19
20
/**
21
 * JoinTrait
22
 *
23
 * Implementation of JoinInterface
24
 *
25
 * @package Phossa2\Query
26
 * @author  Hong Zhang <[email protected]>
27
 * @see     JoinInterface
28
 * @version 2.0.0
29
 * @since   2.0.0 added
30
 */
31
trait JoinTrait
32
{
33
    /**
34
     * {@inheritDoc}
35
     */
36
    public function join($secondTable, $onClause = '', $firstTable = '')
37
    {
38
        return $this->realJoin('INNER JOIN', $secondTable, $onClause, $firstTable);
39
    }
40
41
    /**
42
     * {@inheritDoc}
43
     */
44
    public function leftJoin($secondTable, $onClause = '', $firstTable = '')
45
    {
46
        return $this->realJoin('LEFT JOIN', $secondTable, $onClause, $firstTable);
47
    }
48
49
    /**
50
     * {@inheritDoc}
51
     */
52
    public function rightJoin($secondTable, $onClause = '', $firstTable = '')
53
    {
54
        return $this->realJoin('RIGHT JOIN', $secondTable, $onClause, $firstTable);
55
    }
56
57
    /**
58
     * {@inheritDoc}
59
     */
60
    public function joinRaw(/*# string */ $joinType, /*# string */ $rawString)
61
    {
62
        return $this->realJoin($joinType, $rawString, '', '', true);
63
    }
64
65
    /**
66
     * The real join
67
     *
68
     * @param  string $joinType
69
     * @param  string|string[]|SelectStatementInterface $secondTable
70
     * @param  string|string[]|ExpressionInterface $onClause
71
     * @param  string $firstTable
72
     * @param  bool $rawMode
73
     * @return $this
74
     * @access protected
75
     */
76
    protected function realJoin(
77
        /*# string */ $joinType,
78
        $secondTable,
79
        $onClause = '',
80
        $firstTable = '',
81
        /*# bool */ $rawMode = false
82
    ) {
83
        // totally raw
84
        if ($rawMode || '' === $onClause) {
85
            $rawMode = true;
86
            $alias = 0; // no alias
87
        }
88
89
        // fix table, alias, on clause
90
        if (!$rawMode) {
91
            $onClause = $this->fixOnClause($onClause);
92
            list($secondTable, $alias) = $this->fixJoinTable($secondTable);
93
        }
94
95
        $clause = &$this->getClause('JOIN');
96
        $clause[] = [$rawMode, $joinType, $secondTable, $alias, $onClause, $firstTable];
0 ignored issues
show
Bug introduced by
The variable $alias does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
97
98
        return $this;
99
    }
100
101
    /**
102
     * Fix join table
103
     *
104
     * @param  string|string[]|SelectStatementInterface $table
105
     * @return array [table, alias]
106
     * @access protected
107
     */
108
    protected function fixJoinTable($table)
109
    {
110
        if (is_object($table)) {
111
            return [$table, uniqid()]; // need an alias
112
        } elseif (is_string($table)) {
113
            return [$table, 0]; // alias set 0
114
        } else {
115
            return $table; // array
116
        }
117
    }
118
119
    /**
120
     * Fix 'ON' clause
121
     *
122
     * @param  mixed $onClause
123
     * @return array|ExpressionInterface
124
     * @access protected
125
     */
126
    protected function fixOnClause($onClause)
127
    {
128
        if (is_string($onClause)) {
129
            return [$onClause, '=', $onClause];
130
        } elseif (is_array($onClause) && !isset($onClause[2])) {
131
            return [$onClause[0], '=', $onClause[1]];
132
        } else {
133
            return $onClause;
134
        }
135
    }
136
137
    /**
138
     * Build join
139
     *
140
     * @param  string $prefix
141
     * @param  array $settings
142
     * @return string
143
     * @access protected
144
     */
145
    protected function buildJoin(
146
        /*# string */ $prefix,
1 ignored issue
show
Unused Code introduced by
The parameter $prefix 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...
147
        array $settings
148
    )/*# : string */ {
149
        $string = '';
150
        $clause = &$this->getClause('JOIN');
151
        foreach ($clause as $cls) {
152
            $result = [];
153
            $prefix = $cls[1]; // join type
154
            if ($cls[0]) { // raw mode
155
                $result[] = $cls[2];
156
            } else {
157
                $result[] = $this->buildJoinTable($cls, $settings);
158
                $result[] = $this->buildJoinOn($cls, $settings);
159
            }
160
            $string .= $this->joinClause($prefix, '', $result, $settings);
161
        }
162
        return $string;
163
    }
164
165
    /**
166
     * Build TABLE part
167
     *
168
     * @param  array $cls
169
     * @param  array $settings
170
     * @return string
171
     * @access protected
172
     */
173
    protected function buildJoinTable(array $cls, array $settings)/*# : string */
174
    {
175
        $table = $cls[2];
176
        $alias = $cls[3];
177
        return $this->quoteItem($table, $settings) . $this->quoteAlias($alias, $settings);
178
    }
179
180
    /**
181
     * Build ON part
182
     *
183
     * @param  array $cls
184
     * @param  array $settings
185
     * @return string
186
     * @access protected
187
     */
188
    protected function buildJoinOn(array $cls, array $settings)/*# : string */
189
    {
190
        $on = $cls[4];
191
        $res = ['ON'];
192
193
        if (is_object($on)) {
194
            $res[] = $on->getStatement($settings);
195
        } else {
196
            // first
197
            $res[] = $this->quote($this->getFirstTableAlias($cls) . $on[0], $settings);
0 ignored issues
show
Bug introduced by
It seems like quote() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
198
            // operator
199
            $res[] = $on[1];
200
            // second
201
            $res[] = $this->quote($this->getSecondTableAlias($cls) . $on[2], $settings);
0 ignored issues
show
Bug introduced by
It seems like quote() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
202
        }
203
        return join(' ', $res);
204
    }
205
206
    /**
207
     * Get first table alias
208
     *
209
     * @param  array $cls
210
     * @return string
211
     * @access protected
212
     */
213
    protected function getFirstTableAlias(array $cls)/*# : string */
214
    {
215
        // first table specified
216
        if (!empty($cls[5])) {
217
            return $cls[5] . '.';
218
        } else {
219
            $tables = &$this->getClause('FROM');
220
            reset($tables);
221
            $alias = key($tables);
222
            return (is_int($alias) ? $tables[$alias][0] : $alias) . '.';
223
        }
224
    }
225
226
    /**
227
     * Get second table alias
228
     *
229
     * @param  array $cls
230
     * @return string
231
     * @access protected
232
     */
233
    protected function getSecondTableAlias(array $cls)/*# : string */
234
    {
235
        $alias = $cls[3];
236
        if (!is_string($alias)) {
237
            $alias = $cls[2];
238
        }
239
        return $alias . '.';
240
    }
241
242
    abstract protected function isRaw($str, /*# bool */ $rawMode)/*# : bool */;
243
    abstract protected function &getClause(/*# string */ $clauseName)/*# : array */;
244
    abstract protected function flatSettings(array $settings)/*# : array */;
245
    abstract protected function quoteItem(
246
        $item,
247
        array $settings,
248
        /*# bool */ $rawMode = false
249
    )/*# : string */;
250
    abstract protected function quoteAlias($alias, array $settings)/*# : string */;
251
    abstract protected function joinClause(
252
        /*# : string */ $prefix,
253
        /*# : string */ $seperator,
254
        array $clause,
255
        array $settings
256
    )/*# : string */;
257
}
258