Работа с базой данных в SMF

В этой статье мы разберём функции SMF для создания и изменения таблиц в базе данных.


Если хотите проверить все рассматриваемые функции в деле, потребуется тестовая площадка:

Все нужные методы для работы с таблицами в базе данных находятся в глобальном ассоциативном массиве $smcFunc, который устанавливается в корневом index.php, заполняется в Load.php и дополняется в файлах DbExtra-mysql.php, DbExtra-postgresql.php, DbPackages-mysql.php, DbPackages-postgresql.php, DbSearch-mysql.php, DbSearch-postgresql.php, Subs-Db-mysql.php и Subs-Db-postgresql.php, в зависимости от типа используемой базы данных. А поскольку массив глобальный, не забывайте объявлять global $smcFunc в своих функциях/методах.

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

Набор основных функций для работы с запросами находится в Subs-Db-mysql.php|Subs-Db-postrgesql.php. Рассмотрим их подробнее.

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

$request = $smcFunc['db_query']('', 'SELECT * FROM {db_prefix}members');
dump($smcFunc['db_fetch_all']($request));

Как и db_query, экранирует и заключает в кавычки строку, но не выполняет запрос. Пример:

$userQuery = $smcFunc['db_quote'](
    '(m.id_member IN ({array_int:matched_members}) OR (m.id_member = {int:id_member_guest} AND ({raw:match_possible_guest_names})))',
    array(
        'matched_members' => [1,2,3],
        'id_member_guest' => 0,
        'match_possible_guest_names' => 'm.poster_name LIKE ' . implode(' OR m.poster_name LIKE ', ['Test1', 'Test2', 'Test3']),
    )
);
dump($userQuery);

Результат:

'(m.id_member IN (1, 2, 3) OR (m.id_member = 0 AND (m.poster_name LIKE Test1 OR m.poster_name LIKE Test2 OR m.poster_name LIKE Test3)))'

Возвращает следующую строку результата запроса в виде ассоциативного массива. Пример:

$request = $smcFunc['db_query']('', 'SELECT * FROM {db_prefix}members');
while ($row = $smcFunc['db_fetch_assoc']($request))
    dump($row);

Возвращает следующую строку результата запроса в виде обычного массива. Пример:

$request = $smcFunc['db_query']('', '
    SELECT * FROM {db_prefix}members
    WHERE id_member = {int:id}
    LIMIT 1',
    array(
        'id' => 1
    )
);
dump($smcFunc['db_fetch_row']($request));

Результат будет выглядеть как-то так:

array(
    0 => '1'
    1 => 'Test'
    2 => '1631176348'
    3 => '54'
    4 => '1'
    5 => 'russian'
    6 => '1651629543'
    ...
)

Возвращает все строки результата запроса в виде ассоциативного массива. См. пример использования `$smcFunc['db_query'].

Освобождает память от результата запроса $request. Указывайте после каждого использования $smcFunc['db_fetch_assoc'],$smcFunc['db_fetch_all'] и `$smcFunc['db_free_result']:

$smcFunc['db_free_result']($request);

Добавляет новую запись в указанную таблицу. Пример:

$smcFunc['db_insert']('',
    '{db_prefix}messages',
    $message_columns,
    $message_parameters,
    array('id_msg')
);

