Автоматическая обработка форм
Создание и обработка форм без написания PHP кода с помощью встроенных возможностей MNRFY
Введение
MNRFY предоставляет мощную систему автоматической обработки форм, которая позволяет создавать, редактировать и удалять записи в базе данных без написания PHP кода. Вся логика встроена в фреймворк и настраивается через специальные скрытые поля.
CSRF защита
Важно! Все формы должны содержать CSRF токен для защиты от межсайтовой подделки запросов.
<form method="POST" action="/">
{{ csrf() }} <!-- Обязательно в каждой форме! -->
<!-- Остальные поля формы -->
</form>
Создание записей (CREATE)
Базовая форма создания
<!-- Форма создания пользователя -->
<form method="POST" action="/">
{{ csrf() }}
<!-- Конфигурация обработки -->
<input type="hidden" name="__database" value="1752665380840">
<input type="hidden" name="__table" value="users">
<input type="hidden" name="__action" value="create">
<div class="form-group">
<label>Логин *</label>
<input type="text" name="login" required minlength="3" maxlength="20">
</div>
<div class="form-group">
<label>Имя</label>
<input type="text" name="fname" maxlength="50">
</div>
<div class="form-group">
<label>Фамилия</label>
<input type="text" name="lname" maxlength="50">
</div>
<div class="form-group">
<label>Email</label>
<input type="email" name="email">
</div>
<div class="form-group">
<label>Баланс</label>
<input type="number" name="balance" value="0" step="0.01">
</div>
<div class="form-group">
<label>Роль</label>
<select name="role">
<option value="user">Пользователь</option>
<option value="moderator">Модератор</option>
<option value="admin">Администратор</option>
</select>
</div>
<div class="form-group">
<label>
<input type="checkbox" name="is_active" value="1" checked>
Активен
</label>
</div>
<button type="submit" class="btn btn-primary">Создать пользователя</button>
</form>
Обязательные поля для создания
| Поле | Описание | Пример |
|---|---|---|
__database |
ID подключения к БД | 1752665380840 |
__table |
Имя таблицы | users |
__action |
Действие | create |
Автоматические поля
При создании записи автоматически добавляются:
created_at- текущий timestampupdated_at- текущий timestampip_address- IP адрес пользователя
Обновление записей (UPDATE)
Форма редактирования
<!-- Получаем данные пользователя -->
{% set user = db('1752665380840')->getItem('users', {'id': userId}) %}
<form method="POST" action="/">
{{ csrf() }}
<!-- Конфигурация обработки -->
<input type="hidden" name="__database" value="1752665380840">
<input type="hidden" name="__table" value="users">
<input type="hidden" name="__action" value="update">
<input type="hidden" name="id" value="{{ user.id }}"> <!-- ID записи для обновления -->
<div class="form-group">
<label>Логин</label>
<input type="text" name="login" value="{{ user.login }}" readonly>
<small>Логин нельзя изменить</small>
</div>
<div class="form-group">
<label>Имя</label>
<input type="text" name="fname" value="{{ user.fname }}">
</div>
<div class="form-group">
<label>Фамилия</label>
<input type="text" name="lname" value="{{ user.lname }}">
</div>
<div class="form-group">
<label>Email</label>
<input type="email" name="email" value="{{ user.email }}">
</div>
<div class="form-group">
<label>Баланс</label>
<input type="number" name="balance" value="{{ user.balance }}" step="0.01">
</div>
<div class="form-group">
<label>Роль</label>
<select name="role">
<option value="user" {{ user.role == 'user' ? 'selected' : '' }}>Пользователь</option>
<option value="moderator" {{ user.role == 'moderator' ? 'selected' : '' }}>Модератор</option>
<option value="admin" {{ user.role == 'admin' ? 'selected' : '' }}>Администратор</option>
</select>
</div>
<div class="form-group">
<label>
<input type="checkbox" name="is_active" value="1" {{ user.is_active ? 'checked' : '' }}>
Активен
</label>
</div>
<button type="submit" class="btn btn-success">Сохранить изменения</button>
</form>
Обязательные поля для обновления
| Поле | Описание |
|---|---|
__action |
Значение update |
id |
ID записи для обновления |
Удаление записей (DELETE)
Простое удаление
<form method="POST" action="/"
onsubmit="return confirm('Вы уверены, что хотите удалить этого пользователя?')">
{{ csrf() }}
<input type="hidden" name="__database" value="1752665380840">
<input type="hidden" name="__table" value="users">
<input type="hidden" name="__action" value="delete">
<input type="hidden" name="id" value="{{ user.id }}">
<button type="submit" class="btn btn-danger">
<i class="fas fa-trash"></i> Удалить пользователя
</button>
</form>
Мягкое удаление
<!-- Помечаем как удаленный вместо физического удаления -->
<form method="POST" action="/">
{{ csrf() }}
<input type="hidden" name="__database" value="1752665380840">
<input type="hidden" name="__table" value="users">
<input type="hidden" name="__action" value="update">
<input type="hidden" name="id" value="{{ user.id }}">
<input type="hidden" name="deleted_at" value="{{ time() }}">
<input type="hidden" name="is_active" value="0">
<button type="submit" class="btn btn-warning">Заблокировать пользователя</button>
</form>
Поиск записей
Форма поиска
<form method="POST" action="/">
{{ csrf() }}
<input type="hidden" name="__database" value="1752665380840">
<input type="hidden" name="__table" value="users">
<input type="hidden" name="__action" value="search">
<div class="search-form">
<div class="form-group">
<label>Поисковый запрос</label>
<input type="text" name="q" placeholder="Имя, логин или email..."
value="{{ request.input('q') }}">
</div>
<!-- Поля для поиска -->
<input type="hidden" name="fields[]" value="login">
<input type="hidden" name="fields[]" value="fname">
<input type="hidden" name="fields[]" value="lname">
<input type="hidden" name="fields[]" value="email">
<!-- Дополнительные фильтры -->
<div class="form-group">
<label>Роль</label>
<select name="role">
<option value="">Все роли</option>
<option value="user" {{ request.input('role') == 'user' ? 'selected' : '' }}>Пользователь</option>
<option value="moderator" {{ request.input('role') == 'moderator' ? 'selected' : '' }}>Модератор</option>
<option value="admin" {{ request.input('role') == 'admin' ? 'selected' : '' }}>Администратор</option>
</select>
</div>
<div class="form-group">
<label>
<input type="checkbox" name="is_active" value="1"
{{ request.input('is_active') ? 'checked' : '' }}>
Только активные
</label>
</div>
<!-- Настройки поиска -->
<input type="hidden" name="limit" value="50">
<input type="hidden" name="order_by" value="created_at">
<input type="hidden" name="order_direction" value="DESC">
<button type="submit" class="btn btn-primary">
<i class="fas fa-search"></i> Найти
</button>
<a href="?" class="btn btn-secondary">Сбросить</a>
</div>
</form>
Отображение результатов поиска
<!-- Результаты поиска сохраняются в переменной search_results -->
{% if search_results is defined %}
<div class="search-results">
<h3>Результаты поиска</h3>
<p>Найдено {{ search_results | length }} записей</p>
{% if search_results | length > 0 %}
<div class="results-list">
{% foreach search_results as user %}
<div class="result-item">
<h4>{{ user.login }}</h4>
<p>{{ user.fname }} {{ user.lname }}</p>
<p>{{ user.email }}</p>
<span class="badge">{{ user.role }}</span>
<div class="actions">
<a href="/user/edit/{{ user.id }}" class="btn btn-sm btn-warning">Редактировать</a>
</div>
</div>
{% endforeach %}
</div>
{% else %}
<p>По вашему запросу ничего не найдено</p>
{% endif %}
</div>
{% endif %}
Обработка результатов
Flash сообщения
После обработки формы доступны flash сообщения:
<!-- Сообщения об успехе -->
{% if flash('success') %}
<div class="alert alert-success">
<i class="fas fa-check-circle"></i> {{ flash('success') }}
</div>
{% endif %}
<!-- Сообщения об ошибках -->
{% if flash('error') %}
<div class="alert alert-danger">
<i class="fas fa-exclamation-circle"></i> {{ flash('error') }}
</div>
{% endif %}
<!-- Ошибки валидации -->
{% if flash('validation_errors') %}
<div class="alert alert-warning">
<h5>Ошибки валидации:</h5>
<ul>
{% foreach flash('validation_errors') as error %}
<li>{{ error }}</li>
{% endforeach %}
</ul>
</div>
{% endif %}
Сохранение данных формы
<!-- Старые значения сохраняются при ошибке валидации -->
<form method="POST" action="/">
{{ csrf() }}
<div class="form-group">
<label>Имя</label>
<input type="text" name="fname" value="{{ old('fname') }}">
</div>
<div class="form-group">
<label>Email</label>
<input type="email" name="email" value="{{ old('email') }}">
</div>
<button type="submit">Отправить</button>
</form>
Дополнительные возможности
Перенаправления
<!-- Перенаправление после успешной обработки -->
<input type="hidden" name="__redirect" value="/users">
<input type="hidden" name="__success_message" value="Пользователь успешно создан">
<!-- Перенаправление при ошибке -->
<input type="hidden" name="__error_redirect" value="/users/create">
Пакетные операции
<form method="POST" action="/">
{{ csrf() }}
<input type="hidden" name="__database" value="1752665380840">
<input type="hidden" name="__table" value="users">
<input type="hidden" name="__action" value="batch_update">
<table class="table">
<thead>
<tr>
<th><input type="checkbox" id="select-all"></th>
<th>Пользователь</th>
<th>Роль</th>
<th>Статус</th>
</tr>
</thead>
<tbody>
{% foreach users as user %}
<tr>
<td>
<input type="checkbox" name="selected_ids[]" value="{{ user.id }}">
</td>
<td>{{ user.login }}</td>
<td>{{ user.role }}</td>
<td>{{ user.is_active ? 'Активен' : 'Заблокирован' }}</td>
</tr>
{% endforeach %}
</tbody>
</table>
<div class="batch-actions">
<select name="batch_action">
<option value="">Выберите действие</option>
<option value="activate">Активировать</option>
<option value="deactivate">Деактивировать</option>
<option value="delete">Удалить</option>
</select>
<button type="submit" class="btn btn-primary">Применить к выбранным</button>
</div>
</form>
Валидация на стороне клиента
HTML5 валидация
<form method="POST" action="/" novalidate>
{{ csrf() }}
<div class="form-group">
<label>Email *</label>
<input type="email" name="email" required
pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}"
title="Введите корректный email адрес">
<div class="invalid-feedback">
Введите корректный email адрес
</div>
</div>
<div class="form-group">
<label>Пароль *</label>
<input type="password" name="password" required
minlength="8" maxlength="50"
pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*?&]{8,}$"
title="Пароль должен содержать минимум 8 символов, включая заглавную букву, строчную букву и цифру">
<div class="invalid-feedback">
Пароль не соответствует требованиям
</div>
</div>
<div class="form-group">
<label>Телефон</label>
<input type="tel" name="phone"
pattern="[0-9]{10,11}"
placeholder="89001234567"
title="Введите номер телефона (10-11 цифр)">
</div>
<button type="submit">Отправить</button>
</form>
Практические примеры
CRUD интерфейс для товаров
<!-- Создание товара -->
<form method="POST" action="/" class="product-form">
{{ csrf() }}
<input type="hidden" name="__database" value="1752665380840">
<input type="hidden" name="__table" value="products">
<input type="hidden" name="__action" value="create">
<input type="hidden" name="__redirect" value="/admin/products">
<div class="row">
<div class="col-md-8">
<div class="form-group">
<label>Название товара *</label>
<input type="text" name="name" required maxlength="100">
</div>
<div class="form-group">
<label>Описание</label>
<textarea name="description" rows="5"></textarea>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Цена *</label>
<input type="number" name="price" step="0.01" min="0" required>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>Цена со скидкой</label>
<input type="number" name="sale_price" step="0.01" min="0">
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label>Категория</label>
<select name="category_id">
<option value="">Выберите категорию</option>
{% set categories = db('1752665380840')->getItems('categories', {'active': 1}) %}
{% foreach categories as category %}
<option value="{{ category.id }}">{{ category.name }}</option>
{% endforeach %}
</select>
</div>
<div class="form-group">
<label>Количество на складе</label>
<input type="number" name="stock" value="0" min="0">
</div>
<div class="form-group">
<label>SKU</label>
<input type="text" name="sku" maxlength="50">
</div>
<div class="form-check">
<label>
<input type="checkbox" name="is_active" value="1" checked>
Активен
</label>
</div>
<div class="form-check">
<label>
<input type="checkbox" name="is_featured" value="1">
Рекомендуемый
</label>
</div>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i> Создать товар
</button>
<a href="/admin/products" class="btn btn-secondary">Отмена</a>
</div>
</form>
Быстрое редактирование в таблице
<table class="table table-editable">
<thead>
<tr>
<th>ID</th>
<th>Название</th>
<th>Цена</th>
<th>Статус</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
{% foreach products as product %}
<tr data-id="{{ product.id }}">
<td>{{ product.id }}</td>
<td>
<form method="POST" action="/" class="inline-edit-form">
{{ csrf() }}
<input type="hidden" name="__database" value="1752665380840">
<input type="hidden" name="__table" value="products">
<input type="hidden" name="__action" value="update">
<input type="hidden" name="id" value="{{ product.id }}">
<input type="text" name="name" value="{{ product.name }}"
onchange="this.form.submit()">
</form>
</td>
<td>
<form method="POST" action="/" class="inline-edit-form">
{{ csrf() }}
<input type="hidden" name="__database" value="1752665380840">
<input type="hidden" name="__table" value="products">
<input type="hidden" name="__action" value="update">
<input type="hidden" name="id" value="{{ product.id }}">
<input type="number" name="price" value="{{ product.price }}"
step="0.01" onchange="this.form.submit()">
</form>
</td>
<td>
<form method="POST" action="/" class="inline-edit-form">
{{ csrf() }}
<input type="hidden" name="__database" value="1752665380840">
<input type="hidden" name="__table" value="products">
<input type="hidden" name="__action" value="update">
<input type="hidden" name="id" value="{{ product.id }}">
<select name="is_active" onchange="this.form.submit()">
<option value="1" {{ product.is_active ? 'selected' : '' }}>Активен</option>
<option value="0" {{ not product.is_active ? 'selected' : '' }}>Неактивен</option>
</select>
</form>
</td>
<td>
<form method="POST" action="/" style="display: inline;"
onsubmit="return confirm('Удалить товар?')">
{{ csrf() }}
<input type="hidden" name="__database" value="1752665380840">
<input type="hidden" name="__table" value="products">
<input type="hidden" name="__action" value="delete">
<input type="hidden" name="id" value="{{ product.id }}">
<button type="submit" class="btn btn-sm btn-danger">
<i class="fas fa-trash"></i>
</button>
</form>
</td>
</tr>
{% endforeach %}
</tbody>
</table>
Следующий шаг: Изучите пользовательские обработчики форм для создания более сложной логики.