Query Builder
Внимание
Данная статья документации написана нейросетью. Возможны некоторые расхождения и неточность информации!
Полное руководство по Query Builder и работе с БД в IO7 фреймворке.
Обзор
IO7 Query Builder объединяет raw PDO (для прямых SQL-запросов) и Laravel Illuminate Database Query Builder. Доступ через:
SqlConnection::table()— статический вызов (Laravel Query Builder)DB::table()— через фасад$db->query()— raw PDO-запросы$db->search()— высокоуровневый поиск с IO-фильтрамиSqlConnection::applyFilterToQuery()— применение IO-фильтров к Query BuilderSqlConnection::getWhereFromFilter()— генерация SQL WHERE из IO-фильтра
┌─────────────────────────────────────────────────────────────┐
│ Query Builder API │
├─────────────────────────────────────────────────────────────┤
│ Статические методы: │
│ SqlConnection::table('users') │
│ → Illuminate\Database\Query\Builder │
│ → where(), orderBy(), select(), ... │
│ → get(), first(), count(), ... │
├─────────────────────────────────────────────────────────────┤
│ Raw PDO: │
│ $db->query("SELECT ...") │
│ $db->query_params("SELECT ... WHERE id = ?", [1]) │
├─────────────────────────────────────────────────────────────┤
│ Высокоуровневые CRUD: │
│ $db->search('users', ['filter' => ['status' => 1]]) │
│ $db->insert('users', ['name' => 'Ivan']) │
│ $db->update('users', ['pkid' => 1], ['name' => 'Ivan']) │
│ $db->delete('users', ['pkid' => 1]) │
├─────────────────────────────────────────────────────────────┤
│ IO-фильтры: │
│ SqlConnection::applyFilterToQuery($query, $filter) │
│ SqlConnection::getWhereFromFilter($filter) │
└─────────────────────────────────────────────────────────────┘
Пространство имён: IO\Database
Файл: src/modules/io7/php/Database/SqlConnection.php
SqlConnection — свойства
| Свойство | Тип | Описание | Значение по умолчанию |
|---|---|---|---|
$db_link | ?\PDO | PDO-подключение к БД | null |
$last_query | string | Последний выполненный запрос (экземпляр) | '' |
$last_query_all | string (static) | Последний выполненный запрос (глобальный) | '' |
$db_connections | array (static) | Кэш подключений | [] |
$server | string | Адрес сервера БД | '' |
$user | string | Пользователь БД | '' |
$pass | string | Пароль БД | '' |
$db | string | Имя базы данных | '' |
$driver | string | Движок БД (mysql или pgsql) | 'mysql' |
$lastconnect | int | Разрешение на подключение | 1 |
$log_query | int | Логирование запросов | 0 |
$code_page | string | Кодировка | 'utf8' |
$time_zone | string | Часовой пояс | '+05:00' |
$_errorstr | string | Текст последней ошибки | '' |
$_errorno | string | Код последней ошибки | '' |
$_time_query_max | int | Максимальное время запроса (мс) | 2000 |
$columns | array | Структура таблиц information_schema | [] |
SqlConnection — статические методы
table()
public static function table(string $table): \Illuminate\Database\Query\Builder
Получить Query Builder для указанной таблицы через Laravel Illuminate Database.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$table | string | Имя таблицы | — | Да |
Возвращает: \Illuminate\Database\Query\Builder
// Простое использование
$builder = SqlConnection::table('users');
// С условиями
$users = SqlConnection::table('users')
->where('active', 1)
->get();
// Выборка полей
$user = SqlConnection::table('users')
->select('id', 'name', 'email')
->where('id', 1)
->first();
// Пагинация
$pages = SqlConnection::table('posts')
->where('status', 'published')
->orderBy('created_at', 'desc')
->paginate(25);
connection()
public static function connection(string $name = null): \Illuminate\Database\Connection
Получить объект подключения к БД через Capsule.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$name | ?\string | Имя подключения (конфигурации) | null (по умолчанию) | Нет |
Возвращает: \Illuminate\Database\Connection
// Получить подключение по умолчанию
$conn = SqlConnection::connection();
// Получить именованное подключение
$conn = SqlConnection::connection('mysql');
// Использовать Schema Builder через connection
SqlConnection::connection()->getSchemaBuilder()
->table('users', function (\Illuminate\Database\Schema\Blueprint $table): void {
$table->index('email');
});
// Получить PDO через connection
$pdo = SqlConnection::connection()->getPdo();
create_conn()
public static function create_conn(
string $server,
string $user,
string $pass,
string $db = '',
string $driver = 'mysql'
): self
Создать или получить ранее созданное подключение к БД. Использует кэш подключений — при повторном вызове с теми же параметрами возвращает тот же экземпляр.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$server | string | Адрес сервера БД | — | Да |
$user | string | Имя пользователя БД | — | Да |
$pass | string | Пароль пользователя БД | — | Да |
$db | string | Имя базы данных | '' | Нет |
$driver | string | Тип БД: mysql или pgsql | 'mysql' | Нет |
Возвращает: self (экземпляр SqlConnection)
// MySQL подключение
$db = SqlConnection::create_conn('localhost', 'root', 'password', 'mydb');
$db->tryconnect();
// PostgreSQL подключение
$db = SqlConnection::create_conn('localhost', 'postgres', 'secret', 'mydb', 'pgsql');
$db->tryconnect();
// Повторный вызов — вернёт тот же экземпляр
$db1 = SqlConnection::create_conn('localhost', 'root', 'pass', 'mydb');
$db2 = SqlConnection::create_conn('localhost', 'root', 'pass', 'mydb');
// $db1 === $db2
escape()
public static function escape(string $msg): string
Экранирование специальных символов строки для безопасной вставки в SQL-запрос. Экранирует: \, \0, \n, \r, ', ", \x1a.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$msg | string | Строка для экранирования | — | Да |
Возвращает: string — экранированная строка
// Экранирование одинарной кавычки
$safe = SqlConnection::escape("O'Brien");
// Результат: O\'Brien
// Экранирование спецсимволов
$safe = SqlConnection::escape("Строка\nс переносом");
// Результат: Строка\nс переносом
// Использование в raw-запросе
$name = SqlConnection::escape($userName);
$db->query("INSERT INTO users (name) VALUES ('$name')");
escape2()
public static function escape2(string $field): string
Экранирование имени таблицы или поля для SQL-запроса (обрамление обратными кавычками). Поддерживает составные имена через . (например, table.column). Специальные префиксы: # — отключает экранирование, * — возвращает как есть.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$field | string | Имя таблицы или поля | — | Да |
Возвращает: string — экранированное имя
// Простое имя
$escaped = SqlConnection::escape2('users');
// Результат: `users`
// Составное имя (таблица.поле)
$escaped = SqlConnection::escape2('users.name');
// Результат: `users`.`name`
// Префикс # — отключает экранирование
$escaped = SqlConnection::escape2('#COUNT(*)');
// Результат: COUNT(*)
// Префикс * — возвращает как есть
$escaped = SqlConnection::escape2('*ALL');
// Результат: *ALL
getWhereFromFilter()
public static function getWhereFromFilter(?array $filter = null): string
Генерация SQL WHERE-выражения из массива IO-фильтра. Рекурсивно обрабатывает все операторы, включая логические $or и $and.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$filter | ?\array | Массив фильтрации IO | null | Нет |
Возвращает: string — SQL WHERE-выражение (без ключевого слова WHERE)
// Простой фильтр
$where = SqlConnection::getWhereFromFilter(['status' => 1]);
// Результат: `status` = '1'
// Поиск подстроки
$where = SqlConnection::getWhereFromFilter(['%name' => 'Иван']);
// Результат: `name` like '%Иван%'
// NULL-проверка
$where = SqlConnection::getWhereFromFilter(['~deleted_at' => null]);
// Результат: `deleted_at` is null
// Логический OR
$where = SqlConnection::getWhereFromFilter([
'$or' => [
['role' => 'admin'],
['role' => 'moderator'],
],
]);
// Результат: ( `role` = 'admin' or `role` = 'moderator' )
// Сложный фильтр
$where = SqlConnection::getWhereFromFilter([
'status' => 1,
'%name' => 'Иван',
'!~deleted_at' => null,
]);
// Результат: `status` = '1' and `name` like '%Иван%' and `deleted_at` is not null
// Использование в raw-запросе
$where = SqlConnection::getWhereFromFilter(['active' => 1, '>age' => 18]);
$rows = $db->fetchAll($db->query("SELECT * FROM users WHERE $where"));
applyFilterToQuery()
public static function applyFilterToQuery(
\Illuminate\Database\Query\Builder $query,
?array $filter
): \Illuminate\Database\Query\Builder
Применить IO-фильтр к Laravel Query Builder. Рекурсивно обрабатывает массив фильтров и конвертирует каждый элемент в соответствующий вызов Query Builder (where, whereIn, whereNull, whereNotNull и т.д.).
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$query | Builder | Query Builder | — | Да |
$filter | ?\array | Массив фильтрации IO | — | Да |
Возвращает: Builder — модифицированный Query Builder
// Простое использование
$query = SqlConnection::table('users');
$query = SqlConnection::applyFilterToQuery($query, [
'status' => 1,
'%name' => 'Иван',
]);
$users = $query->get();
// С логическим OR
$query = SqlConnection::table('users');
$query = SqlConnection::applyFilterToQuery($query, [
'status' => 1,
'$or' => [
['role' => 'admin'],
['role' => 'manager'],
],
]);
$users = $query->get();
// В цепочке с другими методами
$users = SqlConnection::table('users')
->select('id', 'name', 'email')
->orderBy('name', 'asc');
$users = SqlConnection::applyFilterToQuery($users, $filter);
$results = $users->paginate(25);
__callStatic()
public static function __callStatic(string $method, array $args)
Магический метод делегации — передаёт вызовы в Illuminate\Database\Capsule\Manager. Позволяет вызывать любые статические методы Capsule через SqlConnection::.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$method | string | Имя метода Capsule | — | Да |
$args | array | Аргументы метода | — | Да |
Возвращает: mixed — результат вызова метода Capsule
// Очистка кэша
SqlConnection::purge();
// Вызов любого метода Capsule
SqlConnection::beginTransaction();
SqlConnection::rollBack();
SqlConnection — методы подключения
__construct()
public function __construct(string $driver = 'mysql')
Конструктор. Устанавливает тип БД и вычисляет часовой пояс из системных настроек.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$driver | string | Тип БД: mysql или pgsql | 'mysql' | Нет |
// MySQL
$db = new SqlConnection('mysql');
// PostgreSQL
$db = new SqlConnection('pgsql');
// По умолчанию (MySQL)
$db = new SqlConnection();
tryconnect()
public function tryconnect(): int
Попытка подключения к БД с использованием сохранённых параметров (server, user, pass, db). Вызывает afterConnect() для установки кодировки и часового пояса.
Возвращает: int — 1 при успехе, 0 при ошибке
$db = new SqlConnection('mysql');
$db->server = 'localhost';
$db->user = 'root';
$db->pass = 'password';
$db->db = 'mydb';
if ($db->tryconnect() == 1) {
echo "Подключение установлено";
} else {
echo "Ошибка подключения";
}
connect()
public function connect(
string $server,
string $user,
string $pass,
?string $db = null
): int
Установить соединение с БД. Создаёт PDO-подключение с заданными параметрами.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$server | string | Адрес сервера БД | — | Да |
$user | string | Имя пользователя | — | Да |
$pass | string | Пароль пользователя | — | Да |
$db | ?\string | Имя базы данных | null | Нет |
Возвращает: int — 1 при успехе, 0 при ошибке
$db = new SqlConnection('mysql');
$result = $db->connect('localhost', 'root', 'password', 'mydb');
if ($result == 1) {
$db->query("SELECT * FROM users");
}
is_valid()
public function is_valid(): bool
Проверка валидности текущего PDO-подключения.
Возвращает: bool — true если подключение активно и валидно
if ($db->is_valid()) {
$db->query("SELECT 1");
} else {
$db->tryconnect();
}
ping()
public function ping(): bool
Проверка доступности соединения с БД (выполняет простой запрос).
Возвращает: bool — true если соединение доступно
if (!$db->ping()) {
$db->tryconnect();
}
usedb()
public function usedb(string $dbname): void
Переключиться на другую базу данных.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$dbname | string | Имя базы данных | — | Да |
$db->usedb('another_database');
connected()
public function connected(): bool
Проверить, было ли ранее установлено подключение.
Возвращает: bool — true если подключение было выполнено
if ($db->connected()) {
echo "Подключение ранее установлено";
}
SqlConnection — raw-запросы (PDO)
query()
public function query(string $query = '', ?array $arr = null, bool $save_log = true)
Выполнить raw SQL-запрос через PDO. Поддерживает подстановку параметров через плейсхолдеры (автоматическое экранирование через escape()). Сохраняет запрос в лог при $save_log = true.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$query | string | SQL-запрос | '' | Нет |
$arr | ?\array | Массив параметров для подстановки (ключ => значение) | null | Нет |
$save_log | bool | Сохранять ли запрос в лог | true | Нет |
Возвращает: \PDOStatement|false
// Простой запрос
$r = $db->query("SELECT * FROM users");
// С подстановкой параметров
$r = $db->query(
"SELECT * FROM users WHERE name = :name AND status = :status",
[':name' => 'Ivan', ':status' => 1]
);
// Без логирования
$r = $db->query("SELECT 1", null, false);
// INSERT
$db->query("INSERT INTO logs (msg, level) VALUES ('test', 'info')");
query_params()
public function query_params(string $query = '', ?array $arr = null, bool $save_log = true)
Алиас для query(). Выполняет raw SQL-запрос с параметрами.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$query | string | SQL-запрос | '' | Нет |
$arr | ?\array | Массив параметров | null | Нет |
$save_log | bool | Сохранять ли в лог | true | Нет |
Возвращает: \PDOStatement|false
$r = $db->query_params(
"SELECT * FROM users WHERE login = :login",
[':login' => 'admin']
);
free_result()
public function free_result(?\PDOStatement $result): bool
Закрыть курсор результата запроса (освободить память).
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$result | ?\PDOStatement | Результат запроса | — | Да |
Возвращает: bool — true при успешном закрытии
$r = $db->query("SELECT * FROM users");
// ... обработка
$db->free_result($r);
fetch()
public function fetch(?\PDOStatement $result)
Получить одну строку из результата запроса (ассоциативный массив). Используется в цикле для последовательного чтения строк.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$result | ?\PDOStatement | Результат запроса | — | Да |
Возвращает: array|false — ассоциативный массив или false при окончании
$r = $db->query("SELECT * FROM users");
while ($row = $db->fetch($r)) {
echo $row['name'] . "\n";
}
$db->free_result($r);
fetch_assoc()
public function fetch_assoc(?\PDOStatement $result)
Алиас для fetch(). Получить одну строку из результата.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$result | ?\PDOStatement | Результат запроса | — | Да |
Возвращает: array|false
$r = $db->query("SELECT * FROM users WHERE id = 1");
$row = $db->fetch_assoc($r);
echo $row['name'];
fetchAll()
public function fetchAll(?\PDOStatement $result)
Получить все строки из результата запроса сразу.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$result | ?\PDOStatement | Результат запроса | — | Да |
Возвращает: array|false — массив ассоциативных массивов
$r = $db->query("SELECT * FROM users WHERE active = 1");
$rows = $db->fetchAll($r);
foreach ($rows as $row) {
echo $row['name'] . "\n";
}
$db->free_result($r);
error()
public function error(): string
Получить код последней ошибки.
Возвращает: string — код ошибки (например, '00000' при успехе)
$r = $db->query("SELECT * FROM non_existing_table");
if ($db->error() != '00000') {
echo "Ошибка: " . $db->errorstr();
}
errorstr()
public function errorstr(): string
Получить текстовое описание последней ошибки.
Возвращает: string — текст ошибки
$r = $db->query("INVALID SQL");
if ($db->error() != '00000') {
echo "Ошибка: " . $db->errorstr();
}
num_rows()
public function num_rows(?\PDOStatement $res): int
Получить количество строк в результате запроса.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$res | ?\PDOStatement | Результат запроса | — | Да |
Возвращает: int — количество строк
$r = $db->query("SELECT * FROM users WHERE active = 1");
echo "Найдено: " . $db->num_rows($r);
last_insert_id()
public function last_insert_id()
Получить ID последней вставленной записи (автоинкремент).
Возвращает: string|int — ID записи или -1 при ошибке
$db->insert('users', ['name' => 'Ivan', 'email' => 'ivan@example.com']);
$id = $db->last_insert_id();
echo "Создан пользователь с ID: $id";
get_var()
public function get_var(string $field, string $q, array $arr = [])
Получить значение одного поля из первого результата запроса.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$field | string | Имя поля для извлечения | — | Да |
$q | string | SQL-запрос | — | Да |
$arr | array | Параметры запроса | [] | Нет |
Возвращает: mixed — значение поля или null
$name = $db->get_var('name', "SELECT name FROM users WHERE id = 1");
$count = $db->get_var('cnt', "SELECT COUNT(*) as cnt FROM users WHERE active = 1");
// С параметрами
$email = $db->get_var('email', "SELECT email FROM users WHERE login = ?", ['admin']);
get_count()
public function get_count(string $q, string $field = 'count')
Получить значение COUNT из запроса.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$q | string | SQL-запрос с COUNT | — | Да |
$field | string | Имя поля с результатом COUNT | 'count' | Нет |
Возвращает: mixed — значение COUNT или 0
$count = $db->get_count("SELECT COUNT(*) as count FROM users WHERE active = 1");
// С произвольным именем поля
$total = $db->get_count("SELECT COUNT(*) as total FROM orders", 'total');
affected_rows()
public function affected_rows()
Получить количество затронутых строк после INSERT/UPDATE/DELETE (MySQL ROW_COUNT()).
Возвращает: int|null
$db->update('users', ['pkid' => 1], ['active' => 0]);
echo "Затронуто строк: " . $db->affected_rows();
found_rows()
public function found_rows()
Получить количество найденных строк (MySQL FOUND_ROWS). Работает после запроса с SQL_CALC_FOUND_ROWS.
Возвращает: int|null
$db->query("SELECT SQL_CALC_FOUND_ROWS * FROM users LIMIT 10");
$count = $db->found_rows();
echo "Всего записей: $count";
SqlConnection — выскоуровневые CRUD-методы
insert()
public function insert(string $table, array $data, ?array $data2 = null): int
Вставить одну запись в таблицу. Использует Laravel Query Builder.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$table | string | Имя таблицы | — | Да |
$data | array | Ассоциативный массив данных | — | Да |
$data2 | ?\array | Дополнительные данные (не используется) | null | Нет |
Возвращает: int — 1 при успехе, -1 при ошибке
// Простая вставка
$db->insert('users', [
'name' => 'Ivan',
'email' => 'ivan@example.com',
'role' => 'user',
]);
// Вставка с null-значениями
$db->insert('users', [
'name' => 'Ivan',
'email' => null,
'phone' => null,
]);
// Проверка результата
$result = $db->insert('users', ['name' => 'Ivan']);
if ($result == 1) {
$id = $db->last_insert_id();
}
update()
public function update(string $table, array $filter, array $data, ?array $data2 = null): int
Обновить записи в таблице по фильтру. Фильтр применяется через applyFilterToQuery().
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$table | string | Имя таблицы | — | Да |
$filter | array | Массив фильтрации (условия WHERE) | — | Да |
$data | array | Данные для обновления | — | Да |
$data2 | ?\array | Дополнительные данные (не используется) | null | Нет |
Возвращает: int — 1 при успехе, -1 при ошибке
// Обновление одной записи по ID
$db->update('users', ['pkid' => 1], ['name' => 'Ivan Updated']);
// Обновление с составным фильтром
$db->update('users', ['status' => 1, 'role' => 'user'], ['role' => 'moderator']);
// Обновление с IO-операторами
$db->update('orders', ['status' => 'pending', '<created_at' => '2024-01-01'], ['status' => 'expired']);
// Обновление нескольких записей
$db->update('users', ['role' => 'user'], ['active' => 1]);
delete()
public function delete(string $table, array $filter, ?int $count = null): int
Удалить записи из таблицы по фильтру. Фильтр применяется через applyFilterToQuery().
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$table | string | Имя таблицы | — | Да |
$filter | array | Массив фильтрации (условия WHERE) | — | Да |
$count | ?\int | Ограничение количества удаляемых записей | null | Нет |
Возвращает: int — 1 при успехе, -1 при ошибке
// Удаление одной записи
$db->delete('users', ['pkid' => 1]);
// Удаление по фильтру
$db->delete('users', ['status' => 'banned']);
// Удаление с лимитом
$db->delete('logs', ['level' => 'debug'], 100);
// Удаление с IO-операторами
$db->delete('sessions', ['<expires_at' => date('Y-m-d H:i:s')]);
// Удаление soft-deleted записей
$db->delete('users', ['!~deleted_at' => null]);
insert_or_update()
public function insert_or_update(string $table, array $data, ?array $data2 = null): int
Вставить запись или обновить при существовании (MySQL: ON DUPLICATE KEY UPDATE, PostgreSQL: ON CONFLICT DO UPDATE).
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$table | string | Имя таблицы | — | Да |
$data | array | Ассоциативный массив данных (должен содержать уникальный ключ) | — | Да |
$data2 | ?\array | Дополнительные данные (не используется) | null | Нет |
Возвращает: int — 1 при успехе, -1 при ошибке
// Upsert по primary key
$db->insert_or_update('users', [
'pkid' => 1,
'name' => 'Ivan Updated',
'email' => 'ivan@example.com',
]);
// Upsert по уникальному полю
$db->insert_or_update('settings', [
'key' => 'site_name',
'value' => 'Новый сайт',
]);
insert_or_ignore()
public function insert_or_ignore(string $table, array $data, ?array $data2 = null): int
Вставить запись или проигнорировать при конфликте (MySQL: INSERT IGNORE, PostgreSQL: ON CONFLICT DO NOTHING).
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$table | string | Имя таблицы | — | Да |
$data | array | Ассоциативный массив данных | — | Да |
$data2 | ?\array | Дополнительные данные (не используется) | null | Нет |
Возвращает: int — 1 при успехе, -1 при ошибке
// Игнорирование дубликата
$db->insert_or_ignore('users', [
'login' => 'admin',
'name' => 'Администратор',
]);
// Безопасная вставка в цикле
$tags = ['php', 'mysql', 'laravel'];
foreach ($tags as $tag) {
$db->insert_or_ignore('tags', ['name' => $tag]);
}
search()
public function search(string $table, array $params): array
Высокоуровневый поиск записей с поддержкой фильтров, JOIN, GROUP BY, ORDER BY, пагинации и агрегации.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$table | string | Имя таблицы | — | Да |
$params | array | Параметры поиска (см. ниже) | — | Да |
Параметры $params:
| Ключ | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$params['filter'] | ?\array | IO-фильтр для условий WHERE | null | Нет |
$params['fields'] | ?\array | Список полей для SELECT (поддерживает # для raw-выражений) | null (все поля) | Нет |
$params['join'] | array|string|null | JOIN-выражение (raw SQL) | null | Нет |
$params['groupby'] | ?\array | Поля для GROUP BY | null | Нет |
$params['order'] | ?\array | Ассоциативный массив field => direction (asc/desc) | null | Нет |
$params['distinct'] | bool | DISTINCT-выборка | false | Нет |
$params['limit'] | int | Лимит строк | 1000 | Нет |
$params['start'] | int | Смещение (offset) | 0 | Нет |
Возвращает: array с ключами:
| Ключ | Тип | Описание |
|---|---|---|
error_str | string | Строка ошибки (пустая при успехе) |
error_code | int | Код ошибки (EIO_OK при успехе) |
res | array | Массив найденных записей (ассоциативные массивы) |
count | int | Общее количество записей (без учёта LIMIT) |
time | int | Время выполнения запроса (мс) |
// Простой поиск
$result = $db->search('users', [
'filter' => ['status' => 1],
]);
foreach ($result['res'] as $user) {
echo $user['name'] . "\n";
}
echo "Всего: {$result['count']}\n";
// Поиск с фильтрами, сортировкой и лимитом
$result = $db->search('users', [
'filter' => [
'status' => 1,
'%name' => 'Иван',
'>age' => 18,
'$or' => [
['role' => 'admin'],
['role' => 'manager'],
],
],
'fields' => ['id', 'name', 'email', 'role'],
'order' => ['name' => 'asc'],
'limit' => 25,
'start' => 0,
]);
// С JOIN
$result = $db->search('orders', [
'filter' => ['status' => 'pending'],
'fields' => ['orders.*', 'users.name as user_name'],
'join' => 'JOIN users ON users.id = orders.user_id',
'order' => ['orders.created_at' => 'desc'],
'limit' => 50,
]);
// С GROUP BY
$result = $db->search('orders', [
'fields' => ['user_id', '#COUNT(*) as order_count'],
'groupby' => ['user_id'],
'filter' => ['>order_count' => 5],
]);
// DISTINCT
$result = $db->search('users', [
'fields' => ['role'],
'distinct' => true,
]);
dbsearch2()
public function dbsearch2(string $table, array $params): array
Алиас для search(). Используется для совместимости с IO v6.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$table | string | Имя таблицы | — | Да |
$params | array | Параметры поиска (аналогично search()) | — | Да |
Возвращает: array — аналогично search()
$result = $db->dbsearch2('users', [
'filter' => ['status' => 1],
'order' => ['name' => 'asc'],
]);
sync_items()
public function sync_items(string $table, array $params): void
Синхронизация элементов: создание новых, обновление существующих и удаление отсутствующих. Выполняет three-way diff между текущими и новыми данными.
| Параметр | Тип | Описание | Значение по умолчанию | Обязателен |
|---|---|---|---|---|
$table | string | Имя таблицы | — | Да |
$params | array | Параметры синхронизации (см. ниже) | — | Да |
Параметры $params:
| Ключ | Тип | Описание | Обязателен |
|---|---|---|---|
$params['new_items'] | array | Новые элементы для синхронизации | Да |
$params['filter'] | array | Фильтр для поиска текущих элементов | Да |
$params['find'] | callable | Функция сравнения: function(array $old, array $new): bool | Да |
$params['create'] | callable|null | Функция создания: function(array $new): void | Нет |
$params['update'] | callable|null | Функция обновления: function(array $old, array $new): void | Нет |
$params['delete'] | callable|null | Функция удаления: function(array $old): void | Нет |
$db->sync_items('categories', [
'new_items' => $importedCategories,
'filter' => ['parent_id' => 0],
'find' => function(array $old, array $new): bool {
return $old['code'] === $new['code'];
},
'create' => function(array $new) use ($db): void {
$db->insert('categories', $new);
},
'update' => function(array $old, array $new) use ($db): void {
$db->update('categories', ['pkid' => $old['pkid']], $new);
},
'delete' => function(array $old) use ($db): void {
$db->delete('categories', ['pkid' => $old['pkid']]);
},
]);
SqlConnection — транзакции
beginTransaction()
public function beginTransaction(): bool
Начать транзакцию.
Возвращает: bool — true при успехе
commit()
public function commit(): bool
Зафиксировать транзакцию.
Возвращает: bool — true при успехе
rollBack()
public function rollBack(): bool
Откатить транзакцию.
Возвращает: bool — true при успехе
$db->beginTransaction();
try {
$db->update('accounts', ['pkid' => 1], ['balance' => '-100']);
$db->update('accounts', ['pkid' => 2], ['balance' => '+100']);
$db->commit();
} catch (\Exception $e) {
$db->rollBack();
throw $e;
}
// Или через Laravel Query Builder
\DB::beginTransaction();
try {
SqlConnection::table('accounts')
->where('pkid', 1)
->decrement('balance', 100);
SqlConnection::table('accounts')
->where('pkid', 2)
->increment('balance', 100);
\DB::commit();
} catch (\Exception $e) {
\DB::rollBack();
throw $e;
}
SqlConnection — вспомогательные методы
information_schema_load_current_db()
public function information_schema_load_current_db(): void
Загрузить структуру таблиц текущей БД из information_schema (MySQL). Результат сохраняется в свойстве $this->columns.
$db->information_schema_load_current_db();
print_r($db->columns);
Laravel Query Builder
После вызова SqlConnection::table() возвращается стандартный Laravel Query Builder. Все методы Query Builder доступны напрямую.
Методы выборки
| Метод | Описание |
|---|---|
get() | Получить все записи |
first() | Получить первую запись |
value($column) | Получить значение одного поля |
pluck($column, $key) | Получить коллекцию значений |
count() | Количество записей |
sum($column) | Сумма значений |
avg($column) | Среднее значение |
min($column) | Минимальное значение |
max($column) | Максимальное значение |
exists() | Существуют ли записи |
doesntExist() | Не существуют ли записи |
Методы фильтрации
| Метод | Описание |
|---|---|
where($col, $op, $val) | Условие WHERE |
orWhere($col, $op, $val) | Условие OR WHERE |
whereNull($col) | WHERE IS NULL |
whereNotNull($col) | WHERE IS NOT NULL |
whereIn($col, $arr) | WHERE IN (...) |
whereNotIn($col, $arr) | WHERE NOT IN (...) |
whereBetween($col, $range) | WHERE BETWEEN |
whereRaw($sql, $bindings) | WHERE raw-выражение |
Методы сортировки и группировки
| Метод | Описание |
|---|---|
orderBy($col, $dir) | ORDER BY |
latest($col) | ORDER BY $col DESC |
oldest($col) | ORDER BY $col ASC |
groupBy(...$cols) | GROUP BY |
having($col, $op, $val) | HAVING |
distinct() | DISTINCT |
Методы JOIN
| Метод | Описание |
|---|---|
join($table, $first, $op, $second) | INNER JOIN |
leftJoin(...) | LEFT JOIN |
rightJoin(...) | RIGHT JOIN |
joinRaw($sql) | JOIN raw-выражение |
Методы пагинации
| Метод | Описание |
|---|---|
skip($n) | OFFSET |
take($n) | LIMIT |
limit($n) | LIMIT |
offset($n) | OFFSET |
paginate($perPage) | Постраничный вывод |
Методы вставки/обновления
| Метод | Описание |
|---|---|
insert($data) | INSERT |
insertGetId($data) | INSERT с возвратом ID |
update($data) | UPDATE |
increment($col, $amt) | Инкремент |
decrement($col, $amt) | Декремент |
delete() | DELETE |
Примеры
// where
$users = SqlConnection::table('users')
->where('active', 1)
->where('age', '>=', 18)
->get();
// orWhere
$admins = SqlConnection::table('users')
->where('role', 'admin')
->orWhere('role', 'superadmin')
->get();
// join
$orders = SqlConnection::table('orders')
->join('users', 'users.id', '=', 'orders.user_id')
->select('orders.*', 'users.name')
->get();
// groupBy + having
$stats = SqlConnection::table('orders')
->select('user_id', \DB::raw('COUNT(*) as cnt'))
->groupBy('user_id')
->having('cnt', '>=', 5)
->get();
// paginate
$users = SqlConnection::table('users')
->where('active', 1)
->orderBy('name')
->paginate(25);
// aggregate
$count = SqlConnection::table('users')->where('active', 1)->count();
$total = SqlConnection::table('orders')->sum('total');
IO-фильтры — справочник синтаксиса
IO-фильтры — единый формат фильтрации, работающий с search(), applyFilterToQuery() и getWhereFromFilter().
Операторы сравнения
| Оператор в ключе | SQL | Описание | Пример |
|---|---|---|---|
field (без префикса) | field = value | Равно (по умолчанию) | 'status' => 1 |
=field | field = value | Явное равно | '=status' => 1 |
!field | field != value | Не равно | '!status' => 'banned' |
!=field | field != value | Не равно (явное) | '!=status' => 'banned' |
<field | field < value | Меньше | '<age' => 18 |
<=field | field <= value | Меньше или равно | '<=price' => 1000 |
>field | field > value | Больше | '>age' => 18 |
>=field | field >= value | Больше или равно | '>=rating' => 4.5 |
%field | field LIKE '%value%' | Поиск подстроки | '%name' => 'Иван' |
~field (value = null) | field IS NULL | IS NULL | '~deleted_at' => null |
!~field (value = null) | field IS NOT NULL | IS NOT NULL | '!~deleted_at' => null |
Логические операторы
| Оператор | Описание | Формат |
|---|---|---|
$or | Логическое ИЛИ — массив условий, соединяемых OR | '$or' => [[$cond1], [$cond2]] |
$and | Логическое И — массив условий, соединяемых AND | '$and' => [[$cond1], [$cond2]] |
Специальные значения
| Значение | Поведение | Пример |
|---|---|---|
null | Для =/~ → IS NULL; для !=/!~ → IS NOT NULL | '~field' => null |
array (пустой) | WHERE 1 = 0 (ничего не вернёт) | 'tags' => [] |
array (с =) | WHERE field IN (...) | 'role' => ['admin', 'user'] |
array (с !=) | WHERE field NOT IN (...) | '!role' => ['banned'] |
array (с %) | WHERE field LIKE '%v1%' AND field LIKE '%v2%' | '%name' => ['Иван', 'Петров'] |
array (с др.) | WHERE (field op 'v1' AND field op 'v2') | '>age' => [18, 21] |
Приоритет парсинга операторов
- Двухсимвольные операторы (проверяются первыми):
!=,<=,>=,!~ - Односимвольные операторы:
=,!,<,>,%,~ - Без префикса:
=(равно)
Примеры фильтров
Простые условия
$filter = [
'status' => 1, // WHERE status = 1
'role' => 'admin', // WHERE role = 'admin'
'active' => true, // WHERE active = 1
];
Поиск подстроки
$filter = [
'%name' => 'Иван', // WHERE name LIKE '%Иван%'
'%email' => '@example.com', // WHERE email LIKE '%@example.com%'
];
Сравнения
$filter = [
'>age' => 18, // WHERE age > 18
'<=price' => 1000, // WHERE price <= 1000
'>=rating' => 4.5, // WHERE rating >= 4.5
'!status' => 'banned', // WHERE status != 'banned'
'!=role' => 'deleted', // WHERE role != 'deleted'
];
NULL-проверки
$filter = [
'~deleted_at' => null, // WHERE deleted_at IS NULL
'!~deleted_at' => null, // WHERE deleted_at IS NOT NULL
];
IN (массив значений)
$filter = [
'role' => ['admin', 'moderator'], // WHERE role IN ('admin', 'moderator')
];
NOT IN
$filter = [
'!role' => ['banned', 'deleted'], // WHERE role NOT IN ('banned', 'deleted')
];
OR
$filter = [
'$or' => [
['type' => 'premium'],
['status' => 'active'],
],
];
// WHERE (type = 'premium') OR (status = 'active')
AND
$filter = [
'$and' => [
['status' => 1],
['>age' => 18],
],
];
// WHERE (status = 1) AND (age > 18)
Сложные комбинации
$filter = [
'status' => 1,
'%name' => 'Иван',
'$or' => [
['role' => 'admin'],
['role' => 'manager'],
],
'!~deleted_at' => null,
];
// WHERE status = 1
// AND name LIKE '%Иван%'
// AND (role = 'admin' OR role = 'manager')
// AND deleted_at IS NOT NULL
Пустой массив
$filter = [
'tags' => [], // WHERE 1 = 0 (ничего не вернёт)
];
Массив с оператором %
$filter = [
'%tags' => ['php', 'mysql'], // WHERE tags LIKE '%php%' AND tags LIKE '%mysql%'
];
Примеры
Поиск с фильтрами
$result = $db->search('users', [
'filter' => [
'status' => 1,
'%name' => 'Иван',
'>age' => 18,
'$or' => [
['role' => 'admin'],
['role' => 'manager'],
],
],
'fields' => ['id', 'name', 'email', 'role'],
'order' => ['name' => 'asc'],
'limit' => 25,
'start' => 0,
]);
foreach ($result['res'] as $user) {
echo "{$user['name']} ({$user['role']})\n";
}
echo "Всего: {$result['count']}\n";
JOIN через search()
$result = $db->search('orders', [
'fields' => [
'orders.id',
'users.name as user_name',
'products.name as product_name',
'orders.total',
],
'join' => [
'JOIN users ON users.id = orders.user_id',
'JOIN products ON products.id = orders.product_id',
],
'filter' => ['orders.status' => 'pending'],
'order' => ['orders.created_at' => 'desc'],
'limit' => 50,
]);
JOIN через Query Builder
$orders = SqlConnection::table('orders')
->join('users', 'users.id', '=', 'orders.user_id')
->join('products', 'products.id', '=', 'orders.product_id')
->select(
'orders.id',
'users.name as user_name',
'products.name as product_name',
'orders.total'
)
->where('orders.status', 'pending')
->orderBy('orders.created_at', 'desc')
->limit(50)
->get();
GROUP BY + HAVING
$stats = SqlConnection::table('orders')
->select(
'user_id',
\DB::raw('COUNT(*) as order_count'),
\DB::raw('SUM(total) as total_spent')
)
->groupBy('user_id')
->having('order_count', '>=', 5)
->orderBy('total_spent', 'desc')
->get();
Пагинация
$page = request('page', 1);
$perPage = 25;
$users = SqlConnection::table('users')
->where('active', 1)
->orderBy('name')
->paginate($perPage);
// В шаблоне
echo $users->links();
Агрегаты
$count = SqlConnection::table('users')->where('active', 1)->count();
$total = SqlConnection::table('orders')->where('status', 'completed')->sum('total');
$avg = SqlConnection::table('orders')->avg('total');
$min = SqlConnection::table('products')->min('price');
$max = SqlConnection::table('products')->max('price');
Подзапросы
$activeUserIds = SqlConnection::table('users')
->where('active', 1)
->pluck('id');
$orders = SqlConnection::table('orders')
->whereIn('user_id', $activeUserIds)
->get();
Union
$admins = SqlConnection::table('users')->where('role', 'admin');
$managers = SqlConnection::table('users')->where('role', 'manager');
$all = $admins->union($managers)->get();
Raw-запросы
// selectRaw
$results = SqlConnection::table('orders')
->selectRaw('DATE(created_at) as date, COUNT(*) as count')
->groupByRaw('DATE(created_at)')
->get();
// whereRaw
$results = SqlConnection::table('users')
->whereRaw('YEAR(created_at) = ?', [2024])
->get();
// havingRaw
$results = SqlConnection::table('orders')
->select('user_id', \DB::raw('COUNT(*) as cnt'))
->groupBy('user_id')
->havingRaw('COUNT(*) > ?', [5])
->get();
Raw-запросы через PDO
// SELECT
$r = $db->query("SELECT * FROM users WHERE active = 1");
$rows = $db->fetchAll($r);
$db->free_result($r);
// INSERT
$db->query("INSERT INTO logs (msg, level) VALUES ('test', 'info')");
// UPDATE
$db->query("UPDATE users SET active = 0 WHERE id = 1");
// DELETE
$db->query("DELETE FROM logs WHERE created_at < '2024-01-01'");
Транзакции
// Через raw PDO
$db->beginTransaction();
try {
$db->update('accounts', ['pkid' => 1], ['balance' => '-100']);
$db->update('accounts', ['pkid' => 2], ['balance' => '+100']);
$db->commit();
} catch (\Exception $e) {
$db->rollBack();
throw $e;
}
// Через Laravel Query Builder
\DB::beginTransaction();
try {
SqlConnection::table('accounts')
->where('pkid', 1)
->decrement('balance', 100);
SqlConnection::table('accounts')
->where('pkid', 2)
->increment('balance', 100);
\DB::commit();
} catch (\Exception $e) {
\DB::rollBack();
throw $e;
}
Raw WHERE + getWhereFromFilter
$where = SqlConnection::getWhereFromFilter([
'status' => 1,
'%name' => 'Иван',
'$or' => [
['role' => 'admin'],
['role' => 'manager'],
],
]);
$r = $db->query("SELECT * FROM users WHERE $where");
$rows = $db->fetchAll($r);
applyFilterToQuery в цепочке
$filter = [
'status' => 1,
'%name' => 'Иван',
'!~deleted_at' => null,
];
$users = SqlConnection::table('users')
->select('id', 'name', 'email')
->orderBy('name');
$users = SqlConnection::applyFilterToQuery($users, $filter);
$results = $users->paginate(25);
Рекомендации
- Используйте
select()вместоSELECT *— указывайте только нужные поля - Используйте IO-фильтры для единообразия фильтрации через
search()иapplyFilterToQuery() - Избегайте N+1 — используйте
join()или eager loading - Используйте
chunk()для обработки больших наборов данных - Кэшируйте частые запросы через Redis
- Используйте
paginate()для постраничного вывода - Проверяйте
exists()вместоcount() > 0 - Используйте
search()для высокоуровневых запросов с фильтрами - Используйте
create_conn()для кэширования подключений - Используйте транзакции для операций, требующих атомарности
FAQ
Как использовать where с null?
// IS NULL
->whereNull('deleted_at')
// IS NOT NULL
->whereNotNull('email')
Как выполнить raw SQL?
// Через PDO
$r = $db->query("SELECT * FROM users WHERE id = 1");
$row = $db->fetch_assoc($r);
// Через query_params
$r = $db->query_params(
"SELECT * FROM users WHERE login = :login",
[':login' => 'admin']
);
Как добавить индекс через Query Builder?
SqlConnection::connection()->getSchemaBuilder()
->table('users', function (\Illuminate\Database\Schema\Blueprint $table): void {
$table->index('email');
$table->unique('login');
});
Как работает applyFilterToQuery?
Метод рекурсивно обрабатывает массив фильтров. Каждый элемент конвертируется в соответствующий вызов Query Builder (where, whereIn, whereNull, whereNotNull и т.д.). Логические операторы $or и $and оборачиваются в групповые условия.
Как использовать DB::raw()?
use Illuminate\Support\Facades\DB;
SqlConnection::table('orders')
->select(DB::raw('SUM(total) as sum_total'))
->groupBy('status')
->get();
Чем search() отличается от query()?
search()— высокоуровневый метод с поддержкой IO-фильтров, JOIN, GROUP BY, ORDER BY и пагинацииquery()— raw PDO-запрос с ручным написанием SQLsearch()безопаснее (использует Query Builder) и удобнее для типовых задач
Как безопасно подставлять параметры в raw-запросы?
Используйте query_params() с плейсхолдерами:
$r = $db->query_params(
"SELECT * FROM users WHERE name = :name AND age > :age",
[':name' => $name, ':age' => $age]
);
Или escape() для ручного экранирования:
$safeName = SqlConnection::escape($name);
$r = $db->query("SELECT * FROM users WHERE name = '$safeName'");