Passed
Push — master ( 914087...c6011d )
by Alexander
11:22
created

Quoter   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 145
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 33
eloc 56
c 0
b 0
f 0
dl 0
loc 145
rs 9.76

11 Methods

Rating   Name   Duplication   Size   Complexity  
A quoteTableName() 0 22 6
A __construct() 0 7 1
A quoteSql() 0 12 2
A quoteSimpleTableName() 0 9 3
A unquoteSimpleColumnName() 0 9 3
A quoteValue() 0 7 2
A quoteSimpleColumnName() 0 10 4
A unquoteSimpleTableName() 0 9 3
A getTableNameParts() 0 3 1
A quoteColumnName() 0 18 5
A ensureNameQuoted() 0 9 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Schema;
6
7
use function addcslashes;
8
use function explode;
9
use function implode;
10
use function is_string;
11
use function preg_replace_callback;
12
use function str_contains;
13
use function str_replace;
14
use function str_starts_with;
15
use function strlen;
16
use function strpos;
17
use function strrpos;
18
use function substr;
19
20
class Quoter implements QuoterInterface
21
{
22
    public function __construct(
23
        /** @psalm-var string[]|string */
24
        private array|string $columnQuoteCharacter,
25
        /** @psalm-var string[]|string */
26
        private array|string $tableQuoteCharacter,
27
        private string $tablePrefix = ''
28
    ) {
29
    }
30
31
    public function ensureNameQuoted(string $name): string
32
    {
33
        $name = str_replace(["'", '"', '`', '[', ']'], '', $name);
34
35
        if ($name && !preg_match('/^{{.*}}$/', $name)) {
36
            return '{{' . $name . '}}';
37
        }
38
39
        return $name;
40
    }
41
42
    public function quoteColumnName(string $name): string
43
    {
44
        if (str_contains($name, '(') || str_contains($name, '[[')) {
45
            return $name;
46
        }
47
48
        if (($pos = strrpos($name, '.')) !== false) {
49
            $prefix = $this->quoteTableName(substr($name, 0, $pos)) . '.';
50
            $name = substr($name, $pos + 1);
51
        } else {
52
            $prefix = '';
53
        }
54
55
        if (str_contains($name, '{{')) {
56
            return $name;
57
        }
58
59
        return $prefix . $this->quoteSimpleColumnName($name);
60
    }
61
62
    public function quoteSimpleColumnName(string $name): string
63
    {
64
        if (is_string($this->columnQuoteCharacter)) {
65
            $startingCharacter = $endingCharacter = $this->columnQuoteCharacter;
66
        } else {
67
            [$startingCharacter, $endingCharacter] = $this->columnQuoteCharacter;
68
        }
69
70
        return $name === '*' || str_contains($name, $startingCharacter) ? $name : $startingCharacter . $name
71
            . $endingCharacter;
72
    }
73
74
    public function quoteSimpleTableName(string $name): string
75
    {
76
        if (is_string($this->tableQuoteCharacter)) {
77
            $startingCharacter = $endingCharacter = $this->tableQuoteCharacter;
78
        } else {
79
            [$startingCharacter, $endingCharacter] = $this->tableQuoteCharacter;
80
        }
81
82
        return str_contains($name, $startingCharacter) ? $name : $startingCharacter . $name . $endingCharacter;
83
    }
84
85
    public function quoteSql(string $sql): string
86
    {
87
        return preg_replace_callback(
88
            '/({{(%?[\w\-. ]+%?)}}|\\[\\[([\w\-. ]+)]])/',
89
            function ($matches) {
90
                if (isset($matches[3])) {
91
                    return $this->quoteColumnName($matches[3]);
92
                }
93
94
                return str_replace('%', $this->tablePrefix, $this->quoteTableName($matches[2]));
95
            },
96
            $sql
97
        );
98
    }
99
100
    public function quoteTableName(string $name): string
101
    {
102
        if (str_starts_with($name, '(') && strpos($name, ')') === strlen($name) - 1) {
103
            return $name;
104
        }
105
106
        if (str_contains($name, '{{')) {
107
            return $name;
108
        }
109
110
        if (!str_contains($name, '.')) {
111
            return $this->quoteSimpleTableName($name);
112
        }
113
114
        /** @var string[] */
115
        $parts = $this->getTableNameParts($name);
116
117
        foreach ($parts as $i => $part) {
118
            $parts[$i] = $this->quoteSimpleTableName($part);
119
        }
120
121
        return implode('.', $parts);
122
    }
123
124
    public function quoteValue(mixed $value): mixed
125
    {
126
        if (!is_string($value)) {
127
            return $value;
128
        }
129
130
        return '\'' . str_replace('\'', '\'\'', addcslashes($value, "\000\032")) . '\'';
131
    }
132
133
    public function unquoteSimpleColumnName(string $name): string
134
    {
135
        if (is_string($this->columnQuoteCharacter)) {
136
            $startingCharacter = $this->columnQuoteCharacter;
137
        } else {
138
            $startingCharacter = $this->columnQuoteCharacter[0];
139
        }
140
141
        return !str_contains($name, $startingCharacter) ? $name : substr($name, 1, -1);
142
    }
143
144
    public function unquoteSimpleTableName(string $name): string
145
    {
146
        if (is_string($this->tableQuoteCharacter)) {
147
            $startingCharacter = $this->tableQuoteCharacter;
148
        } else {
149
            $startingCharacter = $this->tableQuoteCharacter[0];
150
        }
151
152
        return !str_contains($name, $startingCharacter) ? $name : substr($name, 1, -1);
153
    }
154
155
    /**
156
     * Splits full table name into parts
157
     *
158
     * @param string $name
159
     *
160
     * @return array
161
     */
162
    protected function getTableNameParts(string $name): array
163
    {
164
        return explode('.', $name);
165
    }
166
}
167