PageRenderTime 2ms CodeModel.GetById 71ms app.highlight 121ms RepoModel.GetById 81ms app.codeStats 440ms

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