Базовые примеры
Практические примеры использования MNRFY Framework для начинающих
Создание первой страницы
Простая статичная страница
Создайте файл /src/hello.html:
<!DOCTYPE html>
<html lang="{{ locale }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Привет, мир! - {{ config('app.name') }}</title>
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
</head>
<body>
<header>
<h1>{{ t('welcome') }}</h1>
<p>Сегодня: {{ date('d.m.Y') }}</p>
</header>
<main>
<h2>Это моя первая страница на MNRFY!</h2>
<p>Текущее время: {{ date('H:i:s') }}</p>
{% if config('app.debug') %}
<div class="debug">
<p>Режим отладки включен</p>
<p>Время выполнения: {{ (microtime(true) - MNRFY_START_TIME) * 1000 | round(2) }}ms</p>
</div>
{% endif %}
</main>
</body>
</html>
Откройте в браузере: http://yourdomain.com/hello
Работа с переменными
Страница с динамическими данными
Создайте файл /src/variables-demo.html:
<!DOCTYPE html>
<html>
<head>
<title>Демонстрация переменных</title>
<style>
.demo-section { margin: 20px 0; padding: 20px; border: 1px solid #ddd; }
.highlight { background: #fffacd; padding: 5px; }
</style>
</head>
<body>
<h1>Демонстрация работы с переменными</h1>
<!-- Определение переменных -->
{% set site_name = 'Мой крутой сайт' %}
{% set version = '1.0.0' %}
{% set author = {
'name': 'Иван Иванов',
'email': 'ivan@example.com',
'skills': ['PHP', 'JavaScript', 'MNRFY']
} %}
<div class="demo-section">
<h2>Простые переменные</h2>
<p>Название сайта: <span class="highlight">{{ site_name }}</span></p>
<p>Версия: <span class="highlight">{{ version }}</span></p>
</div>
<div class="demo-section">
<h2>Объекты и массивы</h2>
<p>Автор: <strong>{{ author.name }}</strong></p>
<p>Email: <a href="mailto:{{ author.email }}">{{ author.email }}</a></p>
<p>Навыки:</p>
<ul>
{% foreach author.skills as skill %}
<li>{{ skill }}</li>
{% endforeach %}
</ul>
</div>
<div class="demo-section">
<h2>Вычисления</h2>
{% set a = 10 %}
{% set b = 5 %}
<p>{{ a }} + {{ b }} = {{ a + b }}</p>
<p>{{ a }} * {{ b }} = {{ a * b }}</p>
<p>Случайное число: {{ rand(1, 100) }}</p>
</div>
<div class="demo-section">
<h2>Строки и фильтры</h2>
{% set text = 'привет, мир из mnrfy framework!' %}
<p>Оригинал: {{ text }}</p>
<p>В верхнем регистре: {{ text | upper }}</p>
<p>С заглавной буквы: {{ text | title }}</p>
<p>Длина строки: {{ text | length }} символов</p>
</div>
</body>
</html>
Простая форма
Форма обратной связи
Создайте файл /src/contact.html:
<!DOCTYPE html>
<html>
<head>
<title>Обратная связь - {{ config('app.name') }}</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.form-group { margin-bottom: 20px; }
label { display: block; margin-bottom: 5px; font-weight: bold; }
input, textarea { width: 100%; max-width: 400px; padding: 8px; border: 1px solid #ddd; }
button { background: #007bff; color: white; padding: 10px 20px; border: none; cursor: pointer; }
.alert { padding: 15px; margin: 20px 0; border-radius: 4px; }
.alert-success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.alert-error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
</style>
</head>
<body>
<h1>Форма обратной связи</h1>
<!-- Показываем сообщения -->
{% if flash('success') %}
<div class="alert alert-success">
{{ flash('success') }}
</div>
{% endif %}
{% if flash('error') %}
<div class="alert alert-error">
{{ flash('error') }}
</div>
{% endif %}
<form method="POST" action="/contact">
{{ csrf() }}
<input type="hidden" name="__handler" value="contact-form">
<div class="form-group">
<label for="name">Ваше имя:</label>
<input type="text" id="name" name="name" value="{{ old('name') }}" required>
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email" name="email" value="{{ old('email') }}" required>
</div>
<div class="form-group">
<label for="subject">Тема:</label>
<input type="text" id="subject" name="subject" value="{{ old('subject') }}" required>
</div>
<div class="form-group">
<label for="message">Сообщение:</label>
<textarea id="message" name="message" rows="5" required>{{ old('message') }}</textarea>
</div>
<button type="submit">Отправить сообщение</button>
</form>
<p><a href="/">← Вернуться на главную</a></p>
</body>
</html>
Обработчик формы
Создайте файл /src/handlers/contact-form.php:
<?php
return function($request, $response, $context) {
// Получаем данные из формы
$name = trim($request->input('name'));
$email = trim($request->input('email'));
$subject = trim($request->input('subject'));
$message = trim($request->input('message'));
// Простая валидация
$errors = [];
if (empty($name)) {
$errors[] = 'Имя обязательно для заполнения';
}
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = 'Введите корректный email';
}
if (empty($subject)) {
$errors[] = 'Тема сообщения обязательна';
}
if (empty($message)) {
$errors[] = 'Сообщение не может быть пустым';
}
if (!empty($errors)) {
$_SESSION['flash_error'] = implode('<br>', $errors);
return $response->redirect('/contact');
}
// Сохраняем сообщение в файл (в реальном проекте лучше в БД)
$logFile = MNRFY_TEMP . '/contact-messages.log';
$logEntry = date('Y-m-d H:i:s') . " | $name | $email | $subject | $message" . PHP_EOL;
file_put_contents($logFile, $logEntry, FILE_APPEND | LOCK_EX);
// Устанавливаем сообщение об успехе
$_SESSION['flash_success'] = "Спасибо, $name! Ваше сообщение отправлено.";
return $response->redirect('/contact');
};
?>
Работа с базой данных
Список пользователей
Создайте файл /src/users.html:
<!DOCTYPE html>
<html>
<head>
<title>Пользователи - {{ config('app.name') }}</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
th { background-color: #f8f9fa; font-weight: bold; }
tr:hover { background-color: #f5f5f5; }
.user-stats { background: #e9ecef; padding: 20px; border-radius: 8px; margin-bottom: 20px; }
.stat-item { display: inline-block; margin-right: 30px; }
.badge { padding: 3px 8px; border-radius: 12px; font-size: 12px; }
.badge-active { background: #28a745; color: white; }
.badge-inactive { background: #dc3545; color: white; }
.pagination { margin-top: 20px; text-align: center; }
.pagination a { padding: 8px 12px; margin: 0 4px; text-decoration: none; border: 1px solid #ddd; }
.pagination .active { background: #007bff; color: white; }
</style>
</head>
<body>
<h1>Список пользователей</h1>
<!-- Получаем данные из базы -->
{% set page = request.input('page', 1) %}
{% set perPage = 10 %}
{% set users = db('1752665380840')->paginate('users', page, perPage, {}, 'id', 'DESC') %}
<!-- Статистика -->
{% set totalUsers = db('1752665380840')->countItems('users') %}
{% set activeUsers = db('1752665380840')->countItems('users', {'ban': 0}) %}
{% set bannedUsers = totalUsers - activeUsers %}
<div class="user-stats">
<div class="stat-item">
<strong>Всего пользователей:</strong> {{ totalUsers }}
</div>
<div class="stat-item">
<strong>Активных:</strong> {{ activeUsers }}
</div>
<div class="stat-item">
<strong>Заблокированных:</strong> {{ bannedUsers }}
</div>
</div>
{% if users.data and users.data | length > 0 %}
<table>
<thead>
<tr>
<th>ID</th>
<th>Логин</th>
<th>Имя</th>
<th>Баланс</th>
<th>Регистрация</th>
<th>Статус</th>
</tr>
</thead>
<tbody>
{% foreach users.data as user %}
<tr>
<td>{{ user.id }}</td>
<td><strong>{{ user.login }}</strong></td>
<td>
{% if user.fname or user.lname %}
{{ (user.fname ~ ' ' ~ user.lname) | trim }}
{% else %}
<em>Не указано</em>
{% endif %}
</td>
<td>{{ user.balance | money('₽') }}</td>
<td>{{ user.reg | date('d.m.Y H:i') }}</td>
<td>
{% if user.ban == 0 %}
<span class="badge badge-active">Активен</span>
{% else %}
<span class="badge badge-inactive">Заблокирован</span>
{% endif %}
</td>
</tr>
{% endforeach %}
</tbody>
</table>
<!-- Пагинация -->
{% if users.last_page > 1 %}
<div class="pagination">
{% if users.prev_page %}
<a href="?page={{ users.prev_page }}">« Предыдущая</a>
{% endif %}
{% for pageNum in 1..users.last_page %}
{% if pageNum == users.current_page %}
<span class="active">{{ pageNum }}</span>
{% else %}
<a href="?page={{ pageNum }}">{{ pageNum }}</a>
{% endif %}
{% endfor %}
{% if users.next_page %}
<a href="?page={{ users.next_page }}">Следующая »</a>
{% endif %}
</div>
<p>
Показано {{ users.from }}-{{ users.to }} из {{ users.total }} записей
</p>
{% endif %}
{% else %}
<p>Пользователи не найдены.</p>
{% endif %}
<p><a href="/">← На главную</a></p>
</body>
</html>
Создание блога
Главная страница блога
Создайте файл /src/blog.html:
<!DOCTYPE html>
<html>
<head>
<title>Блог - {{ config('app.name') }}</title>
<style>
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background: #f8f9fa; }
.container { max-width: 800px; margin: 0 auto; }
.post { background: white; padding: 30px; margin-bottom: 30px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.post-title { color: #333; margin-bottom: 10px; }
.post-meta { color: #666; font-size: 14px; margin-bottom: 20px; }
.post-excerpt { line-height: 1.6; color: #555; }
.read-more { color: #007bff; text-decoration: none; font-weight: bold; }
.sidebar { background: white; padding: 20px; border-radius: 8px; margin-top: 30px; }
.no-posts { text-align: center; padding: 60px; background: white; border-radius: 8px; }
</style>
</head>
<body>
<div class="container">
<header>
<h1>Мой блог</h1>
<p>Добро пожаловать в мой блог на MNRFY Framework!</p>
</header>
<main>
<!-- Имитация постов блога -->
{% set blogPosts = [
{
'id': 1,
'title': 'Начинаем работу с MNRFY Framework',
'excerpt': 'В этой статье мы рассмотрим основы работы с MNRFY Framework и создадим первое приложение.',
'author': 'Администратор',
'created_at': strtotime('-2 days'),
'views': 150
},
{
'id': 2,
'title': 'Создание форм в MNRFY',
'excerpt': 'Узнайте, как легко создавать и обрабатывать формы с помощью встроенных возможностей фреймворка.',
'author': 'Разработчик',
'created_at': strtotime('-5 days'),
'views': 89
},
{
'id': 3,
'title': 'Работа с базой данных',
'excerpt': 'Подробное руководство по работе с базой данных в MNRFY Framework с примерами кода.',
'author': 'Администратор',
'created_at': strtotime('-1 week'),
'views': 203
}
] %}
{% if blogPosts | length > 0 %}
{% foreach blogPosts as post %}
<article class="post">
<h2 class="post-title">
<a href="/blog/{{ post.id }}" style="text-decoration: none; color: inherit;">
{{ post.title }}
</a>
</h2>
<div class="post-meta">
<span>Автор: {{ post.author }}</span> •
<span>{{ post.created_at | date('d.m.Y') }}</span> •
<span>{{ post.views }} просмотров</span>
</div>
<div class="post-excerpt">
<p>{{ post.excerpt }}</p>
<a href="/blog/{{ post.id }}" class="read-more">Читать далее →</a>
</div>
</article>
{% endforeach %}
{% else %}
<div class="no-posts">
<h2>Пока нет постов</h2>
<p>Скоро здесь появится интересный контент!</p>
</div>
{% endif %}
</main>
<aside class="sidebar">
<h3>О блоге</h3>
<p>Это демонстрационный блог, созданный на MNRFY Framework.</p>
<h3>Статистика</h3>
<ul>
<li>Всего постов: {{ blogPosts | length }}</li>
<li>Общие просмотры: {{ blogPosts | sum('views') }}</li>
<li>Авторов: {{ blogPosts | column('author') | unique | length }}</li>
</ul>
<h3>Последние посты</h3>
<ul>
{% foreach blogPosts | slice(0, 3) as post %}
<li>
<a href="/blog/{{ post.id }}">{{ post.title | truncate(30) }}</a>
<br><small>{{ post.created_at | date('d.m.Y') }}</small>
</li>
{% endforeach %}
</ul>
</aside>
<p><a href="/">← На главную</a></p>
</div>
</body>
</html>
Калькулятор
Простой калькулятор с формой
Создайте файл /src/calculator.html:
<!DOCTYPE html>
<html>
<head>
<title>Калькулятор - {{ config('app.name') }}</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; background: #f0f0f0; }
.calculator { max-width: 400px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
.form-group { margin-bottom: 20px; }
label { display: block; margin-bottom: 8px; font-weight: bold; }
input, select { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; }
button { width: 100%; background: #28a745; color: white; padding: 12px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer; }
button:hover { background: #218838; }
.result { margin-top: 20px; padding: 20px; background: #e7f3ff; border-radius: 4px; text-align: center; font-size: 18px; font-weight: bold; }
.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
.history { margin-top: 30px; }
.history h3 { margin-bottom: 15px; }
.history-item { padding: 10px; background: #f8f9fa; margin-bottom: 5px; border-radius: 4px; font-family: monospace; }
</style>
</head>
<body>
<div class="calculator">
<h1>Калькулятор</h1>
<form method="POST" action="/calculator">
{{ csrf() }}
<input type="hidden" name="__handler" value="calculator">
<div class="form-group">
<label for="number1">Первое число:</label>
<input type="number" id="number1" name="number1" step="any"
value="{{ old('number1') }}" required>
</div>
<div class="form-group">
<label for="operation">Операция:</label>
<select id="operation" name="operation" required>
<option value="">Выберите операцию</option>
<option value="add" {{ old('operation') == 'add' ? 'selected' : '' }}>Сложение (+)</option>
<option value="subtract" {{ old('operation') == 'subtract' ? 'selected' : '' }}>Вычитание (-)</option>
<option value="multiply" {{ old('operation') == 'multiply' ? 'selected' : '' }}>Умножение (*)</option>
<option value="divide" {{ old('operation') == 'divide' ? 'selected' : '' }}>Деление (/)</option>
<option value="power" {{ old('operation') == 'power' ? 'selected' : '' }}>Возведение в степень</option>
<option value="sqrt" {{ old('operation') == 'sqrt' ? 'selected' : '' }}>Квадратный корень</option>
</select>
</div>
<div class="form-group">
<label for="number2">Второе число:</label>
<input type="number" id="number2" name="number2" step="any"
value="{{ old('number2') }}">
<small>(Не требуется для квадратного корня)</small>
</div>
<button type="submit">Вычислить</button>
</form>
<!-- Результат -->
{% if flash('result') %}
<div class="result">
Результат: {{ flash('result') }}
</div>
{% endif %}
{% if flash('error') %}
<div class="result error">
Ошибка: {{ flash('error') }}
</div>
{% endif %}
<!-- История вычислений -->
{% if session('calculator_history') %}
<div class="history">
<h3>История вычислений:</h3>
{% foreach session('calculator_history') | slice(-5) | reverse as calculation %}
<div class="history-item">
{{ calculation }}
</div>
{% endforeach %}
<p><small>Показаны последние 5 вычислений</small></p>
</div>
{% endif %}
<p style="text-align: center; margin-top: 30px;">
<a href="/">← На главную</a>
</p>
</div>
<script>
// Простая клиентская валидация
document.querySelector('select[name="operation"]').addEventListener('change', function() {
const number2Input = document.querySelector('input[name="number2"]');
const number2Label = document.querySelector('label[for="number2"]');
if (this.value === 'sqrt') {
number2Input.required = false;
number2Input.disabled = true;
number2Label.style.opacity = '0.5';
} else {
number2Input.required = true;
number2Input.disabled = false;
number2Label.style.opacity = '1';
}
});
</script>
</body>
</html>
Обработчик калькулятора
Создайте файл /src/handlers/calculator.php:
<?php
return function($request, $response, $context) {
$number1 = floatval($request->input('number1'));
$number2 = floatval($request->input('number2'));
$operation = $request->input('operation');
try {
$result = null;
$expression = '';
switch ($operation) {
case 'add':
$result = $number1 + $number2;
$expression = "$number1 + $number2 = $result";
break;
case 'subtract':
$result = $number1 - $number2;
$expression = "$number1 - $number2 = $result";
break;
case 'multiply':
$result = $number1 * $number2;
$expression = "$number1 × $number2 = $result";
break;
case 'divide':
if ($number2 == 0) {
throw new Exception('Деление на ноль невозможно');
}
$result = $number1 / $number2;
$expression = "$number1 ÷ $number2 = $result";
break;
case 'power':
$result = pow($number1, $number2);
$expression = "$number1^$number2 = $result";
break;
case 'sqrt':
if ($number1 < 0) {
throw new Exception('Квадратный корень из отрицательного числа');
}
$result = sqrt($number1);
$expression = "√$number1 = $result";
break;
default:
throw new Exception('Неизвестная операция');
}
// Форматируем результат
$formattedResult = is_float($result) ? round($result, 8) : $result;
// Сохраняем в историю
if (!isset($_SESSION['calculator_history'])) {
$_SESSION['calculator_history'] = [];
}
$_SESSION['calculator_history'][] = $expression;
// Ограничиваем историю 50 записями
if (count($_SESSION['calculator_history']) > 50) {
array_shift($_SESSION['calculator_history']);
}
$_SESSION['flash_result'] = $formattedResult;
} catch (Exception $e) {
$_SESSION['flash_error'] = $e->getMessage();
}
return $response->redirect('/calculator');
};
?>
Простая авторизация
Форма входа
Создайте файл /src/login.html:
<!DOCTYPE html>
<html>
<head>
<title>Вход в систему - {{ config('app.name') }}</title>
<style>
body { font-family: Arial, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); margin: 0; padding: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
.login-container { background: white; padding: 40px; border-radius: 10px; box-shadow: 0 10px 25px rgba(0,0,0,0.2); width: 100%; max-width: 400px; }
.login-header { text-align: center; margin-bottom: 30px; }
.form-group { margin-bottom: 20px; }
label { display: block; margin-bottom: 8px; font-weight: bold; color: #333; }
input { width: 100%; padding: 12px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; box-sizing: border-box; }
input:focus { outline: none; border-color: #667eea; }
button { width: 100%; background: #667eea; color: white; padding: 12px; border: none; border-radius: 4px; font-size: 16px; cursor: pointer; }
button:hover { background: #5a6fd8; }
.alert { padding: 15px; margin-bottom: 20px; border-radius: 4px; }
.alert-error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
.alert-success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.links { text-align: center; margin-top: 20px; }
.links a { color: #667eea; text-decoration: none; }
.demo-users { background: #f8f9fa; padding: 15px; margin-top: 20px; border-radius: 4px; font-size: 14px; }
</style>
</head>
<body>
<div class="login-container">
<div class="login-header">
<h1>Вход в систему</h1>
<p>Добро пожаловать в {{ config('app.name') }}!</p>
</div>
{% if flash('error') %}
<div class="alert alert-error">{{ flash('error') }}</div>
{% endif %}
{% if flash('success') %}
<div class="alert alert-success">{{ flash('success') }}</div>
{% endif %}
{% if auth() %}
<div class="alert alert-success">
<p>Вы уже авторизованы как <strong>{{ auth().login }}</strong></p>
<p><a href="/profile">Перейти в профиль</a> | <a href="/logout">Выйти</a></p>
</div>
{% else %}
<form method="POST" action="/login">
{{ csrf() }}
<input type="hidden" name="__handler" value="login">
<div class="form-group">
<label for="login">Логин:</label>
<input type="text" id="login" name="login" value="{{ old('login') }}" required autofocus>
</div>
<div class="form-group">
<label for="password">Пароль:</label>
<input type="password" id="password" name="password" required>
</div>
<div class="form-group">
<label>
<input type="checkbox" name="remember" value="1">
Запомнить меня
</label>
</div>
<button type="submit">Войти</button>
</form>
{% endif %}
<div class="links">
<a href="/">← На главную</a> |
<a href="/register">Регистрация</a>
</div>
{% if config('app.debug') %}
<div class="demo-users">
<strong>Демо-пользователи:</strong><br>
admin / admin (администратор)<br>
user / user (обычный пользователь)
</div>
{% endif %}
</div>
</body>
</html>
Готово! Эти примеры покрывают основные сценарии использования MNRFY Framework. Используйте их как отправную точку для создания собственных приложений.
Полезные советы
- Структура файлов: Все HTML шаблоны должны находиться в папке
/src/ - Обработчики: PHP обработчики форм размещайте в
/src/handlers/ - Статические файлы: CSS, JS и изображения помещайте в
/mnrfy-common/ - Отладка: Включайте режим debug в настройках для получения подробной информации об ошибках
- Безопасность: Всегда используйте
{{ csrf() }}в формах - База данных: ID базы данных указывается в настройках подключения
Следующие шаги: Изучите примеры админ-панели или продвинутые примеры.