Skip to content

Instantly share code, notes, and snippets.

@nerdsrescueme
Created May 19, 2011 14:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nerdsrescueme/9b579608422e7442e3d9 to your computer and use it in GitHub Desktop.
Save nerdsrescueme/9b579608422e7442e3d9 to your computer and use it in GitHub Desktop.
Migrations
<?php
private static function _fieldify($field = array(), $include_name = true)
{
if ($include_name)
{
$name = array_shift($field);
}
$field_opts = array();
foreach($field as $option => $val)
{
if($val === true)
{
$field_opts[] = "'$option' => true";
}
else
{
if(is_int($val))
{
$field_opts[] = "'$option' => $val";
}
else
{
$field_opts[] = "'$option' => '$val'";
}
}
}
$field_opts = implode(', ', $field_opts);
if ($include_name)
{
return "'$name' => array({$field_opts})";
}
return "array({$field_opts})";
}
// create_{tablename}
public static function create($subjects, $fields)
{
$field_str = '';
foreach($fields as $field)
{
$field_str .= "\t\t\t" . static::_fieldify($field) . PHP_EOL;
}
// ID Field
$field_str = "\t\t\t'id' => array('constraint' => 11, 'type' => 'int', 'auto_increment' => true),".PHP_EOL . $field_str;
$up = <<<UP
\DBUtil::create_table('{$subjects[1]}', array(
$field_str
), array('id'));
UP;
$down = <<<DOWN
\DBUtil::drop_table('{$subjects[1]}');
DOWN;
return array($up, $down);
}
// add_{thing}_to_{tablename}
public static function add($subjects, $fields)
{
$up, $down = '';
// Adds multiple if given.
foreach ($fields as $field)
{
$name = array_shift($field);
$opts = static::_fieldify($field, false);
$up .= "\t\t\\DBUtil::add_column('{$subjects[1]}', '{$name}', '{$opts}')" . PHP_EOL;
$down .= "\t\t\\DBUtil::remove_column('{$subjects[1]}', '{$name}')" . PHP_EOL;
}
return array($up, $down);
}
// rename_{fieldname}_to_{newfieldname}_on_{table}
public static function rename_field($subjects, $fields)
{
return array(
"\t\t" . \DBUtil::rename_column('{$subjects[2]}', '{$subjects[0]}', '{$subjects[1]}'),
"\t\t" . \DBUtil::rename_column('{$subjects[2]}', '{$subjects[1]}', '{$subjects[0]}'),
);
}
<?php
public function add_column($table, $name, $options = array())
{
$sql = 'ALTER TABLE ' . DB::quote_identifier(DB::table_prefix($table)) . ' '
. 'ADD COLUMN (' . DB::quote_identifier($name) . ' '
. static::process_fields(array($options)) . ')';
return DB::query($sql, \DB::UPDATE)->execute();
}
public function remove_column($table, $name)
{
$sql = 'ALTER TABLE ' . DB::quote_identifier(DB::table_prefix($table) . ' '
. 'DROP COLUMN ' . DB::quote_identifier($name);
return DB::query($sql, \DB::UPDATE)->execute();
}
public function rename_column($table, $old_name, $new_name)
{
$sql = 'ALTER TABLE ' . DB::quote_identifier(DB::table_prefix($table) . ' '
. 'CHANGE COLUMN ' . DB::quote_identifier($old_name) . ' '
. DB::quote_identifier($new_name);
return DB::query($sql, \DB::UPDATE)->execute();
}
<?php
public static function migration($args, $build = true)
{
// Get the migration name
$migration_name = strtolower(str_replace('-', '_', array_shift($args)));
// Check if a migration with this name already exists
if (count($duplicates = glob(APPPATH."migrations/*_{$migration_name}*")) > 0)
{
// Don't override a file
if (\Cli::option('s', \Cli::option('skip')) === true)
{
return;
}
// Tear up the file path and name to get the last duplicate
$file_name = pathinfo(end($duplicates), PATHINFO_FILENAME);
// Override the (most recent) migration with the same name by using its number
if (\Cli::option('f', \Cli::option('force')) === true)
{
list($number) = explode('_', $file_name);
}
// Name clashes but this is done by hand. Assume they know what they're doing and just increment the file
elseif (static::$scaffolding === false)
{
// Increment the name of this
$migration_name = \Str::increment(substr($file_name, 4), 2);
}
}
// See if the action exists
$methods = get_class_methods(__NAMESPACE__ . '\Generate_Migration_Actions');
// For empty migrations that dont have actions
$migration = array('', '');
// Loop through the actions and act on a matching action appropriately
foreach ($methods as $method_name)
{
// If the miration name starts with the name of the action method
if (substr($migration_name, 0, strlen($method_name)) === $method_name)
{
/**
* Create an array of the subject the migration is about
*
* - In a migration named 'create_users' the subject is 'users' since thats what we want to create
* So it would be the second object in the array
* array(false, 'users')
*
* - In a migration named 'add_name_to_users' the object is 'name' and the subject is 'users'.
* So again 'users' would be the second object, but 'name' would be the first
* array('name', 'users')
*
*/
$subjects = array(false, false);
$matches = explode('_', str_replace($method_name . '_', '', $migration_name));
// create_{table}
if (count($matches) == 1)
{
$subjects = array(false, $matches[0]);
}
// add_{field}_to_{table}
else if (count($matches) == 3 && $matches[1] == 'to')
{
$subjects = array($matches[0], $matches[2]);
}
// rename_table_{tablename}_to_{newtablename}
else if (count($matches) == 5 && $matches[1] == 'rename' && $matches[2] == 'table')
{
$subjects = array($matches[3], $matches[5]);
}
// rename_{tablename}_to_{newtablename}_on_{table}
else if (count($matches) == 6 && $matches[1] == 'rename' && $matches[3] == 'to')
{
$subjects = array($matches[2], $matches[4], $matches[6]);
}
// create_{table} (with underscores in table name)
else if (count($matches) !== 0)
{
$subjects = array(false, implode('_', $matches));
}
// There is no subject here so just carry on with a normal empty migration
else
{
break;
}
// We always pass in fields to a migration, so lets sort them out here.
$fields = array();
foreach ($args as $field)
{
$field_array = array();
// Each paramater for a field is seperated by the : character
$parts = explode(":", $field);
// We must have the 'name:type' if nothing else!
if (count($parts) >= 2)
{
$field_array['name'] = array_shift($parts);
foreach ($parts as $part_i => $part)
{
preg_match('/([a-z0-9_-]+)(?:\[([a-z0-9]+)\])?/i', $part, $part_matches);
array_shift($part_matches);
if (count($part_matches) < 1)
{
// Move onto the next part, something is wrong here...
continue;
}
$option_name = ''; // This is the name of the option to be passed to the action in a field
$option = $part_matches;
// The first option always has to be the field type
if ($part_i == 0)
{
$option_name = 'type';
$type = $option[0];
if ($type === 'string')
{
$type = 'varchar';
}
else if ($type === 'integer')
{
$type = 'int';
}
if ( ! in_array($type, array('text', 'blob', 'datetime', 'date', 'timestamp', 'time')))
{
if ( ! isset($option[1]) || $option[1] == NULL)
{
if (isset(self::$_default_constraints[$type]))
{
$field_array['constraint'] = self::$_default_constraints[$type];
}
}
else
{
$field_array['constraint'] = (int) $option[1];
}
}
$option = $type;
}
else
{
// This allows you to put any number of :option or :option[val] into your field and these will...
// ... always be passed through to the action making it really easy to add extra options for a field
$option_name = array_shift($option);
if (count($option) > 0)
{
$option = $option[0];
}
else
{
$option = true;
}
}
$field_array[$option_name] = $option;
}
$fields[] = $field_array;
}
else
{
// Invalid field passed in
continue;
}
}
// Call the magic action which returns an array($up, $down) for the migration
$migration = call_user_func(__NAMESPACE__ . "\Generate_Migration_Actions::{$method_name}", $subjects, $fields);
}
}
// Build the migration
list($up, $down)=$migration;
$migration_name = ucfirst(strtolower($migration_name));
$migration = <<<MIGRATION
<?php
namespace Fuel\Migrations;
class {$migration_name} {
public function up()
{
{$up}
}
public function down()
{
{$down}
}
}
MIGRATION;
$number = isset($number) ? $number : static::_find_migration_number();
$filepath = APPPATH . 'migrations/'.$number.'_' . strtolower($migration_name) . '.php';
static::create($filepath, $migration, 'migration');
$build and static::build();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment