Completed
Push — master ( 78a151...8716b9 )
by Dmitry
33:23 queued 26:41
created

BetweenColumnsConditionBuilder::escapeColumnName()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.0218

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 8
cts 9
cp 0.8889
rs 9.2
c 0
b 0
f 0
cc 4
eloc 9
nc 4
nop 2
crap 4.0218
1
<?php
2
3
namespace yii\db\conditions;
4
5
use yii\db\ExpressionBuilderInterface;
6
use yii\db\ExpressionBuilderTrait;
7
use yii\db\ExpressionInterface;
8
use yii\db\Query;
9
10
/**
11
 * Class BetweenColumnsConditionBuilder builds objects of [[BetweenColumnsCondition]]
12
 *
13
 * @author Dmytro Naumenko <[email protected]>
14
 * @since 2.0.14
15
 */
16
class BetweenColumnsConditionBuilder implements ExpressionBuilderInterface
17
{
18
    use ExpressionBuilderTrait;
19
20
    /**
21
     * Method builds the raw SQL from the $expression that will not be additionally
22
     * escaped or quoted.
23
     *
24
     * @param ExpressionInterface|BetweenColumnsCondition $expression the expression to be built.
25
     * @param array $params the binding parameters.
26
     * @return string the raw SQL that will not be additionally escaped or quoted.
27
     */
28 15
    public function build(ExpressionInterface $expression, array &$params = [])
29
    {
30 15
        $operator = $expression->getOperator();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface yii\db\ExpressionInterface as the method getOperator() does only exist in the following implementations of said interface: yii\db\conditions\AndCondition, yii\db\conditions\BetweenColumnsCondition, yii\db\conditions\BetweenCondition, yii\db\conditions\ConjunctionCondition, yii\db\conditions\ExistsCondition, yii\db\conditions\InCondition, yii\db\conditions\LikeCondition, yii\db\conditions\OrCondition, yii\db\conditions\SimpleCondition.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
31
32 15
        $startColumn = $this->escapeColumnName($expression->getIntervalStartColumn(), $params);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface yii\db\ExpressionInterface as the method getIntervalStartColumn() does only exist in the following implementations of said interface: yii\db\conditions\BetweenColumnsCondition.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
33 15
        $endColumn = $this->escapeColumnName($expression->getIntervalEndColumn(), $params);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface yii\db\ExpressionInterface as the method getIntervalEndColumn() does only exist in the following implementations of said interface: yii\db\conditions\BetweenColumnsCondition.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
34 15
        $value = $this->createPlaceholder($expression->getValue(), $params);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface yii\db\ExpressionInterface as the method getValue() does only exist in the following implementations of said interface: yii\db\ArrayExpression, yii\db\JsonExpression, yii\db\PdoValue, yii\db\conditions\BetweenColumnsCondition, yii\db\conditions\LikeCondition, yii\db\conditions\SimpleCondition.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
35
36 15
        return "$value $operator $startColumn AND $endColumn";
37
    }
38
39
    /**
40
     * Prepares column name to be used in SQL statement.
41
     *
42
     * @param Query|ExpressionInterface|string $columnName
43
     * @param array $params the binding parameters.
44
     * @return string
45
     */
46 15
    protected function escapeColumnName($columnName, &$params = [])
47
    {
48 15
        if ($columnName instanceof Query) {
49 3
            list($sql, $params) = $this->queryBuilder->build($columnName, $params);
50 3
            return "($sql)";
51 15
        } elseif ($columnName instanceof ExpressionInterface) {
52
            return $this->queryBuilder->buildExpression($columnName, $params);
53 15
        } elseif (strpos($columnName, '(') === false) {
54 15
            return $this->queryBuilder->db->quoteColumnName($columnName);
55
        }
56
57 3
        return $columnName;
58
    }
59
60
    /**
61
     * Attaches $value to $params array and returns placeholder.
62
     *
63
     * @param mixed $value
64
     * @param array $params passed by reference
65
     * @return string
66
     */
67 15
    protected function createPlaceholder($value, &$params)
68
    {
69 15
        if ($value instanceof ExpressionInterface) {
70 9
            return $this->queryBuilder->buildExpression($value, $params);
71
        }
72
73 6
        return $this->queryBuilder->bindParam($value, $params);
74
    }
75
}
76