Skip to content

Commit

Permalink
Merge pull request #116 from HavokInspiration/custom-migrations
Browse files Browse the repository at this point in the history
Implements a new way to deal with primary keys
  • Loading branch information
lorenzo committed Sep 5, 2015
2 parents d3117fe + fecbe5f commit 441ffba
Show file tree
Hide file tree
Showing 31 changed files with 1,502 additions and 84 deletions.
42 changes: 42 additions & 0 deletions src/AbstractMigration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
/**
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Migrations;

use Phinx\Migration\AbstractMigration as BaseAbstractMigration;

class AbstractMigration extends BaseAbstractMigration
{

/**
* Whether the tables created in this migration
* should auto-create an `id` field or not
*
* This option is global for all tables created in the migration file.
* If you set it to false, you have to manually add the primary keys for your
* tables using the Migrations\Table::addPrimaryKey() method
*
* @var bool
*/
public $autoId = true;

/**
* {@inheritdoc}
*/
public function table($tableName, $options = array())
{
if ($this->autoId === false) {
$options['id'] = false;
}

return new Table($tableName, $options, $this->getAdapter());
}
}
11 changes: 11 additions & 0 deletions src/Shell/Task/MigrationSnapshotTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ public function templateData()
}
}
}

$autoId = true;
if (isset($this->params['disable-autoid'])) {
$autoId = !$this->params['disable-autoid'];
}

return [
'plugin' => $this->plugin,
'pluginPath' => $pluginPath,
Expand All @@ -150,6 +156,7 @@ public function templateData()
'tables' => $tables,
'action' => 'create_table',
'name' => $this->BakeTemplate->viewVars['name'],
'autoId' => $autoId
];
}

Expand Down Expand Up @@ -271,6 +278,10 @@ public function getOptionParser()
'boolean' => true,
'default' => false,
'help' => 'If require-table is set to true, check also that the table class exists.'
])->addOption('disable-autoid', [
'boolean' => true,
'default' => false,
'help' => 'Disable phinx behavior of automatically adding an id field.'
]);

return $parser;
Expand Down
7 changes: 7 additions & 0 deletions src/Shell/Task/MigrationTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/
class MigrationTask extends SimpleMigrationTask
{

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -75,6 +76,11 @@ public function templateData()
$columnParser = new ColumnParser;
$fields = $columnParser->parseFields($arguments);
$indexes = $columnParser->parseIndexes($arguments);
$primaryKey = $columnParser->parsePrimaryKey($arguments);

if (in_array($action[0], ['alter_table', 'add_field']) && !empty($primaryKey)) {
$this->error('Adding a primary key to an already existing table is not supported.');
}

list($action, $table) = $action;
return [
Expand All @@ -86,6 +92,7 @@ public function templateData()
'columns' => [
'fields' => $fields,
'indexes' => $indexes,
'primaryKey' => $primaryKey
],
'name' => $className
];
Expand Down
116 changes: 116 additions & 0 deletions src/Table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php
/**
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Migrations;

use Cake\Collection\Collection;
use Phinx\Db\Adapter\SQLiteAdapter;
use Phinx\Db\Table as BaseTable;

class Table extends BaseTable
{

/**
* Primary key for this table.
* Can either be a string or an array in case of composite
* primary key.
*
* @var string|array
*/
protected $primaryKey;

/**
* Add a primary key to a database table.
*
* @param string|array $columns Table Column(s)
* @return Table
*/
public function addPrimaryKey($columns)
{
$this->primaryKey = $columns;
return $this;
}

/**
* You can pass `autoIncrement` as an option and it will be converted
* to the correct option for phinx to create the column with an
* auto increment attribute
*
* {@inheritdoc}
*/
public function addColumn($columnName, $type = null, $options = [])
{
if (isset($options['autoIncrement']) && $options['autoIncrement'] === true) {
$options['identity'] = true;
unset($options['autoIncrement']);
}

return parent::addColumn($columnName, $type, $options);
}

/**
* {@inheritdoc}
*/
public function create()
{
if ((!isset($this->options['id']) || $this->options['id'] === false) && !empty($this->primaryKey)) {
$this->options['primary_key'] = $this->primaryKey;
$this->filterPrimaryKey();
}

parent::create();
}

/**
* This method is called in case a primary key was defined using the addPrimaryKey() method.
* It currently does something only if using SQLite.
* If a column is an auto-increment key in SQLite, it has to be a primary key and it has to defined
* when defining the column. Phinx takes care of that so we have to make sure columns defined as autoincrement were
* not added with the addPrimaryKey method, otherwise, SQL queries will be wrong.
*
* @return void
*/
protected function filterPrimaryKey()
{
if (!($this->getAdapter() instanceof SQLiteAdapter) || empty($this->options['primary_key'])) {
return;
}

$primaryKey = $this->options['primary_key'];
if (!is_array($primaryKey)) {
$primaryKey = [$primaryKey];
}
$primaryKey = array_flip($primaryKey);

$columnsCollection = new Collection($this->columns);
$primaryKeyColumns = $columnsCollection->filter(function ($columnDef, $key) use ($primaryKey) {
return isset($primaryKey[$columnDef->getName()]);
})->toArray();

if (empty($primaryKeyColumns)) {
return;
}

foreach ($primaryKeyColumns as $primaryKeyColumn) {
if ($primaryKeyColumn->isIdentity()) {
unset($primaryKey[$primaryKeyColumn->getName()]);
}
}

$primaryKey = array_flip($primaryKey);

if (!empty($primaryKey)) {
$this->options['primary_key'] = $primaryKey;
} else {
unset($this->options['primary_key']);
}
}
}
14 changes: 12 additions & 2 deletions src/Template/Bake/config/skeleton.ctp
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,21 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/

