aimeos/upscheme

简化数据库模式升级

0.8.9 2023-11-15 16:20 UTC

This package is auto-updated.

Last update: 2024-09-15 18:15:56 UTC


README

Build Status Coverage Status License

Upscheme:简化数据库模式更新

易于使用的PHP包,用于更新应用程序的数据库模式并在版本之间迁移数据。

composer req aimeos/upscheme

目录

为什么选择Upscheme

迁移就像数据库的版本控制。它们允许您记录所有更改,并与他人共享,以便他们在安装中获得完全相同的状态。

对于升级关系数据库模式,目前最常用的两个包是Doctrine DBAL和Doctrine迁移。虽然Doctrine DBAL在抽象几个数据库实现的不同之处做得很好,但它的API需要编写大量代码。另一方面,Doctrine迁移有一些缺点,这使得它在所有支持第三方扩展的应用程序中都难以使用。

Doctrine DBAL的缺点

DBAL的API非常冗长,即使是简单的事情也需要编写大量代码。Upscheme使用Doctrine DBAL提供易于使用的API,以最少的代码升级您的应用程序的数据库模式。让我们比较在迁移中必须为DBAL和Upscheme编写的示例代码。

DBAL

$dbalManager = $conn->createSchemaManager();
$from = $manager->createSchema();
$to = $manager->createSchema();

if( $to->hasTable( 'test' ) ) {
	$table = $to->getTable( 'test' );
} else {
	$table = $to->createTable( 'test' );
}

$table->addOption( 'engine', 'InnoDB' );

$table->addColumn( 'id', 'integer', ['autoincrement' => true] );
$table->addColumn( 'domain', 'string', ['length' => 32] );

if( $conn->getDatabasePlatform()->getName() === 'mysql' ) {
	$table->addColumn( 'code', 'string', ['length' => 64, 'customSchemaOptions' => ['charset' => 'binary']] );
} else {
	$table->addColumn( 'code', 'string', ['length' => 64]] );
}

$table->addColumn( 'label', 'string', ['length' => 255] );
$table->addColumn( 'pos', 'integer', ['default' => 0] );
$table->addColumn( 'status', 'smallint', [] );
$table->addColumn( 'mtime', 'datetime', [] );
$table->addColumn( 'ctime', 'datetime', [] );
$table->addColumn( 'editor', 'string', ['length' => 255] );

$table->setPrimaryKey( ['id'] );
$table->addUniqueIndex( ['domain', 'code'] );
$table->addIndex( ['status', 'pos'] );

foreach( $from->getMigrateToSql( $to, $conn->getDatabasePlatform() ) as $sql ) {
	$conn->executeStatement( $sql );
}

Upscheme

$this->db()->table( 'test', function( $t ) {
	$t->engine = 'InnoDB';

	$t->id();
	$t->string( 'domain', 32 );
	$t->string( 'code', 64 )->opt( 'charset', 'binary', 'mysql' );
	$t->string( 'label', 255 );
	$t->int( 'pos' )->default( 0 );
	$t->smallint( 'status' );
	$t->default();

	$t->unique( ['domain', 'code'] );
	$t->index( ['status', 'pos'] );
} );

Doctrine迁移的缺点

Doctrine迁移依赖于以创建时间命名的迁移类,以确保特定的顺序。此外,它将已执行的迁移存储在您的数据库表中。由此产生了两个主要问题。

如果您的应用程序支持第三方扩展,这些扩展可能会向现有表添加列并自行迁移数据。由于无法定义迁移之间的依赖关系,在没有冲突的情况下运行具有多个第三方扩展的应用程序的迁移几乎变得不可能。为了避免这种情况,Upscheme在每个迁移任务中提供了易于使用的before()after()方法,任务可以定义其与其他任务的依赖关系。

因为 Doctrine Migrations 使用数据库表来记录哪些迁移已经被执行,所以在出现问题时,这些记录可能会轻易地失去同步。相反,Upscheme 仅依赖于实际的模式,因此可以从任何状态升级,无论之前发生了什么。

Doctrine Migrations 还在 down() 方法中支持反向操作,因此可以回滚 Upscheme 不支持的迁移。经验表明,通常不可能回滚迁移,例如在添加新列、迁移现有列的数据并随后删除旧列之后。如果迁移数据有损失,就无法在 down() 方法中重新创建相同的状态。如果删除了表,情况也是一样。因此,Upscheme 仅提供模式升级,而不提供降级以避免隐式数据丢失。

集成Upscheme

使用 composer 安装完 aimeos/upscheme 包后,您可以使用 Up 类来执行迁移任务

$config = [
	'driver' => 'pdo_mysql',
	'host' => '127.0.0.1',
	'dbname' => '<database>',
	'user' => '<dbuser>',
	'password' => '<secret>'
];

\Aimeos\Upscheme\Up::use( $config, 'src/migrations' )->up();

Up::use() 方法需要两个参数:数据库配置和迁移任务的路径。对于配置,必须支持 Doctrine DBAL 的 driver 数组键和值。可用的驱动程序有

  • pdo_mysql
  • pdo_pgsql
  • pdo_sqlite
  • pdo_sqlsrv
  • pdo_oci
  • ibm_db2
  • mysqli
  • oci8
  • sqlanywhere
  • sqlsrv

某些数据库需要不同的参数,最值得注意的是 SQLite 和 Oracle

SQLite

$config = [
	'driver' => 'pdo_sqlite',
	'path' => 'path/to/file.sq3'
];

Oracle

$config = [
	'driver' => 'pdo_oci',
	'host' => '<host or IP>',
	'dbname' => '<SID or service name (Oracle 18+)>',
	'service' => true, // for Oracle 18+ only
	'user' => '<dbuser>',
	'password' => '<secret>'
];

如果您之前没有使用过 Doctrine DBAL,则数据库配置可能具有不同的结构,并/或使用不同的数据库类型值。Upscheme 允许您注册一个自定义方法,该方法将您的配置转换为有效的 DBAL 设置,例如

\Aimeos\Upscheme\Up::macro( 'connect', function( array $cfg ) {

	return \Doctrine\DBAL\DriverManager::getConnection( [
		'driver' => $cfg['adapter'],
		'host' => $cfg['host'],
		'dbname' => $cfg['database'],
		'user' => $cfg['username'],
		'password' => $cfg['password']
	] );
} );

Upscheme 还支持多个数据库连接,您可以通过它们的键名来区分它们

$config = [
	'db' => [
		'driver' => 'pdo_mysql',
		'host' => '127.0.0.1',
		'dbname' => '<database>',
		'user' => '<dbuser>',
		'password' => '<secret>'
	],
	'temp' => [
		'driver' => 'pdo_sqlite',
		'path' => '/tmp/mydb.sqlite'
	]
];

\Aimeos\Upscheme\Up::use( $config, 'src/migrations' )->up();

当然,您也可以向 Up 类传递多个迁移路径

\Aimeos\Upscheme\Up::use( $config, ['src/migrations', 'ext/migrations'] )->up();

要启用(调试)输出,请使用 verbose() 方法

\Aimeos\Upscheme\Up::use( $config, 'src/migrations' )->verbose()->up(); // most important only
\Aimeos\Upscheme\Up::use( $config, 'src/migrations' )->verbose( 'vv' )->up(); // more verbose
\Aimeos\Upscheme\Up::use( $config, 'src/migrations' )->verbose( 'vvv' )->up(); // debugging

编写迁移

迁移任务只需实现 up() 方法,并必须存储在传递给 Up 类的目录之一中

<?php

namespace Aimeos\Upscheme\Task;
use Aimeos\Upscheme\Schema\Table;


class TestTable extends Base
{
	public function up()
	{
		$this->db()->table( 'test', function( Table $t ) {
			$t->id();
			$t->string( 'label' );
			$t->bool( 'status' );
		} );
	}
}

存储您的类的文件必须与类本身具有相同的名称(区分大小写)以及 .php 后缀,例如

class TestTable -> TestTable.php

没有严格的迁移任务类命名约定。您可以根据它们的功能(例如,"CreateTestTable")、操作对象(例如,"TestTable")甚至使用时间戳(例如,"20201231_Test")来命名它们。如果任务不包含依赖关系,则它们将按字母顺序排序并执行,排序如下

20201231_Test
CreateTestTable
TestTable

在您的 PHP 文件中,始终首先包含 namespace 语句。use 语句是可选的,并且仅需要作为闭包函数参数类型提示的快捷方式。您的类还必须从 "Base" 任务类扩展或实现 "Iface" 任务接口

依赖项

要指定对其他迁移任务的依赖关系,请使用 after()before() 方法。您的任务将在 after() 返回的任务之后以及 before() 返回的任务之前执行

class TestTable extends Base
{
	public function after() : array
	{
		return ['CreateRefTable'];
	}

	public function before() : array
	{
		return ['InsertTestData'];
	}
}

因此,执行顺序将是

CreateRefTable -> TestTable -> InsertTestData

消息

要在迁移任务中输出消息,请使用 info() 方法

$this->info( 'some message' );
$this->info( 'more verbose message', 'vv' );
$this->info( 'very verbose debug message', 'vvv' );

第二个参数是详细级别,没有或 v 是标准消息,vv 是仅在需要更多详细程度时显示的消息,而 vvv 是用于调试消息的。还有一个第三个参数用于缩进消息

$this->info( 'some message' );
$this->info( 'second level message', 'v', 1 );
$this->info( 'third level message', 'v', 2 );

这将显示

some message
  second level message
    third level message

前提是之前已经调用了 Up 类的 verbose() 方法

\Aimeos\Upscheme\Up::use( $config, '...' )->verbose()->up();

模式

up()方法中,您可以通过db()方法访问数据库模式。如果您向Up::use()传递了多个数据库配置,您可以通过配置键访问不同的模式。

// $config = ['db' => [...], 'temp' => [...]];
// \Aimeos\Upscheme\Up::use( $config, '...' )->up();

$this->db();
$this->db( 'db' );
$this->db( 'temp' );

如果您没有传递配置键或传递了一个不存在的配置键,将返回第一个配置(在本例中为"db")。通过使用数据库模式对象的可用方法,您可以添加、更新或删除表、列、索引和其他数据库对象。您还可以使用insert()select()update()delete()stmt()来操作表中的记录。

在每个迁移任务之后,任务中做出的模式更新将自动应用于数据库。如果您需要立即持久化更改以插入数据,请自行调用$this->db()->up()。在任意的表、序列和列对象中,up()方法都是可用的,因此您可以在任何地方调用up()

如果您需要两个不同的数据库连接,因为您想同时执行SELECT和INSERT/UPDATE/DELETE语句,将TRUE作为db()的第二个参数传递,以获取包括新连接在内的数据库模式。

$db1 = $this->db();
$db2 = $this->db( 'db', true );

foreach( $db1->select( 'users', ['status' => false] ) as $row ) {
	$db2->insert( 'oldusers', $row );
}