Чтобы получить идентификатор добавленной записи, можно указать 1 в качестве последнего параметра или использовать `$smcFunc['db_insert_id'] (см. ниже):

$id = $smcFunc['db_insert']('',
    '{db_prefix}messages',
    $message_columns,
    $message_parameters,
    array('id_msg'),
    1
);

Возвращает идентификатор только что добавленной записи. Пример:

$smcFunc['db_insert']('',
    '{db_prefix}messages',
    $message_columns,
    $message_parameters,
    array('id_msg')
);
dump($smcFunc['db_insert_id']);

Возвращает количество строк результата запроса. Пример:

$request = $smcFunc['db_query']('', 'SELECT * FROM {db_prefix}members');
dump($smcFunc['db_num_rows']($request));

Переходит к заданной строке $i в результирующем наборе $request. Пример:

$smcFunc['db_data_seek']($request, $i);

Пример использования на практике см. в файле Sources/Memberlist.php.

Возвращает количество полей результата запроса. Пример:

$request = $smcFunc['db_query']('', 'SELECT * FROM {db_prefix}members');
dump($smcFunc['db_num_fields']($request));

Возвращает строку с экранированными специальными символами, для использования в выражениях SQL. Пример:

$test = "'123'";
dump($smcFunc['db_escape_string']($test));

Результат:

'\'123\''

Удаляет экранирование символов. Синоним для функции stripslashes. Пример:

$test = "\'123\'";
dump($smcFunc['db_unescape_string']($test));

Результат:

"'123'"

Возвращает версию используемого сервера базы данных. Пример:

dump($smcFunc['db_server_info']());

Результат будет выглядеть как-то так:

'5.5.5-10.6.7-MariaDB'

Возвращает число строк, затронутых последним запросом INSERT, UPDATE, REPLACE или DELETE. Пример:

$smcFunc['db_query']('', '
    DELETE FROM {db_prefix}members
    WHERE id_member IN ({array_int:ids})',
    array(
        'ids' => [12, 13, 14]
    )
);
dump($smcFunc['db_affected_rows']());

Осуществляет один из этапов транзакции (begin, commit, rollback). Пример:

// Инициализация транзакции
$smcFunc['db_transaction']('begin');

$id = $smcFunc['db_insert']('',
    '{db_prefix}messages',
    $message_columns,
    $message_parameters,
    array('id_msg'),
    1
);

// далее могут быть другие запросы

if (empty($id)) {
    // Откат изменений (все запросы выше откатываются, как будто их и не было)
    $smcFunc['db_transaction']('rollback');
    return;
}

// Фиксация изменений (все запросы подтверждаются)
$smcFunc['db_transaction']('commit');

Пример использования на практике можно увидеть в исходном коде Light Portal.

Возвращает строку с описанием последней ошибки. Пример:

dump($smcFunc['db_error']($db_connection));

Устанавливает базу данных для выполняемых запросов. Вряд ли пригодится, но вдруг вам захочется подключиться к другой базе данных во время работы с SMF? Пример:

// Выбираем базу данных
$smcFunc['db_select_db']('other_database');

// Осуществляем другие запросы

Возвращает название используемого движка базы данных. Пример:

dump($smcFunc['db_title']());

Экранирует знаки подстановки и возвращает строку с произведёнными заменами. Пример:

$test = '%some_text%';
dump($smcFunc['db_escape_wildcard_string']($test));

Результат:

'\%some\_text\%'

Конструирует оптимизированную строку пользовательского заказа как улучшенная альтернатива find_in_set(). Пример:

dump($this->smcFunc['db_custom_order']('status', [1, 0]));

Результат:

'CASE status WHEN 1 THEN 0 WHEN 0 THEN 1 END'

Возвращает true, если база данных поддерживает Common Table Expression (Общие Табличные Выражения). Пример подобного выражения:

SELECT * FROM smf_members;
WITH cte_members AS (
    SELECT COUNT(*) as total
    FROM smf_members
    WHERE is_activated = "1" GROUP BY is_activated
)
SELECT total as `Всего активных пользователей`
FROM cte_members;

Пример использования на практике рекурсивных CTE можно посмотреть в плагине RandomTopics для модификации Light Portal. Примеры других CTE-запросов доступны здесь.

Перед использованием этой группы функций нужно подготовить массив $smcFunc с помощью вызова db_extend('packages');.

Добавляет столбец в указанную таблицу. Пример:

$smcFunc['db_add_column'](
    '{db_prefix}my_table',
    array(
        'name'     => 'content',
        'type'     => 'text',
        'null'     => false,
        'not_null' => true
    ),
    array(),
    'do_nothing'
);

Добавляет индекс в указанную таблицу. Пример:

$table_name = '{db_prefix}my_table';
$index_info = array(
    'name' => 'my_index',
    'type' => 'index', // 'index', 'unique', 'primary'
    'columns' => array(
        'column1', 'column2'
    )
);
$smcFunc['db_add_index']($table_name, $index_info);

К сожалению, не все типы индексов можно добавить таким образом. Некоторые (например, FULLTEXT) добавляются лишь «по старинке», с помощью обычного SQL:

$smcFunc['db_query']('', '
    ALTER TABLE {db_prefix}table_name
    ADD FULLTEXT index_name (column_name)',
    array()
);

Возвращает массив с указанными именем и типом столбца. Пример:

dump($smcFunc['db_calculate_type']('varchar', 255));

Результат:

array(
    0 => 'varchar'
    1 => 255
)

Изменяет столбец в указанной таблице. Пример:

$column_info = array(
    'name' => 'new_name',
    'type' => 'new_type',
    ... // и т. д.
);
$smcFunc['db_change_column']('{db_prefix}my_table', 'column_name', $column_info);

Создаёт таблицу с заданными столбцами, каждый из которых представляет собой массив. Пример:

$tables[] = array(
    'name' => 'my_table',
    'columns' => array(
        array(
            'name'     => 'id',
            'type'     => 'int',
            'size'     => 10,
            'unsigned' => true,
            'auto'     => true
        ),
        array(
            'name'     => 'title',
            'type'     => 'varchar',
            'size'     => 255,
            'null'     => false,
            'not_null' => true
        ),
        array(
            'name'     => 'created_at',
            'type'     => 'int',
            'size'     => 10,
            'unsigned' => true
        )
    ),
    'indexes' => array(
        array(
            'type'    => 'primary',
            'columns' => array('id')
        ),
    )
);

db_extend('packages');

foreach ($tables as $table) {
    $smcFunc['db_create_table']('{db_prefix}' . $table['name'], $table['columns'], $table['indexes']);
}

Удаляет указанную таблицу. Пример:

$smcFunc['db_drop_table']('{db_prefix}my_table');

Возвращает структуру таблицы. Пример:

dump($smcFunc['db_table_structure']('{db_prefix}messages'));

Результат:

array(4)
    'name'    => 'smf_messages'
    'columns' => array(18)
    'indexes' => array(11)
    'engine'  => 'InnoDB'

Возвращает информацию о столбцах указанной таблицы. Второй параметр отвечает за отображение подробных сведений о столбцах. Пример:

dump($smcFunc['db_list_columns']('{db_prefix}messages', true));

Возвращает информацию об индексах указанной таблицы. Второй параметр отвечает за отображение подробных сведений о столбцах. Пример:

dump($smcFunc['db_list_indexes']('{db_prefix}messages', true));

Удаляет заданный столбец из указанной таблицы. Пример:

$smcFunc['db_remove_column']('{db_prefix}my_table', 'column_name');

Удаляет заданный индекс из указанной таблицы. Пример:

$smcFunc['db_remove_index']('{db_prefix}my_table', 'index_name');

Перед использованием этой группы функций нужно подготовить массив $smcFunc с помощью вызова db_extend('search');.

Синоним `$smcFunc['db_query'].

