merged skunkworks into develop.
This commit is contained in:
62
laravel/cli/artisan.php
Normal file
62
laravel/cli/artisan.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php namespace Laravel\CLI; defined('APP_PATH') or die('No direct script access.');
|
||||
|
||||
use Laravel\IoC;
|
||||
use Laravel\Bundle;
|
||||
use Laravel\Database as DB;
|
||||
|
||||
/**
|
||||
* Fire up the default bundle. This will ensure any dependencies that
|
||||
* need to be registered in the IoC container are registered and that
|
||||
* the auto-loader mappings are registered.
|
||||
*/
|
||||
Bundle::start(DEFAULT_BUNDLE);
|
||||
|
||||
/**
|
||||
* We will register all of the Laravel provided tasks inside the IoC
|
||||
* container so they can be resolved by the task class. This allows
|
||||
* us to seamlessly add tasks to the CLI so that the Task class
|
||||
* doesn't have to worry about how to resolve core tasks.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The bundle task is responsible for the installation of bundles
|
||||
* and their dependencies. It utilizes the bundles API to get the
|
||||
* meta-data for the available bundles.
|
||||
*/
|
||||
IoC::register('task: bundle', function()
|
||||
{
|
||||
return new Tasks\Bundle\Bundler;
|
||||
});
|
||||
|
||||
/**
|
||||
* The migrate task is responsible for running database migrations
|
||||
* as well as migration rollbacks. We will also create an instance
|
||||
* of the migration resolver and database classes, which are used
|
||||
* to perform various support functions for the migrator.
|
||||
*/
|
||||
IoC::register('task: migrate', function()
|
||||
{
|
||||
$database = new Tasks\Migrate\Database;
|
||||
|
||||
$resolver = new Tasks\Migrate\Resolver($database);
|
||||
|
||||
return new Tasks\Migrate\Migrator($resolver, $database);
|
||||
});
|
||||
|
||||
/**
|
||||
* We will wrap the command execution in a try / catch block and
|
||||
* simply write out any exception messages we receive to the CLI
|
||||
* for the developer. Note that this only writes out messages
|
||||
* for the CLI exceptions. All others will be not be caught
|
||||
* and will be totally dumped out to the CLI.
|
||||
*/
|
||||
try
|
||||
{
|
||||
Command::run(array_slice($_SERVER['argv'], 1));
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
echo $e->getMessage();
|
||||
}
|
||||
|
||||
echo PHP_EOL;
|
||||
109
laravel/cli/command.php
Normal file
109
laravel/cli/command.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php namespace Laravel\CLI;
|
||||
|
||||
use Laravel\IoC;
|
||||
use Laravel\Str;
|
||||
use Laravel\Bundle;
|
||||
|
||||
class Command {
|
||||
|
||||
/**
|
||||
* Run a CLI task with the given arguments.
|
||||
*
|
||||
* @param array $arguments
|
||||
* @return void
|
||||
*/
|
||||
public static function run($arguments = array())
|
||||
{
|
||||
if ( ! isset($arguments[0]))
|
||||
{
|
||||
throw new \Exception("Whoops! You forgot to provide the task name.");
|
||||
}
|
||||
|
||||
list($bundle, $task, $method) = static::parse($arguments[0]);
|
||||
|
||||
// If the task exists within a bundle, we will start the bundle so that
|
||||
// any dependencies can be registered in the application IoC container.
|
||||
// If the task is registered in the container, it will be resolved
|
||||
// via the container instead of by this class.
|
||||
if (Bundle::exists($bundle)) Bundle::start($bundle);
|
||||
|
||||
if (is_null($task = static::resolve($bundle, $task)))
|
||||
{
|
||||
throw new \Exception("Sorry, I can't find that task.");
|
||||
}
|
||||
|
||||
$task->$method(array_slice($arguments, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the task name to extract the bundle, task, and method.
|
||||
*
|
||||
* @param string $task
|
||||
* @return array
|
||||
*/
|
||||
protected static function parse($task)
|
||||
{
|
||||
list($bundle, $task) = Bundle::parse($task);
|
||||
|
||||
// Extract the task method from the task string. Methods are called
|
||||
// on tasks by separating the task and method with a single colon.
|
||||
// If no task is specified, "run" is used as the default method.
|
||||
if (str_contains($task, ':'))
|
||||
{
|
||||
list($task, $method) = explode(':', $task);
|
||||
}
|
||||
else
|
||||
{
|
||||
$method = 'run';
|
||||
}
|
||||
|
||||
return array($bundle, $task, $method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve an instance of the given task name.
|
||||
*
|
||||
* @param string $bundle
|
||||
* @param string $task
|
||||
* @return object
|
||||
*/
|
||||
public static function resolve($bundle, $task)
|
||||
{
|
||||
$identifier = Bundle::identifier($bundle, $task);
|
||||
|
||||
// First we'll check to see if the task has been registered in
|
||||
// the application IoC container. This allows dependencies to
|
||||
// be injected into tasks for more testability.
|
||||
if (IoC::registered("task: {$identifier}"))
|
||||
{
|
||||
return IoC::resolve("task: {$identifier}");
|
||||
}
|
||||
|
||||
// If the task file exists, we'll format the bundle and task
|
||||
// name into a task class name and resolve an instance of
|
||||
// the so that the requested method may be executed.
|
||||
if (file_exists($path = Bundle::path($bundle).'tasks/'.$task.EXT))
|
||||
{
|
||||
require $path;
|
||||
|
||||
$task = static::format($bundle, $task);
|
||||
|
||||
return new $task;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a bundle and task into a task class name.
|
||||
*
|
||||
* @param string $bundle
|
||||
* @param string $task
|
||||
* @return string
|
||||
*/
|
||||
protected static function format($bundle, $task)
|
||||
{
|
||||
$prefix = Bundle::class_prefix($bundle);
|
||||
|
||||
return '\\'.$prefix.Str::clasify($task).'_Task';
|
||||
}
|
||||
|
||||
}
|
||||
127
laravel/cli/tasks/bundle/bundler.php
Normal file
127
laravel/cli/tasks/bundle/bundler.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php namespace Laravel\CLI\Tasks\Bundle; defined('APP_PATH') or die('No direct script access.');
|
||||
|
||||
use Laravel\IoC;
|
||||
use Laravel\Bundle;
|
||||
use Laravel\CLI\Tasks\Task;
|
||||
|
||||
IoC::singleton('bundle.repository', function()
|
||||
{
|
||||
return new Repository;
|
||||
});
|
||||
|
||||
IoC::singleton('bundle.publisher', function()
|
||||
{
|
||||
return new Publisher;
|
||||
});
|
||||
|
||||
IoC::singleton('bundle.provider: github', function()
|
||||
{
|
||||
return new Providers\Github;
|
||||
});
|
||||
|
||||
class Bundler extends Task {
|
||||
|
||||
/**
|
||||
* Install the given bundles into the application.
|
||||
*
|
||||
* @param array $bundles
|
||||
* @return void
|
||||
*/
|
||||
public function install($bundles)
|
||||
{
|
||||
$publisher = IoC::resolve('bundle.publisher');
|
||||
|
||||
foreach ($this->get($bundles) as $bundle)
|
||||
{
|
||||
if (is_dir(BUNDLE_PATH.$bundle['name']))
|
||||
{
|
||||
echo "Bundle {$bundle['name']} is already installed.";
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Once we have the bundle information, we can resolve an instance
|
||||
// of a provider and install the bundle into the application and
|
||||
// all of its registered dependencies as well.
|
||||
//
|
||||
// Each bundle provider implements the Provider interface and
|
||||
// is repsonsible for retrieving the bundle source from its
|
||||
// hosting party and installing it into the application.
|
||||
$provider = "bundle.provider: {$bundle['provider']}";
|
||||
|
||||
IoC::resolve($provider)->install($bundle);
|
||||
|
||||
$publisher->publish($bundle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish bundle assets to the public directory.
|
||||
*
|
||||
* @param array $bundles
|
||||
* @return void
|
||||
*/
|
||||
public function publish($bundles)
|
||||
{
|
||||
// If no bundles are passed to the command, we'll just gather all
|
||||
// of the installed bundle names and publish the assets for each
|
||||
// for each one of the bundles to the public directory.
|
||||
if (count($bundles) == 0) $bundles = Bundle::all();
|
||||
|
||||
$publisher = IoC::resolve('bundle.publisher');
|
||||
|
||||
foreach ($bundles as $bundle)
|
||||
{
|
||||
$publisher->publish($bundle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gather all of the bundles from the bundle repository.
|
||||
*
|
||||
* @param array $bundles
|
||||
* @return array
|
||||
*/
|
||||
protected function get($bundles)
|
||||
{
|
||||
$responses = array();
|
||||
|
||||
$repository = IoC::resolve('bundle.repository');
|
||||
|
||||
// This method is primarily responsible for gathering the data
|
||||
// for all bundles that need to be installed. This allows us
|
||||
// to verify the existence of the bundle before even getting
|
||||
// started on the actual installation process.
|
||||
foreach ($bundles as $bundle)
|
||||
{
|
||||
// First we'll call the bundle repository to gather the bundle data
|
||||
// array, which contains all of the information needed to install
|
||||
// the bundle into the application. We'll verify that the bundle
|
||||
// exists and the API is responding for each bundle.
|
||||
$response = $repository->get($bundle);
|
||||
|
||||
if ( ! $response)
|
||||
{
|
||||
throw new \Exception("The bundle API is not responding.");
|
||||
}
|
||||
|
||||
if ($response['status'] == 'not-found')
|
||||
{
|
||||
throw new \Exception("There is not a bundle named [$bundle].");
|
||||
}
|
||||
|
||||
// If the bundle was retrieved successfully, we will add it to
|
||||
// our array of bundles, as well as merge all of the bundle's
|
||||
// dependencies into the array of responses so that they are
|
||||
// installed along with the consuming dependency.
|
||||
$bundle = $response['bundle'];
|
||||
|
||||
$responses[] = $bundle;
|
||||
|
||||
$responses = array_merge($responses, $this->get($bundle['dependencies']));
|
||||
}
|
||||
|
||||
return $responses;
|
||||
}
|
||||
|
||||
}
|
||||
27
laravel/cli/tasks/bundle/providers/github.php
Normal file
27
laravel/cli/tasks/bundle/providers/github.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php namespace Laravel\CLI\Tasks\Bundle\Providers;
|
||||
|
||||
class Github implements Provider {
|
||||
|
||||
/**
|
||||
* Install the given bundle into the application.
|
||||
*
|
||||
* @param string $bundle
|
||||
* @return void
|
||||
*/
|
||||
public function install($bundle)
|
||||
{
|
||||
$repository = "git://github.com/{$bundle['location']}.git";
|
||||
|
||||
// We need to just extract the basename of the bundle path when
|
||||
// adding the submodule. Of course, we can't add a submodule to
|
||||
// a location outside of the Git repository, so we don't need
|
||||
// the full bundle path. We'll just take the basename in case
|
||||
// the bundle directory has been renamed.
|
||||
$path = basename(BUNDLE_PATH).'/';
|
||||
|
||||
passthru('git submodule add '.$repository.' '.$path.$bundle['name']);
|
||||
|
||||
passthru('git submodule update');
|
||||
}
|
||||
|
||||
}
|
||||
13
laravel/cli/tasks/bundle/providers/provider.php
Normal file
13
laravel/cli/tasks/bundle/providers/provider.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php namespace Laravel\CLI\Tasks\Bundle\Providers;
|
||||
|
||||
interface Provider {
|
||||
|
||||
/**
|
||||
* Install the given bundle into the application.
|
||||
*
|
||||
* @param string $bundle
|
||||
* @return void
|
||||
*/
|
||||
public function install($bundle);
|
||||
|
||||
}
|
||||
90
laravel/cli/tasks/bundle/publisher.php
Normal file
90
laravel/cli/tasks/bundle/publisher.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php namespace Laravel\CLI\Tasks\Bundle;
|
||||
|
||||
use Laravel\Bundle;
|
||||
use FilesystemIterator;
|
||||
|
||||
class Publisher {
|
||||
|
||||
/**
|
||||
* Publish a bundle's assets to the public directory.
|
||||
*
|
||||
* @param string $bundle
|
||||
* @return void
|
||||
*/
|
||||
public function publish($bundle)
|
||||
{
|
||||
$this->move($bundle, $this->from($bundle), $this->to($bundle));
|
||||
|
||||
echo "Assets published for bundle [$bundle].".PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the contents of a bundle's assets to the public folder.
|
||||
*
|
||||
* @param string $bundle
|
||||
* @param string $source
|
||||
* @param string $destination
|
||||
* @return void
|
||||
*/
|
||||
protected function move($bundle, $source, $destination)
|
||||
{
|
||||
if ( ! is_dir($source)) return;
|
||||
|
||||
// First we need to create the destination directory if it doesn't
|
||||
// already exists. This directory hosts all of the assets we copy
|
||||
// from the installed bundle's source directory.
|
||||
if ( ! is_dir($destination))
|
||||
{
|
||||
mkdir($destination);
|
||||
}
|
||||
|
||||
$items = new FilesystemIterator($source, FilesystemIterator::SKIP_DOTS);
|
||||
|
||||
foreach ($items as $item)
|
||||
{
|
||||
// If the file system item is a directory, we will recurse the
|
||||
// function, passing in the item directory. To get the proper
|
||||
// destination path, we'll replace the root bundle asset
|
||||
// directory with the root public asset directory.
|
||||
if ($item->isDir())
|
||||
{
|
||||
$path = $item->getRealPath();
|
||||
|
||||
$recurse = str_replace($this->from($bundle), $this->to($bundle), $path);
|
||||
|
||||
$this->move($bundle, $path, $recurse);
|
||||
}
|
||||
// If the file system item is an actual file, we can copy the
|
||||
// file from the bundle asset directory to the public asset
|
||||
// directory. The "copy" method will overwrite any existing
|
||||
// files with the same name.
|
||||
else
|
||||
{
|
||||
copy($item->getRealPath(), $destination.DS.$item->getBasename());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "to" location of the bundle's assets.
|
||||
*
|
||||
* @param string $bundle
|
||||
* @return string
|
||||
*/
|
||||
protected function to($bundle)
|
||||
{
|
||||
return PUBLIC_PATH.'bundles'.DS.$bundle.DS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "from" location of the bundle's assets.
|
||||
*
|
||||
* @param string $bundle
|
||||
* @return string
|
||||
*/
|
||||
protected function from($bundle)
|
||||
{
|
||||
return Bundle::path($bundle).'public';
|
||||
}
|
||||
|
||||
}
|
||||
29
laravel/cli/tasks/bundle/repository.php
Normal file
29
laravel/cli/tasks/bundle/repository.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php namespace Laravel\CLI\Tasks\Bundle;
|
||||
|
||||
class Repository {
|
||||
|
||||
/**
|
||||
* The root of the Laravel bundle API.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $api = 'http://bundles.laravel.com/api/';
|
||||
|
||||
/**
|
||||
* Get the decoded JSON information for a bundle.
|
||||
*
|
||||
* @param string|int $bundle
|
||||
* @return array
|
||||
*/
|
||||
public function get($bundle)
|
||||
{
|
||||
// The Bundle API will return a JSON string that we can decode and
|
||||
// pass back to the consumer. The decoded array will contain info
|
||||
// regarding the bundle's provider and location, as well as all
|
||||
// of the bundle's dependencies.
|
||||
$bundle = @file_get_contents($this->api.$bundle);
|
||||
|
||||
return json_decode($bundle, true);
|
||||
}
|
||||
|
||||
}
|
||||
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()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
}
|
||||
3
laravel/cli/tasks/task.php
Normal file
3
laravel/cli/tasks/task.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php namespace Laravel\CLI\Tasks;
|
||||
|
||||
abstract class Task {}
|
||||
Reference in New Issue
Block a user