$db2->delete( 'users', ['status' => false] );

在返回新连接的模式之前,所有做出的模式更改都将应用于数据库。为了避免数据库连接堆积直到数据库服务器拒绝新连接,始终为新创建的连接调用close()(例如,使用db( '<name>', true )创建的连接)。

$db2->close();

数据库

访问对象

您可以通过调用$this->db()来获取任务中的数据库模式对象,如模式部分所述。它为您提供对数据库模式的完全访问权限,包括所有表、序列和其他模式对象。

$table = $this->db()->table( 'users' );
$seq = $this->db()->sequence( 'seq_users' );

如果表或序列不存在,它将被创建。否则,将返回现有的表或序列对象。在两种情况下,您都可以随后修改这些对象,例如向表中添加新列。

检查存在性

您可以使用由$this->db()返回的数据库模式来测试表、列、索引、外键和序列。

$db = $this->db();

if( $db->hasTable( 'users' ) ) {
    // The "users" table exists
}

if( $db->hasColumn( 'users', 'name' ) ) {
    // The "name" column in the "users" table exists
}

if( $db->hasIndex( 'users', 'idx_name' ) ) {
    // The "idx_name" index in the "users" table exists
}

if( $db->hasForeign( 'users_address', 'fk_users_id' ) ) {
    // The foreign key "fk_users_id" in the "users_address" table exists
}

if( $db->hasSequence( 'seq_users' ) ) {
    // The "seq_users" sequence exists
}

if( $db->hasView( 'testview' ) ) {
    // The "testview" view exists
}

重命名对象

$this->db()返回的数据库对象提供了使用renameTable()renameColumn()renameIndex()重命名表、列和索引的可能性。

$db = $this->db();

// Renames the table "users" to "accounts"
$db->renameTable( 'users', 'account' );

// Renames the column "label" to "name" in the "users" table
$db->renameColumn( 'users', 'label', 'name' );

// Renames the column "idx_label" to "idx_name" in the "users" table
$db->renameIndex( 'users', 'idx_label', 'idx_name' );

删除对象

$this->db()返回的数据库对象还具有删除表、列、索引、外键和序列的方法。

$db = $this->db();

// Drops the foreign key "fk_users_id" from the "users_address" table
$db->dropForeign( 'users_address', 'fk_users_id' );

// Drops the "idx_name" index from the "users" table
$db->dropIndex( 'users', 'idx_name' );

// Drops the "name" column from the "users" table
$db->dropColumn( 'users', 'name' );

// Drops the "seq_users" sequence
$db->dropSequence( 'seq_users' );

// Drops the "users" table
$db->dropTable( 'users' );

// Drops the "testview" view
$db->dropView( 'testview' );

如果表、列、索引、外键或序列不存在,它将被静默忽略。对于您需要知道它们是否存在的情况,在使用"检查存在性"部分中描述的hasTable()hasColumn()hasIndex()hasForeign()hasSeqence()方法之前。

查询/修改表行

《insert()》方法、`select()`方法、`update()`方法和`delete()`方法是一种简单的方法,可以用来向任何表中添加、检索、修改和删除行。

$db1 = $this->db();
$db2 = $this->db( 'db', true );

$db2->transaction( function( $db2 ) use ( $db1 ) {

	foreach( $db1->select( 'users', ['status' => false] ) as $row )
	{
		$db2->insert( 'newusers', ['userid' => $row['id'], 'status' => true] );
		$db2->update( 'users', ['refid' => $db2->lastId()], ['id' => $row['id']] );
	}

	$db2->delete( 'newusers', ['status' => false] );
	$db2->close();
} );

如果您同时使用`select()`、`insert()`、`update()`或`delete()`,则必须创建第二个数据库连接,因为在向数据库服务器发送新命令的同时,`select()`语句将返回行。这只适用于单独的连接,而不是同一连接。

要将所有删除/插入/更新操作包装在一个事务中,您必须使用`database`对象的`transaction()`方法。

$this->db()->transaction( function( $db ) {
	// $db->insert( ... )
	// $db->update( ... )
	// $db->delete( ... )
} );

这确保了所有写操作要么原子性地执行,要么在出现错误时全部不执行。`transaction()`方法确保在匿名函数返回控制权给方法后,事务自动提交或回滚。

如果您需要在匿名函数中添加额外的参数,您可以在函数的`use`列表中传递它们。

$userid = 123;
$this->db()->transaction( function( $db ) use ( $userid ) {
	$db->insert( 'newusers', ['userid' => userid, 'status' => true] );
} );

您只能将简单的键/值对作为条件传递给方法,这些方法通过AND组合。如果您需要更复杂的查询,请使用`stmt()`代替。

$db = $this->db();

$result = $db->stmt()->select( 'id', 'name' )
	->from( 'users' )
	->where( 'status != ?' )
	->setParameter( 0, false )
	->execute();

$db->stmt()->delete( 'users' )
	->where( 'status != ?' )
	->setParameter( 0, false )
	->execute();

$db->stmt()->update( 'users' )
	->set( 'status', '?' )
	->where( 'status != ?' )
	->setParameters( [true, false] )
	->execute();

`stmt()`方法返回一个`Doctrine\DBAL\Query\QueryBuilder`对象,它使您能够构建更复杂的语句。有关详细信息,请参阅Doctrine Query Builder文档。

如果您想在SQL语句中直接使用值(出于安全考虑,尽可能使用预定义语句!),您必须使用`q()`方法来引用这些值。

$db = $this->db();

$result = $db->stmt()->select( '*' )->from( 'products' )
	->where( 'status = ' . $db->q( $_GET['status'] ) )->execute();

类似地,如果您的模式包含保留关键字,例如作为列名,您也必须使用`qi()`方法来引用它们。

$db = $this->db();

$result = $db->stmt()->select( $db->qi( 'key' ) )->from( 'products' )->execute();

执行自定义SQL

Doctrine只支持SQL语句的常见子集,而不是数据库供应商实现的所有可能性。为了消除这种限制,Upscheme提供了`exec()`、`for()`和`query()`方法来执行由Doctrine DBAL不支持的自定义SQL语句。

要执行自定义SQL查询,请使用`query()`方法,它返回一个您可以迭代的结果集。

$sql = 'SELECT id, label, status FROM product WHERE label LIKE ?';
$result = $this->db()->query( $sql, ['test%'] );

foreach( $result->iterateAssociative() as $row ) {
	// ...
}

对于所有其他SQL语句,请使用`exec()`方法,它返回受影响行的数量。

$sql = 'UPDATE product SET status=? WHERE status=?';
$num = $this->db()->exec( $sql, [1, 0] );

使用`for()`方法,您还可以根据数据库平台执行语句。

$this->db()->for( 'mysql', 'CREATE FULLTEXT INDEX idx_text ON product (text)' );

指定数据库平台对于创建在数据库实现之间语法不同的特殊类型索引非常有用。

数据库方法

数据库

DB::__call()

调用自定义方法或将未知方法调用传递给Doctrine模式对象

public function __call( string $method, array $args )
  • @param string $method 方法名称
  • @param array<mixed> $args 方法参数
  • @return mixed 调用方法返回值

示例

您可以注册具有访问Upscheme DB对象类属性的定制方法

\Aimeos\Upscheme\Schema\DB::macro( 'hasFkIndexes', function( $val ) {
	return $this->to->hasExplicitForeignKeyIndexes();
} );

$db->hasFkIndexes();
// returns true/false

可用的类属性包括

$this->from : 表示当前数据库的原生Doctrine数据库模式

$this->to : 包含到目前为止所做的更改的Doctrine数据库模式

$this->conn : Doctrine数据库连接

$this->up : Upscheme对象

此外,您可以直接调用任何Doctrine模式方法,例如。

$db->hasExplicitForeignKeyIndexes();

DB::close()

关闭数据库连接

public function close() : void

仅对使用$this->db( '...', true )创建的DB模式对象调用close()。否则,您将关闭主连接,DBAL必须重新连接到服务器,这将降低性能!

示例

$db = $this->db( 'temp', true );
$db->dropTable( 'test' );
$db->close();

DB::delete()

从给定的表中删除记录

public function delete( string $table, array $conditions = [] ) : self
  • @param string $table 表名称
  • @param array<string,mixed> $conditions 列名称和要比较的值的键/值对
  • @return self 同一对象,用于流畅的方法调用

警告:条件值被转义,但表名和条件列名没有被转义!仅使用固定字符串作为表名和条件列名,不要使用外部输入!

示例

$db->delete( 'test', ['status' => false, 'type' => 'old'] );
$db->delete( 'test' );

在第二个参数中传递的多个条件通过"AND"组合。如果需要更复杂的语句,请使用stmt()方法。

DB::dropColumn()

如果存在,则删除给定名称的列

public function dropColumn( string $table, $name ) : self
  • @param string $table 列所属的表名称
  • @param array<string>|string $name 列名称或列名称
  • @return self 同一对象,用于流畅的方法调用

示例

$db->dropColumn( 'test', 'oldcol' );
$db->dropColumn( 'test', ['oldcol', 'oldcol2'] );

如果列或列之一不存在,它将被静默忽略。

DB::dropForeign()

如果存在,则删除给定名称的外键约束

public function dropForeign( string $table, $name ) : self
  • @param string $table 外键约束所属的表名称
  • @param array<string>|string $name 外键约束名称或约束
  • @return self 同一对象,用于流畅的方法调用

示例

$db->dropForeign( 'test', 'fk_old' );
$db->dropForeign( 'test', ['fk_old', 'fk_old2'] );

如果外键约束或约束之一不存在,它将被静默忽略。

DB::dropIndex()

如果存在,则删除给定名称的索引

public function dropIndex( string $table, $name ) : self
  • @param string $table 索引所属的表名称
  • @param array<string>|string $name 索引名称或索引
  • @return self 同一对象,用于流畅的方法调用

示例

$db->dropIndex( 'test', 'idx_old' );
$db->dropIndex( 'test', ['idx_old', 'idx_old2'] );

如果索引或索引之一不存在,它将被静默忽略。

DB::dropSequence()

如果存在,则删除给定名称的序列

public function dropSequence( $name ) : self
  • @param array<string>|string $name 序列名称或序列
  • @return self 同一对象,用于流畅的方法调用

示例

$db->dropSequence( 'seq_old' );
$db->dropSequence( ['seq_old', 'seq_old2'] );

如果序列或序列之一不存在,它将被静默忽略。

DB::dropTable()

如果存在,则删除给定名称的表

public function dropTable( $name ) : self
  • @param array<string>|string $name 表名称或表
  • @return self 同一对象,用于流畅的方法调用

示例

$db->dropTable( 'test' );
$db->dropTable( ['test', 'test2'] );

如果表或表之一不存在,它将被静默忽略。

DB::dropView()

如果存在,则删除给定名称的视图