Возвращает true, если базой данных поддерживается указанный тип поиска. Пример:

dump($smcFunc['db_search_support']('fulltext'));

Используется для создания пользовательской таблицы с индексами слов (см. Поисковое индексирование в настройках поиска).

Возвращает язык для индекса текстового поиска. Пример:

dump($smcFunc['db_search_language']())

Пример использования на практике можно увидеть в исходном коде Similar Topics.

Перед использованием этой группы функций нужно подготовить массив $smcFunc с помощью вызова db_extend('extra'); или просто db_extend() (extra является значением по умолчанию).

Создает резервную копию указанной таблицы. Пример:

$smcFunc['db_backup_table']('{db_prefix}members', 'backup_members');

Оптимизирует указанную таблицу. Пример:

$smcFunc['db_optimize_table']('{db_prefix}members');

Выводит в виде дампа SQL-схему CREATE для указанной таблицы. Пример:

dump($smcFunc['db_table_sql']('{db_prefix}user_likes'));

Результат будет выглядеть как-то так:

DROP TABLE IF EXISTS `smf_user_likes`;

CREATE TABLE `smf_user_likes` (
 `id_member` mediumint(8) unsigned NOT NULL default 0,
 `content_type` char(6) NOT NULL default '',
 `content_id` int(10) unsigned NOT NULL default 0,
 `like_time` int(10) unsigned NOT NULL default 0,
 PRIMARY KEY (`content_id`, `content_type`, `id_member`),
 KEY `content` (`content_id`, `content_type`),
 KEY `liker` (`id_member`)
) ENGINE=InnoDB'

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

Пример 1 — получаем массив с именами всех таблиц в текущей базе данных:

dump($smcFunc['db_list_tables']());

Пример 2 — получаем пустой массив, если таблицы my_table в базе данных my_database нет:

dump($smcFunc['db_list_tables']('my_database', '{db_prefix}my_table'));

Выводит версию используемого движка базы данных. Пример:

dump($smcFunc['db_get_version']());

Результат будет выглядеть как-то так:

'10.6.7-MariaDB'

Возвращает название используемого движка базы данных. Пример:

dump($smcFunc['db_get_vendor']());

Результат будет выглядеть как-то так:

'MariaDB'

Возвращает true, если разрешено постоянное соединение с базой данных.