Passed
Pull Request — master (#362)
by Wilmer
02:12
created

Quoter::escapeString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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 escapeString(mixed $value): mixed
32
    {
33
        return '\'' . str_replace('\'', '\'\'', addcslashes($value, "\000\032")) . '\'';
34
    }
35
36
    public function getTableNameParts(string $name): array
37
    {
38
        $parts = array_slice(explode('.', $name), -2, 2);
39
        return array_map(function ($part) {
40
            return $this->unquoteSimpleTableName($part);
41
        }, $parts);
42
    }
43
44
    public function ensureNameQuoted(string $name): string
45
    {
46
        $name = str_replace(["'", '"', '`', '[', ']'], '', $name);
47
48
        if ($name && !preg_match('/^{{.*}}$/', $name)) {
49
            return '{{' . $name . '}}';
50
        }
51
52
        return $name;
53
    }
54
55
    public function quoteColumnName(string $name): string
56
    {
57
        if (str_contains($name, '(') || str_contains($name, '[[')) {
58
            return $name;
59
        }
60
61
        if (($pos = strrpos($name, '.')) !== false) {
62
            $prefix = $this->quoteTableName(substr($name, 0, $pos)) . '.';
63
            $name = substr($name, $pos + 1);
64
        } else {
65
            $prefix = '';
66
        }
67
68
        if (str_contains($name, '{{')) {
69
            return $name;
70
        }
71
72
        return $prefix . $this->quoteSimpleColumnName($name);
73
    }
74
75
    public function quoteSimpleColumnName(string $name): string
76
    {
77
        if (is_string($this->columnQuoteCharacter)) {
78
            $startingCharacter = $endingCharacter = $this->columnQuoteCharacter;
79
        } else {
80
            [$startingCharacter, $endingCharacter] = $this->columnQuoteCharacter;
81
        }
82
83
        return $name === '*' || str_contains($name, $startingCharacter) ? $name : $startingCharacter . $name
84
            . $endingCharacter;
85
    }
86
87
    public function quoteSimpleTableName(string $name): string
88
    {
89
        if (is_string($this->tableQuoteCharacter)) {
90
            $startingCharacter = $endingCharacter = $this->tableQuoteCharacter;
91
        } else {
92
            [$startingCharacter, $endingCharacter] = $this->tableQuoteCharacter;
93
        }
94
95
        return str_contains($name, $startingCharacter) ? $name : $startingCharacter . $name . $endingCharacter;
96
    }
97
98
    public function quoteSql(string $sql): string
99
    {
100
        return preg_replace_callback(
101
            '/({{(%?[\w\-. ]+%?)}}|\\[\\[([\w\-. ]+)]])/',
102
            function ($matches) {
103
                if (isset($matches[3])) {
104
                    return $this->quoteColumnName($matches[3]);
105
                }
106
107
                return str_replace('%', $this->tablePrefix, $this->quoteTableName($matches[2]));
108
            },
109
            $sql
110
        );
111
    }
112
113
    public function quoteTableName(string $name): string
114
    {
115
        if (str_starts_with($name, '(') && strpos($name, ')') === strlen($name) - 1) {
116
            return $name;
117
        }
118
119
        if (str_contains($name, '{{')) {
120
            return $name;
121
        }
122
123
        if (!str_contains($name, '.')) {
124
            return $this->quoteSimpleTableName($name);
125
        }
126
127
        $parts = $this->getTableNameParts($name);
128
129
        foreach ($parts as $i => $part) {
130
            $parts[$i] = $this->quoteSimpleTableName($part);
131
        }
132
133
        return implode('.', $parts);
134
    }
135
136
    public function unquoteSimpleColumnName(string $name): string
137
    {
138
        if (is_string($this->columnQuoteCharacter)) {
139
            $startingCharacter = $this->columnQuoteCharacter;
140
        } else {
141
            $startingCharacter = $this->columnQuoteCharacter[0];
142
        }
143
144
        return !str_contains($name, $startingCharacter) ? $name : substr($name, 1, -1);
145
    }
146
147
    public function unquoteSimpleTableName(string $name): string
148
    {
149
        if (is_string($this->tableQuoteCharacter)) {
150
            $startingCharacter = $this->tableQuoteCharacter;
151
        } else {
152
            $startingCharacter = $this->tableQuoteCharacter[0];
153
        }
154
155
        return !str_contains($name, $startingCharacter) ? $name : substr($name, 1, -1);
156
    }
157
}
158