public function dropView( $name ) : self
  • @param string数组|string $name 视图或视图名称
  • @return self 同一对象,用于流畅的方法调用

示例

$db->dropView( 'test' );
$db->dropView( ['test', 'test2'] );

如果视图或其中之一不存在,它将被静默忽略。

DB::exec()

执行自定义SQL语句

public function exec( string $sql, array $params = [], array $types = [] ) : int
  • @param string $sql 自定义SQL语句
  • @param int|string,mixed数组 $params 位置参数列表或占位符和参数的关联列表
  • @param int|string,mixed数组 $types 位置或关联占位符参数的DBAL数据类型列表
  • @return int 受影响的行数

数据库更改不会立即应用,因此在执行自定义语句之前始终调用up(),以确保在使用之前已创建所需的表!

示例

$sql = 'UPDATE product SET status=? WHERE status=?';
$num = $this->db()->exec( $sql, [1, 0] );

DB::for()

如果数据库类型给定,则执行自定义SQL语句

public function for( $type, $sql ) : self
  • @param string数组|string $type 应执行语句的数据库类型
  • @param string数组|string $sql 自定义SQL语句或语句
  • @return self 同一对象,用于流畅的方法调用

可用的数据库平台类型有

  • mysql
  • postgresql
  • sqlite
  • mssql
  • oracle
  • db2

数据库更改不会立即应用,因此在执行自定义语句之前始终调用up(),以确保在使用之前已创建所需的表!

示例

$db->for( 'mysql', 'CREATE INDEX idx_test_label ON test (label(16))' );

$db->for( ['mysql', 'sqlite'], [
	'DROP INDEX unq_test_status',
	'UPDATE test SET status = 0 WHERE status IS NULL',
] );

DB::hasColumn()

检查列或列是否存在

public function hasColumn( string $table, $name ) : bool
  • @param string $table 列所属的表名称
  • @param array<string>|string $name 列名称或列名称
  • @return bool 如果列存在,则返回TRUE,如果不存在,则返回FALSE

示例

$db->hasColumn( 'test', 'testcol' );
$db->hasColumn( 'test', ['testcol', 'testcol2'] );

DB::hasForeign()

检查外键约束是否存在

public function hasForeign( string $table, $name ) : bool
  • @param string $table 外键约束所属的表名称
  • @param array<string>|string $name 外键约束名称或约束
  • @return bool 如果外键约束存在,则返回TRUE,如果不存在,则返回FALSE

示例

$db->hasForeign( 'test', 'fk_testcol' );
$db->hasForeign( 'test', ['fk_testcol', 'fk_testcol2'] );

DB::hasIndex()

检查索引是否存在

public function hasIndex( string $table, $name ) : bool
  • @param string $table 索引所属的表名称
  • @param array<string>|string $name 索引名称或索引
  • @return bool 如果索引存在,则返回TRUE,如果不存在,则返回FALSE

示例

$db->hasIndex( 'test', 'idx_test_col' );
$db->hasIndex( 'test', ['idx_test_col', 'idx_test_col2'] );

DB::hasSequence()

检查序列是否存在

public function hasSequence( $name ) : bool
  • @param array<string>|string $name 序列名称或序列
  • @return bool 如果序列存在,则返回TRUE,如果不存在,则返回FALSE

示例

$db->hasSequence( 'seq_test' );
$db->hasSequence( ['seq_test', 'seq_test2'] );

DB::hasTable()

检查表是否存在

public function hasTable( $name ) : bool
  • @param array<string>|string $name 表名称或表
  • @return bool 如果表存在,则返回TRUE,如果不存在,则返回FALSE

示例

$db->hasTable( 'test' );
$db->hasTable( ['test', 'test2'] );

DB::hasView()

检查视图是否存在

public function hasView( $name ) : bool
  • @param string数组|string $name 视图或视图名称
  • @return bool 如果视图存在,则返回TRUE,如果不存在,则返回FALSE

示例

$db->hasView( 'test' );
$db->hasView( ['test', 'test2'] );

DB::insert()

将记录插入给定的表

	public function insert( string $table, array $data ) : self
  • @param string $table 表名称
  • @param string,mixed数组 $data 要插入的列名/值键值对
  • @return self 同一对象,用于流畅的方法调用

示例

$db->insert( 'test', ['label' => 'myvalue', 'status' => true] );

DB::lastId()

返回最后插入到任何数据库表中的行的ID

public function lastId( string $seq = null ) : string
  • @param string|null $seq 生成ID的序列名称
  • @return string 数据库生成的ID
  • @throws \RuntimeException 如果序列不存在

示例

$db->lastId();
$db->lastId( 'seq_test' );

DB::name()

返回数据库名称

public function name() : string
  • @return string 数据库名

示例

$db->name();

DB::q()

引用一个值

public function q( $value, $type = \Doctrine\DBAL\ParameterType::STRING ) : string
  • @param mixed $value 用于非预编译SQL查询的值
  • @param mixed $type DBAL参数类型
  • @return string 引用值

示例

$result = $db->stmt()->select( '*' )->from( 'products' )
	->where( 'status = ' . $db->q( $_GET['status'] ) )->execute();

DB::qi()

引用数据库标识符

public function qi( string $identifier ) : string
  • @param string $identifier 标识符,如表名或列名
  • @return string 引用标识符

示例

$result = $db->stmt()->select( $db->qi( 'key' ) )->from( 'products' )->execute();

DB::query()

执行自定义SQL查询

public function query( string $sql, array $params = [], array $types = [] ) : \Doctrine\DBAL\Result
  • @param string $sql 自定义SQL语句
  • @param int|string,mixed数组 $params 位置参数列表或占位符和参数的关联列表
  • @param int|string,mixed数组 $types 位置或关联占位符参数的DBAL数据类型列表
  • @return \Doctrine\DBAL\Result DBAL结果集对象

示例

$result = $db->query( 'SELECT id, label, status FROM product WHERE label LIKE ?', ['test%'] );

foreach( $result->iterateAssociative() as $row ) {
	// ...
}

提示:有关获取数据的更多信息,请参阅DBAL方法

DB::renameColumn()

重命名列或列列表

public function renameColumn( string $table, $from, string $to = null ) : self
  • @param string $table 表名称
  • @param string,string数组 $from 列名或旧/新列名数组
  • @param string|null $to 如果第一个参数是数组,则忽略新列名
  • @return self 同一对象,用于流畅的方法调用

限制

  • SQLite自3.25.0版本起

示例

// single column
$db->renameColumn( 'testtable', 'test_col', 'test_column' );

// rename several columns at once
$db->renameColumn( 'testtable', ['tcol' => 'testcol', 'tcol2' => 'testcol2'] );

DB::renameIndex()

重命名列或列列表

public function renameIndex( string $table, $from, string $to = null ) : self
  • @param string $table 表名称
  • @param string,string数组 $from 索引名或旧/新索引名数组
  • @param string|null $to 新索引名称在第一个参数为数组时将被忽略
  • @return self 同一对象,用于流畅的方法调用

示例

// single index
$db->renameIndex( 'testtable', 'idxcol', 'idx_column' );

// rename several indexes at once
$db->renameIndex( 'testtable', ['idxcol' => 'idx_column', 'idxcol2' => 'idx_column2'] );

DB::renameTable()

重命名表或多个表

public function renameTable( $from, string $to = null ) : self
  • @param array<string,string>|string $from 表名或旧/新表名的数组
  • @param string|null $to 新表名在第一个参数为数组时将被忽略
  • @return self 同一对象,用于流畅的方法调用
  • @throws \RuntimeException 如果发生错误

示例

// single table
$db->renameTable( 'testtable', 'newtable' );

// rename several tables at once
$db->renameTable( ['testtable' => 'newtable', 'oldtable' => 'testtable2'] );

DB::select()

返回给定表中的记录

public function select( string $table, array $conditions = null ) : array
  • @param string $table 表名称
  • @param array<string>|null $conditions 列名和要比较的值的键值对
  • @return array<int,array<string,mixed>> 包含列名/值对的关联数组列表

示例

$db->select( 'test', ['status' => false, 'type' => 'old'] );
$db->select( 'test' );

在第二个参数中传递的多个条件通过"AND"组合。如果需要更复杂的语句,请使用stmt()方法。

DB::sequence()

返回给定名称的序列对象

public function sequence( string $name, \Closure $fcn = null ) : Sequence
  • @param string $name 序列名称
  • @param \Closure|null $fcn 带有($sequence)参数的匿名函数,用于创建或更新序列定义
  • @return \Aimeos\Upscheme\Schema\Sequence 序列对象

如果序列尚不存在,它将被创建。为了在数据库中持久化更改,您必须调用 up()

示例

$sequence = $db->sequence( 'seq_test' );

$sequence = $db->sequence( 'seq_test', function( $seq ) {
	$seq->start( 1000 )->step( 2 )->cache( 100 );
} )->up();

DB::stmt()

返回用于新SQL语句的查询构建器

public function stmt() : \Doctrine\DBAL\Query\QueryBuilder
  • @return \Doctrine\DBAL\Query\QueryBuilder 查询构建器对象

示例

$db->stmt()->delete( 'test' )->where( 'stat = ?' )->setParameter( 0, false )->execute();
$db->stmt()->update( 'test' )->set( 'stat', '?' )->setParameter( 0, true )->execute();
$result = $db->stmt()->select( 'id', 'code' )->from( 'test' )->where( 'stat = 1' )->execute();

while( $row = $result->fetchAssociative() ) {
    $id = $row['id'];
}

有关可用的Doctrine QueryBuilder方法的更多详细信息,请参阅Doctrine文档

DB::table()

返回给定名称的表对象

public function table( string $name, \Closure $fcn = null ) : Table
  • @param string $name 表名称
  • @param \Closure|null $fcn 带有($table)参数的匿名函数,用于创建或更新表定义
  • @return \Aimeos\Upscheme\Schema\Table 表对象

如果表尚不存在,它将被创建。为了在数据库中持久化更改,您必须调用 up()

示例

$table = $db->table( 'test' );

$table = $db->table( 'test', function( $t ) {
	$t->id();
	$t->string( 'label' );
	$t->bool( 'status' );
} )->up();

DB::transaction()

在事务中执行给定的闭包

public function transaction( \Closure $fcn ) : self
  • @param \Closure $fcn 带有(\Aimeos\Upscheme\Schema $db)参数的匿名函数
  • @return self 用于连续方法调用的相同对象
  • @throws \Exception 如果发生错误

示例

$this->db()->transaction( function( $db ) {
	// $db->insert( ... )
	// $db->update( ... )
	// $db->delete( ... )
} );

DB::type()

返回数据库类型

public function type() : string
  • @return string 数据库类型

可能的值是

  • db2
  • mssql
  • mysql
  • oracle
  • postgresql
  • sqlite

示例

$type = $db->type();

