Grammar.php 8.0KB

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