directus/migrations

用于生成和管理数据库迁移的框架

此包的官方仓库似乎已删除,因此包已被冻结。

dev-master 2017-09-15 17:34 UTC

This package is auto-updated.

Last update: 2020-03-28 20:37:22 UTC


README

基于 Ruckusing 的迁移。

仍然是相同的,但我计划基于我的口味和需求创建一个迁移库,不依赖于第三方库,就像Ruckusing一样。

介绍

Ruckusing 是一个用 PHP5 编写的框架,用于生成和管理一组“数据库迁移”。数据库迁移是声明性文件,代表了数据库在特定时间点的状态(其表、列、索引等)。通过使用数据库迁移,多个开发人员可以共同工作在同一个应用上,并确保应用程序在所有远程开发人员的机器上处于一致状态。

该框架的想法借鉴了 Ruby on Rails 内置的迁移系统。任何熟悉 RoR 中迁移的人都会感到非常熟悉。

Build Status

入门 & 文档

有关支持迁移方法和如何入门的完整文档,请参阅 Wiki

支持的数据库

  • Postgres
  • MySQL
  • Sqlite

功能

  • 便携性:描述要创建的表、列、索引等的迁移文件本身是用纯 PHP5 编写的,然后在运行时转换为适当的 SQL。这允许使用单个迁移文件集透明地支持任何 RDBMS(假设有适配器,见下文)。

  • 类似 "rake" 的对基本任务的支持。该框架有一个“任务”的概念(实际上,框架的主要焦点,迁移,只是一个普通的任务),它们是实现接口的纯 PHP5 类。可以自由编写任务,只要它们遵循特定的命名约定并实现特定的接口,框架就会自动注册它们并允许它们执行。

  • 能够向上或向下到特定的迁移状态。

  • 用于生成骨架迁移文件的代码生成器。

  • 支持基于模块的迁移目录,迁移文件可以从指定的模块目录生成/运行。

  • 对基本任务的支持,如初始化数据库模式信息表(db:setup)、询问当前版本(db:version)和导出当前模式(db:schema)。

限制

  • PHP 5.2+ 是强制要求。该框架广泛使用了 PHP5 的面向对象特性。没有计划使框架向后兼容。

配置

  • /path/to/ruckusing-migrations/config/database.inc.php 复制到 /path/to/mycodebase/ruckusing.conf.php,并用您的数据库凭证更新 development

type 是根据数据库类型选择 pgsqlmysqlsqlite 等,同时还需要更新 migrations_dirdb_dirlog_dirruckusing_base 路径。

  • 如果您想使用模块迁移目录,编辑 /path/to/mycodebase/ruckusing.conf.php 并更新 migrations_dir,例如 array('default' => '/default/path', 'module_name' => '/module/migration/path') 路径。

  • /path/to/ruckusing-migrations/ruckus.php 复制到 /path/to/mycodebase/ruckus.php

自定义任务

默认情况下,所有 lib/Task 中的任务都是启用的。如果您想实现自定义任务,可以在您重写的 ruckusing.conf.php 中的 tasks_dir 键指定您的任务目录。

# ruckusing.conf.php

return array(
 /* ... snip ... */,
 'tasks_dir' => RUCKUSING_WORKING_BASE . '/custom_tasks'
);

生成骨架迁移文件

从代码库的顶层运行

$ php ruckus.php db:generate create_users_table

Created OK
Created migration: 20121112163653_CreateUsersTable.php

模块迁移目录示例

$ php ruckus.php db:generate create_items_table module=module_name

Created OK
Created migration: 20121112163653_CreateItemsTable.php

生成的文件位于 migrations 目录中。打开该文件,您会看到它看起来像

class CreateUsersTable extends Ruckusing_Migration_Base {

	public function up() {

	}//up()

	public function down() {

	}//down()
}

以下所有方法都需要在 up()down() 方法中实现。

运行迁移

运行所有挂起的迁移

$ php ruckus.php db:migrate

回滚最近的迁移

$ php ruckus.php db:migrate VERSION=-1

回滚到特定的迁移(指定要回滚到的迁移文件的文件名中的时间戳)

$ php ruckus.php db:migrate VERSION=20121114001742

可用的迁移方法概述

以下列出了可用的方法(以下为简要列表,详细用法见下文)

数据库级别操作

  • create_database
  • drop_database

表级别操作

  • create_table
  • drop_table
  • rename_table

列级别操作

  • add_column
  • remove_column
  • rename_column
  • change_column

索引级别操作

  • add_index
  • remove_index

查询执行

  • execute
  • select_one
  • select_all

