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

Quoter   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 136
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 57
dl 0
loc 136
rs 9.84
c 1
b 0
f 0
wmc 32

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A quoteTableName() 0 21 6
A quoteSql() 0 12 2
A quoteSimpleTableName() 0 9 3
A unquoteSimpleColumnName() 0 9 3
A quoteSimpleColumnName() 0 10 4
A escapeString() 0 3 1
A unquoteSimpleTableName() 0 9 3
A getTableNameParts() 0 6 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 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