Add pagination in users administration.
This commit is contained in:
parent
70b75f8426
commit
cd382c5c7b
|
|
@ -11,24 +11,126 @@ class AdminController extends BaseController {
|
||||||
|
|
||||||
public function users() {
|
public function users() {
|
||||||
$userModel = new User($this->pdo);
|
$userModel = new User($this->pdo);
|
||||||
$users = $userModel->findAll();
|
|
||||||
|
// Параметры пагинации
|
||||||
|
$current_page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||||
|
$per_page = isset($_GET['per_page']) ? (int)$_GET['per_page'] : 10;
|
||||||
|
|
||||||
|
// Валидация параметров
|
||||||
|
$current_page = max(1, $current_page);
|
||||||
|
$allowed_per_page = [5, 10, 50, 100];
|
||||||
|
if (!in_array($per_page, $allowed_per_page)) {
|
||||||
|
$per_page = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем общее количество пользователей
|
||||||
|
$total_users = $userModel->getTotalUsersCount();
|
||||||
|
|
||||||
|
// Вычисляем общее количество страниц
|
||||||
|
$total_pages = ceil($total_users / $per_page);
|
||||||
|
|
||||||
|
// Корректируем текущую страницу, если она выходит за пределы
|
||||||
|
if ($current_page > $total_pages && $total_pages > 0) {
|
||||||
|
$current_page = $total_pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вычисляем смещение
|
||||||
|
$offset = ($current_page - 1) * $per_page;
|
||||||
|
|
||||||
|
// Получаем пользователей для текущей страницы
|
||||||
|
$users = $userModel->getUsersPaginated($offset, $per_page);
|
||||||
|
|
||||||
|
// Генерируем пагинацию
|
||||||
|
$pagination = $this->generatePagination($current_page, $total_pages);
|
||||||
|
|
||||||
$this->render('admin/users', [
|
$this->render('admin/users', [
|
||||||
'users' => $users,
|
'users' => $users,
|
||||||
'page_title' => 'Управление пользователями'
|
'page_title' => 'Управление пользователями',
|
||||||
|
'pagination' => $pagination,
|
||||||
|
'current_page' => $current_page,
|
||||||
|
'total_pages' => $total_pages,
|
||||||
|
'per_page' => $per_page,
|
||||||
|
'total_users' => $total_users,
|
||||||
|
'allowed_per_page' => $allowed_per_page
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function generatePagination($current_page, $total_pages) {
|
||||||
|
if ($total_pages <= 1) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$pagination = [];
|
||||||
|
$max_visible_pages = 5; // Количество видимых страниц до и после текущей
|
||||||
|
|
||||||
|
// Всегда добавляем первую страницу
|
||||||
|
$pagination[] = [
|
||||||
|
'page' => 1,
|
||||||
|
'label' => '1',
|
||||||
|
'active' => (1 == $current_page),
|
||||||
|
'type' => 'page'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Определяем диапазон видимых страниц
|
||||||
|
$start_page = max(2, $current_page - $max_visible_pages);
|
||||||
|
$end_page = min($total_pages - 1, $current_page + $max_visible_pages);
|
||||||
|
|
||||||
|
// Добавляем многоточие после первой страницы, если нужно
|
||||||
|
if ($start_page > 2) {
|
||||||
|
$pagination[] = [
|
||||||
|
'page' => null,
|
||||||
|
'label' => '...',
|
||||||
|
'active' => false,
|
||||||
|
'type' => 'ellipsis'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавляем видимые страницы
|
||||||
|
for ($i = $start_page; $i <= $end_page; $i++) {
|
||||||
|
$pagination[] = [
|
||||||
|
'page' => $i,
|
||||||
|
'label' => $i,
|
||||||
|
'active' => ($i == $current_page),
|
||||||
|
'type' => 'page'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавляем многоточие перед последней страницей, если нужно
|
||||||
|
if ($end_page < $total_pages - 1) {
|
||||||
|
$pagination[] = [
|
||||||
|
'page' => null,
|
||||||
|
'label' => '...',
|
||||||
|
'active' => false,
|
||||||
|
'type' => 'ellipsis'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавляем последнюю страницу, если она не первая
|
||||||
|
if ($total_pages > 1) {
|
||||||
|
$pagination[] = [
|
||||||
|
'page' => $total_pages,
|
||||||
|
'label' => $total_pages,
|
||||||
|
'active' => ($total_pages == $current_page),
|
||||||
|
'type' => 'page'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $pagination;
|
||||||
|
}
|
||||||
|
|
||||||
public function toggleUserStatus($user_id) {
|
public function toggleUserStatus($user_id) {
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !verify_csrf_token($_POST['csrf_token'] ?? '')) {
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !verify_csrf_token($_POST['csrf_token'] ?? '')) {
|
||||||
$_SESSION['error'] = "Неверный метод запроса или токен безопасности";
|
$_SESSION['error'] = "Неверный метод запроса или токен безопасности";
|
||||||
$this->redirect('/admin/users');
|
$this->redirect('/admin/users');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Сохраняем параметры пагинации
|
||||||
|
$page = $_GET['page'] ?? 1;
|
||||||
|
$per_page = $_GET['per_page'] ?? 10;
|
||||||
|
|
||||||
if ($user_id == $_SESSION['user_id']) {
|
if ($user_id == $_SESSION['user_id']) {
|
||||||
$_SESSION['error'] = "Нельзя изменить статус собственного аккаунта";
|
$_SESSION['error'] = "Нельзя изменить статус собственного аккаунта";
|
||||||
$this->redirect('/admin/users');
|
$this->redirect("/admin/users?page=$page&per_page=$per_page");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,7 +139,7 @@ class AdminController extends BaseController {
|
||||||
|
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
$_SESSION['error'] = "Пользователь не найден";
|
$_SESSION['error'] = "Пользователь не найден";
|
||||||
$this->redirect('/admin/users');
|
$this->redirect("/admin/users?page=$page&per_page=$per_page");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,7 +150,7 @@ class AdminController extends BaseController {
|
||||||
$_SESSION['error'] = "Ошибка при обновлении статуса";
|
$_SESSION['error'] = "Ошибка при обновлении статуса";
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->redirect('/admin/users');
|
$this->redirect("/admin/users?page=$page&per_page=$per_page");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteUser($user_id) {
|
public function deleteUser($user_id) {
|
||||||
|
|
@ -58,9 +160,13 @@ class AdminController extends BaseController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Сохраняем параметры пагинации
|
||||||
|
$page = $_GET['page'] ?? 1;
|
||||||
|
$per_page = $_GET['per_page'] ?? 10;
|
||||||
|
|
||||||
if ($user_id == $_SESSION['user_id']) {
|
if ($user_id == $_SESSION['user_id']) {
|
||||||
$_SESSION['error'] = "Нельзя удалить собственный аккаунт";
|
$_SESSION['error'] = "Нельзя удалить собственный аккаунт";
|
||||||
$this->redirect('/admin/users');
|
$this->redirect("/admin/users?page=$page&per_page=$per_page");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,7 +175,7 @@ class AdminController extends BaseController {
|
||||||
|
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
$_SESSION['error'] = "Пользователь не найден";
|
$_SESSION['error'] = "Пользователь не найден";
|
||||||
$this->redirect('/admin/users');
|
$this->redirect("/admin/users?page=$page&per_page=$per_page");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,13 +185,17 @@ class AdminController extends BaseController {
|
||||||
$_SESSION['error'] = "Ошибка при удалении пользователя";
|
$_SESSION['error'] = "Ошибка при удалении пользователя";
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->redirect('/admin/users');
|
$this->redirect("/admin/users?page=$page&per_page=$per_page");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addUser() {
|
public function addUser() {
|
||||||
$error = '';
|
$error = '';
|
||||||
$success = '';
|
$success = '';
|
||||||
|
|
||||||
|
// Сохраняем параметры пагинации для возврата
|
||||||
|
$return_page = $_GET['page'] ?? 1;
|
||||||
|
$return_per_page = $_GET['per_page'] ?? 10;
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
if (!verify_csrf_token($_POST['csrf_token'] ?? '')) {
|
if (!verify_csrf_token($_POST['csrf_token'] ?? '')) {
|
||||||
$error = "Ошибка безопасности";
|
$error = "Ошибка безопасности";
|
||||||
|
|
@ -119,9 +229,9 @@ class AdminController extends BaseController {
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($userModel->create($data)) {
|
if ($userModel->create($data)) {
|
||||||
$success = 'Пользователь успешно создан';
|
$_SESSION['success'] = 'Пользователь успешно создан';
|
||||||
// Очищаем поля формы
|
$this->redirect("/admin/users?page=1&per_page=$return_per_page");
|
||||||
$_POST = [];
|
return;
|
||||||
} else {
|
} else {
|
||||||
$error = 'Ошибка при создании пользователя';
|
$error = 'Ошибка при создании пользователя';
|
||||||
}
|
}
|
||||||
|
|
@ -133,7 +243,9 @@ class AdminController extends BaseController {
|
||||||
$this->render('admin/add_user', [
|
$this->render('admin/add_user', [
|
||||||
'error' => $error,
|
'error' => $error,
|
||||||
'success' => $success,
|
'success' => $success,
|
||||||
'page_title' => 'Добавление пользователя'
|
'page_title' => 'Добавление пользователя',
|
||||||
|
'return_page' => $return_page,
|
||||||
|
'return_per_page' => $return_per_page
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,5 +115,23 @@ class User {
|
||||||
$stmt = $this->pdo->prepare($sql);
|
$stmt = $this->pdo->prepare($sql);
|
||||||
return $stmt->execute($params);
|
return $stmt->execute($params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getTotalUsersCount() {
|
||||||
|
$stmt = $this->pdo->prepare("SELECT COUNT(*) FROM users");
|
||||||
|
$stmt->execute();
|
||||||
|
return $stmt->fetchColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUsersPaginated($offset, $limit) {
|
||||||
|
$stmt = $this->pdo->prepare("
|
||||||
|
SELECT * FROM users
|
||||||
|
ORDER BY id DESC
|
||||||
|
LIMIT :limit OFFSET :offset
|
||||||
|
");
|
||||||
|
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<h1 class="h2">Добавление пользователя</h1>
|
<h1 class="h2">Добавление пользователя</h1>
|
||||||
<a href="<?= SITE_URL ?>/admin/users" class="btn btn-outline-secondary">
|
<a href="<?= SITE_URL ?>/admin/users?page=<?= $return_page ?? 1 ?>&per_page=<?= $return_per_page ?? 10 ?>" class="btn btn-outline-secondary">
|
||||||
<i class="bi bi-arrow-left"></i> Назад к пользователям
|
<i class="bi bi-arrow-left"></i> Назад к пользователям
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,12 @@
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="h2">Управление пользователями</h1>
|
<h1 class="h2">Управление пользователями</h1>
|
||||||
<p class="text-muted mb-0">Всего пользователей: <?= count($users) ?></p>
|
<p class="text-muted mb-0">
|
||||||
|
Всего пользователей: <?= $total_users ?>
|
||||||
|
<?php if ($total_users > 0): ?>
|
||||||
|
| Показано <?= (($current_page - 1) * $per_page) + 1 ?>-<?= min($current_page * $per_page, $total_users) ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<a href="<?= SITE_URL ?>/admin/add-user" class="btn btn-primary">
|
<a href="<?= SITE_URL ?>/admin/add-user" class="btn btn-primary">
|
||||||
<i class="bi bi-person-plus"></i> Добавить пользователя
|
<i class="bi bi-person-plus"></i> Добавить пользователя
|
||||||
|
|
@ -27,6 +32,30 @@
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<!-- Выбор количества элементов на странице -->
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="get" class="row g-3 align-items-center">
|
||||||
|
<div class="col-auto">
|
||||||
|
<label for="per_page" class="col-form-label">Показывать по:</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<select name="per_page" id="per_page" class="form-select" onchange="this.form.submit()">
|
||||||
|
<?php foreach ($allowed_per_page as $value): ?>
|
||||||
|
<option value="<?= $value ?>" <?= $per_page == $value ? 'selected' : '' ?>>
|
||||||
|
<?= $value ?> пользователей
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<input type="hidden" name="page" value="1">
|
||||||
|
<button type="submit" class="btn btn-outline-primary">Применить</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php if (empty($users)): ?>
|
<?php if (empty($users)): ?>
|
||||||
<div class="text-center py-5">
|
<div class="text-center py-5">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
|
|
@ -111,7 +140,66 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Пагинация -->
|
||||||
|
<?php if (!empty($pagination)): ?>
|
||||||
|
<nav aria-label="Навигация по страницам" class="mt-4">
|
||||||
|
<ul class="pagination justify-content-center">
|
||||||
|
<!-- Кнопка "Назад" -->
|
||||||
|
<li class="page-item <?= $current_page <= 1 ? 'disabled' : '' ?>">
|
||||||
|
<a class="page-link" href="?page=<?= $current_page - 1 ?>&per_page=<?= $per_page ?>" aria-label="Предыдущая">
|
||||||
|
<span aria-hidden="true">«</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- Элементы пагинации -->
|
||||||
|
<?php foreach ($pagination as $item): ?>
|
||||||
|
<?php if ($item['type'] === 'ellipsis'): ?>
|
||||||
|
<li class="page-item disabled">
|
||||||
|
<span class="page-link"><?= $item['label'] ?></span>
|
||||||
|
</li>
|
||||||
|
<?php else: ?>
|
||||||
|
<li class="page-item <?= $item['active'] ? 'active' : '' ?>">
|
||||||
|
<a class="page-link" href="?page=<?= $item['page'] ?>&per_page=<?= $per_page ?>">
|
||||||
|
<?= $item['label'] ?>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<!-- Кнопка "Вперед" -->
|
||||||
|
<li class="page-item <?= $current_page >= $total_pages ? 'disabled' : '' ?>">
|
||||||
|
<a class="page-link" href="?page=<?= $current_page + 1 ?>&per_page=<?= $per_page ?>" aria-label="Следующая">
|
||||||
|
<span aria-hidden="true">»</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Информация о странице -->
|
||||||
|
<div class="text-center mt-3">
|
||||||
|
<p class="text-muted">
|
||||||
|
Страница <?= $current_page ?> из <?= $total_pages ?>
|
||||||
|
<?php if ($total_pages > 1): ?>
|
||||||
|
| Перейти:
|
||||||
|
<form method="get" class="d-inline">
|
||||||
|
<input type="hidden" name="per_page" value="<?= $per_page ?>">
|
||||||
|
<input type="number" name="page" min="1" max="<?= $total_pages ?>" value="<?= $current_page ?>"
|
||||||
|
class="form-control d-inline-block" style="width: 80px;"
|
||||||
|
onchange="this.form.submit()">
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.form-control[type="number"] {
|
||||||
|
display: inline-block;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<?php include 'views/layouts/footer.php'; ?>
|
<?php include 'views/layouts/footer.php'; ?>
|
||||||
Loading…
Reference in New Issue