merged skunkworks into develop.
This commit is contained in:
83
laravel/cli/tasks/migrate/database.php
Normal file
83
laravel/cli/tasks/migrate/database.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php namespace Laravel\CLI\Tasks\Migrate;
|
||||
|
||||
use Laravel\Database as DB;
|
||||
|
||||
class Database {
|
||||
|
||||
/**
|
||||
* Log a migration in the migration table.
|
||||
*
|
||||
* @param string $bundle
|
||||
* @param string $name
|
||||
* @param int $batch
|
||||
* @return void
|
||||
*/
|
||||
public function log($bundle, $name, $batch)
|
||||
{
|
||||
$this->table()->insert(compact('bundle', 'name', 'batch'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a row from the migration table.
|
||||
*
|
||||
* @param string $bundle
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function delete($bundle, $name)
|
||||
{
|
||||
$this->table()->where_bundle_and_name($bundle, $name)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of the last batch of migrations.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function last()
|
||||
{
|
||||
$table = $this->table();
|
||||
|
||||
// First we need to grab the last batch ID from the migration table,
|
||||
// as this will allow us to grab the lastest batch of migrations
|
||||
// that need to be run for a rollback command.
|
||||
$id = $this->batch();
|
||||
|
||||
// Once we have the batch ID, we will pull all of the rows for that
|
||||
// batch. Then we can feed the results into the resolve method to
|
||||
// get the migration instances for the command.
|
||||
return $table->where_batch($id)->order_by('name', 'desc')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the migrations that have run for a bundle.
|
||||
*
|
||||
* @param string $bundle
|
||||
* @return array
|
||||
*/
|
||||
public function ran($bundle)
|
||||
{
|
||||
return $this->table()->where_bundle($bundle)->lists('name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum batch ID from the migration table.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function batch()
|
||||
{
|
||||
return $this->table()->max('batch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a database query instance for the migration table.
|
||||
*
|
||||
* @return Query
|
||||
*/
|
||||
protected function table()
|
||||
{
|
||||
return DB::connection()->table('laravel_migrations');
|
||||
}
|
||||
|
||||
}
|
||||
235
laravel/cli/tasks/migrate/migrator.php
Normal file
235
laravel/cli/tasks/migrate/migrator.php
Normal file
@@ -0,0 +1,235 @@
|
||||
<?php namespace Laravel\CLI\Tasks\Migrate;
|
||||
|
||||
use Laravel\Str;
|
||||
use Laravel\File;
|
||||
use Laravel\Bundle;
|
||||
use Laravel\CLI\Tasks\Task;
|
||||
use Laravel\Database\Schema;
|
||||
|
||||
class Migrator extends Task {
|
||||
|
||||
/**
|
||||
* The migration resolver instance.
|
||||
*
|
||||
* @var Resolver
|
||||
*/
|
||||
protected $resolver;
|
||||
|
||||
/**
|
||||
* The migration database instance.
|
||||
*
|
||||
* @var Database
|
||||
*/
|
||||
protected $database;
|
||||
|
||||
/**
|
||||
* Create a new instance of the Migrator CLI task.
|
||||
*
|
||||
* @param Resolver $resolver
|
||||
* @param Database $database
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Resolver $resolver, Database $database)
|
||||
{
|
||||
$this->resolver = $resolver;
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a database migration command.
|
||||
*
|
||||
* @param array $arguments
|
||||
* @return void
|
||||
*/
|
||||
public function run($arguments = array())
|
||||
{
|
||||
// If no arguments were passed to the task, we will just migrate
|
||||
// to the latest version across all bundles. Otherwise, we will
|
||||
// parse the arguments to determine the bundle for which the
|
||||
// database migrations should be run.
|
||||
if (count($arguments) == 0)
|
||||
{
|
||||
$this->migrate();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->migrate(array_get($arguments, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the outstanding migrations for a given bundle.
|
||||
*
|
||||
* @param string $bundle
|
||||
* @param int $version
|
||||
* @return void
|
||||
*/
|
||||
public function migrate($bundle = null, $version = null)
|
||||
{
|
||||
$migrations = $this->resolver->outstanding($bundle);
|
||||
|
||||
if (count($migrations) == 0)
|
||||
{
|
||||
echo "No outstanding migrations.";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to grab the latest batch ID and increment it
|
||||
// by one. This allows us to group the migrations such
|
||||
// that we can easily determine which migrations need
|
||||
// to be rolled back for a given command.
|
||||
$batch = $this->database->batch() + 1;
|
||||
|
||||
foreach ($migrations as $migration)
|
||||
{
|
||||
$migration['migration']->up();
|
||||
|
||||
echo 'Migrated: '.$this->display($migration).PHP_EOL;
|
||||
|
||||
// After running a migration, we log its execution in the
|
||||
// migration table so that we can easily determine which
|
||||
// migrations we will need to reverse on a rollback.
|
||||
$this->database->log($migration['bundle'], $migration['name'], $batch);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the latest migration command.
|
||||
*
|
||||
* @param array $arguments
|
||||
* @return bool
|
||||
*/
|
||||
public function rollback($arguments = array())
|
||||
{
|
||||
$migrations = $this->resolver->last();
|
||||
|
||||
if (count($migrations) == 0)
|
||||
{
|
||||
echo "Nothing to rollback.";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// The "last" method on the resolver returns an array of migrations,
|
||||
// along with their bundles and names. We will iterate through each
|
||||
// migration and run the "down" method, removing them from the
|
||||
// database as we go.
|
||||
foreach ($migrations as $migration)
|
||||
{
|
||||
$migration['migration']->down();
|
||||
|
||||
echo 'Rolled back: '.$this->display($migration).PHP_EOL;
|
||||
|
||||
// By only removing the migration after it has successfully rolled back,
|
||||
// we can re-run the rollback command in the event of any errors with
|
||||
// the migration. When we re-run, only the migrations that have not
|
||||
// been rolled-back for the batch will still be in the database.
|
||||
$this->database->delete($migration['bundle'], $migration['name']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback all of the executed migrations.
|
||||
*
|
||||
* @param array $arguments
|
||||
* @return void
|
||||
*/
|
||||
public function reset($arguments = array())
|
||||
{
|
||||
while ($this->rollback()) {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the database tables used by the migration system.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function install()
|
||||
{
|
||||
Schema::table('laravel_migrations', function($table)
|
||||
{
|
||||
$table->create();
|
||||
|
||||
// Migrations can be run for a specific bundle, so we'll use
|
||||
// the bundle name and string migration name as an unique ID
|
||||
// for the migrations, allowing us to easily identify which
|
||||
// migrations have been run for each bundle.
|
||||
$table->string('bundle');
|
||||
|
||||
$table->string('name');
|
||||
|
||||
// When running a migration command, we will store a batch
|
||||
// ID with each of the rows on the table. This will allow
|
||||
// us to grab all of the migrations that were run for the
|
||||
// last command when performing rollbacks.
|
||||
$table->integer('batch');
|
||||
|
||||
$table->primary(array('bundle', 'name'));
|
||||
});
|
||||
|
||||
echo "Migration table created successfully.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new migration file.
|
||||
*
|
||||
* @param array $arguments
|
||||
* @return void
|
||||
*/
|
||||
public function make($arguments = array())
|
||||
{
|
||||
if (count($arguments) == 0)
|
||||
{
|
||||
throw new \Exception("I need to know what to name the migration.");
|
||||
}
|
||||
|
||||
list($bundle, $migration) = Bundle::parse($arguments[0]);
|
||||
|
||||
// The migration path is prefixed with the UNIX timestamp, which
|
||||
// is a better way of ordering migrations than a simple integer
|
||||
// incrementation, since developers may start working on the
|
||||
// next migration at the same time unknowingly.
|
||||
$date = date('Y_m_d').'_'.time();
|
||||
|
||||
$path = Bundle::path($bundle).'migrations/'.$date.'_'.$migration.EXT;
|
||||
|
||||
File::put($path, $this->stub($bundle, $migration));
|
||||
|
||||
echo "Great! New migration created!";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stub migration with the proper class name.
|
||||
*
|
||||
* @param string $bundle
|
||||
* @param string $migration
|
||||
* @return string
|
||||
*/
|
||||
protected function stub($bundle, $migration)
|
||||
{
|
||||
$stub = File::get(SYS_PATH.'cli/tasks/migrate/stub'.EXT);
|
||||
|
||||
// The class name is formatted simialrly to tasks and controllers,
|
||||
// where the bundle name is prefixed to the class if it is not in
|
||||
// the default bundle. However, unlike tasks, there is nothing
|
||||
// appended to the class name since they're already unique.
|
||||
$class = Bundle::class_prefix($bundle).Str::classify($migration);
|
||||
|
||||
return str_replace('{{class}}', $class, $stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the migration bundle and name for display.
|
||||
*
|
||||
* @param array $migration
|
||||
* @return string
|
||||
*/
|
||||
protected function display($migration)
|
||||
{
|
||||
return $migration['bundle'].'/'.$migration['name'];
|
||||
}
|
||||
|
||||
}
|
||||
159
laravel/cli/tasks/migrate/resolver.php
Normal file
159
laravel/cli/tasks/migrate/resolver.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?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.
|
||||
*
|
||||
* @param Database $datbase
|
||||
* @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))
|
||||
{
|
||||
$bundles = array_merge(Bundle::all(), array('application'));
|
||||
}
|
||||
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);
|
||||
|
||||
$class = $prefix.substr($name, 22);
|
||||
|
||||
$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');
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
25
laravel/cli/tasks/migrate/stub.php
Normal file
25
laravel/cli/tasks/migrate/stub.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
class {{class}} {
|
||||
|
||||
/**
|
||||
* Make changes to the database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert the changes to the database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user