DB::up()

将更改应用到数据库模式

public function up() : self
  • @return self 同一对象,用于流畅的方法调用

示例

$db->up();

DB::update()

更新给定表中的记录

public function update( string $table, array $data, array $conditions = [] ) : self
  • @param string $table 表名称
  • @param array<string,mixed> $data 要更新的列名/值键值对
  • @param array<string,mixed> $conditions 列名称和要比较的值的键/值对
  • @return self 同一对象,用于流畅的方法调用

示例

$db->update( 'test', ['status' => true] );
$db->update( 'test', ['status' => true], ['status' => false, 'type' => 'new'] );

在第二个参数中传递的多个条件通过"AND"组合。如果需要更复杂的语句,请使用stmt()方法。

DB::view()

如果尚不存在,则创建具有给定名称的视图

public function view( string $name, string $sql, $for = null ) : self
  • @param string $name 视图名称
  • @param string $sql 用于填充视图的SELECT语句
  • @param array<string>|string|null $for 应用于此SQL的数据库类型("mysql", "postgresql", "sqlite", "mssql", "oracle", "db2")
  • @return self 同一对象,用于流畅的方法调用

如果视图尚不存在,则创建。否则,不会发生任何操作。

示例

$db->view( 'testview', 'SELECT * FROM testtable' );
$db->view( 'testview', 'SELECT id, label, status FROM testtable WHERE status = 1' );
$db->view( 'testview', 'SELECT * FROM `testtable` WHERE `status` = 1', 'mysql' );

创建表

在迁移任务中调用 table() 获得的表方案对象为您提供了对表的完全访问权限,您可以为列、索引和外键添加、更改或删除,例如

$this->db()->table( 'test', function( $table ) {
	$table->id();
	$table->string( 'label' );
	$table->col( 'status', 'tinyint' )->default( 0 );
} );

除了可以添加任意类型列的 col() 方法之外,还有一些适用于所有数据库服务器实现的类型快捷方法

设置表选项

MySQL(或MariaDB等)支持一些选项来定义表的一些方面。engine 选项将指定用于表的存储引擎

$this->db()->table( 'test', function( $table ) {
	$table->opt( 'engine', 'InnoDB' );
} );

作为快捷方式,也可以将选项设置为属性

$this->db()->table( 'test', function( $table ) {
	$table->engine = 'InnoDB';
} );

要创建一个临时表,使用

$this->db()->table( 'test', function( $table ) {
	$table->temporary = true;
} );

还可以设置字符串和文本列的默认charsetcollation

$this->db()->table( 'test', function( $table ) {
	$table->charset = 'utf8mb4';
	$table->collation = 'utf8mb4_unicode_ci';
} );

注意: PostgreSQL 和 SQL Server 也支持排序规则,但它们的值不同。因此,无法为所有服务器类型使用相同的值。为了避免这个问题,使用列 opt() 方法并将数据库服务器类型作为第三个参数传递。

$this->db()->table( 'test', function( $table ) {
	$table->opt( 'charset', 'utf8mb4', 'mysql' );
	$table->opt( 'collation', 'utf8mb4_unicode_ci', 'mysql' );
} );

现在,默认的 charsetcollation 将仅针对 MySQL 数据库服务器(或 MariaDB 和类似分支)设置。

如果需要知道表选项的当前值

$this->db()->table( 'test', function( $table ) {
	// return the used table engine (only MySQL, MariaDB, etc.)
	$engine = $table->engine;

	// returns TRUE if it's a temporary table
	$isTemp = $table->temporary;

	// return the current charset
	$charset = $table->charset;

	// return the current collation
	$collation = $table->collation;
} );

检查表存在性

要检查表是否已存在,请使用 hasTable() 方法

if( $this->db()->hasTable( 'users' ) ) {
    // The "users" table exists
}

您也可以一次检查多个表

if( $this->db()->hasTable( ['users', 'addresses'] ) ) {
    // The "users" and "addresses" tables exist
}

hasTable() 方法仅在所有表都存在时才返回 TRUE。

更改表

除了创建和访问表外,还可以使用模式对象的 table() 方法来更新表模式。它接受表名和一个闭包,该闭包将接收表模式对象。

首先创建一个名为 test 的表,包括三个列

$this->db()->table( 'test', function( $table ) {
	$table->id();
	$table->string( 'label' );
	$table->col( 'status', 'tinyint' )->default( 0 );
} );

现在,我们想在另一个迁移中更新表,添加一个 code 列并更改现有 status 列的默认值

$this->db()->table( 'test', function( $table ) {
	$table->string( 'code' );
	$table->col( 'status', 'tinyint' )->default( 1 );
} );

只要 table() 方法返回,更改就会被持久化到数据库中,因此不需要自己调用 up()。有关可用列类型和选项的信息,请参阅 列部分

重命名表

当使用 renameTable() 方法时,$this->db() 返回的数据库对象可以重命名表

// Renames the table "users" to "accounts"
$this->db()->renameTable( 'users', 'account' );

如果您传递一个包含旧名称和新名称作为键/值对的关联数组,也可以一次重命名多个表

// Renames the table "users" to "accounts" and "blog" to "posts"
$this->db()->renameTable( ['users' => 'account', 'blog' => 'posts'] );

删除表

要删除表,应使用数据库模式中的 dropTable() 方法

$this->db()->dropTable( 'users' );

您也可以通过传递数组来一次删除多个表

$this->db()->dropTable( ['users', 'addresses'] );

只有在表存在时才会删除表。如果表不再存在,不会报告错误

$this->db()->dropTable( 'notexist' );

在这种情况下,方法调用将成功,但不会发生任何操作。

表方法

Table::__call()

调用自定义方法或将未知方法调用传递给 Doctrine 表对象

public function __call( string $method, array $args )
  • @param string $method 方法名称
  • @param array<mixed> $args 方法参数
  • @return mixed 调用方法返回值

示例

您可以为具有访问 Upscheme 表对象类属性的自定义方法注册

\Aimeos\Upscheme\Schema\Table::macro( 'addConstraint', function( array $columns ) {
	return $this->to->addUniqueConstraint( $columns );
} );

$table->addConstraint( ['col1', 'col2'] );

可用的类属性包括

$this->table : Doctrine 表模式

$this->up : Upscheme对象

此外,您可以直接调用任何 Doctrine 表 方法,例如。

$table->addUniqueConstraint( ['col1', 'col2'] );

Table::__get()

返回给定表选项的值

public function __get( string $name )
  • @param string $name 表选项名称
  • @return mixed 表选项值

可用的表选项列表如下

  • charset (MySQL)
  • collation (MySQL)
  • engine (MySQL)
  • temporary (MySQL)

示例

$engine = $table->engine;

// same as
$engine = $table->opt( 'engine' );

Table::__set()

设置给定表选项的新值

public function __set( string $name, $value )
  • @param string $name 表选项名称
  • @param mixed 表选项值

可用的表选项列表如下

  • charset (MySQL)
  • collation (MySQL)
  • engine (MySQL)
  • temporary (MySQL)

示例

$table->engine = 'InnoDB';

// same as
$table->opt( 'engine', 'InnoDB' );

Table::bigid()

创建一个新的类型为 "bigint" 的 ID 列,或返回现有的 ID 列

public function bigid( string $name = null ) : Column
  • @param string|null $name ID 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

列会自动分配一个序列(自增)和主键。如果列尚不存在,则会创建。

示例

$table->bigid();
$table->bigid( 'uid' );

Table::bigint()

创建一个新的类型为 "bigint" 的列,或返回现有的列

public function bigint( string $name ) : Column
  • @param string $name 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建。

示例

$table->bigint( 'testcol' );

Table::binary()

创建一个新的类型为 "binary" 的列,或返回现有的列

public function binary( string $name, int $length = 255 ) : Column
  • @param string $name 列的名称
  • @param int $length 列的字节长度
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建。

示例

$table->binary( 'testcol' );
$table->binary( 'testcol', 32 );

Table::blob()

创建一个新的类型为 "blob" 的列,或返回现有的列

public function blob( string $name, int $length = 0x7fff ) : Column
  • @param string $name 列的名称
  • @param int $length 列的字节长度
  • @return \Aimeos\Upscheme\Schema\Column 列对象

"blob" 列的最大长度为 2GB。如果列尚不存在,则会创建。

示例

$table->blob( 'testcol' );
$table->blob( 'testcol', 0x7fffffff );

Table::bool()

创建一个新的类型为 "boolean" 的列,或返回现有的列

public function bool( string $name ) : Column
  • @param string $name 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

此方法是 boolean() 的别名。如果列尚不存在,则会创建。

示例

$table->bool( 'testcol' );

Table::boolean()

创建一个新的类型为 "boolean" 的列,或返回现有的列

public function boolean( string $name ) : Column
  • @param string $name 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建。

示例

$table->boolean( 'testcol' );

Table::char()

创建一个新的类型为 "char" 的列,或返回现有的列

public function char( string $name, int $length ) : Column
  • @param string $name 列的名称
  • @param int $length 列的字符长度
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建。

示例

$table->char( 'testcol', 3 );

Table::col()

创建一个新的列,或返回现有的列

public function col( string $name, string $type = null ) : Column
  • @param string $name 列的名称
  • @param string|null $type 列的类型
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建。

示例

$table->col( 'testcol' );
$table->col( 'testcol', 'tinyint' );

Table::date()

创建一个新的类型为 "date" 的列,或返回现有的列

public function date( string $name ) : Column
  • @param string $name 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建。

示例

$table->date( 'testcol' );

Table::datetime()

创建一个新的类型为 "datetime" 的列,或返回现有的列

public function datetime( string $name ) : Column
  • @param string $name 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建。

示例

$table->datetime( 'testcol' );

Table::datetimetz()

创建一个新的类型为 "datetimetz" 的列,或返回现有的列

public function datetimetz( string $name ) : Column
  • @param string $name 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建。

示例

$table->datetimetz( 'testcol' );

Table::decimal()

创建一个新的类型为 "decimal" 的列,或返回现有的列

public function decimal( string $name, int $digits, int $decimals = 2 ) : Column
  • @param string $name 列的名称
  • @param int $digits 包含小数在内的总小数位数
  • @param int $decimals 小数点后的位数
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建。

示例

$table->decimal( 'testcol', 10 ); // 10 digits incl. 2 decimals
$table->decimal( 'testcol', 10, 4 ); // 10 digits incl. 4 decimals

Table::dropColumn()

如果存在,则删除给定名称的列

public function dropColumn( $name ) : self
  • @param array<string>|string $name 列名称或列名称
  • @return self 同一对象,用于流畅的方法调用

如果列或列之一不存在,则将静默忽略。更改不会在迁移任务完成或调用 up() 之前应用。

示例

$table->dropColumn( 'testcol' );
$table->dropColumn( ['testcol', 'testcol2'] );

Table::dropIndex()

