PageRenderTime 142ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/vervcreations/projectis.at
PHP | 383 lines | 152 code | 59 blank | 172 comment | 8 complexity | b2c03131a04826bd8f73bc18f1cdf74e MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, BSD-3-Clause
  1. <?php namespace Illuminate\Database\Migrations;
  2. use Closure;
  3. use Illuminate\Events\Dispatcher;
  4. use Illuminate\Database\Connection;
  5. use Illuminate\Filesystem\Filesystem;
  6. use Symfony\Component\Console\Output\OutputInterface;
  7. use Illuminate\Database\ConnectionResolverInterface as Resolver;
  8. class Migrator {
  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
  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 = array();
  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 $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 bool $pretend
  60. * @return void
  61. */
  62. public function run($path, $pretend = false)
  63. {
  64. $this->notes = array();
  65. $this->requireFiles($path, $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 all of the oustanding migrations against the database connection.
  69. $ran = $this->repository->getRan();
  70. $migrations = array_diff($files, $ran);
  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. {
  87. $this->note('<info>Nothing to migrate.</info>');
  88. return;
  89. }
  90. $batch = $this->repository->getNextBatchNumber();
  91. // Once we have the array of migrations, we will spin through them and run the
  92. // migrations "up" so the changes are made to the databases. We'll then log
  93. // that the migration was run so we don't repeat it next time we execute.
  94. foreach ($migrations as $file)
  95. {
  96. $this->runUp($file, $batch, $pretend);
  97. }
  98. }
  99. /**
  100. * Run "up" a migration instance.
  101. *
  102. * @param string $file
  103. * @param int $batch
  104. * @param bool $pretend
  105. * @return void
  106. */
  107. protected function runUp($file, $batch, $pretend)
  108. {
  109. // First we will resolve a "real" instance of the migration class from this
  110. // migration file name. Once we have the instances we can run the actual
  111. // command such as "up" or "down", or we can just simulate the action.
  112. $migration = $this->resolve($file);
  113. if ($pretend)
  114. {
  115. return $this->pretendToRun($migration, 'up');
  116. }
  117. $migration->up();
  118. // Once we have run a migrations class, we will log that it was run in this
  119. // repository so that we don't try to run it next time we do a migration
  120. // in the application. A migration repository keeps the migrate order.
  121. $this->repository->log($file, $batch);
  122. $this->note("<info>Migrated:</info> $file");
  123. }
  124. /**
  125. * Rollback the last migration operation.
  126. *
  127. * @param bool $pretend
  128. * @return int
  129. */
  130. public function rollback($pretend = false)
  131. {
  132. $this->notes = array();
  133. // We want to pull in the last batch of migrations that ran on the previous
  134. // migration operation. We'll then reverse those migrations and run each
  135. // of them "down" to reverse the last migration "operation" which ran.
  136. $migrations = $this->repository->getLast();
  137. if (count($migrations) == 0)
  138. {
  139. $this->note('<info>Nothing to rollback.</info>');
  140. return count($migrations);
  141. }
  142. // We need to reverse these migrations so that they are "downed" in reverse
  143. // to what they run on "up". It lets us backtrack through the migrations
  144. // and properly reverse the entire database schema operation that ran.
  145. foreach ($migrations as $migration)
  146. {
  147. $this->runDown((object) $migration, $pretend);
  148. }
  149. return count($migrations);
  150. }
  151. /**
  152. * Run "down" a migration instance.
  153. *
  154. * @param StdClass $migration
  155. * @param bool $pretend
  156. * @return void
  157. */
  158. protected function runDown($migration, $pretend)
  159. {
  160. $file = $migration->migration;
  161. // First we will get the file name of the migration so we can resolve out an
  162. // instance of the migration. Once we get an instance we can either run a
  163. // pretend execution of the migration or we can run the real migration.
  164. $instance = $this->resolve($file);
  165. if ($pretend)
  166. {
  167. return $this->pretendToRun($instance, 'down');
  168. }
  169. $instance->down();
  170. // Once we have successfully run the migration "down" we will remove it from
  171. // the migration repository so it will be considered to have not been run
  172. // by the application then will be able to fire by any later operation.
  173. $this->repository->delete($migration);
  174. $this->note("<info>Rolled back:</info> $file");
  175. }
  176. /**
  177. * Get all of the migration files in a given path.
  178. *
  179. * @param string $path
  180. * @return array
  181. */
  182. public function getMigrationFiles($path)
  183. {
  184. $files = $this->files->glob($path.'/*_*.php');
  185. // Once we have the array of files in the directory we will just remove the
  186. // extension and take the basename of the file which is all we need when
  187. // finding the migrations that haven't been run against the databases.
  188. if ($files === false) return array();
  189. $files = array_map(function($file)
  190. {
  191. return str_replace('.php', '', basename($file));
  192. }, $files);
  193. // Once we have all of the formatted file names we will sort them and since
  194. // they all start with a timestamp this should give us the migrations in
  195. // the order they were actually created by the application developers.
  196. sort($files);
  197. return $files;
  198. }
  199. /**
  200. * Require in all the migration files in a given path.
  201. *
  202. * @param array $files
  203. * @return void
  204. */
  205. public function requireFiles($path, array $files)
  206. {
  207. foreach ($files as $file) $this->files->requireOnce($path.'/'.$file.'.php');
  208. }
  209. /**
  210. * Pretend to run the migrations.
  211. *
  212. * @param object $migration
  213. * @return void
  214. */
  215. protected function pretendToRun($migration, $method)
  216. {
  217. foreach ($this->getQueries($migration, $method) as $query)
  218. {
  219. $name = get_class($migration);
  220. $this->note("<info>{$name}:</info> {$query['query']}");
  221. }
  222. }
  223. /**
  224. * Get all of the queries that would be run for a migration.
  225. *
  226. * @param object $migration
  227. * @param string $method
  228. * @return array
  229. */
  230. protected function getQueries($migration, $method)
  231. {
  232. $connection = $migration->getConnection();
  233. // Now that we have the connections we can resolve it and pretend to run the
  234. // queries against the database returning the array of raw SQL statements
  235. // that would get fired against the database system for this migration.
  236. $db = $this->resolveConnection($connection);
  237. return $db->pretend(function() use ($migration, $method)
  238. {
  239. $migration->$method();
  240. });
  241. }
  242. /**
  243. * Resolve a migration instance from a file.
  244. *
  245. * @param string $file
  246. * @return object
  247. */
  248. public function resolve($file)
  249. {
  250. $file = implode('_', array_slice(explode('_', $file), 4));
  251. $class = studly_case($file);
  252. return new $class;
  253. }
  254. /**
  255. * Raise a note event for the migrator.
  256. *
  257. * @param string $message
  258. * @return void
  259. */
  260. protected function note($message)
  261. {
  262. $this->notes[] = $message;
  263. }
  264. /**
  265. * Get the notes for the last operation.
  266. *
  267. * @return array
  268. */
  269. public function getNotes()
  270. {
  271. return $this->notes;
  272. }
  273. /**
  274. * Resolve the database connection instance.
  275. *
  276. * @return \Illuminate\Database\Connection
  277. */
  278. public function resolveConnection()
  279. {
  280. return $this->resolver->connection($this->connection);
  281. }
  282. /**
  283. * Set the default connection name.
  284. *
  285. * @param string $name
  286. * @return void
  287. */
  288. public function setConnection($name)
  289. {
  290. if ( ! is_null($name))
  291. {
  292. $this->resolver->setDefaultConnection($name);
  293. }
  294. $this->repository->setSource($name);
  295. $this->connection = $name;
  296. }
  297. /**
  298. * Get the migration repository instance.
  299. *
  300. * @return \Illuminate\Database\Migrations\MigrationRepositoryInterface
  301. */
  302. public function getRepository()
  303. {
  304. return $this->repository;
  305. }
  306. /**
  307. * Determine if the migration repository exists.
  308. *
  309. * @return bool
  310. */
  311. public function repositoryExists()
  312. {
  313. return $this->repository->repositoryExists();
  314. }
  315. /**
  316. * Get the file system instance.
  317. *
  318. * @return \Illuminate\Filesystem
  319. */
  320. public function getFilesystem()
  321. {
  322. return $this->files;
  323. }
  324. }