PageRenderTime 25ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/laravel/framework/src/Illuminate/Database/Schema/Grammars/Grammar.php

https://gitlab.com/Laolballs/cbtapp
PHP | 432 lines | 203 code | 68 blank | 161 comment | 15 complexity | b333fc197482617a343ee8d55ec193fe MD5 | raw file
  1. <?php namespace Illuminate\Database\Schema\Grammars;
  2. use Doctrine\DBAL\Types\Type;
  3. use Illuminate\Support\Fluent;
  4. use Doctrine\DBAL\Schema\Table;
  5. use Doctrine\DBAL\Schema\Column;
  6. use Doctrine\DBAL\Schema\TableDiff;
  7. use Illuminate\Database\Connection;
  8. use Doctrine\DBAL\Schema\Comparator;
  9. use Illuminate\Database\Query\Expression;
  10. use Illuminate\Database\Schema\Blueprint;
  11. use Illuminate\Database\Grammar as BaseGrammar;
  12. use Doctrine\DBAL\Schema\AbstractSchemaManager as SchemaManager;
  13. abstract class Grammar extends BaseGrammar {
  14. /**
  15. * Compile a rename column command.
  16. *
  17. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  18. * @param \Illuminate\Support\Fluent $command
  19. * @param \Illuminate\Database\Connection $connection
  20. * @return array
  21. */
  22. public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Connection $connection)
  23. {
  24. $schema = $connection->getDoctrineSchemaManager();
  25. $table = $this->getTablePrefix().$blueprint->getTable();
  26. $column = $connection->getDoctrineColumn($table, $command->from);
  27. $tableDiff = $this->getRenamedDiff($blueprint, $command, $column, $schema);
  28. return (array) $schema->getDatabasePlatform()->getAlterTableSQL($tableDiff);
  29. }
  30. /**
  31. * Get a new column instance with the new column name.
  32. *
  33. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  34. * @param \Illuminate\Support\Fluent $command
  35. * @param \Doctrine\DBAL\Schema\Column $column
  36. * @param \Doctrine\DBAL\Schema\AbstractSchemaManager $schema
  37. * @return \Doctrine\DBAL\Schema\TableDiff
  38. */
  39. protected function getRenamedDiff(Blueprint $blueprint, Fluent $command, Column $column, SchemaManager $schema)
  40. {
  41. $tableDiff = $this->getDoctrineTableDiff($blueprint, $schema);
  42. return $this->setRenamedColumns($tableDiff, $command, $column);
  43. }
  44. /**
  45. * Set the renamed columns on the table diff.
  46. *
  47. * @param \Doctrine\DBAL\Schema\TableDiff $tableDiff
  48. * @param \Illuminate\Support\Fluent $command
  49. * @param \Doctrine\DBAL\Schema\Column $column
  50. * @return \Doctrine\DBAL\Schema\TableDiff
  51. */
  52. protected function setRenamedColumns(TableDiff $tableDiff, Fluent $command, Column $column)
  53. {
  54. $newColumn = new Column($command->to, $column->getType(), $column->toArray());
  55. $tableDiff->renamedColumns = array($command->from => $newColumn);
  56. return $tableDiff;
  57. }
  58. /**
  59. * Compile a foreign key command.
  60. *
  61. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  62. * @param \Illuminate\Support\Fluent $command
  63. * @return string
  64. */
  65. public function compileForeign(Blueprint $blueprint, Fluent $command)
  66. {
  67. $table = $this->wrapTable($blueprint);
  68. $on = $this->wrapTable($command->on);
  69. // We need to prepare several of the elements of the foreign key definition
  70. // before we can create the SQL, such as wrapping the tables and convert
  71. // an array of columns to comma-delimited strings for the SQL queries.
  72. $columns = $this->columnize($command->columns);
  73. $onColumns = $this->columnize((array) $command->references);
  74. $sql = "alter table {$table} add constraint {$command->index} ";
  75. $sql .= "foreign key ({$columns}) references {$on} ({$onColumns})";
  76. // Once we have the basic foreign key creation statement constructed we can
  77. // build out the syntax for what should happen on an update or delete of
  78. // the affected columns, which will get something like "cascade", etc.
  79. if ( ! is_null($command->onDelete))
  80. {
  81. $sql .= " on delete {$command->onDelete}";
  82. }
  83. if ( ! is_null($command->onUpdate))
  84. {
  85. $sql .= " on update {$command->onUpdate}";
  86. }
  87. return $sql;
  88. }
  89. /**
  90. * Compile the blueprint's column definitions.
  91. *
  92. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  93. * @return array
  94. */
  95. protected function getColumns(Blueprint $blueprint)
  96. {
  97. $columns = array();
  98. foreach ($blueprint->getAddedColumns() as $column)
  99. {
  100. // Each of the column types have their own compiler functions which are tasked
  101. // with turning the column definition into its SQL format for this platform
  102. // used by the connection. The column's modifiers are compiled and added.
  103. $sql = $this->wrap($column).' '.$this->getType($column);
  104. $columns[] = $this->addModifiers($sql, $blueprint, $column);
  105. }
  106. return $columns;
  107. }
  108. /**
  109. * Add the column modifiers to the definition.
  110. *
  111. * @param string $sql
  112. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  113. * @param \Illuminate\Support\Fluent $column
  114. * @return string
  115. */
  116. protected function addModifiers($sql, Blueprint $blueprint, Fluent $column)
  117. {
  118. foreach ($this->modifiers as $modifier)
  119. {
  120. if (method_exists($this, $method = "modify{$modifier}"))
  121. {
  122. $sql .= $this->{$method}($blueprint, $column);
  123. }
  124. }
  125. return $sql;
  126. }
  127. /**
  128. * Get the primary key command if it exists on the blueprint.
  129. *
  130. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  131. * @param string $name
  132. * @return \Illuminate\Support\Fluent|null
  133. */
  134. protected function getCommandByName(Blueprint $blueprint, $name)
  135. {
  136. $commands = $this->getCommandsByName($blueprint, $name);
  137. if (count($commands) > 0)
  138. {
  139. return reset($commands);
  140. }
  141. }
  142. /**
  143. * Get all of the commands with a given name.
  144. *
  145. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  146. * @param string $name
  147. * @return array
  148. */
  149. protected function getCommandsByName(Blueprint $blueprint, $name)
  150. {
  151. return array_filter($blueprint->getCommands(), function($value) use ($name)
  152. {
  153. return $value->name == $name;
  154. });
  155. }
  156. /**
  157. * Get the SQL for the column data type.
  158. *
  159. * @param \Illuminate\Support\Fluent $column
  160. * @return string
  161. */
  162. protected function getType(Fluent $column)
  163. {
  164. return $this->{"type".ucfirst($column->type)}($column);
  165. }
  166. /**
  167. * Add a prefix to an array of values.
  168. *
  169. * @param string $prefix
  170. * @param array $values
  171. * @return array
  172. */
  173. public function prefixArray($prefix, array $values)
  174. {
  175. return array_map(function($value) use ($prefix)
  176. {
  177. return $prefix.' '.$value;
  178. }, $values);
  179. }
  180. /**
  181. * Wrap a table in keyword identifiers.
  182. *
  183. * @param mixed $table
  184. * @return string
  185. */
  186. public function wrapTable($table)
  187. {
  188. if ($table instanceof Blueprint) $table = $table->getTable();
  189. return parent::wrapTable($table);
  190. }
  191. /**
  192. * {@inheritdoc}
  193. */
  194. public function wrap($value, $prefixAlias = false)
  195. {
  196. if ($value instanceof Fluent) $value = $value->name;
  197. return parent::wrap($value, $prefixAlias);
  198. }
  199. /**
  200. * Format a value so that it can be used in "default" clauses.
  201. *
  202. * @param mixed $value
  203. * @return string
  204. */
  205. protected function getDefaultValue($value)
  206. {
  207. if ($value instanceof Expression) return $value;
  208. if (is_bool($value)) return "'".(int) $value."'";
  209. return "'".strval($value)."'";
  210. }
  211. /**
  212. * Create an empty Doctrine DBAL TableDiff from the Blueprint.
  213. *
  214. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  215. * @param \Doctrine\DBAL\Schema\AbstractSchemaManager $schema
  216. * @return \Doctrine\DBAL\Schema\TableDiff
  217. */
  218. protected function getDoctrineTableDiff(Blueprint $blueprint, SchemaManager $schema)
  219. {
  220. $table = $this->getTablePrefix().$blueprint->getTable();
  221. $tableDiff = new TableDiff($table);
  222. $tableDiff->fromTable = $schema->listTableDetails($table);
  223. return $tableDiff;
  224. }
  225. /**
  226. * Compile a change column command into a series of SQL statements.
  227. *
  228. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  229. * @param \Illuminate\Support\Fluent $command
  230. * @param \Illuminate\Database\Connection $connection
  231. * @return array
  232. */
  233. public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection)
  234. {
  235. $schema = $connection->getDoctrineSchemaManager();
  236. $tableDiff = $this->getChangedDiff($blueprint, $schema);
  237. if ($tableDiff !== false)
  238. {
  239. return (array) $schema->getDatabasePlatform()->getAlterTableSQL($tableDiff);
  240. }
  241. return [];
  242. }
  243. /**
  244. * Get the Doctrine table difference for the given changes.
  245. *
  246. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  247. * @param \Doctrine\DBAL\Schema\AbstractSchemaManager $schema
  248. * @return \Doctrine\DBAL\Schema\TableDiff|bool
  249. */
  250. protected function getChangedDiff(Blueprint $blueprint, SchemaManager $schema)
  251. {
  252. $table = $schema->listTableDetails($this->getTablePrefix().$blueprint->getTable());
  253. return (new Comparator)->diffTable($table, $this->getTableWithColumnChanges($blueprint, $table));
  254. }
  255. /**
  256. * Get a copy of the given Doctrine table after making the column changes.
  257. *
  258. * @param \Illuminate\Database\Schema\Blueprint $blueprint
  259. * @param \Doctrine\DBAL\Schema\Table $table
  260. * @return \Doctrine\DBAL\Schema\TableDiff
  261. */
  262. protected function getTableWithColumnChanges(Blueprint $blueprint, Table $table)
  263. {
  264. $table = clone $table;
  265. foreach($blueprint->getChangedColumns() as $fluent)
  266. {
  267. $column = $this->getDoctrineColumnForChange($table, $fluent);
  268. // Here we will spin through each fluent column definition and map it to the proper
  269. // Doctrine column definitions, which is necessasry because Laravel and Doctrine
  270. // use some different terminology for various column attributes on the tables.
  271. foreach ($fluent->getAttributes() as $key => $value)
  272. {
  273. if ( ! is_null($option = $this->mapFluentOptionToDoctrine($key)))
  274. {
  275. if (method_exists($column, $method = 'set'.ucfirst($option)))
  276. {
  277. $column->{$method}($this->mapFluentValueToDoctrine($option, $value));
  278. }
  279. }
  280. }
  281. }
  282. return $table;
  283. }
  284. /**
  285. * Get the Doctrine column instance for a column change.
  286. *
  287. * @param \Doctrine\DBAL\Schema\Table $table
  288. * @param \Illuminate\Support\Fluent $fluent
  289. * @return \Doctrine\DBAL\Schema\Column
  290. */
  291. protected function getDoctrineColumnForChange(Table $table, Fluent $fluent)
  292. {
  293. return $table->changeColumn(
  294. $fluent['name'], $this->getDoctrineColumnChangeOptions($fluent)
  295. )->getColumn($fluent['name']);
  296. }
  297. /**
  298. * Get the Doctrine column change options.
  299. *
  300. * @param \Illuminate\Support\Fluent $fluent
  301. * @return array
  302. */
  303. protected function getDoctrineColumnChangeOptions(Fluent $fluent)
  304. {
  305. $options = ['type' => Type::getType($fluent['type'])];
  306. if (in_array($fluent['type'], ['text', 'mediumText', 'longText']))
  307. {
  308. $options['length'] = $this->calculateDoctrineTextLength($fluent['type']);
  309. }
  310. return $options;
  311. }
  312. /**
  313. * Calculate the proper column length to force the Doctrine text type.
  314. *
  315. * @param string $type
  316. * @return int
  317. */
  318. protected function calculateDoctrineTextLength($type)
  319. {
  320. switch ($type)
  321. {
  322. case 'mediumText':
  323. return 65535 + 1;
  324. case 'longText':
  325. return 16777215 + 1;
  326. default:
  327. return 255 + 1;
  328. }
  329. }
  330. /**
  331. * Get the matching Doctrine option for a given Fluent attribute name.
  332. *
  333. * @param string $attribute
  334. * @return string
  335. */
  336. protected function mapFluentOptionToDoctrine($attribute)
  337. {
  338. switch($attribute)
  339. {
  340. case 'type':
  341. case 'name':
  342. return;
  343. case 'nullable':
  344. return 'notnull';
  345. case 'total':
  346. return 'precision';
  347. case 'places':
  348. return 'scale';
  349. default:
  350. return $attribute;
  351. }
  352. }
  353. /**
  354. * Get the matching Doctrine value for a given Fluent attribute.
  355. *
  356. * @param string $option
  357. * @param mixed $value
  358. * @return mixed
  359. */
  360. protected function mapFluentValueToDoctrine($option, $value)
  361. {
  362. return $option == 'notnull' ? ! $value : $value;
  363. }
  364. }