如果存在,则删除给定名称的索引

public function dropIndex( $name ) : self
  • @param array<string>|string $name 索引名称或索引
  • @return self 同一对象,用于流畅的方法调用

如果索引或索引之一不存在,则将静默忽略。更改不会在迁移任务完成或调用 up() 之前应用。

示例

$table->dropIndex( 'idx_test_col' );
$table->dropIndex( ['idx_test_col', 'idx_test_col2'] );

Table::dropForeign()

如果存在,则删除给定名称的外键约束

public function dropForeign( $name ) : self
  • @param array<string>|string $name 外键约束名称或约束
  • @return self 同一对象,用于流畅的方法调用

如果外键约束或约束之一不存在,则将静默忽略。更改不会在迁移任务完成或调用 up() 之前应用。

示例

$table->dropForeign( 'fk_test_col' );
$table->dropForeign( ['fk_test_col', 'fk_test_col2'] );

Table::dropPrimary()

如果存在主键,则将其删除

public function dropPrimary() : self
  • @return self 同一对象,用于流畅的方法调用

如果主键不存在,则将静默忽略。更改不会在迁移任务完成或调用 up() 之前应用。

示例

$table->dropPrimary();

Table::float()

创建一个新的类型为 "float" 的列,或返回现有的列

public function float( string $name ) : Column
  • @param string $name 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建。

示例

$table->float( 'testcol' );

Table::foreign()

创建一个新的外键,或返回现有的外键

public function foreign( $localcolumn, string $foreigntable, $foreigncolumn = 'id', string $name = null ) : Foreign
  • @param array<string>|string $localcolumn 本地列的名称或列
  • @param string $foreigntable 引用表的名称
  • @param array<string>|string $foreigncolumn 引用列的名称或列
  • @param string|null $name 外键约束和外键索引的名称,或为自动生成的名称
  • @return \Aimeos\Upscheme\Schema\Foreign 外键约束对象

外键名称的长度不应超过 30 个字符,以确保最大兼容性。

示例

$table->foreign( 'parentid', 'test' );
$table->foreign( 'parentid', 'test', 'uid' );
$table->foreign( 'parentid', 'test', 'id', 'fk_test_pid' );
$table->foreign( ['parentid', 'siteid'], 'test', ['uid', 'siteid'] );

Table::guid()

创建一个新的类型为 "guid" 的列,或返回现有的列

public function guid( string $name ) : Column
  • @param string $name 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建。

示例

$table->guid( 'testcol' );

Table::hasColumn()

检查列是否存在

public function hasColumn( $name ) : bool
  • @param array<string>|string $name 列名称或列名称
  • @return bool 如果列存在,则返回TRUE,如果不存在,则返回FALSE

示例

$table->hasColumn( 'testcol' );
$table->hasColumn( ['testcol', 'testcol2'] );

Table::hasIndex()

检查索引是否存在

public function hasIndex( $name ) : bool
  • @param array<string>|string $name 索引名称或索引
  • @return bool 如果索引存在,则为 TRUE,如果不存在,则为 FALSE

示例

$table->hasIndex( 'idx_test_col' );
$table->hasIndex( ['idx_test_col', 'idx_test_col2'] );

Table::hasForeign()

检查外键约束是否存在

public function hasForeign( $name ) : bool
  • @param array<string>|string $name 外键约束名称或约束
  • @return bool 如果外键约束存在,则为 TRUE,如果不存在,则为 FALSE

示例

$table->hasForeign( 'fk_test_col' );
$table->hasForeign( ['fk_test_col', 'fk_test_col2'] );

Table::id()

创建一个新的“整数”类型ID列或返回现有的一个

public function id( string $name = null ) : Column
  • @param string|null $name ID 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

列会自动分配一个序列(自增)和主键。如果列尚不存在,则会创建。

示例

$table->id();
$table->id( 'uid' );

Table::index()

创建一个新的索引或替换现有的一个

public function index( $columns, string $name = null ) : self
  • @param array<string>|string $columns 索引列的名称或生成索引的列
  • @param string|null $name 索引名称或NULL自动生成名称
  • @return self 同一对象,用于流畅的方法调用

索引名称的长度不应超过30个字符,以实现最大兼容性。

示例