数据库级别操作

有两种数据库级别操作,即 create_databasedrop_database。在如此高级别的数据库上执行迁移很少使用。

创建新数据库

此命令稍微有些无用,因为通常您会针对现有的数据库运行迁移(使用传统的关系型数据库管理系统创建和设置)。但是,如果您想从迁移中创建另一个数据库,此方法可用。

方法调用: create_database

参数 name : 新数据库的名称

示例

    $this->create_database("my_project");

删除数据库

完全删除数据库及其所有表(及其数据)!

方法调用: drop_database

参数 name : 已存在数据库的名称

示例

    $this->drop_database("my_project");

此方法可能是所有方法中最复杂的,但也是使用最广泛的方法之一。

方法调用: create_table

参数

name : 新表的名称

options : (可选) 创建新表时的选项关联数组。

支持的选项键/值对是

id : 布尔值 - 框架是否应自动生成主键。对于 MySQL,该列将称为 id 并为整数类型,具有自增属性。

options : 表示传递给创建表命令末尾的最终参数的字符串。通常,这用于指定 MySQL 的存储引擎,例如 'options' => 'Engine=InnoDB'

假设 最终此方法委托给适当的 RDMBS 适配器,MySQL 适配器对表的结构做了一些重要的假设。

表级操作

数据库迁移框架提供了一套丰富的功能,用于创建、删除和重命名表。

创建表

调用 $this->create_table(...) 实际上返回一个 TableDefinition 对象。框架的此方法是非常少数几个实际上返回结果供用户交互的方法之一。

创建新表的步骤如下

  • 使用名称和任何可选选项创建表,并将返回值存储以供以后使用
    $users = $this->create_table("users");
  • 向表定义中添加列
    $users->column("first_name", "string");
    $users->column("last_name", "string");
  • 调用 finish() 以使用定义及其列实际创建表
    $users->finish();

默认情况下,表类型将与您的数据库默认类型相同。要指定不同的表类型(例如 InnoDB),请将 options 键传递到 $options 数组中,例如

示例 A: 创建一个名为 users 的新 InnoDB 表。

    $this->create_table('users', array('options' => 'Engine=InnoDB'));
  • 此命令还假设您想要一个 id 列。此列不需要指定,它将被自动生成,除非通过 $options 数组中的 id 键明确告诉不要生成。

示例 B: 创建一个名为 users 的新表,但不要自动创建主键。

    $this->create_table('users', array('id' => false));

主键列将被创建,具有 int(11) unsigned auto_increment 属性。

示例 C: 要指定自己的主键名为 'guid'

    $t = $this->create_table('users', array('id' => false, 'options' => 'Engine=InnoDB'));
    $t->column('guid', 'string', array('primary_key' => true, 'limit' => 64));
    $t->finish();

删除表

可以使用 drop_table 方法调用删除表。正如预期的那样,删除表也将删除其所有列和任何索引。

方法调用: drop_table

参数: table_name:要删除的表的名称。

示例

   $this->drop_table("users");

重命名表

可以使用 rename_table 方法重命名表。

方法调用: rename_table

参数: table_name:现有表的名称。 new_name:新表的名称。

示例

   // rename from "users" to "people"
   $this->rename_table("users", "people");

列级操作

向表中添加新列

有关添加新列的完整文档,请参阅 添加列

删除列

删除数据库列非常简单,但请注意,与该列关联的任何索引也将被删除。

方法调用: remove_column

参数 table_name:要从其中删除列的表名。

column_name:要删除的列。

示例A:users 表中删除 age 列。

    $this->remove_column("users", "age");

重命名列

数据库列可以被重命名(假设底层的 RDMBS/适配器支持此操作)。

方法调用: rename_column

参数: table_name:要从其中重命名列的表名。

column_name:现有列的名称。

new_column_name:新列的名称。

示例A:users 表中,将 first_name 重命名为 fname

    $this->rename_column("users", "first_name", "fname");

修改现有列

可以修改现有列的类型、默认值或对 NULL 的支持。如果您只想重命名列,请使用 rename_column 方法。此方法接受列类型的通用类型以及影响列定义的选项数组。有关可用类型和选项的信息,请参阅添加新列的文档,添加列。

方法调用: change_column

参数: table_name:要从其中更改列的表名。

column_name:要更改的列的名称。

type:列所需的通用类型。

options:可选)一个关联数组,包含影响列定义的选项。

示例A:users 表中,将 first_name 列的长度更改为 128。

    $this->change_column("users", "first_name", "string", array('limit' => 128) );

索引级别操作

