Passed
Push — master ( 1265f7...db8617 )
by Alexander
01:41
created

Command   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 119
Duplicated Lines 0 %

Test Coverage

Coverage 98%

Importance

Changes 0
Metric Value
eloc 47
c 0
b 0
f 0
dl 0
loc 119
ccs 49
cts 50
cp 0.98
rs 10
wmc 15

4 Methods

Rating   Name   Duplication   Size   Complexity  
A extractUsedParams() 0 16 4
A splitStatements() 0 23 5
A queryInternal() 0 27 3
A execute() 0 23 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Sqlite\Command;
6
7
use Yiisoft\Db\Commands\Command as BaseCommand;
8
use Yiisoft\Db\Sqlite\Token\SqlToken;
9
use Yiisoft\Db\Sqlite\Token\SqlTokenizer;
10
use Yiisoft\Strings\StringHelper;
11
12
/**
13
 * Command represents an SQLite's SQL statement to be executed against a database.
14
 *
15
 * {@inheritdoc}
16
 */
17
class Command extends BaseCommand
18
{
19
    /**
20
     * {@inheritdoc}
21
     */
22 45
    public function execute(): int
23
    {
24 45
        $sql = $this->getSql();
25
26 45
        $params = $this->params;
27
28 45
        $statements = $this->splitStatements($sql, $params);
29
30 45
        if ($statements === false) {
0 ignored issues
show
introduced by
The condition $statements === false is always true.
Loading history...
31 40
            return parent::execute();
32
        }
33
34 5
        $result = 0;
35
36 5
        foreach ($statements as $statement) {
37 5
            [$statementSql, $statementParams] = $statement;
38 5
            $this->setSql($statementSql)->bindValues($statementParams);
39 5
            $result = parent::execute();
40
        }
41
42 5
        $this->setSql($sql)->bindValues($params);
43
44 5
        return $result;
45
    }
46
47
    /**
48
     * {@inheritdoc}
49
     */
50 151
    protected function queryInternal($method, $fetchMode = null)
51
    {
52 151
        $sql = $this->getSql();
53
54 151
        $params = $this->params;
55
56 151
        $statements = $this->splitStatements($sql, $params);
57
58 151
        if ($statements === false) {
0 ignored issues
show
introduced by
The condition $statements === false is always true.
Loading history...
59 151
            return parent::queryInternal($method, $fetchMode);
60
        }
61
62 1
        [$lastStatementSql, $lastStatementParams] = array_pop($statements);
63
64 1
        foreach ($statements as $statement) {
65 1
            [$statementSql, $statementParams] = $statement;
66 1
            $this->setSql($statementSql)->bindValues($statementParams);
67 1
            parent::execute();
68
        }
69
70 1
        $this->setSql($lastStatementSql)->bindValues($lastStatementParams);
71
72 1
        $result = parent::queryInternal($method, $fetchMode);
73
74 1
        $this->setSql($sql)->bindValues($params);
75
76 1
        return $result;
77
    }
78
79
    /**
80
     * Splits the specified SQL code into individual SQL statements and returns them or `false` if there's a single
81
     * statement.
82
     *
83
     * @param string $sql
84
     * @param array $params
85
     *
86
     * @return string[]|false
87
     */
88 155
    private function splitStatements($sql, $params)
89
    {
90 155
        $semicolonIndex = strpos($sql, ';');
91
92 155
        if ($semicolonIndex === false || $semicolonIndex === StringHelper::byteLength($sql) - 1) {
93 155
            return false;
94
        }
95
96 5
        $tokenizer = new SqlTokenizer($sql);
97
98 5
        $codeToken = $tokenizer->tokenize();
99
100 5
        if (count($codeToken->getChildren()) === 1) {
101
            return false;
102
        }
103
104 5
        $statements = [];
105
106 5
        foreach ($codeToken->getChildren() as $statement) {
107 5
            $statements[] = [$statement->getSql(), $this->extractUsedParams($statement, $params)];
108
        }
109
110 5
        return $statements;
111
    }
112
113
    /**
114
     * Returns named bindings used in the specified statement token.
115
     *
116
     * @param SqlToken $statement
117
     * @param array $params
118
     * @return array
119
     */
120 5
    private function extractUsedParams(SqlToken $statement, $params)
121
    {
122 5
        preg_match_all('/(?P<placeholder>[:][a-zA-Z0-9_]+)/', $statement->getSql(), $matches, PREG_SET_ORDER);
123
124 5
        $result = [];
125
126 5
        foreach ($matches as $match) {
127 5
            $phName = ltrim($match['placeholder'], ':');
128 5
            if (isset($params[$phName])) {
129 1
                $result[$phName] = $params[$phName];
130 4
            } elseif (isset($params[':' . $phName])) {
131 4
                $result[':' . $phName] = $params[':' . $phName];
132
            }
133
        }
134
135 5
        return $result;
136
    }
137
}
138