$table->index( 'testcol' );
$table->index( ['testcol', 'testcol2'] );
$table->index( 'testcol', 'idx_test_testcol );

Table::int()

创建一个新的“整数”类型列或返回现有的一个

public function int( string $name ) : Column
  • @param string $name 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

此方法是对integer()的别名。如果列尚不存在,则会创建它。

示例

$table->int( 'testcol' );

Table::integer()

创建一个新的“整数”类型列或返回现有的一个

public function integer( string $name ) : Column
  • @param string $name 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建。

示例

$table->integer( 'testcol' );

Table::json()

创建一个新的“json”类型列或返回现有的一个

public function json( string $name ) : Column
  • @param string $name 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建。

示例

$table->json( 'testcol' );

Table::name()

返回表的名称

public function name() : string
  • @return string 表名称

示例

$tablename = $table->name();

Table::opt()

设置自定义模式选项或返回当前值

public function opt( string $name, $value = null )
  • @param string $name 与表相关的自定义模式选项名称
  • @param mixed $value 自定义模式选项的值
  • @return self|mixed 设置值时的相同对象,没有第二个参数时的当前值

可用的自定义模式选项包括

  • charset (MySQL)
  • collation (MySQL)
  • engine (MySQL)
  • temporary (MySQL)

示例

$charset = $table->opt( 'charset' );
$table->opt( 'charset', 'utf8' )->opt( 'collation', 'utf8_bin' );

// Magic methods:
$charset = $table->charset;
$table->charset = 'binary';

Table::primary()

创建一个新的主索引或替换现有的一个

public function primary( $columns, string $name = null ) : self
  • @param array<string>|string $columns 索引列的名称或生成索引的列
  • @param string|null $name 索引名称或NULL自动生成名称
  • @return self 同一对象,用于流畅的方法调用

索引名称的长度不应超过30个字符,以实现最大兼容性。

示例

$table->primary( 'testcol' );
$table->primary( ['testcol', 'testcol2'] );
$table->primary( 'testcol', 'pk_test_testcol' );

Table::renameColumn()

重命名列或列列表

public function renameColumn( $from, string $to = null ) : self
  • @param string,string数组 $from 列名或旧/新列名数组
  • @param string|null $to 如果第一个参数是数组,则忽略新列名
  • @return self 同一对象,用于流畅的方法调用
  • @throws \RuntimeException 如果发生错误

示例

// single column
$table->renameColumn( 'test_col', 'test_column' );

// rename several columns at once
$table->renameColumn( ['tcol' => 'testcol', 'tcol2' => 'testcol2'] );

Table::renameIndex()

重命名索引或索引列表

public function renameIndex( $from, string $to = null ) : self
  • @param array|string $from 索引名称或旧/新索引名称数组(如果新索引名称为NULL,则将自动生成)
  • @param string|null $to 新索引名称或NULL自动生成名称(如果第一个参数是数组,则忽略)
  • @return self 同一对象,用于流畅的方法调用

索引名称的长度不应超过30个字符,以实现最大兼容性。

示例

// generate a new name automatically
$table->renameIndex( 'test_col_index' );

// custom name
$table->renameIndex( 'test_col_index', 'idx_test_col' );

// rename several indexes at once
$table->renameIndex( ['test_col_index' => null, 'test_index' => 'idx_test_col'] );

Table::smallint()

创建一个新的“小整数”类型列或返回现有的一个

public function smallint( string $name ) : Column
  • @param string $name 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建。

示例

$table->smallint( 'testcol' );

Table::spatial()

创建一个新的空间索引或替换现有的一个

public function spatial( $columns, string $name = null ) : self
  • @param array|string $columns 索引列的名称或生成索引的列
  • @param string|null $name 索引名称或NULL自动生成名称
  • @return self 同一对象,用于流畅的方法调用

索引名称的长度不应超过30个字符,以实现最大兼容性。

示例

$table->spatial( 'testcol' );
$table->spatial( ['testcol', 'testcol2'] );
$table->spatial( 'testcol', 'idx_test_testcol' );

Table::string()

创建一个新的“字符串”类型列或返回现有的一个

public function string( string $name, int $length = 255 ) : Column
  • @param string $name 列的名称
  • @param int $length 列的字符长度
  • @return \Aimeos\Upscheme\Schema\Column 列对象

此类型应用于最多255个字符。对于更多字符,请使用“text”类型。如果列尚不存在,则会创建它。

示例

$table->string( 'testcol' );
$table->string( 'testcol', 32 );

Table::text()

创建一个新的“文本”类型列或返回现有的一个

public function text( string $name, int $length = 0xffff ) : Column
  • @param string $name 列的名称
  • @param int $length 列的字符长度
  • @return \Aimeos\Upscheme\Schema\Column 列对象

“文本”列的最大长度为2GB。如果列尚不存在,则会创建它。

示例

$table->text( 'testcol' );
$table->text( 'testcol', 0x7fffffff );

Table::time()

创建一个新的“时间”类型列或返回现有的一个

public function time( string $name ) : Column
  • @param string $name 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

如果列尚不存在,则会创建它。此数据类型在使用Oracle数据库时不可用。

示例

$table->time( 'testcol' );

Table::unique()

创建一个新的唯一索引或替换现有的一个

public function unique( $columns, string $name = null ) : self
  • @param array|string $columns 索引列的名称或生成索引的列
  • @param string|null $name 索引名称或NULL自动生成名称
  • @return self 同一对象,用于流畅的方法调用

索引名称的长度不应超过30个字符,以实现最大兼容性。

示例

$table->unique( 'testcol' );
$table->unique( ['testcol', 'testcol2'] );
$table->unique( 'testcol', 'unq_test_testcol' );

Table::uuid()

创建一个新的类型为 "guid" 的列,或返回现有的列

public function uuid( string $name ) : Column
  • @param string $name 列的名称
  • @return \Aimeos\Upscheme\Schema\Column 列对象

此方法是对guid()的别名。如果列尚不存在,则会创建它。

示例

$table->uuid( 'testcol' );

Table::up()

将更改应用到数据库模式

public function up() : self
  • @return self 同一对象,用于流畅的方法调用

示例

$table->up();

添加列

在迁移任务中调用col()方法获得的列模式对象为您提供了访问所有列属性的方法。对于所有数据库都支持的列类型,也提供了快捷方式。每个列可以通过一个或多个修饰方法进行更改,您还可以为单个列添加索引,例如

$this->db()->table( 'test', function( $table ) {
	$table->id()->unsigned( true );
	$table->string( 'label' )->index();
	$table->col( 'status', 'tinyint' )->default( 0 );
} );

以下示例将添加以下列

  • id类型为整数,无符号修饰符
  • label类型为字符串,255个字符,并带有索引
  • status类型为tinyint(仅MySQL),默认值为零

可用的列类型

所有数据库服务器实现中都提供了一些列类型的快捷方法

要添加特定于数据库的列类型,请使用col()方法,例如

$this->db()->table( 'test', function( $table ) {
	$table->col( 'status', 'tinyint' );
} );

列修饰符

还可以通过调用一个或多个列修改方法来更改列定义

$this->db()->table( 'test', function( $table ) {
	$table->int( 'number' )->null( true )->unsigned( true );
} );

可用的列修改方法有

要为列设置自定义模式选项,请使用opt()方法,例如:

$this->db()->table( 'test', function( $table ) {
	$table->string( 'code' )->opt( 'collation', 'utf8mb4' );
} );

甚至可以通过传递数据库类型作为第三个参数来为特定的数据库实现设置列修饰符

$this->db()->table( 'test', function( $table ) {
	$table->string( 'code' )->opt( 'collation', 'utf8mb4', 'mysql' );
} );

检查列存在性

要检查列是否已存在,请使用hasColumn()方法

if( $this->db()->hasColumn( 'users', 'name' ) ) {
    // The "name" column in the "users" table exists
}

您也可以同时检查多个列。在这种情况下,hasColumn()方法仅在所有列都存在时才返回TRUE

if( $this->db()->hasColumn( 'users', ['name', 'status'] ) ) {
    // The "name" and "status" columns in the "users" table exists
}

如果您已经有了表对象,您也可以使用hasColumn()

if( $table->hasColumn( 'name' ) ) {
    // The "name" column in the table exists
}

if( $table->hasColumn( ['name', 'status'] ) ) {
    // The "name" and "status" columns in the table exists
}

除了列之外,您还可以检查是否设置了列修饰符以及它们的值

if( $table->string( 'code' )->null() ) {
	// The "code" columns is nullable
}

使用这些方法可以检索当前列修饰符的值

要检查非标准列修饰符,请使用不带第二个参数的opt()方法。然后,它将返回列修饰符的当前值

if( $table->string( 'code' )->opt( 'charset' ) === 'utf8' ) {
	// The "code" columns uses UTF-8 charset (MySQL only)
}

更改列

可以更改大多数列修饰符,如字符串列的长度

$this->db()->table( 'test', function( $table ) {
	$table->string( 'code' )->length( 64 );
} );

一些方法还提供额外的参数,可以直接设置最常用的修饰符

$this->db()->table( 'test', function( $table ) {
	$table->string( 'code', 64 );
} );

如果您需要立即更改列修饰符,因为您想在之后迁移行,请使用up()方法来持久化更改

$this->db()->table( 'test', function( $table ) {
	$table->string( 'code', 64 )->null( true )->up();
	// modify rows from "test" table
} );

可以通过使用适用于该类型的新方法或col()方法来更改列类型

$this->db()->table( 'test', function( $table ) {
	$table->text( 'code' );
	// or
	$table->col( 'code', 'text' );
} );

请注意,并非所有列类型都可以转换为另一种类型,或者至少不能不丢失数据。可以将 INTEGER 列更改为 BIGINT 列而不会出现问题,但反过来将失败。如果您想将 VARCHAR 列(字符串)更改为 INTEGER 列,也会发生相同的情况。

重命名列

如果已经存在表对象,您可以使用其renameColumn()方法重命名一个或多个列

$this->db()->table( 'testtable', function( $table ) {
	// single column
	$table->renameColumn( 'label', 'name' );

	// multiple columns
	$table->renameColumn( ['label' => 'name', 'stat' => 'status'] );
} );

还可以直接使用 DB 模式renameColumn()方法重命名列

// single column
$this->db()->renameColumn( 'testtable', 'label', 'name' );

// multiple columns
$this->db()->renameColumn( 'testtable', ['label' => 'name', 'stat' => 'status'] );

删除列

要删除列,请使用 DB 模式对象中的dropColumn()方法

$this->db()->dropColumn( 'users', 'name' );

如果您传递了要删除的所有列的名称作为数组,则可以一次删除多个列

$this->db()->dropColumn( 'users', ['name', 'status'] );

如果您已经有了表对象,您也可以使用dropColumn()

// single column
$table->dropColumn( 'name' );

// multiple columns
$table->dropColumn( ['name', 'status'] );

在所有情况下,如果列存在,则才会删除。如果表中不存在一个或多个列,则不会报告错误。

列方法

Column::__call()

调用自定义方法或将未知方法调用传递给 Doctrine 列对象

public function __call( string $method, array $args )
  • @param string $method 方法名称
  • @param array<mixed> $args 方法参数
  • @return mixed 调用方法返回值

示例

您可以注册自定义方法,这些方法可以访问 Upscheme 列对象的类属性

\Aimeos\Upscheme\Schema\Column::macro( 'platform', function( array $options ) {
	return $this->to->setPlatformOptions( $options );
} );

$column->platform( ['option' => 'value'] );

可用的类属性包括

$this->db : Upscheme DB 对象

$this->table : Doctrine 表模式

$this->column : Doctrine 列模式

此外,您可以直接调用任何 Doctrine 列 方法,例如:

$column->setPlatformOptions( ['option' => 'value'] );

Column::__get()

返回给定列选项的值

public function __get( string $name )
  • @param string $name 列选项名称
  • @return mixed 列选项值

可用的列选项列表如下:

  • charset (MySQL)
  • collation(MySQL、PostgreSQL、Sqlite 和 SQL Server)
  • check
  • unique(所有)

示例

$charset = $column->charset;

// same as
$charset = $column->opt( 'charset' );

Column::__set()

设置给定列选项的新值

public function __set( string $name, $value )
  • @param string $name 列选项名称
  • @param mixed $value 列选项值

可用的列选项列表如下:

  • charset (MySQL)
  • collation(MySQL、PostgreSQL、Sqlite 和 SQL Server)
  • check
  • unique(所有)

示例

$column->charset = 'utf8';

// same as
$column->opt( 'charset', 'utf8' );

Column::autoincrement()

将列设置为自增或返回当前值

public function autoincrement( bool $value = null )
  • @param bool|null $value 新的自增标志或 NULL 返回当前值
  • @return self|bool 设置值的相同对象,带参数的当前值

此方法是对 seq() 方法的别名。

示例

$value = $column->autoincrement();
$column->autoincrement( true );

Column::charset()

设置列字符集或返回当前值

public function charset( string $value = null )
  • @param string|null $value 新的列字符集或 NULL 返回当前值
  • @return self|string 设置值的相同对象,不带参数的当前值

示例

$comment = $column->charset();
$column->charset( 'utf8' );

Column::collation()

设置列校对或返回当前值

public function collation( string $value = null )
  • @param string|null $value 新的列校对或 NULL 返回当前值
  • @return self|string 设置值的相同对象,不带参数的当前值

示例

$comment = $column->collation();
$column->collation( 'binary' );

Column::comment()

设置列注释或返回当前值

public function comment( string $value = null )
  • @param string|null $value 新的列注释或 NULL 返回当前值
  • @return self|string 设置值的相同对象,不带参数的当前值

示例

$comment = $column->comment();
$column->comment( 'column comment' );

Column::default()

设置列默认值或返回当前值

public function default( $value = null )
  • @param mixed $value 新的列默认值或 NULL 返回当前值
  • @return self|mixed 设置值的相同对象,不带参数的当前值

示例

$value = $column->default();
$column->default( 0 );

Column::fixed()

设置列固定标志或返回当前值

public function fixed( bool $value = null )
  • @param bool|null $value 新的列固定标志或 NULL 返回当前值
  • @return self|bool 设置值的相同对象,带参数的当前值

示例

$value = $column->fixed();
$column->fixed( true );

Column::index()

为列创建常规索引

public function index( string $name = null ) : self
  • @param string|null $name 索引名称或 NULL 自动生成
  • @return self 同一对象,用于流畅的方法调用

示例

$column->index();
$column->index( 'idx_col' );

Column::length()

设置列长度或返回当前值

public function length( int $value = null )
  • @param int|null $value 新的列长度或 NULL 返回当前值
  • @return self|int 设置值的相同对象,不带参数的当前值

示例

$value = $column->length();
$column->length( 32 );

Column::name()

返回列名称

public function name() : string
  • @return string 列名称

示例

$name = $column->name();

Column::null()

设置列空标志或返回当前值

public function null( bool $value = null )
  • @param bool|null $value 新的列空标志或 NULL 返回当前值
  • @return self|bool 设置值的相同对象,带参数的当前值

示例

$value = $column->null();
$column->null( true );

Column::opt()

设置列选项值或返回当前值

public function opt( string $option, $value = null, $for = null )
  • @param string $option 列选项名称
  • @param mixed $value 新的列选项值或 NULL 返回当前值
  • @param array<string>|string|null $for 此选项应使用的数据库类型("mysql"、"postgresql"、"sqlite"、"mssql"、"oracle"、"db2")
  • @return self|mixed 设置值的相同对象,不带参数的当前值

示例

$value = $column->opt( 'length' );
$column->opt( 'length', 64 );

Column::precision()

设置列精度或返回当前值

public function precision( int $value = null )
  • @param int|null $value 新的列精度值或 NULL 返回当前值
  • @return self|int 设置值的相同对象,不带参数的当前值

示例

$value = $column->precision();
$column->precision( 10 );

Column::primary()

为列创建主索引

public function primary( string $name = null ) : self
  • @param string|null $name 索引名称或 NULL 自动生成
  • @return self 同一对象,用于流畅的方法调用

示例

$column->primary();
$column->primary( 'pk_col' );

Column::scale()

设置列刻度或返回当前值

public function scale( int $value = null )
  • @param int|null $value 新的列刻度值或 NULL 返回当前值
  • @return self|int 设置值的相同对象,不带参数的当前值

示例

$value = $column->scale();
$column->scale( 3 );

Column::seq()

将列设置为自增或返回当前值

public function seq( bool $value = null )
  • @param bool|null $value 新的自增标志或 NULL 返回当前值
  • @return self|bool 设置值的相同对象,带参数的当前值

示例

$value = $column->seq();
$column->seq( true );

Column::spatial()

为列创建空间索引

public function spatial( string $name = null ) : self
  • @param string|null $name 索引名称或 NULL 自动生成
  • @return self 同一对象,用于流畅的方法调用

示例

$column->spatial();
$column->spatial( 'idx_col' );

Column::type()

设置列类型或返回当前值

public function type( string $value = null )
  • @param string|null $value 新的列类型或 NULL 返回当前值
  • @return self|string 设置值的相同对象,不带参数的当前值

示例

$value = $column->type();
$column->type( 'tinyint' );

Column::unique()

为列创建唯一索引

public function unique( string $name = null ) : self
  • @param string|null $name 索引名称或 NULL 自动生成
  • @return self 同一对象,用于流畅的方法调用

示例

$column->unique();
$column->unique( 'unq_col' );

Column::unsigned()

设置列无符号标志或返回当前值

public function unsigned( bool $value = null )
  • @param bool|null $value 新的列无符号标志或NULL以返回当前值
  • @return self|bool 设置值的相同对象,带参数的当前值

示例

$value = $column->unsigned();
$column->unsigned( true );

Column::up()

将更改应用到数据库模式

public function up() : self
  • @return self 同一对象,用于流畅的方法调用

示例

$column->up();

外键

创建外键

Upscheme提供了对外键约束的支持,该约束强制两个表之间数据的完整性。例如,如果users_address表的parentid列引用了users表的id列,则users_address表中不能有在users表中没有匹配行的行。调用foreign()方法将创建此类约束

$this->db()->table( 'users', function( $table ) {
	$table->id();
} );

$this->db()->table( 'users_address', function( $table ) {
	$table->foreign( 'parentid', 'users' );
} );

注意:列(parentid)必须具有与引用列(id)相同的数据类型和列修饰符。foreign()方法将确保这一点,并会自动创建一个与外键约束同名的索引。

如果users表的ID列名称不同,请将它的名称作为foreign()方法的第三个参数传递

$this->db()->table( 'users_address', function( $table ) {
	$table->foreign( 'parentid', 'users', 'uid' );
} );

建议传递外键约束的名称作为第四个参数,这样以后更改或删除约束会更方便

$this->db()->table( 'users_address', function( $table ) {
	$table->foreign( 'parentid', 'users', 'id', 'fk_test_pid' );
} );

如果需要多个列来获取外键所需的不同值,请将列名称作为数组传递

$this->db()->table( 'users_address', function( $table ) {
	$table->foreign( ['parentid', 'siteid'], 'users_address', ['id', 'siteid'] );
} );

如果引用表中的引用列被删除或更新,外键约束可以执行不同的操作。标准操作是限制删除行或更新引用ID值。要更改行为,请使用onDelete()onUpdate()方法

$this->db()->table( 'users_address', function( $table ) {
	$table->foreign( 'parentid', 'users' )->onDelete( 'SET NULL' )->onUpdate( 'RESTRICT' );
} );

如果您想设置两个值相同,则有一个快捷方式

$this->db()->table( 'users_address', function( $table ) {
	$table->foreign( 'parentid', 'users' )->do( 'SET NULL' );
} );

两种方法的可能值是

  • CASCADE:更新引用值
  • NO ACTION:不更改引用值(与RESTRICT相同)
  • RESTRICT:禁止更改值
  • SET DEFAULT:将引用值设置为默认值
  • SET NULL:将引用值设置为NULL

删除或更新行时的默认操作是CASCADE,因此外键列的值将更新为外键表中相同的值。

检查外键存在性

要检查是否存在外键,请使用hasForeign()方法

if( $this->db()->hasForeign( 'users_address', 'fk_usrad_parentid' ) ) {
    // The "fk_usrad_parentid" foreign key in the "users_address" table exists
}

也可以一次性检查多个外键约束。在这种情况下,hasForeign()方法只有在第一个参数传递的表中所有约束都存在时才会返回TRUE

if( $this->db()->hasForeign( 'users_address', ['fk_usrad_parentid', 'fk_usrad_siteid'] ) ) {
    // The "fk_usrad_parentid" and "fk_usrad_siteid" foreign keys exist in the "users_address" table
}

如果有一个表对象可用,则可以使用表的hasForeign()方法代替

$this->db()->table( 'users_address', function( $table ) {
	$table->hasForeign( 'fk_usrad_parentid' ) ) {
	    // The "fk_usrad_parentid" foreign key in the "users_address" table exists
	}
} );