$wantedOptions = array_flip(['length', 'limit', 'default', 'unsigned', 'null', 'comment']);
$wantedOptions = array_flip(['length', 'limit', 'default', 'unsigned', 'null', 'comment', 'autoIncrement']);
$tableMethod = $this->Migration->tableMethod($action);
$columnMethod = $this->Migration->columnMethod($action);
$indexMethod = $this->Migration->indexMethod($action);
%>
<?php
use Phinx\Migration\AbstractMigration;
use Migrations\AbstractMigration;

class <%= $name %> extends AbstractMigration
{
<%- if ($tableMethod === 'create' && !empty($columns['primaryKey'])): %>

public $autoId = false;

<%- endif; %>
/**
* Change Method.
*
Expand Down Expand Up @@ -61,6 +66,11 @@ class <%= $name %> extends AbstractMigration
echo $this->Migration->stringifyList($config['options'], ['indent' => 3]);
%>]);
<% endforeach; %>
<% if ($tableMethod === 'create' && !empty($columns['primaryKey'])): %>
$table->addPrimaryKey([<%=
$this->Migration->stringifyList($columns['primaryKey'], ['indent' => 3])
%>]);
<% endif; %>
<% endif; %>
<% endif; %>
$table-><%= $tableMethod %>();
Expand Down
22 changes: 18 additions & 4 deletions src/Template/Bake/config/snapshot.ctp
Original file line number Diff line number Diff line change
Expand Up @@ -13,42 +13,53 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/

$wantedOptions = array_flip(['length', 'limit', 'default', 'unsigned', 'null', 'comment']);
$wantedOptions = array_flip(['length', 'limit', 'default', 'unsigned', 'null', 'comment', 'autoIncrement']);
$tableMethod = $this->Migration->tableMethod($action);
$columnMethod = $this->Migration->columnMethod($action);
$indexMethod = $this->Migration->indexMethod($action);
$constraints = $foreignKeys = $dropForeignKeys = [];
%>
<?php
use Phinx\Migration\AbstractMigration;
use Migrations\AbstractMigration;

class <%= $name %> extends AbstractMigration
{
<%- if (!$autoId): %>

public $autoId = false;

<%- endif; %>
public function up()
{
<%- foreach ($tables as $table):
$foreignKeys = [];
$primaryKeysColumns = $this->Migration->primaryKeysColumnsList($table);
$primaryKeys = $this->Migration->primaryKeys($table);
$specialPk = count($primaryKeys) > 1 || $primaryKeys[0]['name'] !== 'id' || $primaryKeys[0]['info']['columnType'] !== 'integer';
$specialPk = (count($primaryKeys) > 1 || $primaryKeys[0]['name'] !== 'id' || $primaryKeys[0]['info']['columnType'] !== 'integer') && $autoId;
if ($specialPk):
%>
$table = $this->table('<%= $table%>', ['id' => false, 'primary_key' => ['<%= implode("', '", \Cake\Utility\Hash::extract($primaryKeys, '{n}.name')) %>']]);
<%- else: %>
$table = $this->table('<%= $table%>');
<%- endif; %>
$table
<%- if ($specialPk):
<%- if ($specialPk || !$autoId):
foreach ($primaryKeys as $primaryKey) : %>
-><%= $columnMethod %>('<%= $primaryKey['name'] %>', '<%= $primaryKey['info']['columnType'] %>', [<%
$options = [];
$columnOptions = array_intersect_key($primaryKey['info']['options'], $wantedOptions);
if (empty($columnOptions['comment'])) {
unset($columnOptions['comment']);
}
if (empty($columnOptions['autoIncrement'])) {
unset($columnOptions['autoIncrement']);
}
echo $this->Migration->stringifyList($columnOptions, ['indent' => 4]);
%>])
<%- endforeach;
if (!$autoId): %>
->addPrimaryKey(['<%= implode("', '", \Cake\Utility\Hash::extract($primaryKeys, '{n}.name')) %>'])
<%- endif;
endif;
foreach ($this->Migration->columns($table) as $column => $config): %>
-><%= $columnMethod %>('<%= $column %>', '<%= $config['columnType'] %>', [<%
Expand All @@ -57,6 +68,9 @@ class <%= $name %> extends AbstractMigration
if (empty($columnOptions['comment'])) {
unset($columnOptions['comment']);
}
if (empty($columnOptions['autoIncrement'])) {
unset($columnOptions['autoIncrement']);
}
echo $this->Migration->stringifyList($columnOptions, ['indent' => 4]);
%>])
<%- endforeach;
Expand Down
Loading

0 comments on commit 441ffba

Please sign in to comment.