PageRenderTime 49ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

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

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