$this->db()->table( 'users_address', function( $table ) {
	$table->hasForeign( ['fk_usrad_parentid', 'fk_usrad_siteid'] ) ) {
	    // The "fk_usrad_parentid" and "fk_usrad_siteid" foreign keys exist in the "users_address" table
	}
} );

如果需要现有约束的当前值

$this->db()->table( 'users_address', function( $table ) {
	$fk = $table->foreign( 'parentid', 'users' );

	// returns the name of the constraint
	$name = $fk->name()

	// returns the action when deleting rows
	$action = $fk->onDelete;

	// returns the action when updating the foreign ID
	$action = $fk->onUpdate;
} );

删除外键

要从表中删除外键约束,请使用dropForeign()方法,并传递表名和外键名称作为参数

$this->db()->dropForeign( 'users_address', 'fk_usrad_parentid' );

您也可以传递多个外键名称以一次性删除它们

$this->db()->dropForeign( 'users_address', ['fk_usrad_parentid', 'fk_usrad_siteid'] );

在传递给table()方法的匿名函数中,您还可以使用dropForeign()方法

$this->db()->table( 'users_address', function( $table ) {
	$table->dropForeign( 'fk_usrad_parentid' );
} );

$this->db()->table( 'users_address', function( $table ) {
	$table->dropForeign( ['fk_usrad_parentid', 'fk_usrad_siteid'] );
} );

外键方法

外键

Foreign::__call()

调用自定义方法

public function __call( string $method, array $args )
  • @param string $method 方法名称
  • @param array<mixed> $args 方法参数
  • @return mixed 调用方法返回值

示例

您可以注册具有访问Upscheme Foreign对象类属性的定制方法

\Aimeos\Upscheme\Schema\Foreign::macro( 'default', function() {
	$this->opts = ['onDelete' => 'SET NULL', 'onUpdate' => 'SET NULL'];
} );

$foreign->default();

可用的类属性包括

$this->dbaltable : Doctrine表模式

$this->table : Upscheme表对象

$this->localcol : 本地列名或名称

$this->fktable : 外部表名

$this->fkcol : 外部列名或名称

$this->name : 外键名称

$this->opts : 外键选项的关联列表(主要是"onDelete"和"onUpdate")

Foreign::__get()

返回给定外键选项的值

public function __get( string $name )
  • @param string $name 外键选项名称
  • @return mixed 外键选项值

可用的外键选项列表:

  • onDelete
  • onUpdate

这两个选项的可能值是:

  • CASCADE:更新引用值
  • NO ACTION:不更改引用值(与RESTRICT相同)
  • RESTRICT:禁止更改值
  • SET DEFAULT:将引用值设置为默认值
  • SET NULL:将引用值设置为NULL

示例

$value = $foreign->onDelete;
// same as
$value = $foreign->opt( 'onDelete' );

Foreign::__set()

设置给定外键选项的新值

public function __set( string $name, $value )
  • @param string $name 外键选项名称
  • @param mixed 外键选项值

可用的外键选项列表:

  • onDelete
  • onUpdate

这两个选项的可能值是:

  • CASCADE:更新引用值
  • NO ACTION:不更改引用值(与RESTRICT相同)
  • RESTRICT:禁止更改值
  • SET DEFAULT:将引用值设置为默认值
  • SET NULL:将引用值设置为NULL

示例

$foreign->onDelete = 'SET NULL';
// same as
$foreign->onDelete( 'SET NULL' );
$foreign->opt( 'onDelete', 'SET NULL' );

Foreign::do()

设置给定外键选项的新值

public function do( string $action ) : self
  • @param string $action 执行的操作
  • @return self 同一对象,用于流畅的方法调用

可能的操作有:

  • CASCADE : 删除或更新引用值
  • NO ACTION:不更改引用值(与RESTRICT相同)
  • RESTRICT:禁止更改值
  • SET DEFAULT:将引用值设置为默认值
  • SET NULL:将引用值设置为NULL

示例

$foreign->do( 'RESTRICT' );

Foreign::name()

  • 返回外键约束的当前名称
public function name()
  • @return string|null 约束名称或不可用时的NULL

示例

$fkname = $foreign->name();

Foreign::onDelete()

  • 设置引用行被删除时的操作或返回当前值
public function onDelete( string $value = null )
  • @param string|null $value 执行的操作或NULL以返回当前值

  • @return self|string 设置值的相同对象,不带参数的当前值

  • 可用的操作有:

    • CASCADE : 删除引用值
    • NO ACTION : 不更改引用值
    • RESTRICT:禁止更改值
    • SET DEFAULT:将引用值设置为默认值
    • SET NULL:将引用值设置为NULL

示例

$value = $foreign->onDelete();

$foreign->onDelete( 'SET NULL' );
// same as
$foreign->onDelete = 'SET NULL';
// same as
$foreign->opt( 'onDelete', 'SET NULL' );

$foreign->onDelete( 'SET NULL' )->onUpdate( 'SET NULL' );

Foreign::onUpdate()

  • 设置引用行更新时的操作或返回当前值
public function onUpdate( string $value = null )
  • @param string|null $value 执行的操作或NULL以返回当前值

  • @return self|string 设置值的相同对象,不带参数的当前值

  • 可用的操作有:

    • CASCADE:更新引用值
    • NO ACTION : 不更改引用值
    • RESTRICT:禁止更改值
    • SET DEFAULT:将引用值设置为默认值
    • SET NULL:将引用值设置为NULL

示例

$value = $foreign->onUpdate();

$foreign->onUpdate( 'SET NULL' );
// same as
$foreign->onUpdate = 'SET NULL';
// same as
$foreign->opt( 'onUpdate', 'SET NULL' );

$foreign->onUpdate( 'SET NULL' )->onDelete( 'SET NULL' );

Foreign::up()

  • 将更改应用到数据库模式
public function up() : self
  • @return self 同一对象,用于流畅的方法调用

示例

$foreign->up();

序列

添加序列

一些数据库实现提供序列而不是自增/标识列,例如Oracle和PostgreSQL。序列是创建按顺序递增的数字的函数,当插入新行时应用于表列。要创建名为seq_test的新序列,请使用sequence()方法

$this->db()->sequence( 'seq_test' );

要使用不同于1的不同起始值和步长,请调用start()step()方法

$this->db()->sequence( 'seq_test', function( $seq ) {
	$seq->start( 1000 )->step( 2 );
} );

检查序列存在性

要检查序列是否存在,请使用hasSequence()方法

if( $this->db()->hasSequence( 'seq_test' ) ) {
    // The "seq_test" sequence exists
}

也可以一次性检查多个序列。此时,hasSequence()方法将仅在所有序列都存在时返回TRUE

if( $this->db()->hasSequence( ['seq_id', 'seq_test'] ) ) {
    // The "seq_id" and "seq_test" sequences exist
}

如果需要知道表选项的当前值

$this->db()->sequence( 'seq_test', function( $seq ) {
	// returns how many generated numbers are cached
	$cache = $seq->cache;

	// returns the number the sequence has started from
	$start = $seq->start;

	// returns the step width for newly generated numbers
	$step = $seq->step;
} );

删除序列

要删除序列,请使用dropSequence()方法,并传递序列名称作为参数

$this->db()->dropSequence( 'seq_id' );

也可以传递多个序列名称,一次性删除它们

