MigrationCreator.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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\Migrations;
  12. use Closure;
  13. use Exception;
  14. use Hyperf\Stringable\Str;
  15. use Hyperf\Support\Filesystem\Filesystem;
  16. use InvalidArgumentException;
  17. class MigrationCreator
  18. {
  19. /**
  20. * The registered post create hooks.
  21. */
  22. protected array $postCreate = [];
  23. /**
  24. * Create a new migration creator instance.
  25. */
  26. public function __construct(protected Filesystem $files)
  27. {
  28. }
  29. /**
  30. * Create a new migration at the given path.
  31. *
  32. * @throws Exception
  33. */
  34. public function create(string $name, string $path, ?string $table = null, bool $create = false): string
  35. {
  36. $this->ensureMigrationDoesntAlreadyExist($name, $path);
  37. // First we will get the stub file for the migration, which serves as a type
  38. // of template for the migration. Once we have those we will populate the
  39. // various place-holders, save the file, and run the post create event.
  40. $stub = $this->getStub($table, $create);
  41. if (! file_exists($path)) {
  42. mkdir($path, 0755, true);
  43. }
  44. $this->files->put(
  45. $path = $this->getPath($name, $path),
  46. $this->populateStub($name, $stub, $table)
  47. );
  48. // Next, we will fire any hooks that are supposed to fire after a migration is
  49. // created. Once that is done we'll be ready to return the full path to the
  50. // migration file so it can be used however it's needed by the developer.
  51. $this->firePostCreateHooks($table);
  52. return $path;
  53. }
  54. /**
  55. * Register a post migration create hook.
  56. */
  57. public function afterCreate(Closure $callback)
  58. {
  59. $this->postCreate[] = $callback;
  60. }
  61. /**
  62. * Get the path to the stubs.
  63. */
  64. public function stubPath(): string
  65. {
  66. return __DIR__ . '/stubs';
  67. }
  68. /**
  69. * Get the filesystem instance.
  70. */
  71. public function getFilesystem(): Filesystem
  72. {
  73. return $this->files;
  74. }
  75. /**
  76. * Ensure that a migration with the given name doesn't already exist.
  77. *
  78. * @throws InvalidArgumentException
  79. */
  80. protected function ensureMigrationDoesntAlreadyExist(string $name, ?string $migrationPath = null)
  81. {
  82. if (! empty($migrationPath)) {
  83. $migrationFiles = $this->files->glob($migrationPath . '/*.php');
  84. foreach ($migrationFiles as $migrationFile) {
  85. $this->files->requireOnce($migrationFile);
  86. }
  87. }
  88. if (class_exists($className = $this->getClassName($name))) {
  89. throw new InvalidArgumentException("A {$className} class already exists.");
  90. }
  91. }
  92. /**
  93. * Get the migration stub file.
  94. */
  95. protected function getStub(?string $table, bool $create): string
  96. {
  97. if (is_null($table)) {
  98. return $this->files->get($this->stubPath() . '/blank.stub');
  99. }
  100. // We also have stubs for creating new tables and modifying existing tables
  101. // to save the developer some typing when they are creating a new tables
  102. // or modifying existing tables. We'll grab the appropriate stub here.
  103. $stub = $create ? 'create.stub' : 'update.stub';
  104. return $this->files->get($this->stubPath() . "/{$stub}");
  105. }
  106. /**
  107. * Populate the place-holders in the migration stub.
  108. */
  109. protected function populateStub(string $name, string $stub, ?string $table): string
  110. {
  111. $stub = str_replace('DummyClass', $this->getClassName($name), $stub);
  112. // Here we will replace the table place-holders with the table specified by
  113. // the developer, which is useful for quickly creating a tables creation
  114. // or update migration from the console instead of typing it manually.
  115. if (! is_null($table)) {
  116. $stub = str_replace('DummyTable', $table, $stub);
  117. }
  118. return $stub;
  119. }
  120. /**
  121. * Get the class name of a migration name.
  122. */
  123. protected function getClassName(string $name): string
  124. {
  125. return Str::studly($name);
  126. }
  127. /**
  128. * Get the full path to the migration.
  129. */
  130. protected function getPath(string $name, string $path): string
  131. {
  132. return $path . '/' . $this->getDatePrefix() . '_' . $name . '.php';
  133. }
  134. /**
  135. * Fire the registered post create hooks.
  136. */
  137. protected function firePostCreateHooks(?string $table)
  138. {
  139. foreach ($this->postCreate as $callback) {
  140. call_user_func($callback, $table);
  141. }
  142. }
  143. /**
  144. * Get the date prefix for the migration.
  145. */
  146. protected function getDatePrefix(): string
  147. {
  148. return date('Y_m_d_His');
  149. }
  150. }