Создание простого блога на Laravel 11: Добавление пагинации и поиска
В прошлой статье мы реализовали CRUD функционал для постов. В этой статье мы добавим пагинацию и поиск постов для нашего блога.
Реализация пагинации на Laravel
Laravel поддерживает пагинацию «из коробки». В предыдущей статье мы уже использовали метод paginate(). Теперь добавим оформление для удобства работы с постами.
Про пагинацию более подробно вы можете почитать в официальной документации Laravel.
Добавляем пагинацию в контроллер
Обновим метод index в PostController:
public function index(Request $request)
{
$search = $request->query('search'); // Получаем запрос поиска из URL
$posts = Post::query()
->when($search, function ($query, $search) {
$query->where('title', 'like', "%{$search}%"); // Фильтрация по заголовку
})
->latest()
->paginate(5); // Пагинация: 5 записей на страницу
return view('posts.index', compact('posts', 'search'));
}Здесь:
- Мы добавили параметр
$searchдля фильтрации постов. - Использовали метод
when()для условного применения поиска. - Установили пагинацию на 5 записей на страницу.
Обновление шаблона для пагинации
В шаблоне resources/views/posts/index.blade.php добавим ссылки пагинации.
Список постов с пагинацией
Заменим вызов пагинации, отобразив стиль Bootstrap для пагинации:
{{ $posts->links('pagination::bootstrap-5') }}Добавляем форму поиска
Перед таблицей с постами добавим форму поиска:
<form action="{{ route('posts.index') }}" method="GET" class="mb-4">
<div class="input-group">
<input type="text" name="search" class="form-control" placeholder="Искать посты..." value="{{ $search }}">
<button class="btn btn-outline-secondary" type="submit">Найти</button>
</div>
</form>Теперь, когда пользователь вводит запрос и нажимает «Найти», URL будет выглядеть как /search?search=example.
Улучшение UX при отсутствии постов
Если постов нет, мы добавим сообщение в шаблоне posts/index.blade.php:
@if($posts->isEmpty())
<p>Посты не найдены.</p>
@else
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Заголовок</th>
<th>Автор</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
@foreach($posts as $post)
<tr>
<td>{{ $post->id }}</td>
<td>{{ $post->title }}</td>
<td>{{ $post->author }}</td>
<td>
<a href="{{ route('posts.edit', $post) }}" class="btn btn-warning">Редактировать</a>
<form action="{{ route('posts.destroy', $post) }}" method="POST" style="display:inline-block">
@csrf
@method('DELETE')
<button class="btn btn-danger" onclick="return confirm('Удалить пост?')">Удалить</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
{{ $posts->links('pagination::bootstrap-5') }}
@endif
Теперь, если поиск не дал результатов, будет выводиться сообщение «Посты не найдены».
Итог изменений
После всех изменений:
- На главной странице будет форма поиска.
- Отображается только 5 постов на одной странице.
- Пагинация позволяет перемещаться между страницами.
Итоговый код
Метод index в контроллере PostController:
public function index(Request $request)
{
$search = $request->query('search');
$posts = Post::query()
->when($search, function ($query, $search) {
$query->where('title', 'like', "%{$search}%");
})
->latest()
->paginate(5);
return view('posts.index', compact('posts', 'search'));
}Шаблон posts/index.blade.php:
@extends('layout')
@section('content')
<h1>Список постов</h1>
<a href="{{ route('posts.create') }}" class="btn btn-primary mb-3">Создать пост</a>
<form action="{{ route('posts.index') }}" method="GET" class="mb-4">
<div class="input-group">
<input type="text" name="search" class="form-control" placeholder="Искать посты..." value="{{ $search }}">
<button class="btn btn-outline-secondary" type="submit">Найти</button>
</div>
</form>
@if($posts->isEmpty())
<p>Посты не найдены.</p>
@else
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Заголовок</th>
<th>Автор</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
@foreach($posts as $post)
<tr>
<td>{{ $post->id }}</td>
<td>{{ $post->title }}</td>
<td>{{ $post->author }}</td>
<td>
<a href="{{ route('posts.edit', $post) }}" class="btn btn-warning">Редактировать</a>
<form action="{{ route('posts.destroy', $post) }}" method="POST" style="display:inline-block">
@csrf
@method('DELETE')
<button class="btn btn-danger" onclick="return confirm('Удалить пост?')">Удалить</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
{{ $posts->links('pagination::bootstrap-5') }}
@endif
@endsectionСледующие шаги по блогу на Laravel
В следующий статье мы добавим авторизацию пользователей в блог и ограничим доступ, чтобы пользователи могли изменять и удалять только свои посты.
Супер