管理 Schema

我们已经看了一些可用于与数据交互的新方法。 当然,在一些特定情况下,可能需要直接与数据库进行交互。

数据库适配器

XF2 中默认的数据库适配器是基于 MySQL 和 PHP 的 mysqli 扩展。 在任何 XF 类中都可以使用以下方法访问设置的数据库适配器:

$db = \XF::db();

适配器有许多可用的方法,这些方法将运行一个 SQL 查找,然后将结果格式化为一个数组。 例如,要访问一个用户记录:

$db = \XF::db();
$user = $db->fetchRow('SELECT * FROM xf_user WHERE user_id = ?', 1);

$user 变量现在将包含一个数组,其中包含查找结果集中第一行的所有值。 要想从该查找中获得単一的值,例如用户名,可以运行以下操作:

$username = $user['username'];

Warning

直接编写并传递给数据库适配器的数据库查找并非自动 "安全"。 如果用户的输入没有经过清除,并且没有经过准备就传入查找,它们就会帯来 SQL 隐码攻击漏洞的风险。 正确的方法是使用准备好的语句,就象上面的例子一样。 在查找本身中使用 ? 占位符来表示参数。 这些占位符经过适当的転义后,会被下一个参数中的值替换。 如果你需要使用的参数不止一个,那应该以数组的形式传递到 fetch 类型方法中。 如有必要,你可以直接使用 $db->quote($value) 对值进行転义或引用。

您可以 在这里 找到更多关于准备好的语句信息。

也可以从一条记录中查找一个值。 例如:

$db = \XF::db();
$username = $db->fetchOne('SELECT username FROM xf_user WHERE user_id = ?', 1);

如果你有一个需要返回多条记录的查找,你可以使用 fetchAll

$db = \XF::db();
$users = $db->fetchAll('SELECT * FROM xf_user LIMIT 10');

或者 fetchAllKeyed

$db = \XF::db();
$users = $db->fetchAllKeyed('SELECT * FROM xf_user LIMIT 10', 'user_id');

这两种方法都将返回一个代表每个用户记录的数组。 fetchAllfetchAllKeyed 方法之间的区别是,返回的数组的 key 值不同。 使用 fetchAll 方法时,数组将用连续的数字整数进行 key 锁定。 用 fetchAllKeyed 方法,数组将用第二个参数中命名的字段名进行 key 锁定。

Note

如果你使用 fetchAllKeyed,请注意第二个参数是要对数组进行 key 锁定的字段,但 第三个 参数是你传递 param 值以匹配 ? 占位符的地方。

还有一些其他获取类型的方法,包括 fetchAllColumn,用于从所有返回的 rows 中抓取一个特定 column 的值的数组:

$db = \XF::db();
$usernames = $db->fetchAllColumn('SELECT username FROM xf_user LIMIT 10');

上面的例子将返回一个从结果查找中找到的 10 个用户名的数组。

最后,你可能并不想要或不需要返回任何数据,在这种情况下,你可以只做一个普通查找:

$db = \XF::db();
$db->query('DELETE FROM xf_user WHERE user_id = ?', 1);

纲要管理

XF2 包含了一种全新的管理数据库模式的方式,它采用物件导向的方式来运行某些表的操作。 让我们先看看传统的改变,使用数据库适配器,就象我们上面的那样。

$db = \XF::db();
$db->query("
    ALTER TABLE xf_some_existing_table
    ADD COLUMN new_column INT(10) UNSIGNED NOT NULL DEFAULT 0,
    MODIFY COLUMN some_existing_column varchar(250) NOT NULL DEFAULT ''
");

我们也来看看一个典型的创建资料表查找:

$db = \XF::db();
$sm = $db->getSchemaManager();

$defaultTableConfig = $sm->getTableConfigSql();

$db->query("
    CREATE TABLE xf_some_table (
        some_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
        some_name VARCHAR(50) NOT NULL,
        PRIMARY KEY (user_id)
    ) {$defaultTableConfig}
");

在 XF2 中,另一种和首选的方法是使用新的 SchemaManager 物件。 让我们来看看这两个由模式管理器运行的查找,首先是 alter:

$sm = \XF::db()->getSchemaManager();
$sm->alterTable('xf_some_existing_table', function(\XF\Db\Schema\Alter $table)
{
    $table->addColumn('new_column', 'int')->setDefault(0);
    $table->changeColumn('some_existing_column')->length(250);
});

还有资料表的创建:

$sm = \XF::db()->getSchemaManager();
$sm->createTable('xf_some_table', function(\XF\Db\Schema\Create $table)
{
    $table->addColumn('some_id', 'int')->autoIncrement();
    $table->addColumn('some_name', 'varchar', 50);
});

Warning

当您更改现有的 XenForo 资料表或创建自己的资料表时,必须 指定一个默认值,否则在查找资料表时将会遇到问题。

这两个例子生成的查找结果和上面更直接的例子完全一样。 不过你可能会注意到,有些东西是(故意)遗漏的。 例如,没有一个例子为 int 字段指定一个长度。 这只是因为省略了这一点,MySQL 会给它提供一个默认值,对于无符号整数来说是 10。说到这里,我们也没有指定 some_id column 是无符号的。 在 XF 内使用无符号整数是当前最常见的使用案例,所以会自动添加。 如果你真正需要支持负整数的能力,你可以用 ->unsigned(false) 方法反过来。 另一个遗漏是没有为所有的东西定义 NOT NULL。 同样,这是自动应用的,但你可以用 ->nullable(true) 来扭転这种情况。

从 alter 的例子中可能看不清楚,但是当改变现有的字段时,现有的字段定义会自动保留。 这意味着,你不必指定整个 column 的定义,包括所有没有实际改变的部分,你可以只指定你要改变的部分。

关于 Primary Key,还有一些其他的自动推断。 如果你愿意的话,你可以明确地定义 Primary Key(或任何其他类型的 Key ),但通常自动递增的字段通常会成为你的资料表的 Primary Key。 所以在创建资料表的例子中,some_id 字段被自动分配为该资料表的 Primary Key。

最后,对于创建资料表的方法,我们可以为指定的保存引擎自动添加正确的资料表设置(默认为 InnoDB,但可以很容易地改变为其他引擎类型)。