resolver.php 4.46 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<?php namespace Laravel\CLI\Tasks\Migrate;

use Laravel\Bundle;

class Resolver {

	/**
	 * The migration database instance.
	 *
	 * @var Database
	 */
	protected $database;

	/**
	 * Create a new instance of the migration resolver.
	 *
Phill Sparks committed
17
	 * @param  Database  $database
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
	 * @return void
	 */
	public function __construct(Database $database)
	{
		$this->database = $database;
	}

	/**
	 * Resolve all of the outstanding migrations for a bundle.
	 *
	 * @param  string  $bundle
	 * @return array
	 */
	public function outstanding($bundle = null)
	{
		$migrations = array();

		// If no bundle was given to the command, we'll grab every bundle for
		// the application, including the "application" bundle, which is not
		// returned by "all" method on the Bundle class.
		if (is_null($bundle))
		{
Taylor Otwell committed
40
			$bundles = array_merge(Bundle::names(), array('application'));
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
		}
		else
		{
			$bundles = array($bundle);
		}

		foreach ($bundles as $bundle)
		{
			// First we need to grab all of the migrations that have already
			// run for this bundle, as well as all of the migration files
			// for the bundle. Once we have these, we can determine which
			// migrations are still outstanding.
			$ran = $this->database->ran($bundle);

			$files = $this->migrations($bundle);

			// To find outstanding migrations, we will simply iterate over
			// the migration files and add the files that do not exist in
			// the array of ran migrations to the outstanding array.
			foreach ($files as $key => $name)
			{
				if ( ! in_array($name, $ran))
				{
					$migrations[] = compact('bundle', 'name');
				}
			}
		}

		return $this->resolve($migrations);
	}

	/**
	 * Resolve an array of the last batch of migrations.
	 *
	 * @return array
	 */
	public function last()
	{
		return $this->resolve($this->database->last());
	}

	/**
	 * Resolve an array of migration instances.
	 *
	 * @param  array  $migrations
	 * @return array
	 */
	protected function resolve($migrations)
	{
		$instances = array();

		foreach ($migrations as $migration)
		{
			$migration = (array) $migration;

			// The migration array contains the bundle name, so we will get the
			// path to the bundle's migrations and resolve an instance of the
			// migration using the name.
			$bundle = $migration['bundle'];

			$path = Bundle::path($bundle).'migrations/';

			// Migrations are not resolved through the auto-loader, so we will
			// manually instantiate the migration class instances for each of
			// the migration names we're given.
			$name = $migration['name'];

			require_once $path.$name.EXT;

			// Since the migration name will begin with the numeric ID, we'll
			// slice off the ID so we are left with the migration class name.
			// The IDs are for sorting when resolving outstanding migrations.
			//
			// Migrations that exist within bundles other than the default
			// will be prefixed with the bundle name to avoid any possible
			// naming collisions with other bundle's migrations.
			$prefix = Bundle::class_prefix($bundle);

119
			$class = $prefix.\Laravel\Str::classify(substr($name, 18));
120 121 122 123 124 125 126 127 128 129

			$migration = new $class;

			// When adding to the array of instances, we will actually
			// add the migration instance, the bundle, and the name.
			// This allows the migrator to log the bundle and name
			// when the migration is executed.
			$instances[] = compact('bundle', 'name', 'migration');
		}

130
		// At this point the migrations are only sorted within their
Taylor Otwell committed
131
		// bundles so we need to resort them by name to ensure they
132
		// are in a consistent order.
133
		usort($instances, function($a, $b)
134 135 136 137
		{
			return strcmp($a['name'], $b['name']);
		});

138 139 140 141 142 143 144 145 146 147 148 149 150
		return $instances;
	}

	/**
	 * Grab all of the migration filenames for a bundle.
	 *
	 * @param  string  $bundle
	 * @return array
	 */
	protected function migrations($bundle)
	{
		$files = glob(Bundle::path($bundle).'migrations/*_*'.EXT);

151 152 153 154 155 156 157 158
		// When open_basedir is enabled, glob will return false on an
		// empty directory, so we will return an empty array in this
		// case so the application doesn't bomb out.
		if ($files === false)
		{
			return array();
		}

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
		// Once we have the array of files in the migration directory,
		// we'll take the basename of the file and remove the PHP file
		// extension, which isn't needed.
		foreach ($files as &$file)
		{
			$file = str_replace(EXT, '', basename($file));
		}

		// We'll also sort the files so that the earlier migrations
		// will be at the front of the array and will be resolved
		// first by this class' resolve method.
		sort($files);

		return $files;
	}

}