Управление схемой

Мы рассмотрели некоторые из новых подходов, доступных для взаимодействия с данными. Конечно, есть особые обстоятельства, при которых может потребоваться прямое взаимодействие с базой данных.

Адаптер базы данных

Адаптер базы данных по умолчанию в XF2 основан на MySQL и расширении mysqli PHP. Настроенный адаптер базы данных доступен в любом классе 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-инъекции, если вводимые пользователем данные не очищаются и не передаются в запрос без предварительной подготовки. Чтобы сделать это правильно, используйте подготовленные операторы, как в приведенном выше примере. Параметры представлены в самом запросе с помощью заполнителя ?. Эти заполнители затем заменяются значениями в следующем аргументе после того, как они были соответствующим образом экранированы. Если вам необходимо использовать более одного параметра, его следует передать в метод типа выборки в виде массива. В случае необходимости вы можете экранировать или цитировать значения напрямую, используя $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');

Оба эти метода вернут массив массивов, представляющих каждую запись пользователя. Разница между методами fetchAll и fetchAllKeyed состоит в том, что возвращаемый массив будет иметь разные ключи. С помощью fetchAll массив будет иметь ключи с числовыми последовательными целыми числами. С помощью fetchAllKeyed массив будет привязан к имени поля, указанного во втором аргументе.

Note

Если вы используете fetchAllKeyed, обратите внимание, что второй аргумент - это поле для ввода ключа в массив, но третий аргумент - это то место, где вы передаете значения параметров для соответствия заполнителям ?.

Доступны некоторые другие методы типа выборки, включая fetchAllColumn для захвата массива значений определенного столбца из всех возвращаемых строк:

$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 беззнаковый. Использование беззнаковых целых чисел в XF, безусловно, является наиболее распространенным вариантом использования, поэтому оно добавляется автоматически. Если вам действительно нужна возможность поддерживать отрицательные целые числа, вы можете отменить это с помощью метода ->unsigned(false). Еще одно упущение - отсутствие определения NOT NULL для всего. Опять же, это применяется автоматически, но вы можете отменить это с помощью ->nullable(true).

Это может быть неясно из примера изменения, но при изменении существующих полей определение существующего поля автоматически сохраняется. Это означает, что вместо того, чтобы указывать полное определение столбца, включая все биты, которые фактически не изменились, вы можете просто указать части, которые хотите изменить.

Есть и другой автоматический вывод, который происходит в отношении первичных ключей. вы можете явно определить первичный ключ (или любой другой тип ключа), если хотите, но часто автоматически увеличивающиеся поля обычно будут Вашим первичным ключом для таблицы. Итак, в примере создания таблицы поле some_id автоматически назначается в качестве первичного ключа для этой таблицы.

Наконец, для подхода создания таблицы мы можем автоматически добавить правильную конфигурацию таблицы для указанного механизма хранения (который по умолчанию имеет значение InnoDB, но может быть легко изменен на другие типы движка).