Основы работы с БД
Изучите базовые принципы работы с базами данных в MNRFY Framework
Введение
MNRFY Framework предоставляет мощный и интуитивный интерфейс для работы с различными типами баз данных. Система поддерживает MySQL, PostgreSQL и SQLite, обеспечивая единообразный API для всех типов подключений.
🔗 Множественные подключения
Подключайтесь к нескольким базам данных одновременно
🛡️ Безопасность
Автоматическая защита от SQL-инъекций
⚡ Производительность
Встроенное кеширование запросов
🔄 Транзакции
Поддержка транзакций для безопасных операций
Настройка подключения
Конфигурационный файл database.json
Создайте файл /src/config/database.json для настройки подключений:
{
"connections": {
"1752665380840": {
"type": "mysql",
"host": "localhost",
"port": 3306,
"database": "mnrfy_app",
"username": "mnrfy_user",
"password": "secure_password",
"charset": "utf8mb4",
"collation": "utf8mb4_unicode_ci",
"strict": true,
"engine": "InnoDB"
},
"sqlite_connection": {
"type": "sqlite",
"path": "/src/sqlite/app.db"
},
"postgres_connection": {
"type": "postgresql",
"host": "localhost",
"port": 5432,
"database": "mnrfy_app",
"username": "postgres",
"password": "password",
"charset": "utf8",
"schema": "public"
}
},
"default": "1752665380840"
}
Типы баз данных
| Тип | Описание | Конфигурация |
|---|---|---|
| MySQL | Популярная реляционная БД | host, port, database, username, password |
| PostgreSQL | Мощная объектно-реляционная БД | host, port, database, username, password, schema |
| SQLite | Локальная файловая БД | path (путь к файлу .db) |
Автоматическое создание SQLite
При использовании IDE MNRFY, SQLite файлы создаются автоматически в папке /src/sqlite/:
/src/sqlite/
├── users.db # База пользователей
├── products.db # База товаров
└── logs.db # База логов
Основные методы работы
Получение подключения
<!-- В шаблонах -->
{% set database = db('1752665380840') %}
<!-- Использование по умолчанию -->
{% set database = db() %}
Получение записей (SELECT)
<!-- Все записи -->
{% set users = db('1752665380840')->getItems('users') %}
<!-- С условиями -->
{% set activeUsers = db('1752665380840')->getItems('users', {
'active': 1,
'ban': 0
}) %}
<!-- С выбором полей -->
{% set usernames = db('1752665380840')->getItems('users', {}, [
'id', 'login', 'email'
]) %}
<!-- С сортировкой -->
{% set sortedUsers = db('1752665380840')->getItems(
'users', # таблица
{'ban': 0}, # условия
['*'], # поля
'created_at', # поле сортировки
'DESC' # направление
) %}
<!-- С лимитом -->
{% set recentUsers = db('1752665380840')->getItems(
'users',
{'active': 1},
['*'],
'created_at',
'DESC',
null, # сырой SQL
10 # лимит
) %}
Получение одной записи
<!-- По ID -->
{% set user = db('1752665380840')->getItem('users', {'id': userId}) %}
<!-- По логину -->
{% set user = db('1752665380840')->getItem('users', {'login': username}) %}
<!-- По email -->
{% set user = db('1752665380840')->getItem('users', {
'email': email,
'active': 1
}) %}
Подсчет записей
<!-- Общее количество -->
{% set totalUsers = db('1752665380840')->countItems('users') %}
<!-- С условиями -->
{% set activeUsers = db('1752665380840')->countItems('users', {'active': 1}) %}
{% set bannedUsers = db('1752665380840')->countItems('users', {'ban': 1}) %}
{% set onlineUsers = db('1752665380840')->countItems('users', {
'last_seen': '>' ~ (time() - 300)
}) %}
Условия WHERE
Простые условия
<!-- Равенство -->
{% set admins = db('1752665380840')->getItems('users', {'role': 'admin'}) %}
<!-- Не равенство -->
{% set nonGuests = db('1752665380840')->getItems('users', {'role': '!=guest'}) %}
<!-- Числовые сравнения -->
{% set richUsers = db('1752665380840')->getItems('users', {'balance': '>1000'}) %}
{% set youngUsers = db('1752665380840')->getItems('users', {'age': '<25'}) %}
{% set eligibleUsers = db('1752665380840')->getItems('users', {'age': '>=18'}) %}
Поиск по шаблону
<!-- LIKE запросы -->
{% set johnUsers = db('1752665380840')->getItems('users', {'name': '%John%'}) %}
{% set gmailUsers = db('1752665380840')->getItems('users', {'email': '%@gmail.com'}) %}
<!-- Начинается с -->
{% set aUsers = db('1752665380840')->getItems('users', {'login': 'admin%'}) %}
Множественный выбор (IN)
<!-- Массив значений -->
{% set moderators = db('1752665380840')->getItems('users', {
'role': ['admin', 'moderator', 'supervisor']
}) %}
{% set specificUsers = db('1752665380840')->getItems('users', {
'id': [1, 5, 10, 15, 20]
}) %}
Логические операторы
AND условия (по умолчанию)
<!-- Все условия должны выполняться -->
{% set targetUsers = db('1752665380840')->getItems('users', {
'active': 1,
'ban': 0,
'verified': 1,
'balance': '>100'
}) %}
OR условия
<!-- Любое из условий -->
{% set vipUsers = db('1752665380840')->getItems('users', {
'role': 'admin',
'balance': '>10000',
'is_premium': 1,
'implode': 'OR'
}) %}
Работа с датами
Временные интервалы
<!-- Сегодня -->
{% set todayUsers = db('1752665380840')->getItems('users', {
'created_at': '>=' ~ strtotime('today')
}) %}
<!-- За последнюю неделю -->
{% set weekUsers = db('1752665380840')->getItems('users', {
'created_at': '>' ~ (time() - 604800)
}) %}
<!-- За последний час онлайн -->
{% set recentlyOnline = db('1752665380840')->getItems('users', {
'last_seen': '>' ~ (time() - 3600)
}) %}
Диапазоны дат
<!-- Между датами -->
{% set monthUsers = db('1752665380840')->getItems('users', {
'created_at': '>=' ~ strtotime('first day of this month'),
'created_at ': '<=' ~ strtotime('last day of this month')
}) %}
Пагинация
Автоматическая пагинация
<!-- Получение страницы из запроса -->
{% set page = request.input('page', 1) %}
{% set perPage = 20 %}
<!-- Пагинированный результат -->
{% set users = db('1752665380840')->paginate(
'users', # таблица
page, # номер страницы
perPage, # записей на страницу
{'ban': 0}, # условия
'created_at', # сортировка
'DESC' # направление
) %}
<!-- Отображение данных -->
{% foreach users.data as user %}
<div class="user-card">
<h3>{{ user.login }}</h3>
<p>{{ user.email }}</p>
</div>
{% endforeach %}
<!-- Информация о пагинации -->
<div class="pagination-info">
<p>
Показано {{ users.from }} - {{ users.to }}
из {{ users.total }} записей
</p>
<p>Страница {{ users.current_page }} из {{ users.last_page }}</p>
</div>
Навигация по страницам
<!-- Простая навигация -->
<nav class="pagination">
{% if users.prev_page %}
<a href="?page={{ users.prev_page }}" class="prev">
← Предыдущая
</a>
{% endif %}
<span class="current">
Страница {{ users.current_page }}
</span>
{% if users.next_page %}
<a href="?page={{ users.next_page }}" class="next">
Следующая →
</a>
{% endif %}
</nav>
<!-- Детальная навигация -->
<nav class="pagination-detailed">
{% if users.current_page > 1 %}
<a href="?page=1">Первая</a>
{% endif %}
{% for page in (users.current_page - 2)..(users.current_page + 2) %}
{% if page >= 1 and page <= users.last_page %}
{% if page == users.current_page %}
<span class="active">{{ page }}</span>
{% else %}
<a href="?page={{ page }}">{{ page }}</a>
{% endif %}
{% endif %}
{% endfor %}
{% if users.current_page < users.last_page %}
<a href="?page={{ users.last_page }}">Последняя</a>
{% endif %}
</nav>
Практические примеры
Список пользователей с фильтрами
<!-- Получение параметров фильтров -->
{% set filterRole = request.input('role') %}
{% set filterStatus = request.input('status') %}
{% set search = request.input('search') %}
<!-- Построение условий -->
{% set conditions = {} %}
{% if filterRole %}
{% set conditions = conditions | merge({'role': filterRole}) %}
{% endif %}
{% if filterStatus == 'active' %}
{% set conditions = conditions | merge({'ban': 0}) %}
{% elseif filterStatus == 'banned' %}
{% set conditions = conditions | merge({'ban': 1}) %}
{% endif %}
{% if search %}
{% set conditions = conditions | merge({'login': '%' ~ search ~ '%'}) %}
{% endif %}
<!-- Получение данных -->
{% set page = request.input('page', 1) %}
{% set users = db('1752665380840')->paginate(
'users', page, 25, conditions, 'created_at', 'DESC'
) %}
<!-- Форма фильтров -->
<form method="GET" class="filters">
<div class="filter-group">
<label>Роль:</label>
<select name="role">
<option value="">Все роли</option>
<option value="user" {{ filterRole == 'user' ? 'selected' : '' }}>Пользователи</option>
<option value="admin" {{ filterRole == 'admin' ? 'selected' : '' }}>Администраторы</option>
</select>
</div>
<div class="filter-group">
<label>Статус:</label>
<select name="status">
<option value="">Все статусы</option>
<option value="active" {{ filterStatus == 'active' ? 'selected' : '' }}>Активные</option>
<option value="banned" {{ filterStatus == 'banned' ? 'selected' : '' }}>Заблокированные</option>
</select>
</div>
<div class="filter-group">
<label>Поиск:</label>
<input type="text" name="search" value="{{ search }}" placeholder="Логин пользователя">
</div>
<button type="submit">Фильтровать</button>
<a href="?">Сбросить</a>
</form>
<!-- Результаты -->
<div class="results">
<h3>Найдено пользователей: {{ users.total }}</h3>
{% foreach users.data as user %}
<div class="user-row">
<div class="user-info">
<strong>{{ user.login }}</strong>
<span class="role role-{{ user.role }}">{{ user.role | upper }}</span>
<span class="status {{ user.ban ? 'banned' : 'active' }}">
{{ user.ban ? 'Заблокирован' : 'Активен' }}
</span>
</div>
<div class="user-stats">
<span>Баланс: {{ user.balance | money('₽') }}</span>
<span>Регистрация: {{ user.created_at | date('d.m.Y') }}</span>
</div>
</div>
{% endforeach %}
</div>
Статистическая сводка
<!-- Основная статистика -->
<div class="dashboard-stats">
{% set totalUsers = db('1752665380840')->countItems('users') %}
{% set activeUsers = db('1752665380840')->countItems('users', {'ban': 0}) %}
{% set onlineUsers = db('1752665380840')->countItems('users', {
'last_seen': '>' ~ (time() - 300)
}) %}
{% set todayUsers = db('1752665380840')->countItems('users', {
'created_at': '>=' ~ strtotime('today')
}) %}
<div class="stat-card">
<div class="stat-number">{{ totalUsers | number }}</div>
<div class="stat-label">Всего пользователей</div>
</div>
<div class="stat-card">
<div class="stat-number">{{ activeUsers | number }}</div>
<div class="stat-label">Активных пользователей</div>
<div class="stat-percentage">
{{ (activeUsers / totalUsers * 100) | round(1) }}%
</div>
</div>
<div class="stat-card">
<div class="stat-number">{{ onlineUsers | number }}</div>
<div class="stat-label">Сейчас онлайн</div>
</div>
<div class="stat-card">
<div class="stat-number">{{ todayUsers | number }}</div>
<div class="stat-label">Новых сегодня</div>
</div>
</div>
Безопасность: Все запросы автоматически защищены от SQL-инъекций. MNRFY использует подготовленные запросы (prepared statements) для всех операций с базой данных.
Следующий шаг: Изучите запросы и операторы для более сложных операций с БД.