View Source

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[{zone-template-instance:ZFDEV:Zend Proposal Zone Template}

{zone-data:component-name}
Zend_Db_Schema_Manager
{zone-data}

{zone-data:proposer-list}
[Rob Allen|mailto:rob@akrabat.com]
[Thomas Weidner|~thomas]
{zone-data}

{zone-data:revision}
0.1 - 25 October 2006: Initial release.
0.2 - 30 November 2007: Additional features
{zone-data}

{zone-data:overview}

h1. *ACTUAL BEING REWORKED*

Zend_Db_Schema_Manager maintains a database schema in a database agnostic format.
This ensures that the same change can be applied to multiple databases and all changes can be stored in
a version control system.
The schema itself can be given in several formats like XML, PHP. Additional input formats could be integrated.
{zone-data}

{zone-data:references}
* [Rails: ActiveRecord::Migration|http://rubyonrails.org/api/classes/ActiveRecord/Migration.html]
* [Rails Migration Cheat Sheet|http://garrettsnider.backpackit.com/pub/367902]
* [Phing DBDeploy|http://phing.info/docs/guide/current/chapters/appendixes/AppendixC-OptionalTasks.html#DbDeployTask]
{zone-data}

{zone-data:requirements}
* Zend_Db_Schema_Manager requires a database specific adapter for each supported database.
{zone-data}

{zone-data:dependencies}
* Zend_Exception
* Zend_Db
{zone-data}

{zone-data:operation}
Zend_Db_SchemaManager enables easy changes to a database schema without destroying
data. They can also be rolled back if required. The schema manager executes database
migration scripts which are collections of database operations such as adding a field to
a table.

Each migration script is a class extending from Zend_Db_Schema_Change which contains two
abstract methods: up() and down(). Migration script files are named like 001_initialSchema.php
so that they can be operated upon in order. The class within 001_initialSchema.php is called
initialSchema.

Note that for Zend_Db_Schema_Manager to work, a new table is required within the the database
being managed. This table, schema_info, holds the current version of the schema and is used
by the Manager to decide if the current operation is an upgrade or a rollback.

In order to work, a database independent structure to describe a table is used.

{zone-data}

{zone-data:milestones}
* Milestone 1: Completed design on wiki
* Milestone 2: Working prototype with unit tests checked into the incubator.
* Milestone 3: Documentation exists
{zone-data}

{zone-data:class-list}
* Zend_Db_Schema_Exception - exception handler
* Zend_Db_Schema_Manager - class to manage migrating from one schema version to another
* Zend_Db_Schema_Change - abstract class to inherit each migrations script from
* Zend_Db_Schema_Table - database independant table creation and altering
* Zend_Db_Schema_Adapter - abstract class for database specific schema-change adapters
* Zend_Db_Schema_Adapter_Mysql - MySQL adapter for adding/deleting/editing tables
* Zend_Db_Schema_Adapter_Mssql - MSSQL adapter for adding/deleting/editing tables

{zone-data}

{zone-data:use-cases}
||UC-01||
The main use case is when you need to change the database schema of a live application.
Obviously this is done on the development machine first and the Schema_Manager will
ensure that the same changes to the database will occur on the live site.

Example migration script: 001_AddSecondEmailAddressColumn.php
{code}
<?php
class AddSecondEmailAddressColumn extends Zend_Db_Schema_Change
{
function up()
{
$table = $this->table('users');
$table->addColumn('email_address2', 'string', array('length'=>50));
$table->save();
}

function down()
{
$table = $this->table('users');
$table->removeColumn('email_address2');
$table->save();
}
}
{code}

Example CLI script to run the Manager: updateSchema.php
{code}
<?php
$configSection = getCommandLineArgment('config_section');
$schemaDirectory = getCommandLineArgment('schema_directory');
$versionToMigrateTo = getCommandLineArgment('version');


$config = new Zend_Config_Ini('config.ini', $configSection);
$db = Zend_Db::factory($config->dbAdapter, $config->db);

$manager = new Zend_Db_Schema_Manager($schemaDirectory, $db);
$manager->run($versionToMigrateTo);
echo 'Schema updated to version ' . $manager->getCurrentSchemaVersion();

{code}

{zone-data}

{zone-data:skeletons}
{code}
class Zend_Db_Schema_Exception extends Zend_Exception {}

class Zend_Db_Schema_Manager
{
protected $_dir;
/**
* @var Zend_Db_Adapter_Abstract
*/
protected $_db;

function __construct($dir, $db) {}
function getCurrentSchemaVersion() {}
function run($version = null) {}

protected function _getMigrationFiles($currentVersion, $stopVersion=null) {}
protected function _processFile($file, $direction) {}
protected function _updateSchemaVersion($direction, $version, $last_change = '') {}
}


abstract class Zend_Db_Schema_Change
{
/**
* @var Zend_Db_Schema_Adapter_Abstract
*/
protected $_db;


function __construct($db) {}

/**
* @return Zend_Db_Schema_Table
*/
function table() {}

/**
* Changes to be applied in this change
*/
abstract function up();

/**
* Rollback changes made in up()
*/
abstract function down();

}


class Zend_Db_Schema_Table
{
function __construct($adapter, $tableName, $hasPrimaryColumn = true) {}
function removeColumn($name) {}
function addColumn($name, $type, $options = array()) {}
function save() {}

protected function _loadTable() {}
protected function _getGenericType($typeName) {}


}

abstract class Zend_Db_Schema_Adapter
{
/**
* @var Zend_Db_Adapter_Abstract
*/
protected $_db;

function __construct($db)

abstract function createTable($name, $columns);
abstract function getType($genericType, $requestedlength);

function dropTable($tableName) {}

/**
* call through to the underlying Zend_Db_Adapter
*/
function __call($name, $arguments) {}

function

}

class Zend_Db_Schema_Adapter_Mysql extends Zend_Db_Schema_Adapter
{
function createTable($name, $columns) {}
function getType($genericType, $requestedlength) {}
}

class Zend_Db_Schema_Adapter_Mssql extends Zend_Db_Schema_Adapter
{
function createTable($name, $columns) {}
function getType($genericType, $requestedlength) {}
}

{code}
{zone-data}

{zone-template-instance}]]></ac:plain-text-body></ac:macro>