Grammar.php 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. <?php
  2. namespace Illuminate\Database\Schema\Grammars;
  3. use Illuminate\Support\Fluent;
  4. use Doctrine\DBAL\Schema\TableDiff;
  5. use Illuminate\Database\Connection;
  6. use Illuminate\Database\Query\Expression;
  7. use Illuminate\Database\Schema\Blueprint;
  8. use Illuminate\Database\Grammar as BaseGrammar;
  9. use Doctrine\DBAL\Schema\AbstractSchemaManager as SchemaManager;
  10. abstract class Grammar extends BaseGrammar
  11. {
  12. /**
  13. * If this Grammar supports schema changes wrapped in a transaction.
  14. *
  15. * @var bool
  16. */
  17. protected $transactions = false;
  18. /**
  19. * Compile a rename column command.
  20. *
  21. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  22. * @param \Illuminate\Support\Fluent $command
  23. * @param \Illuminate\Database\Connection $connection
  24. * @return array
  25. */
  26. public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Connection $connection)
  27. {
  28. return RenameColumn::compile($this, $blueprint, $command, $connection);
  29. }
  30. /**
  31. * Compile a change column command into a series of SQL statements.
  32. *
  33. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  34. * @param \Illuminate\Support\Fluent $command
  35. * @param \Illuminate\Database\Connection $connection
  36. * @return array
  37. *
  38. * @throws \RuntimeException
  39. */
  40. public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection)
  41. {
  42. return ChangeColumn::compile($this, $blueprint, $command, $connection);
  43. }
  44. /**
  45. * Compile a foreign key command.
  46. *
  47. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  48. * @param \Illuminate\Support\Fluent $command
  49. * @return string
  50. */
  51. public function compileForeign(Blueprint $blueprint, Fluent $command)
  52. {
  53. // We need to prepare several of the elements of the foreign key definition
  54. // before we can create the SQL, such as wrapping the tables and convert
  55. // an array of columns to comma-delimited strings for the SQL queries.
  56. $sql = sprintf('alter table %s add constraint %s ',
  57. $this->wrapTable($blueprint),
  58. $this->wrap($command->index)
  59. );
  60. // Once we have the initial portion of the SQL statement we will add on the
  61. // key name, table name, and referenced columns. These will complete the
  62. // main portion of the SQL statement and this SQL will almost be done.
  63. $sql .= sprintf('foreign key (%s) references %s (%s)',
  64. $this->columnize($command->columns),
  65. $this->wrapTable($command->on),
  66. $this->columnize((array) $command->references)
  67. );
  68. // Once we have the basic foreign key creation statement constructed we can
  69. // build out the syntax for what should happen on an update or delete of
  70. // the affected columns, which will get something like "cascade", etc.
  71. if (! is_null($command->onDelete)) {
  72. $sql .= " on delete {$command->onDelete}";
  73. }
  74. if (! is_null($command->onUpdate)) {
  75. $sql .= " on update {$command->onUpdate}";
  76. }
  77. return $sql;
  78. }
  79. /**
  80. * Compile the blueprint's column definitions.
  81. *
  82. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  83. * @return array
  84. */
  85. protected function getColumns(Blueprint $blueprint)
  86. {
  87. $columns = [];
  88. foreach ($blueprint->getAddedColumns() as $column) {
  89. // Each of the column types have their own compiler functions which are tasked
  90. // with turning the column definition into its SQL format for this platform
  91. // used by the connection. The column's modifiers are compiled and added.
  92. $sql = $this->wrap($column).' '.$this->getType($column);
  93. $columns[] = $this->addModifiers($sql, $blueprint, $column);
  94. }
  95. return $columns;
  96. }
  97. /**
  98. * Get the SQL for the column data type.
  99. *
  100. * @param \Illuminate\Support\Fluent $column
  101. * @return string
  102. */
  103. protected function getType(Fluent $column)
  104. {
  105. return $this->{'type'.ucfirst($column->type)}($column);
  106. }
  107. /**
  108. * Add the column modifiers to the definition.
  109. *
  110. * @param string $sql
  111. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  112. * @param \Illuminate\Support\Fluent $column
  113. * @return string
  114. */
  115. protected function addModifiers($sql, Blueprint $blueprint, Fluent $column)
  116. {
  117. foreach ($this->modifiers as $modifier) {
  118. if (method_exists($this, $method = "modify{$modifier}")) {
  119. $sql .= $this->{$method}($blueprint, $column);
  120. }
  121. }
  122. return $sql;
  123. }
  124. /**
  125. * Get the primary key command if it exists on the blueprint.
  126. *
  127. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  128. * @param string $name
  129. * @return \Illuminate\Support\Fluent|null
  130. */
  131. protected function getCommandByName(Blueprint $blueprint, $name)
  132. {
  133. $commands = $this->getCommandsByName($blueprint, $name);
  134. if (count($commands) > 0) {
  135. return reset($commands);
  136. }
  137. }
  138. /**
  139. * Get all of the commands with a given name.
  140. *
  141. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  142. * @param string $name
  143. * @return array
  144. */
  145. protected function getCommandsByName(Blueprint $blueprint, $name)
  146. {
  147. return array_filter($blueprint->getCommands(), function ($value) use ($name) {
  148. return $value->name == $name;
  149. });
  150. }
  151. /**
  152. * Add a prefix to an array of values.
  153. *
  154. * @param string $prefix
  155. * @param array $values
  156. * @return array
  157. */
  158. public function prefixArray($prefix, array $values)
  159. {
  160. return array_map(function ($value) use ($prefix) {
  161. return $prefix.' '.$value;
  162. }, $values);
  163. }
  164. /**
  165. * Wrap a table in keyword identifiers.
  166. *
  167. * @param mixed $table
  168. * @return string
  169. */
  170. public function wrapTable($table)
  171. {
  172. return parent::wrapTable(
  173. $table instanceof Blueprint ? $table->getTable() : $table
  174. );
  175. }
  176. /**
  177. * Wrap a value in keyword identifiers.
  178. *
  179. * @param \Illuminate\Database\Query\Expression|string $value
  180. * @param bool $prefixAlias
  181. * @return string
  182. */
  183. public function wrap($value, $prefixAlias = false)
  184. {
  185. return parent::wrap(
  186. $value instanceof Fluent ? $value->name : $value, $prefixAlias
  187. );
  188. }
  189. /**
  190. * Format a value so that it can be used in "default" clauses.
  191. *
  192. * @param mixed $value
  193. * @return string
  194. */
  195. protected function getDefaultValue($value)
  196. {
  197. if ($value instanceof Expression) {
  198. return $value;
  199. }
  200. return is_bool($value)
  201. ? "'".(int) $value."'"
  202. : "'".(string) $value."'";
  203. }
  204. /**
  205. * Create an empty Doctrine DBAL TableDiff from the Blueprint.
  206. *
  207. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  208. * @param \Doctrine\DBAL\Schema\AbstractSchemaManager $schema
  209. * @return \Doctrine\DBAL\Schema\TableDiff
  210. */
  211. public function getDoctrineTableDiff(Blueprint $blueprint, SchemaManager $schema)
  212. {
  213. $table = $this->getTablePrefix().$blueprint->getTable();
  214. return tap(new TableDiff($table), function ($tableDiff) use ($schema, $table) {
  215. $tableDiff->fromTable = $schema->listTableDetails($table);
  216. });
  217. }
  218. /**
  219. * Check if this Grammar supports schema changes wrapped in a transaction.
  220. *
  221. * @return bool
  222. */
  223. public function supportsSchemaTransactions()
  224. {
  225. return $this->transactions;
  226. }
  227. }