| 148 |
lars |
1 |
<?php
|
|
|
2 |
|
|
|
3 |
namespace Doctrine\DBAL\Schema;
|
|
|
4 |
|
|
|
5 |
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
|
|
6 |
use Doctrine\Deprecations\Deprecation;
|
|
|
7 |
|
|
|
8 |
use function array_map;
|
|
|
9 |
use function crc32;
|
|
|
10 |
use function dechex;
|
|
|
11 |
use function explode;
|
|
|
12 |
use function implode;
|
|
|
13 |
use function str_replace;
|
|
|
14 |
use function strpos;
|
|
|
15 |
use function strtolower;
|
|
|
16 |
use function strtoupper;
|
|
|
17 |
use function substr;
|
|
|
18 |
|
|
|
19 |
/**
|
|
|
20 |
* The abstract asset allows to reset the name of all assets without publishing this to the public userland.
|
|
|
21 |
*
|
|
|
22 |
* This encapsulation hack is necessary to keep a consistent state of the database schema. Say we have a list of tables
|
|
|
23 |
* array($tableName => Table($tableName)); if you want to rename the table, you have to make sure
|
|
|
24 |
*/
|
|
|
25 |
abstract class AbstractAsset
|
|
|
26 |
{
|
|
|
27 |
/** @var string */
|
|
|
28 |
protected $_name = '';
|
|
|
29 |
|
|
|
30 |
/**
|
|
|
31 |
* Namespace of the asset. If none isset the default namespace is assumed.
|
|
|
32 |
*
|
|
|
33 |
* @var string|null
|
|
|
34 |
*/
|
|
|
35 |
protected $_namespace;
|
|
|
36 |
|
|
|
37 |
/** @var bool */
|
|
|
38 |
protected $_quoted = false;
|
|
|
39 |
|
|
|
40 |
/**
|
|
|
41 |
* Sets the name of this asset.
|
|
|
42 |
*
|
|
|
43 |
* @param string $name
|
|
|
44 |
*
|
|
|
45 |
* @return void
|
|
|
46 |
*/
|
|
|
47 |
protected function _setName($name)
|
|
|
48 |
{
|
|
|
49 |
if ($this->isIdentifierQuoted($name)) {
|
|
|
50 |
$this->_quoted = true;
|
|
|
51 |
$name = $this->trimQuotes($name);
|
|
|
52 |
}
|
|
|
53 |
|
|
|
54 |
if (strpos($name, '.') !== false) {
|
|
|
55 |
$parts = explode('.', $name);
|
|
|
56 |
$this->_namespace = $parts[0];
|
|
|
57 |
$name = $parts[1];
|
|
|
58 |
}
|
|
|
59 |
|
|
|
60 |
$this->_name = $name;
|
|
|
61 |
}
|
|
|
62 |
|
|
|
63 |
/**
|
|
|
64 |
* Is this asset in the default namespace?
|
|
|
65 |
*
|
|
|
66 |
* @param string $defaultNamespaceName
|
|
|
67 |
*
|
|
|
68 |
* @return bool
|
|
|
69 |
*/
|
|
|
70 |
public function isInDefaultNamespace($defaultNamespaceName)
|
|
|
71 |
{
|
|
|
72 |
return $this->_namespace === $defaultNamespaceName || $this->_namespace === null;
|
|
|
73 |
}
|
|
|
74 |
|
|
|
75 |
/**
|
|
|
76 |
* Gets the namespace name of this asset.
|
|
|
77 |
*
|
|
|
78 |
* If NULL is returned this means the default namespace is used.
|
|
|
79 |
*
|
|
|
80 |
* @return string|null
|
|
|
81 |
*/
|
|
|
82 |
public function getNamespaceName()
|
|
|
83 |
{
|
|
|
84 |
return $this->_namespace;
|
|
|
85 |
}
|
|
|
86 |
|
|
|
87 |
/**
|
|
|
88 |
* The shortest name is stripped of the default namespace. All other
|
|
|
89 |
* namespaced elements are returned as full-qualified names.
|
|
|
90 |
*
|
|
|
91 |
* @param string|null $defaultNamespaceName
|
|
|
92 |
*
|
|
|
93 |
* @return string
|
|
|
94 |
*/
|
|
|
95 |
public function getShortestName($defaultNamespaceName)
|
|
|
96 |
{
|
|
|
97 |
$shortestName = $this->getName();
|
|
|
98 |
if ($this->_namespace === $defaultNamespaceName) {
|
|
|
99 |
$shortestName = $this->_name;
|
|
|
100 |
}
|
|
|
101 |
|
|
|
102 |
return strtolower($shortestName);
|
|
|
103 |
}
|
|
|
104 |
|
|
|
105 |
/**
|
|
|
106 |
* The normalized name is full-qualified and lower-cased. Lower-casing is
|
|
|
107 |
* actually wrong, but we have to do it to keep our sanity. If you are
|
|
|
108 |
* using database objects that only differentiate in the casing (FOO vs
|
|
|
109 |
* Foo) then you will NOT be able to use Doctrine Schema abstraction.
|
|
|
110 |
*
|
|
|
111 |
* Every non-namespaced element is prefixed with the default namespace
|
|
|
112 |
* name which is passed as argument to this method.
|
|
|
113 |
*
|
|
|
114 |
* @deprecated Use {@see getNamespaceName()} and {@see getName()} instead.
|
|
|
115 |
*
|
|
|
116 |
* @param string $defaultNamespaceName
|
|
|
117 |
*
|
|
|
118 |
* @return string
|
|
|
119 |
*/
|
|
|
120 |
public function getFullQualifiedName($defaultNamespaceName)
|
|
|
121 |
{
|
|
|
122 |
Deprecation::triggerIfCalledFromOutside(
|
|
|
123 |
'doctrine/dbal',
|
|
|
124 |
'https://github.com/doctrine/dbal/pull/4814',
|
|
|
125 |
'AbstractAsset::getFullQualifiedName() is deprecated.'
|
|
|
126 |
. ' Use AbstractAsset::getNamespaceName() and ::getName() instead.',
|
|
|
127 |
);
|
|
|
128 |
|
|
|
129 |
$name = $this->getName();
|
|
|
130 |
if ($this->_namespace === null) {
|
|
|
131 |
$name = $defaultNamespaceName . '.' . $name;
|
|
|
132 |
}
|
|
|
133 |
|
|
|
134 |
return strtolower($name);
|
|
|
135 |
}
|
|
|
136 |
|
|
|
137 |
/**
|
|
|
138 |
* Checks if this asset's name is quoted.
|
|
|
139 |
*
|
|
|
140 |
* @return bool
|
|
|
141 |
*/
|
|
|
142 |
public function isQuoted()
|
|
|
143 |
{
|
|
|
144 |
return $this->_quoted;
|
|
|
145 |
}
|
|
|
146 |
|
|
|
147 |
/**
|
|
|
148 |
* Checks if this identifier is quoted.
|
|
|
149 |
*
|
|
|
150 |
* @param string $identifier
|
|
|
151 |
*
|
|
|
152 |
* @return bool
|
|
|
153 |
*/
|
|
|
154 |
protected function isIdentifierQuoted($identifier)
|
|
|
155 |
{
|
|
|
156 |
return isset($identifier[0]) && ($identifier[0] === '`' || $identifier[0] === '"' || $identifier[0] === '[');
|
|
|
157 |
}
|
|
|
158 |
|
|
|
159 |
/**
|
|
|
160 |
* Trim quotes from the identifier.
|
|
|
161 |
*
|
|
|
162 |
* @param string $identifier
|
|
|
163 |
*
|
|
|
164 |
* @return string
|
|
|
165 |
*/
|
|
|
166 |
protected function trimQuotes($identifier)
|
|
|
167 |
{
|
|
|
168 |
return str_replace(['`', '"', '[', ']'], '', $identifier);
|
|
|
169 |
}
|
|
|
170 |
|
|
|
171 |
/**
|
|
|
172 |
* Returns the name of this schema asset.
|
|
|
173 |
*
|
|
|
174 |
* @return string
|
|
|
175 |
*/
|
|
|
176 |
public function getName()
|
|
|
177 |
{
|
|
|
178 |
if ($this->_namespace !== null) {
|
|
|
179 |
return $this->_namespace . '.' . $this->_name;
|
|
|
180 |
}
|
|
|
181 |
|
|
|
182 |
return $this->_name;
|
|
|
183 |
}
|
|
|
184 |
|
|
|
185 |
/**
|
|
|
186 |
* Gets the quoted representation of this asset but only if it was defined with one. Otherwise
|
|
|
187 |
* return the plain unquoted value as inserted.
|
|
|
188 |
*
|
|
|
189 |
* @return string
|
|
|
190 |
*/
|
|
|
191 |
public function getQuotedName(AbstractPlatform $platform)
|
|
|
192 |
{
|
|
|
193 |
$keywords = $platform->getReservedKeywordsList();
|
|
|
194 |
$parts = explode('.', $this->getName());
|
|
|
195 |
foreach ($parts as $k => $v) {
|
|
|
196 |
$parts[$k] = $this->_quoted || $keywords->isKeyword($v) ? $platform->quoteIdentifier($v) : $v;
|
|
|
197 |
}
|
|
|
198 |
|
|
|
199 |
return implode('.', $parts);
|
|
|
200 |
}
|
|
|
201 |
|
|
|
202 |
/**
|
|
|
203 |
* Generates an identifier from a list of column names obeying a certain string length.
|
|
|
204 |
*
|
|
|
205 |
* This is especially important for Oracle, since it does not allow identifiers larger than 30 chars,
|
|
|
206 |
* however building idents automatically for foreign keys, composite keys or such can easily create
|
|
|
207 |
* very long names.
|
|
|
208 |
*
|
|
|
209 |
* @param string[] $columnNames
|
|
|
210 |
* @param string $prefix
|
|
|
211 |
* @param int $maxSize
|
|
|
212 |
*
|
|
|
213 |
* @return string
|
|
|
214 |
*/
|
|
|
215 |
protected function _generateIdentifierName($columnNames, $prefix = '', $maxSize = 30)
|
|
|
216 |
{
|
|
|
217 |
$hash = implode('', array_map(static function ($column): string {
|
|
|
218 |
return dechex(crc32($column));
|
|
|
219 |
}, $columnNames));
|
|
|
220 |
|
|
|
221 |
return strtoupper(substr($prefix . '_' . $hash, 0, $maxSize));
|
|
|
222 |
}
|
|
|
223 |
}
|