/vendor/laravel/framework/src/Illuminate/Database/Migrations/Migrator.php

https://gitlab.com/Pasantias/pasantiasASLG · PHP · 405 lines · 161 code · 63 blank · 181 comment · 10 complexity · cdb9ec9e964d6d7a6c6d680fe9319f15 MD5 · raw file

  1. <?php
  2. namespace Illuminate\Database\Migrations;
  3. use Illuminate\Support\Str;
  4. use Illuminate\Filesystem\Filesystem;
  5. use Illuminate\Database\ConnectionResolverInterface as Resolver;
  6. class Migrator
  7. {
  8. /**
  9. * The migration repository implementation.
  10. *
  11. * @var \Illuminate\Database\Migrations\MigrationRepositoryInterface
  12. */
  13. protected $repository;
  14. /**
  15. * The filesystem instance.
  16. *
  17. * @var \Illuminate\Filesystem\Filesystem
  18. */
  19. protected $files;
  20. /**
  21. * The connection resolver instance.
  22. *
  23. * @var \Illuminate\Database\ConnectionResolverInterface
  24. */
  25. protected $resolver;
  26. /**
  27. * The name of the default connection.
  28. *
  29. * @var string
  30. */
  31. protected $connection;
  32. /**
  33. * The notes for the current operation.
  34. *
  35. * @var array
  36. */
  37. protected $notes = [];
  38. /**
  39. * Create a new migrator instance.
  40. *
  41. * @param \Illuminate\Database\Migrations\MigrationRepositoryInterface $repository
  42. * @param \Illuminate\Database\ConnectionResolverInterface $resolver
  43. * @param \Illuminate\Filesystem\Filesystem $files
  44. * @return void
  45. */
  46. public function __construct(MigrationRepositoryInterface $repository,
  47. Resolver $resolver,
  48. Filesystem $files)
  49. {
  50. $this->files = $files;
  51. $this->resolver = $resolver;
  52. $this->repository = $repository;
  53. }
  54. /**
  55. * Run the outstanding migrations at a given path.
  56. *
  57. * @param string $path
  58. * @param bool $pretend
  59. * @return void
  60. */
  61. public function run($path, $pretend = false)
  62. {
  63. $this->notes = [];
  64. $files = $this->getMigrationFiles($path);
  65. // Once we grab all of the migration files for the path, we will compare them
  66. // against the migrations that have already been run for this package then
  67. // run each of the outstanding migrations against a database connection.
  68. $ran = $this->repository->getRan();
  69. $migrations = array_diff($files, $ran);
  70. $this->requireFiles($path, $migrations);
  71. $this->runMigrationList($migrations, $pretend);
  72. }
  73. /**
  74. * Run an array of migrations.
  75. *
  76. * @param array $migrations
  77. * @param bool $pretend
  78. * @return void
  79. */
  80. public function runMigrationList($migrations, $pretend = false)
  81. {
  82. // First we will just make sure that there are any migrations to run. If there
  83. // aren't, we will just make a note of it to the developer so they're aware
  84. // that all of the migrations have been run against this database system.
  85. if (count($migrations) == 0) {
  86. $this->note('<info>Nothing to migrate.</info>');
  87. return;
  88. }
  89. $batch = $this->repository->getNextBatchNumber();
  90. // Once we have the array of migrations, we will spin through them and run the
  91. // migrations "up" so the changes are made to the databases. We'll then log
  92. // that the migration was run so we don't repeat it next time we execute.
  93. foreach ($migrations as $file) {
  94. $this->runUp($file, $batch, $pretend);
  95. }
  96. }
  97. /**
  98. * Run "up" a migration instance.
  99. *
  100. * @param string $file
  101. * @param int $batch
  102. * @param bool $pretend
  103. * @return void
  104. */
  105. protected function runUp($file, $batch, $pretend)
  106. {
  107. // First we will resolve a "real" instance of the migration class from this
  108. // migration file name. Once we have the instances we can run the actual
  109. // command such as "up" or "down", or we can just simulate the action.
  110. $migration = $this->resolve($file);
  111. if ($pretend) {
  112. return $this->pretendToRun($migration, 'up');
  113. }
  114. $migration->up();
  115. // Once we have run a migrations class, we will log that it was run in this
  116. // repository so that we don't try to run it next time we do a migration
  117. // in the application. A migration repository keeps the migrate order.
  118. $this->repository->log($file, $batch);
  119. $this->note("<info>Migrated:</info> $file");
  120. }
  121. /**
  122. * Rollback the last migration operation.
  123. *
  124. * @param bool $pretend
  125. * @return int
  126. */
  127. public function rollback($pretend = false)
  128. {
  129. $this->notes = [];
  130. // We want to pull in the last batch of migrations that ran on the previous
  131. // migration operation. We'll then reverse those migrations and run each
  132. // of them "down" to reverse the last migration "operation" which ran.
  133. $migrations = $this->repository->getLast();
  134. $count = count($migrations);
  135. if ($count === 0) {
  136. $this->note('<info>Nothing to rollback.</info>');
  137. } else {
  138. // We need to reverse these migrations so that they are "downed" in reverse
  139. // to what they run on "up". It lets us backtrack through the migrations
  140. // and properly reverse the entire database schema operation that ran.
  141. foreach ($migrations as $migration) {
  142. $this->runDown((object) $migration, $pretend);
  143. }
  144. }
  145. return $count;
  146. }
  147. /**
  148. * Rolls all of the currently applied migrations back.
  149. *
  150. * @param bool $pretend
  151. * @return int
  152. */
  153. public function reset($pretend = false)
  154. {
  155. $this->notes = [];
  156. $migrations = array_reverse($this->repository->getRan());
  157. $count = count($migrations);
  158. if ($count === 0) {
  159. $this->note('<info>Nothing to rollback.</info>');
  160. } else {
  161. foreach ($migrations as $migration) {
  162. $this->runDown((object) ['migration' => $migration], $pretend);
  163. }
  164. }
  165. return $count;
  166. }
  167. /**
  168. * Run "down" a migration instance.
  169. *
  170. * @param object $migration
  171. * @param bool $pretend
  172. * @return void
  173. */
  174. protected function runDown($migration, $pretend)
  175. {
  176. $file = $migration->migration;
  177. // First we will get the file name of the migration so we can resolve out an
  178. // instance of the migration. Once we get an instance we can either run a
  179. // pretend execution of the migration or we can run the real migration.
  180. $instance = $this->resolve($file);
  181. if ($pretend) {
  182. return $this->pretendToRun($instance, 'down');
  183. }
  184. $instance->down();
  185. // Once we have successfully run the migration "down" we will remove it from
  186. // the migration repository so it will be considered to have not been run
  187. // by the application then will be able to fire by any later operation.
  188. $this->repository->delete($migration);
  189. $this->note("<info>Rolled back:</info> $file");
  190. }
  191. /**
  192. * Get all of the migration files in a given path.
  193. *
  194. * @param string $path
  195. * @return array
  196. */
  197. public function getMigrationFiles($path)
  198. {
  199. $files = $this->files->glob($path.'/*_*.php');
  200. // Once we have the array of files in the directory we will just remove the
  201. // extension and take the basename of the file which is all we need when
  202. // finding the migrations that haven't been run against the databases.
  203. if ($files === false) {
  204. return [];
  205. }
  206. $files = array_map(function ($file) {
  207. return str_replace('.php', '', basename($file));
  208. }, $files);
  209. // Once we have all of the formatted file names we will sort them and since
  210. // they all start with a timestamp this should give us the migrations in
  211. // the order they were actually created by the application developers.
  212. sort($files);
  213. return $files;
  214. }
  215. /**
  216. * Require in all the migration files in a given path.
  217. *
  218. * @param string $path
  219. * @param array $files
  220. * @return void
  221. */
  222. public function requireFiles($path, array $files)
  223. {
  224. foreach ($files as $file) {
  225. $this->files->requireOnce($path.'/'.$file.'.php');
  226. }
  227. }
  228. /**
  229. * Pretend to run the migrations.
  230. *
  231. * @param object $migration
  232. * @param string $method
  233. * @return void
  234. */
  235. protected function pretendToRun($migration, $method)
  236. {
  237. foreach ($this->getQueries($migration, $method) as $query) {
  238. $name = get_class($migration);
  239. $this->note("<info>{$name}:</info> {$query['query']}");
  240. }
  241. }
  242. /**
  243. * Get all of the queries that would be run for a migration.
  244. *
  245. * @param object $migration
  246. * @param string $method
  247. * @return array
  248. */
  249. protected function getQueries($migration, $method)
  250. {
  251. $connection = $migration->getConnection();
  252. // Now that we have the connections we can resolve it and pretend to run the
  253. // queries against the database returning the array of raw SQL statements
  254. // that would get fired against the database system for this migration.
  255. $db = $this->resolveConnection($connection);
  256. return $db->pretend(function () use ($migration, $method) {
  257. $migration->$method();
  258. });
  259. }
  260. /**
  261. * Resolve a migration instance from a file.
  262. *
  263. * @param string $file
  264. * @return object
  265. */
  266. public function resolve($file)
  267. {
  268. $file = implode('_', array_slice(explode('_', $file), 4));
  269. $class = Str::studly($file);
  270. return new $class;
  271. }
  272. /**
  273. * Raise a note event for the migrator.
  274. *
  275. * @param string $message
  276. * @return void
  277. */
  278. protected function note($message)
  279. {
  280. $this->notes[] = $message;
  281. }
  282. /**
  283. * Get the notes for the last operation.
  284. *
  285. * @return array
  286. */
  287. public function getNotes()
  288. {
  289. return $this->notes;
  290. }
  291. /**
  292. * Resolve the database connection instance.
  293. *
  294. * @param string $connection
  295. * @return \Illuminate\Database\Connection
  296. */
  297. public function resolveConnection($connection)
  298. {
  299. return $this->resolver->connection($connection);
  300. }
  301. /**
  302. * Set the default connection name.
  303. *
  304. * @param string $name
  305. * @return void
  306. */
  307. public function setConnection($name)
  308. {
  309. if (! is_null($name)) {
  310. $this->resolver->setDefaultConnection($name);
  311. }
  312. $this->repository->setSource($name);
  313. $this->connection = $name;
  314. }
  315. /**
  316. * Get the migration repository instance.
  317. *
  318. * @return \Illuminate\Database\Migrations\MigrationRepositoryInterface
  319. */
  320. public function getRepository()
  321. {
  322. return $this->repository;
  323. }
  324. /**
  325. * Determine if the migration repository exists.
  326. *
  327. * @return bool
  328. */
  329. public function repositoryExists()
  330. {
  331. return $this->repository->repositoryExists();
  332. }
  333. /**
  334. * Get the file system instance.
  335. *
  336. * @return \Illuminate\Filesystem\Filesystem
  337. */
  338. public function getFilesystem()
  339. {
  340. return $this->files;
  341. }
  342. }