/vendor/illuminate/database/Illuminate/Database/Migrations/Migrator.php

https://gitlab.com/supriyanto-edodoe22/manpro · PHP · 380 lines · 148 code · 59 blank · 173 comment · 8 complexity · 2609c0774ab22afbfcedf05d67b17442 MD5 · raw file

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