Blueprint.php 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * This file is part of Hyperf.
  5. *
  6. * @link https://www.hyperf.io
  7. * @document https://hyperf.wiki
  8. * @contact group@hyperf.io
  9. * @license https://github.com/hyperf/hyperf/blob/master/LICENSE
  10. */
  11. namespace Hyperf\Database\Schema;
  12. use BadMethodCallException;
  13. use Closure;
  14. use Hyperf\Collection\Collection;
  15. use Hyperf\Database\Connection;
  16. use Hyperf\Database\Query\Expression;
  17. use Hyperf\Database\Schema\Grammars\Grammar;
  18. use Hyperf\Database\SQLiteConnection;
  19. use Hyperf\Macroable\Macroable;
  20. use Hyperf\Support\Fluent;
  21. use function Hyperf\Collection\collect;
  22. class Blueprint
  23. {
  24. use Macroable;
  25. /**
  26. * The storage engine that should be used for the table.
  27. *
  28. * @var string
  29. */
  30. public $engine;
  31. /**
  32. * The default character set that should be used for the table.
  33. */
  34. public $charset;
  35. /**
  36. * The collation that should be used for the table.
  37. */
  38. public $collation;
  39. /**
  40. * Whether to make the table temporary.
  41. *
  42. * @var bool
  43. */
  44. public $temporary = false;
  45. /**
  46. * The column to add new columns after.
  47. *
  48. * @var string
  49. */
  50. public $after;
  51. /**
  52. * The comment of the table.
  53. *
  54. * @var string
  55. */
  56. protected $comment = '';
  57. /**
  58. * The table the blueprint describes.
  59. *
  60. * @var string
  61. */
  62. protected $table;
  63. /**
  64. * The prefix of the table.
  65. *
  66. * @var string
  67. */
  68. protected $prefix;
  69. /**
  70. * The columns that should be added to the table.
  71. *
  72. * @var \Hyperf\Database\Schema\ColumnDefinition[]
  73. */
  74. protected $columns = [];
  75. /**
  76. * The commands that should be run for the table.
  77. *
  78. * @var Fluent[]
  79. */
  80. protected $commands = [];
  81. /**
  82. * Create a new schema blueprint.
  83. *
  84. * @param string $table
  85. * @param string $prefix
  86. */
  87. public function __construct($table, ?Closure $callback = null, $prefix = '')
  88. {
  89. $this->table = $table;
  90. $this->prefix = $prefix;
  91. if (! is_null($callback)) {
  92. $callback($this);
  93. }
  94. }
  95. /**
  96. * Execute the blueprint against the database.
  97. */
  98. public function build(Connection $connection, Grammar $grammar)
  99. {
  100. foreach ($this->toSql($connection, $grammar) as $statement) {
  101. $connection->statement($statement);
  102. }
  103. }
  104. /**
  105. * Get the raw SQL statements for the blueprint.
  106. *
  107. * @return array
  108. */
  109. public function toSql(Connection $connection, Grammar $grammar)
  110. {
  111. $this->addImpliedCommands($grammar);
  112. $statements = [];
  113. // Each type of command has a corresponding compiler function on the schema
  114. // grammar which is used to build the necessary SQL statements to build
  115. // the blueprint element, so we'll just call that compilers function.
  116. $this->ensureCommandsAreValid($connection);
  117. foreach ($this->commands as $command) {
  118. $method = 'compile' . ucfirst($command->name);
  119. if (method_exists($grammar, $method)) {
  120. if (! is_null($sql = $grammar->{$method}($this, $command, $connection))) {
  121. $statements = array_merge($statements, (array) $sql);
  122. }
  123. }
  124. }
  125. return $statements;
  126. }
  127. /**
  128. * Add the fluent commands specified on any columns.
  129. */
  130. public function addFluentCommands(Grammar $grammar)
  131. {
  132. foreach ($this->columns as $column) {
  133. foreach ($grammar->getFluentCommands() as $commandName) {
  134. $attributeName = lcfirst($commandName);
  135. if (! isset($column->{$attributeName})) {
  136. continue;
  137. }
  138. $value = $column->{$attributeName};
  139. $this->addCommand(
  140. $commandName,
  141. compact('value', 'column')
  142. );
  143. }
  144. }
  145. }
  146. /**
  147. * Indicate that the table needs to be created.
  148. *
  149. * @return Fluent
  150. */
  151. public function create()
  152. {
  153. return $this->addCommand('create');
  154. }
  155. /**
  156. * Set the table comment.
  157. */
  158. public function comment(string $comment)
  159. {
  160. $this->comment = $comment;
  161. }
  162. /**
  163. * Indicate that the table needs to be temporary.
  164. */
  165. public function temporary()
  166. {
  167. $this->temporary = true;
  168. }
  169. /**
  170. * Indicate that the table should be dropped.
  171. *
  172. * @return Fluent
  173. */
  174. public function drop()
  175. {
  176. return $this->addCommand('drop');
  177. }
  178. /**
  179. * Indicate that the table should be dropped if it exists.
  180. *
  181. * @return Fluent
  182. */
  183. public function dropIfExists()
  184. {
  185. return $this->addCommand('dropIfExists');
  186. }
  187. /**
  188. * Indicate that the given columns should be dropped.
  189. *
  190. * @param array|mixed $columns
  191. * @return Fluent
  192. */
  193. public function dropColumn($columns)
  194. {
  195. $columns = is_array($columns) ? $columns : func_get_args();
  196. return $this->addCommand('dropColumn', compact('columns'));
  197. }
  198. /**
  199. * Indicate that the given columns should be renamed.
  200. *
  201. * @param string $from
  202. * @param string $to
  203. * @return Fluent
  204. */
  205. public function renameColumn($from, $to)
  206. {
  207. return $this->addCommand('renameColumn', compact('from', 'to'));
  208. }
  209. /**
  210. * Indicate that the given primary key should be dropped.
  211. *
  212. * @param array|string $index
  213. * @return Fluent
  214. */
  215. public function dropPrimary($index = null)
  216. {
  217. return $this->dropIndexCommand('dropPrimary', 'primary', $index);
  218. }
  219. /**
  220. * Indicate that the given unique key should be dropped.
  221. *
  222. * @param array|string $index
  223. * @return Fluent
  224. */
  225. public function dropUnique($index)
  226. {
  227. return $this->dropIndexCommand('dropUnique', 'unique', $index);
  228. }
  229. /**
  230. * Indicate that the given index should be dropped.
  231. *
  232. * @param array|string $index
  233. * @return Fluent
  234. */
  235. public function dropIndex($index)
  236. {
  237. return $this->dropIndexCommand('dropIndex', 'index', $index);
  238. }
  239. /**
  240. * Indicate that the given fulltext index should be dropped.
  241. *
  242. * @param array|string $index
  243. * @return Fluent
  244. */
  245. public function dropFullText($index)
  246. {
  247. return $this->dropIndexCommand('dropFullText', 'fulltext', $index);
  248. }
  249. /**
  250. * Indicate that the given spatial index should be dropped.
  251. *
  252. * @param array|string $index
  253. * @return Fluent
  254. */
  255. public function dropSpatialIndex($index)
  256. {
  257. return $this->dropIndexCommand('dropSpatialIndex', 'spatialIndex', $index);
  258. }
  259. /**
  260. * Indicate that the given foreign key should be dropped.
  261. *
  262. * @param array|string $index
  263. * @return Fluent
  264. */
  265. public function dropForeign($index)
  266. {
  267. return $this->dropIndexCommand('dropForeign', 'foreign', $index);
  268. }
  269. /**
  270. * Indicate that the given indexes should be renamed.
  271. *
  272. * @param string $from
  273. * @param string $to
  274. * @return Fluent
  275. */
  276. public function renameIndex($from, $to)
  277. {
  278. return $this->addCommand('renameIndex', compact('from', 'to'));
  279. }
  280. /**
  281. * Indicate that the timestamp columns should be dropped.
  282. */
  283. public function dropTimestamps()
  284. {
  285. $this->dropColumn('created_at', 'updated_at');
  286. }
  287. /**
  288. * Indicate that the timestamp columns should be dropped.
  289. */
  290. public function dropTimestampsTz()
  291. {
  292. $this->dropTimestamps();
  293. }
  294. /**
  295. * Indicate that the soft delete column should be dropped.
  296. *
  297. * @param string $column
  298. */
  299. public function dropSoftDeletes($column = 'deleted_at')
  300. {
  301. $this->dropColumn($column);
  302. }
  303. /**
  304. * Indicate that the soft delete column should be dropped.
  305. *
  306. * @param string $column
  307. */
  308. public function dropSoftDeletesTz($column = 'deleted_at')
  309. {
  310. $this->dropSoftDeletes($column);
  311. }
  312. /**
  313. * Indicate that the remember token column should be dropped.
  314. */
  315. public function dropRememberToken()
  316. {
  317. $this->dropColumn('remember_token');
  318. }
  319. /**
  320. * Indicate that the polymorphic columns should be dropped.
  321. *
  322. * @param string $name
  323. * @param null|string $indexName
  324. */
  325. public function dropMorphs($name, $indexName = null)
  326. {
  327. $this->dropIndex($indexName ?: $this->createIndexName('index', ["{$name}_type", "{$name}_id"]));
  328. $this->dropColumn("{$name}_type", "{$name}_id");
  329. }
  330. /**
  331. * Rename the table to a given name.
  332. *
  333. * @param string $to
  334. * @return Fluent
  335. */
  336. public function rename($to)
  337. {
  338. return $this->addCommand('rename', compact('to'));
  339. }
  340. /**
  341. * Specify the primary key(s) for the table.
  342. *
  343. * @param array|string $columns
  344. * @param string $name
  345. * @param null|string $algorithm
  346. * @return Fluent
  347. */
  348. public function primary($columns, $name = null, $algorithm = null)
  349. {
  350. return $this->indexCommand('primary', $columns, $name, $algorithm);
  351. }
  352. /**
  353. * Specify a unique index for the table.
  354. *
  355. * @param array|string $columns
  356. * @param string $name
  357. * @param null|string $algorithm
  358. * @return Fluent
  359. */
  360. public function unique($columns, $name = null, $algorithm = null)
  361. {
  362. return $this->indexCommand('unique', $columns, $name, $algorithm);
  363. }
  364. /**
  365. * Specify an index for the table.
  366. *
  367. * @param array|string $columns
  368. * @param string $name
  369. * @param null|string $algorithm
  370. * @return Fluent
  371. */
  372. public function index($columns, $name = null, $algorithm = null)
  373. {
  374. return $this->indexCommand('index', $columns, $name, $algorithm);
  375. }
  376. /**
  377. * Specify a spatial index for the table.
  378. *
  379. * @param array|string $columns
  380. * @param string $name
  381. * @return Fluent
  382. */
  383. public function spatialIndex($columns, $name = null)
  384. {
  385. return $this->indexCommand('spatialIndex', $columns, $name);
  386. }
  387. /**
  388. * Specify a foreign key for the table.
  389. *
  390. * @param array|string $columns
  391. * @param string $name
  392. * @return Fluent|ForeignKeyDefinition
  393. */
  394. public function foreign($columns, $name = null)
  395. {
  396. return $this->indexCommand('foreign', $columns, $name);
  397. }
  398. /**
  399. * Create a new auto-incrementing integer (4-byte) column on the table.
  400. *
  401. * @param string $column
  402. * @return ColumnDefinition
  403. */
  404. public function increments($column)
  405. {
  406. return $this->unsignedInteger($column, true);
  407. }
  408. /**
  409. * Create a new auto-incrementing integer (4-byte) column on the table.
  410. *
  411. * @param string $column
  412. * @return ColumnDefinition
  413. */
  414. public function integerIncrements($column)
  415. {
  416. return $this->unsignedInteger($column, true);
  417. }
  418. /**
  419. * Create a new auto-incrementing tiny integer (1-byte) column on the table.
  420. *
  421. * @param string $column
  422. * @return ColumnDefinition
  423. */
  424. public function tinyIncrements($column)
  425. {
  426. return $this->unsignedTinyInteger($column, true);
  427. }
  428. /**
  429. * Create a new auto-incrementing small integer (2-byte) column on the table.
  430. *
  431. * @param string $column
  432. * @return ColumnDefinition
  433. */
  434. public function smallIncrements($column)
  435. {
  436. return $this->unsignedSmallInteger($column, true);
  437. }
  438. /**
  439. * Create a new auto-incrementing medium integer (3-byte) column on the table.
  440. *
  441. * @param string $column
  442. * @return ColumnDefinition
  443. */
  444. public function mediumIncrements($column)
  445. {
  446. return $this->unsignedMediumInteger($column, true);
  447. }
  448. /**
  449. * Create a new auto-incrementing big integer (8-byte) column on the table.
  450. *
  451. * @param string $column
  452. * @return ColumnDefinition
  453. */
  454. public function bigIncrements($column)
  455. {
  456. return $this->unsignedBigInteger($column, true);
  457. }
  458. /**
  459. * Create a new char column on the table.
  460. *
  461. * @param string $column
  462. * @param int $length
  463. * @return ColumnDefinition
  464. */
  465. public function char($column, $length = null)
  466. {
  467. $length = $length ?: Builder::$defaultStringLength;
  468. return $this->addColumn('char', $column, compact('length'));
  469. }
  470. /**
  471. * Create a new string column on the table.
  472. *
  473. * @param string $column
  474. * @param int $length
  475. * @return ColumnDefinition
  476. */
  477. public function string($column, $length = null)
  478. {
  479. $length = $length ?: Builder::$defaultStringLength;
  480. return $this->addColumn('string', $column, compact('length'));
  481. }
  482. /**
  483. * Create a new text column on the table.
  484. *
  485. * @param string $column
  486. * @return ColumnDefinition
  487. */
  488. public function text($column)
  489. {
  490. return $this->addColumn('text', $column);
  491. }
  492. /**
  493. * Create a new medium text column on the table.
  494. *
  495. * @param string $column
  496. * @return ColumnDefinition
  497. */
  498. public function mediumText($column)
  499. {
  500. return $this->addColumn('mediumText', $column);
  501. }
  502. /**
  503. * Create a new long text column on the table.
  504. *
  505. * @param string $column
  506. * @return ColumnDefinition
  507. */
  508. public function longText($column)
  509. {
  510. return $this->addColumn('longText', $column);
  511. }
  512. /**
  513. * Create a new integer (4-byte) column on the table.
  514. *
  515. * @param string $column
  516. * @param bool $autoIncrement
  517. * @param bool $unsigned
  518. * @return ColumnDefinition
  519. */
  520. public function integer($column, $autoIncrement = false, $unsigned = false)
  521. {
  522. return $this->addColumn('integer', $column, compact('autoIncrement', 'unsigned'));
  523. }
  524. /**
  525. * Create a new tiny integer (1-byte) column on the table.
  526. *
  527. * @param string $column
  528. * @param bool $autoIncrement
  529. * @param bool $unsigned
  530. * @return ColumnDefinition
  531. */
  532. public function tinyInteger($column, $autoIncrement = false, $unsigned = false)
  533. {
  534. return $this->addColumn('tinyInteger', $column, compact('autoIncrement', 'unsigned'));
  535. }
  536. /**
  537. * Create a new small integer (2-byte) column on the table.
  538. *
  539. * @param string $column
  540. * @param bool $autoIncrement
  541. * @param bool $unsigned
  542. * @return ColumnDefinition
  543. */
  544. public function smallInteger($column, $autoIncrement = false, $unsigned = false)
  545. {
  546. return $this->addColumn('smallInteger', $column, compact('autoIncrement', 'unsigned'));
  547. }
  548. /**
  549. * Create a new medium integer (3-byte) column on the table.
  550. *
  551. * @param string $column
  552. * @param bool $autoIncrement
  553. * @param bool $unsigned
  554. * @return ColumnDefinition
  555. */
  556. public function mediumInteger($column, $autoIncrement = false, $unsigned = false)
  557. {
  558. return $this->addColumn('mediumInteger', $column, compact('autoIncrement', 'unsigned'));
  559. }
  560. /**
  561. * Create a new big integer (8-byte) column on the table.
  562. *
  563. * @param string $column
  564. * @param bool $autoIncrement
  565. * @param bool $unsigned
  566. * @return ColumnDefinition
  567. */
  568. public function bigInteger($column, $autoIncrement = false, $unsigned = false)
  569. {
  570. return $this->addColumn('bigInteger', $column, compact('autoIncrement', 'unsigned'));
  571. }
  572. /**
  573. * Create a new unsigned integer (4-byte) column on the table.
  574. *
  575. * @param string $column
  576. * @param bool $autoIncrement
  577. * @return ColumnDefinition
  578. */
  579. public function unsignedInteger($column, $autoIncrement = false)
  580. {
  581. return $this->integer($column, $autoIncrement, true);
  582. }
  583. /**
  584. * Create a new unsigned tiny integer (1-byte) column on the table.
  585. *
  586. * @param string $column
  587. * @param bool $autoIncrement
  588. * @return ColumnDefinition
  589. */
  590. public function unsignedTinyInteger($column, $autoIncrement = false)
  591. {
  592. return $this->tinyInteger($column, $autoIncrement, true);
  593. }
  594. /**
  595. * Create a new unsigned small integer (2-byte) column on the table.
  596. *
  597. * @param string $column
  598. * @param bool $autoIncrement
  599. * @return ColumnDefinition
  600. */
  601. public function unsignedSmallInteger($column, $autoIncrement = false)
  602. {
  603. return $this->smallInteger($column, $autoIncrement, true);
  604. }
  605. /**
  606. * Create a new unsigned medium integer (3-byte) column on the table.
  607. *
  608. * @param string $column
  609. * @param bool $autoIncrement
  610. * @return ColumnDefinition
  611. */
  612. public function unsignedMediumInteger($column, $autoIncrement = false)
  613. {
  614. return $this->mediumInteger($column, $autoIncrement, true);
  615. }
  616. /**
  617. * Create a new unsigned big integer (8-byte) column on the table.
  618. *
  619. * @param string $column
  620. * @param bool $autoIncrement
  621. * @return ColumnDefinition
  622. */
  623. public function unsignedBigInteger($column, $autoIncrement = false)
  624. {
  625. return $this->bigInteger($column, $autoIncrement, true);
  626. }
  627. /**
  628. * Create a new float column on the table.
  629. *
  630. * @param string $column
  631. * @param int $total
  632. * @param int $places
  633. * @return ColumnDefinition
  634. */
  635. public function float($column, $total = 8, $places = 2)
  636. {
  637. return $this->addColumn('float', $column, compact('total', 'places'));
  638. }
  639. /**
  640. * Create a new double column on the table.
  641. *
  642. * @param string $column
  643. * @param null|int $total
  644. * @param null|int $places
  645. * @return ColumnDefinition
  646. */
  647. public function double($column, $total = null, $places = null)
  648. {
  649. return $this->addColumn('double', $column, compact('total', 'places'));
  650. }
  651. /**
  652. * Create a new decimal column on the table.
  653. *
  654. * @param string $column
  655. * @param int $total
  656. * @param int $places
  657. * @return ColumnDefinition
  658. */
  659. public function decimal($column, $total = 8, $places = 2)
  660. {
  661. return $this->addColumn('decimal', $column, compact('total', 'places'));
  662. }
  663. /**
  664. * Create a new unsigned decimal column on the table.
  665. *
  666. * @param string $column
  667. * @param int $total
  668. * @param int $places
  669. * @return ColumnDefinition
  670. */
  671. public function unsignedDecimal($column, $total = 8, $places = 2)
  672. {
  673. return $this->addColumn('decimal', $column, [
  674. 'total' => $total, 'places' => $places, 'unsigned' => true,
  675. ]);
  676. }
  677. /**
  678. * Create a new boolean column on the table.
  679. *
  680. * @param string $column
  681. * @return ColumnDefinition
  682. */
  683. public function boolean($column)
  684. {
  685. return $this->addColumn('boolean', $column);
  686. }
  687. /**
  688. * Create a new enum column on the table.
  689. *
  690. * @param string $column
  691. * @return ColumnDefinition
  692. */
  693. public function enum($column, array $allowed)
  694. {
  695. return $this->addColumn('enum', $column, compact('allowed'));
  696. }
  697. /**
  698. * Create a new json column on the table.
  699. *
  700. * @param string $column
  701. * @return ColumnDefinition
  702. */
  703. public function json($column)
  704. {
  705. return $this->addColumn('json', $column);
  706. }
  707. /**
  708. * Create a new jsonb column on the table.
  709. *
  710. * @param string $column
  711. * @return ColumnDefinition
  712. */
  713. public function jsonb($column)
  714. {
  715. return $this->addColumn('jsonb', $column);
  716. }
  717. /**
  718. * Create a new date column on the table.
  719. *
  720. * @param string $column
  721. * @return ColumnDefinition
  722. */
  723. public function date($column)
  724. {
  725. return $this->addColumn('date', $column);
  726. }
  727. /**
  728. * Create a new date-time column on the table.
  729. *
  730. * @param string $column
  731. * @param int $precision
  732. * @return ColumnDefinition
  733. */
  734. public function dateTime($column, $precision = 0)
  735. {
  736. return $this->addColumn('dateTime', $column, compact('precision'));
  737. }
  738. /**
  739. * Create a new date-time column (with time zone) on the table.
  740. *
  741. * @param string $column
  742. * @param int $precision
  743. * @return ColumnDefinition
  744. */
  745. public function dateTimeTz($column, $precision = 0)
  746. {
  747. return $this->addColumn('dateTimeTz', $column, compact('precision'));
  748. }
  749. /**
  750. * Create a new time column on the table.
  751. *
  752. * @param string $column
  753. * @param int $precision
  754. * @return ColumnDefinition
  755. */
  756. public function time($column, $precision = 0)
  757. {
  758. return $this->addColumn('time', $column, compact('precision'));
  759. }
  760. /**
  761. * Create a new time column (with time zone) on the table.
  762. *
  763. * @param string $column
  764. * @param int $precision
  765. * @return ColumnDefinition
  766. */
  767. public function timeTz($column, $precision = 0)
  768. {
  769. return $this->addColumn('timeTz', $column, compact('precision'));
  770. }
  771. /**
  772. * Create a new timestamp column on the table.
  773. *
  774. * @param string $column
  775. * @param int $precision
  776. * @return ColumnDefinition
  777. */
  778. public function timestamp($column, $precision = 0)
  779. {
  780. return $this->addColumn('timestamp', $column, compact('precision'));
  781. }
  782. /**
  783. * Create a new timestamp (with time zone) column on the table.
  784. *
  785. * @param string $column
  786. * @param int $precision
  787. * @return ColumnDefinition
  788. */
  789. public function timestampTz($column, $precision = 0)
  790. {
  791. return $this->addColumn('timestampTz', $column, compact('precision'));
  792. }
  793. /**
  794. * Add nullable creation and update timestamps to the table.
  795. *
  796. * @param int $precision
  797. */
  798. public function timestamps($precision = 0)
  799. {
  800. $this->timestamp('created_at', $precision)->nullable();
  801. $this->timestamp('updated_at', $precision)->nullable();
  802. }
  803. /**
  804. * Add nullable creation and update timestamps to the table.
  805. *
  806. * Alias for self::timestamps().
  807. *
  808. * @param int $precision
  809. */
  810. public function nullableTimestamps($precision = 0)
  811. {
  812. $this->timestamps($precision);
  813. }
  814. /**
  815. * Add creation and update timestampTz columns to the table.
  816. *
  817. * @param int $precision
  818. */
  819. public function timestampsTz($precision = 0)
  820. {
  821. $this->timestampTz('created_at', $precision)->nullable();
  822. $this->timestampTz('updated_at', $precision)->nullable();
  823. }
  824. /**
  825. * Add creation and update datetime columns to the table.
  826. *
  827. * @param null|int $precision
  828. */
  829. public function datetimes($precision = 0)
  830. {
  831. $this->datetime('created_at', $precision)->nullable();
  832. $this->datetime('updated_at', $precision)->nullable();
  833. }
  834. /**
  835. * Add a "deleted at" timestamp for the table.
  836. *
  837. * @param string $column
  838. * @param int $precision
  839. * @return ColumnDefinition
  840. */
  841. public function softDeletes($column = 'deleted_at', $precision = 0)
  842. {
  843. return $this->timestamp($column, $precision)->nullable();
  844. }
  845. /**
  846. * Add a "deleted at" timestampTz for the table.
  847. *
  848. * @param string $column
  849. * @param int $precision
  850. * @return ColumnDefinition
  851. */
  852. public function softDeletesTz($column = 'deleted_at', $precision = 0)
  853. {
  854. return $this->timestampTz($column, $precision)->nullable();
  855. }
  856. /**
  857. * Create a new year column on the table.
  858. *
  859. * @param string $column
  860. * @return ColumnDefinition
  861. */
  862. public function year($column)
  863. {
  864. return $this->addColumn('year', $column);
  865. }
  866. /**
  867. * Create a new binary column on the table.
  868. *
  869. * @param string $column
  870. * @return ColumnDefinition
  871. */
  872. public function binary($column)
  873. {
  874. return $this->addColumn('binary', $column);
  875. }
  876. /**
  877. * Create a new auto-incrementing big integer (8-byte) column on the table.
  878. *
  879. * @param string $column
  880. * @return ColumnDefinition
  881. */
  882. public function id($column = 'id')
  883. {
  884. return $this->bigIncrements($column);
  885. }
  886. /**
  887. * Create a new ULID column on the table.
  888. *
  889. * @param string $column
  890. * @param null|int $length
  891. * @return ColumnDefinition
  892. */
  893. public function ulid($column = 'ulid', $length = 26)
  894. {
  895. return $this->char($column, $length);
  896. }
  897. /**
  898. * Create a new uuid column on the table.
  899. *
  900. * @param string $column
  901. * @return ColumnDefinition
  902. */
  903. public function uuid($column)
  904. {
  905. return $this->addColumn('uuid', $column);
  906. }
  907. /**
  908. * Create a new IP address column on the table.
  909. *
  910. * @param string $column
  911. * @return ColumnDefinition
  912. */
  913. public function ipAddress($column)
  914. {
  915. return $this->addColumn('ipAddress', $column);
  916. }
  917. /**
  918. * Create a new MAC address column on the table.
  919. *
  920. * @param string $column
  921. * @return ColumnDefinition
  922. */
  923. public function macAddress($column)
  924. {
  925. return $this->addColumn('macAddress', $column);
  926. }
  927. /**
  928. * Create a new geometry column on the table.
  929. *
  930. * @param string $column
  931. * @return ColumnDefinition
  932. */
  933. public function geometry($column)
  934. {
  935. return $this->addColumn('geometry', $column);
  936. }
  937. /**
  938. * Create a new point column on the table.
  939. *
  940. * @param string $column
  941. * @param null|int $srid
  942. * @return ColumnDefinition
  943. */
  944. public function point($column, $srid = null)
  945. {
  946. return $this->addColumn('point', $column, compact('srid'));
  947. }
  948. /**
  949. * Create a new linestring column on the table.
  950. *
  951. * @param string $column
  952. * @return ColumnDefinition
  953. */
  954. public function lineString($column)
  955. {
  956. return $this->addColumn('linestring', $column);
  957. }
  958. /**
  959. * Create a new polygon column on the table.
  960. *
  961. * @param string $column
  962. * @return ColumnDefinition
  963. */
  964. public function polygon($column)
  965. {
  966. return $this->addColumn('polygon', $column);
  967. }
  968. /**
  969. * Create a new geometrycollection column on the table.
  970. *
  971. * @param string $column
  972. * @return ColumnDefinition
  973. */
  974. public function geometryCollection($column)
  975. {
  976. return $this->addColumn('geometrycollection', $column);
  977. }
  978. /**
  979. * Create a new multipoint column on the table.
  980. *
  981. * @param string $column
  982. * @return ColumnDefinition
  983. */
  984. public function multiPoint($column)
  985. {
  986. return $this->addColumn('multipoint', $column);
  987. }
  988. /**
  989. * Create a new multilinestring column on the table.
  990. *
  991. * @param string $column
  992. * @return ColumnDefinition
  993. */
  994. public function multiLineString($column)
  995. {
  996. return $this->addColumn('multilinestring', $column);
  997. }
  998. /**
  999. * Create a new multipolygon column on the table.
  1000. *
  1001. * @param string $column
  1002. * @return ColumnDefinition
  1003. */
  1004. public function multiPolygon($column)
  1005. {
  1006. return $this->addColumn('multipolygon', $column);
  1007. }
  1008. /**
  1009. * Add the proper columns for a polymorphic table.
  1010. *
  1011. * @param string $name
  1012. * @param null|string $indexName
  1013. */
  1014. public function morphs($name, $indexName = null)
  1015. {
  1016. $this->string("{$name}_type");
  1017. $this->unsignedBigInteger("{$name}_id");
  1018. $this->index(["{$name}_type", "{$name}_id"], $indexName);
  1019. }
  1020. /**
  1021. * Add nullable columns for a polymorphic table.
  1022. *
  1023. * @param string $name
  1024. * @param null|string $indexName
  1025. */
  1026. public function nullableMorphs($name, $indexName = null)
  1027. {
  1028. $this->string("{$name}_type")->nullable();
  1029. $this->unsignedBigInteger("{$name}_id")->nullable();
  1030. $this->index(["{$name}_type", "{$name}_id"], $indexName);
  1031. }
  1032. /**
  1033. * Adds the `remember_token` column to the table.
  1034. *
  1035. * @return ColumnDefinition
  1036. */
  1037. public function rememberToken()
  1038. {
  1039. return $this->string('remember_token', 100)->nullable();
  1040. }
  1041. /**
  1042. * Add a new column to the blueprint.
  1043. *
  1044. * @param string $type
  1045. * @param string $name
  1046. * @return ColumnDefinition
  1047. */
  1048. public function addColumn($type, $name, array $parameters = [])
  1049. {
  1050. $this->columns[] = $column = new ColumnDefinition(
  1051. array_merge(compact('type', 'name'), $parameters)
  1052. );
  1053. return $column;
  1054. }
  1055. /**
  1056. * Remove a column from the schema blueprint.
  1057. *
  1058. * @param string $name
  1059. * @return $this
  1060. */
  1061. public function removeColumn($name)
  1062. {
  1063. $this->columns = array_values(array_filter($this->columns, function ($c) use ($name) {
  1064. return $c['attributes']['name'] != $name;
  1065. }));
  1066. return $this;
  1067. }
  1068. /**
  1069. * Get the table the blueprint describes.
  1070. *
  1071. * @return string
  1072. */
  1073. public function getTable()
  1074. {
  1075. return $this->table;
  1076. }
  1077. /**
  1078. * Get the comment on the blueprint.
  1079. *
  1080. * @return string
  1081. */
  1082. public function getComment()
  1083. {
  1084. return $this->comment;
  1085. }
  1086. /**
  1087. * Get the columns on the blueprint.
  1088. *
  1089. * @return \Hyperf\Database\Schema\ColumnDefinition[]
  1090. */
  1091. public function getColumns()
  1092. {
  1093. return $this->columns;
  1094. }
  1095. /**
  1096. * Get the commands on the blueprint.
  1097. *
  1098. * @return Fluent[]
  1099. */
  1100. public function getCommands()
  1101. {
  1102. return $this->commands;
  1103. }
  1104. /**
  1105. * Get the columns on the blueprint that should be added.
  1106. *
  1107. * @return \Hyperf\Database\Schema\ColumnDefinition[]
  1108. */
  1109. public function getAddedColumns()
  1110. {
  1111. return array_filter($this->columns, function ($column) {
  1112. return ! $column->change;
  1113. });
  1114. }
  1115. /**
  1116. * Get the columns on the blueprint that should be changed.
  1117. *
  1118. * @return \Hyperf\Database\Schema\ColumnDefinition[]
  1119. */
  1120. public function getChangedColumns()
  1121. {
  1122. return array_filter($this->columns, function ($column) {
  1123. return (bool) $column->change;
  1124. });
  1125. }
  1126. /**
  1127. * Determine if the blueprint has auto-increment columns.
  1128. */
  1129. public function hasAutoIncrementColumn(): bool
  1130. {
  1131. return ! is_null(collect($this->getAddedColumns())->first(function ($column) {
  1132. return $column->autoIncrement === true;
  1133. }));
  1134. }
  1135. /**
  1136. * Get the auto-increment column starting values.
  1137. */
  1138. public function autoIncrementingStartingValues(): array
  1139. {
  1140. if (! $this->hasAutoIncrementColumn()) {
  1141. return [];
  1142. }
  1143. return collect($this->getAddedColumns())->mapWithKeys(function ($column) {
  1144. return $column->autoIncrement === true
  1145. ? [$column->name => $column->get('startingValue', $column->get('from'))]
  1146. : [$column->name => null];
  1147. })->filter()->all();
  1148. }
  1149. /**
  1150. * Specify an fulltext for the table.
  1151. *
  1152. * @param array|string $columns
  1153. * @param null|string $name
  1154. * @param null|string $algorithm
  1155. * @return Fluent
  1156. */
  1157. public function fullText($columns, $name = null, $algorithm = null)
  1158. {
  1159. return $this->indexCommand('fulltext', $columns, $name, $algorithm);
  1160. }
  1161. /**
  1162. * Specify a raw index for the table.
  1163. *
  1164. * @param string $expression
  1165. * @param string $name
  1166. * @return Fluent
  1167. */
  1168. public function rawIndex($expression, $name)
  1169. {
  1170. return $this->index([new Expression($expression)], $name);
  1171. }
  1172. /**
  1173. * Create a new ULID column on the table with a foreign key constraint.
  1174. *
  1175. * @param string $column
  1176. * @param null|int $length
  1177. * @return ForeignIdColumnDefinition
  1178. */
  1179. public function foreignUlid($column = 'ulid', $length = 26)
  1180. {
  1181. return $this->addColumnDefinition(new ForeignIdColumnDefinition($this, [
  1182. 'type' => 'char',
  1183. 'name' => $column,
  1184. 'length' => $length,
  1185. ]));
  1186. }
  1187. /**
  1188. * Create a new UUID column on the table with a foreign key constraint.
  1189. *
  1190. * @param string $column
  1191. * @return ForeignIdColumnDefinition
  1192. */
  1193. public function foreignUuid($column)
  1194. {
  1195. return $this->addColumnDefinition(new ForeignIdColumnDefinition($this, [
  1196. 'type' => 'uuid',
  1197. 'name' => $column,
  1198. ]));
  1199. }
  1200. /**
  1201. * Ensure the commands on the blueprint are valid for the connection type.
  1202. *
  1203. * @throws BadMethodCallException
  1204. */
  1205. protected function ensureCommandsAreValid(Connection $connection)
  1206. {
  1207. if ($connection instanceof SQLiteConnection) {
  1208. if ($this->commandsNamed(['dropColumn', 'renameColumn'])->count() > 1) {
  1209. throw new BadMethodCallException(
  1210. "SQLite doesn't support multiple calls to dropColumn / renameColumn in a single modification."
  1211. );
  1212. }
  1213. if ($this->commandsNamed(['dropForeign'])->count() > 0) {
  1214. throw new BadMethodCallException(
  1215. "SQLite doesn't support dropping foreign keys (you would need to re-create the table)."
  1216. );
  1217. }
  1218. }
  1219. }
  1220. /**
  1221. * Get all of the commands matching the given names.
  1222. *
  1223. * @return Collection
  1224. */
  1225. protected function commandsNamed(array $names)
  1226. {
  1227. return collect($this->commands)->filter(function ($command) use ($names) {
  1228. return in_array($command->name, $names);
  1229. });
  1230. }
  1231. /**
  1232. * Add the commands that are implied by the blueprint's state.
  1233. */
  1234. protected function addImpliedCommands(Grammar $grammar)
  1235. {
  1236. if (count($this->getAddedColumns()) > 0 && ! $this->creating()) {
  1237. array_unshift($this->commands, $this->createCommand('add'));
  1238. }
  1239. if (count($this->getChangedColumns()) > 0 && ! $this->creating()) {
  1240. array_unshift($this->commands, $this->createCommand('change'));
  1241. }
  1242. $this->addFluentIndexes();
  1243. $this->addFluentCommands($grammar);
  1244. }
  1245. /**
  1246. * Add the index commands fluently specified on columns.
  1247. */
  1248. protected function addFluentIndexes()
  1249. {
  1250. foreach ($this->columns as $column) {
  1251. foreach (['primary', 'unique', 'index', 'fullText', 'spatialIndex'] as $index) {
  1252. // If the index has been specified on the given column, but is simply equal
  1253. // to "true" (boolean), no name has been specified for this index so the
  1254. // index method can be called without a name and it will generate one.
  1255. if ($column->{$index} === true) {
  1256. $this->{$index}($column->name);
  1257. continue 2;
  1258. }
  1259. // If the index has been specified on the given column, and it has a string
  1260. // value, we'll go ahead and call the index method and pass the name for
  1261. // the index since the developer specified the explicit name for this.
  1262. if (isset($column->{$index})) {
  1263. $this->{$index}($column->name, $column->{$index});
  1264. continue 2;
  1265. }
  1266. }
  1267. }
  1268. }
  1269. /**
  1270. * Determine if the blueprint has a create command.
  1271. *
  1272. * @return bool
  1273. */
  1274. protected function creating()
  1275. {
  1276. return collect($this->commands)->contains(function ($command) {
  1277. return $command->name === 'create';
  1278. });
  1279. }
  1280. /**
  1281. * Add a new index command to the blueprint.
  1282. *
  1283. * @param string $type
  1284. * @param array|string $columns
  1285. * @param string $index
  1286. * @param null|string $algorithm
  1287. * @return Fluent
  1288. */
  1289. protected function indexCommand($type, $columns, $index, $algorithm = null)
  1290. {
  1291. $columns = (array) $columns;
  1292. // If no name was specified for this index, we will create one using a basic
  1293. // convention of the table name, followed by the columns, followed by an
  1294. // index type, such as primary or index, which makes the index unique.
  1295. $index = $index ?: $this->createIndexName($type, $columns);
  1296. return $this->addCommand(
  1297. $type,
  1298. compact('index', 'columns', 'algorithm')
  1299. );
  1300. }
  1301. /**
  1302. * Create a new drop index command on the blueprint.
  1303. *
  1304. * @param string $command
  1305. * @param string $type
  1306. * @param array|string $index
  1307. * @return Fluent
  1308. */
  1309. protected function dropIndexCommand($command, $type, $index)
  1310. {
  1311. $columns = [];
  1312. // If the given "index" is actually an array of columns, the developer means
  1313. // to drop an index merely by specifying the columns involved without the
  1314. // conventional name, so we will build the index name from the columns.
  1315. if (is_array($index)) {
  1316. $index = $this->createIndexName($type, $columns = $index);
  1317. }
  1318. return $this->indexCommand($command, $columns, $index);
  1319. }
  1320. /**
  1321. * Create a default index name for the table.
  1322. *
  1323. * @param string $type
  1324. * @return string
  1325. */
  1326. protected function createIndexName($type, array $columns)
  1327. {
  1328. $index = strtolower($this->prefix . $this->table . '_' . implode('_', $columns) . '_' . $type);
  1329. return str_replace(['-', '.'], '_', $index);
  1330. }
  1331. /**
  1332. * Add a new command to the blueprint.
  1333. *
  1334. * @param string $name
  1335. * @return Fluent
  1336. */
  1337. protected function addCommand($name, array $parameters = [])
  1338. {
  1339. $this->commands[] = $command = $this->createCommand($name, $parameters);
  1340. return $command;
  1341. }
  1342. /**
  1343. * Create a new Fluent command.
  1344. *
  1345. * @param string $name
  1346. * @return Fluent
  1347. */
  1348. protected function createCommand($name, array $parameters = [])
  1349. {
  1350. return new Fluent(array_merge(compact('name'), $parameters));
  1351. }
  1352. /**
  1353. * Add a new column definition to the blueprint.
  1354. *
  1355. * @param ColumnDefinition $definition
  1356. * @return ColumnDefinition
  1357. */
  1358. protected function addColumnDefinition($definition)
  1359. {
  1360. $this->columns[] = $definition;
  1361. if ($this->after) {
  1362. $definition->after($this->after);
  1363. $this->after = $definition->name;
  1364. }
  1365. return $definition;
  1366. }
  1367. }