$this->db()->dropSequence( ['seq_id', 'seq_test'] );

序列方法

序列

Sequence::__call()

调用自定义方法或将未知方法调用传递给 Doctrine 表对象

public function __call( string $method, array $args )
  • @param string $method 方法名称
  • @param array<mixed> $args 方法参数
  • @return mixed 调用方法返回值

示例

您可以注册具有访问Upscheme Sequence对象类属性的定制方法

\Aimeos\Upscheme\Schema\Sequence::macro( 'default', function() {
	$this->start( 1 )->step( 2 );
} );

$sequence->default();

可用的类属性包括

$this->db : Upscheme DB 对象

$this->sequence : Doctrine序列模式

Sequence::__get()

返回给定序列选项的值

public function __get( string $name )
  • @param string $name 序列选项名称
  • @return mixed 序列选项值

示例

$value = $sequence->getInitialValue();
// same as
$value = $sequence->start();

Sequence::__set()

设置给定序列选项的新值

public function __set( string $name, $value )
  • @param string $name 序列选项名称
  • @param mixed 序列选项值

示例

$value = $sequence->setInitialValue( 1000 );
// same as
$value = $sequence->start( 1000 );

Sequence::cache()

设置序列的缓存大小或返回当前值

public function cache( int $value = null )
  • @param int $value 客户端缓存的序列ID新数量或NULL返回当前值
  • @return self|int 设置值时的相同对象,带参数时的当前值

示例

$value = $sequence->cache();
$sequence->cache( 100 );

Sequence::name()

返回序列的名称

public function name()
  • @return string 序列名称
$name = $sequence->name();

Sequence::start()

设置序列的新起始值或返回当前值

public function start( int $value = null )
  • @param int $value 序列的新起始值或NULL返回当前值
  • @return self|int 设置值时的相同对象,带参数时的当前值
$value = $sequence->start();
$sequence->start( 1000 );

Sequence::step()

设置新序列值的步长或返回当前值

public function step( int $value = null )
  • @param int $value 序列增加或减少的新步长或NULL返回当前值
  • @return self|int 设置值时的相同对象,带参数时的当前值
$value = $sequence->step();
$sequence->step( 2 );

Sequence::up()

将更改应用到数据库模式

public function up() : self
  • @return self 同一对象,用于流畅的方法调用
$sequence->up();

索引

索引可以加快数据库查询速度,如果使用得当,查询所需时间可以从几分钟缩短到毫秒。有几种索引类型可供选择

  • primary:所有值都必须唯一,不允许NULL值,每个表中只允许一个索引
  • unique:值必须唯一,但允许NULL值(且可以多次出现)
  • index:标准索引,无限制
  • spatial:在坐标系统(如地理地图)中的快速查找

所有索引可以由一个或多个列组成,但如果用于查询,列的顺序有很大的影响。

添加索引

所有索引都绑定到包含索引列的表。创建单个列的索引的最简单方法是使用列对象的index()方法

$this->db()->table( 'test', function( $table ) {
	$table->string( 'label' )->index();
} );

index()方法的第二个参数允许您为索引设置自定义名称

$this->db()->table( 'test', function( $table ) {
	$table->string( 'label' )->index( 'idx_test_label' );
} );

注意:为了在不同数据库类型之间实现最大兼容性,索引名称的长度应为30个字符或更短。

对于主索引、唯一索引和空间索引也是如此

$this->db()->table( 'test', function( $table ) {
	// primary key
	$table->int( 'id' )->primary();
	$table->int( 'id' )->primary( 'pk_test_id' ); // ignored by MySQL, MariaDB, etc.

	// unique key
	$table->string( 'code' )->unique();
	$table->string( 'code' )->unique( 'unq_test_code' );

	// spatial index
	$table->col( 'location', 'point' )->spatial();
	$table->col( 'location', 'point' )->spatial( 'idx_test_location' );
} );

对于多列索引,表对象提供了primary()unique()index()方法

$this->db()->table( 'test', function( $table ) {
	// primary composite index
	$table->primary( ['siteid', 'code'] );

	// unique composite index
	$table->unique( ['parentid', 'type'] );

	// regular composite index
	$table->index( ['label', 'status'] );
} );

空间索引不能跨越多列,但也可以使用表对象的spatial()方法创建它们

$this->db()->table( 'test', function( $table ) {
	$table->spatial( 'location' );
} );

检查索引存在性

要检查索引是否已存在,请使用hasIndex()方法

if( $this->db()->hasIndex( 'users', 'idx_users_name' ) ) {
    // The "idx_users_name" index in the "users" table exists
}

您也可以一次检查多个索引。在这种情况下,如果所有索引都存在,则hasIndex()方法将仅返回TRUE

if( $this->db()->hasIndex( 'users', ['idx_users_name', 'idx_users_status'] ) ) {
    // The "idx_users_name" and "idx_users_status" indexes in the "users" table exists
}

如果您已经有了表对象,您也可以使用hasIndex()

if( $table->hasIndex( 'idx_users_name' ) ) {
    // The "idx_users_name" index in the table exists
}

if( $table->hasIndex( ['idx_users_name', 'idx_users_status'] ) ) {
    // The "idx_users_name" and "idx_users_status" indexes in the table exists
}

重命名索引

要直接重命名索引,请使用DB模式对象的renameIndex()方法

// single index
$this->db()->renameIndex( 'testtable', 'idx_test_label', 'idx_test_name' );

// multiple indexes
$this->db()->renameIndex( 'testtable', ['idx_test_label' => 'idx_test_name', 'idx_text_stat' => 'idx_test_status'] );

如果已经存在表对象,您也可以使用其renameIndex()方法重命名一个或多个索引

$this->db()->table( 'test', function( $table ) {
	// single index
	$table->renameIndex( 'idx_test_label', 'idx_test_name' );

	// multiple indexes
	$table->renameIndex( ['idx_test_label' => 'idx_test_name', 'idx_text_stat' => 'idx_test_status'] );
} );

删除索引

要删除索引,请使用DB模式对象的dropIndex()方法

$this->db()->dropIndex( 'users', 'idx_test_name' );

如果您传递要删除的所有索引名称的数组,您可以一次删除多个索引

$this->db()->dropIndex( 'users', ['idx_test_name', 'idx_test_status'] );

如果您已经有了表对象,您也可以使用dropIndex()

// single index
$table->dropIndex( 'idx_test_name' );

// multiple indexes
$table->dropIndex( ['idx_test_name', 'idx_test_status'] );

在任何情况下,如果索引存在,则才会删除。如果表中不存在一个或多个索引,则不会报告错误。

自定义索引命名

在创建新索引时,无需传递自定义索引名称。此时,索引名称将自动生成,但其名称将包含一个难以阅读的哈希值。此外,您也无法从索引名称中知道索引跨越哪些列。

Upscheme 允许您为索引添加自己的命名函数,如果未传递索引名称到创建索引的方法,则使用该命名函数。在运行迁移之前,请使用表格对象中的 macro() 方法注册您的命名函数。

use \Aimeos\Upscheme\Schema\Table;

Table::marco( 'nameIndex', function( string $table, array $columns, string $type ) {
	return $type . '_' . $table . '_' . join( '_', $columns );
} );

\Aimeos\Upscheme\Up::use( $config, './migrations/' )->up()

对于名为 "testtable" 的表,列 "label" 和类型 "idx",这将返回 idx_testtable_label 而不是哈希值。

可用的索引类型有

  • idx : 普通和空间索引
  • fk : 外键索引
  • pk : 主键索引
  • unq : 唯一索引

注意:为了与所有支持的数据库类型兼容,索引名称的最大长度必须不超过 30 个字符!

自定义Upscheme

添加自定义方法

您可以使用 macro() 方法向所有 Upscheme 对象添加新方法。每个自定义方法都可以访问其注册的类属性和方法,包括 Doctrine DBAL 对象。

要在 DB 模式对象中注册一个名为 test() 的方法,该方法有两个参数 $arg1$arg2,并且可以访问与 DB __call() 方法相同的类属性,请使用以下方法:

\Aimeos\Upscheme\Schema\DB::marco( 'test', function( $arg1, $arg2 ) {
	// $this->conn : Doctrine connection
	// $this->from : Doctrine start schema
	// $this->to : Doctrine current schema
	// $this->up : Upscheme object
	// return $this or a value
} );

$db->test( 'key', 'value' );

在 Table 模式对象中注册一个名为 test() 的方法,该方法有一个参数 $arg1,并且可以访问与 Table __call() 方法相同的类属性。

\Aimeos\Upscheme\Schema\Table::marco( 'test', function( $arg1 ) {
	// $this->db : Upscheme DB object
	// $this->table : Doctrine Table object
	// return $this or a value
} );

$table->test( 'something' );

同样,对于 Column 模式对象中的 test() 方法,有一个可选参数 $value,并且可以访问与 Column __call() 方法相同的类属性。

\Aimeos\Upscheme\Schema\Column::marco( 'test', function( $value = null ) {
	// $this->db : Upscheme DB object
	// $this->table : Upscheme Table object
	// $this->column : Doctrine Column object
	// return $this or a value
} );

$column->test();

要扩展 Foreign 对象以使用具有无参数的 test() 方法,并且可以访问与 Foreign __call() 方法相同的类属性。

\Aimeos\Upscheme\Schema\Foreign::marco( 'test', function() {
	// $this->table : Upscheme Table object
	// $this->dbaltable : Doctrine Table object
	// $this->localcol : Array of local column names
	// $this->fktable : Foreign table name
	// $this->fkcol : Foreign table column names
	// $this->name : Foreign key name
	// $this->opts : Array of foreign key options ("onDelete" and "onUpdate")
	// return $this or a value
} );

$foreign->test();

最后,扩展 Sequence 对象以使用无参数的 test() 方法,并且可以访问与 Sequence __call() 方法相同的类属性。

\Aimeos\Upscheme\Schema\Sequence::marco( 'test', function() {
	// $this->db : Upscheme DB object
	// $this->sequence : Doctrine Sequence object
	// return $this or a value
} );

$sequence->test();

实现自定义列

您无需每次都调用 Table 对象的 col() 方法并传递所有参数和修饰符,而是可以创建自己的快捷方法,例如:

\Aimeos\Upscheme\Schema\Table::marco( 'utinyint', function( string $name ) {
	return $this->col( $name, 'tinyint' )->unsigned( true );
} );

如果您想将它们添加到多个表中,也可以一次性创建多个列。

\Aimeos\Upscheme\Schema\Table::marco( 'defaults', function() {
	$this->id();
	$this->datetime( 'ctime' );
	$this->datetime( 'mtime' );
	$this->string( 'editor' );
	return $this;
} );

然后,在创建或更新表时使用您自定义的方法。

$this->db()->table( 'test', function( $table ) {
	$table->defaults();
	$table->utinyint( 'status' );
} );