可以使用框架方法创建和删除索引。

添加新索引

方法调用: add_index

参数: table:要添加索引的表名。

column:要创建索引的列。如果这是一个字符串,那么它被假定为列名,索引将是一个单列索引。如果它是一个数组,那么它被假定为列名列表,然后索引将是一个多列索引,在指定的列上。

options:可选)一个关联数组,用于控制索引生成。键 / 值对

unique:值:truefalse。是否为此列创建唯一索引。默认为 false

name:值:用户定义。索引的名称。如果未指定,将根据表和列名生成默认名称。

已知问题/解决方案:MySQL当前对标识符名称的限制为64个字符。当使用add_index而未指定索引名称时,Ruckusing将根据表名和索引的列(s)生成一个合适的名称。例如,如果有users表,并在username列上生成索引,则生成的索引名称将为:idx_users_username。如果尝试添加多列索引,则生成的名称可能超过MySQL的64个字符限制。在这种情况下,Ruckusing将引发错误,建议您通过name选项参数使用自定义索引名称。请参阅示例C

示例A:users表的email列上创建索引。

    $this->add_index("users", "email");

示例B:users表的ssn列上创建唯一索引。

    $this->add_index("users", "ssn", array('unique' => true)));

示例C:posts表的blog_id列上创建索引,但指定索引的特定名称。

    $this->add_index("posts", "blog_id", array('name' => 'index_on_blog_id'));

示例D:users表的emailssn列上创建多列索引。

    $this->add_index("users", array('email', 'ssn') );

删除索引

这很简单。如果索引是使用此方法(add_index)的兄弟方法创建的,那么只需指定该方法相同的参数(但调用remove_index)。

方法调用: remove_index

参数: table_name:要从其中删除索引的表名。

column_name:要从其中删除索引的列名。

options:(可选)一个关联数组,用于控制索引删除过程。键/值对:name:用户定义。要删除的索引名称。如果未指定,则将根据表和列名生成默认名称。如果在创建索引过程中(使用add_index方法)指定了name,那么您需要在这里做同样的事情并指定相同的名称。否则,生成的默认名称可能与实际的索引名称不匹配。

示例A:users表上的email列删除(单列)索引。

    $this->remove_index("users", "email");

示例B:users表上的emailssn列删除(多列)索引。

    $this->remove_index("users", array("email", "ssn") );

示例C:users表上的email列删除(单列)命名的索引。

    $this->remove_index("users", "email", array('name' => "index_on_email_column") );

查询执行

通过一组方法提供任意查询执行。

执行方法

execute()方法旨在用于不返回任何数据的查询,例如INSERTUPDATEDELETE

示例A:根据某些条件更新所有行。

    $this->execute("UPDATE foo SET name = 'bar' WHERE .... ");

返回结果的查询

对于返回结果的查询,例如SELECT查询,请根据返回的内容使用select_oneselect_all

这两个方法都返回一个关联数组,其中数组的每个元素本身又是另一个关联数组,包含列名及其值。

select_one()旨在用于期望单个结果集的查询,而select_all()适用于所有其他情况(您可能不知道将获取多少行)。

注意:由于这些方法以原始SQL查询为输入,它们可能无法在所有关系型数据库管理系统(RDBMS)之间通用。

示例A(select_one):获取某一列的总和

    $result = $this->select_one("SELECT SUM(total_price) AS total_price FROM orders");
    if($result) {
     echo "Your revenue is: " . $result['total_price'];
    }

**示例B(select_all)**:获取所有行并遍历每一行,执行某些操作

    $result = $this->select_all("SELECT email, first_name, last_name FROM users WHERE created_at >= SUBDATE( NOW(), INTERVAL 7 DAY)");

    if($result) {
      echo "New customers: (" . count($result) . ")\n";
      foreach($result as $row) {
        printf("(%s) %s %s\n", $row['email'], $row['first_name'], $row['last_name']);
      }
    }

测试

单元测试需要安装phpunit:[http://www.phpunit.de/manual/current/en/installation.html](http://www.phpunit.de/manual/current/en/installation.html)

运行完整测试套件

$ vi config/database.inc.php
$ mysql -uroot -p < tests/test.sql
$ psql -Upostgres -f tests/test.sql
$ phpunit

将在tests/unit目录下运行所有测试类。

运行单个测试文件

$ vi config/database.inc.php
$ mysql -uroot -p < tests/test.sql
$ phpunit tests/unit/MySQLAdapterTest.php

某些测试需要定义mysql_testpg_test数据库配置。如果需要此配置但未满足,则测试将适当报错。

=======