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

/Streaming-Safe-for-Kids/vendor/laravel/framework/src/Illuminate/Database/Schema/Grammars/Grammar.php

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