AbstractAsset.php 5.6 KB

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