Лаб. работа 4 “Создание индексных страниц и пагинация”
Цель: Научиться выводить данные из БД на страницы приложения, реализовать пагинацию и фильтрацию, использовать связи между моделями.
Задачи:
- Создать страницу со списком постов.
- Реализовать пагинацию и сортировку.
- Отображать связанные данные (категории, теги, комментарии).
- Стилизовать интерфейс с использованием Tailwind CSS.
Методическая часть
1. Создание контроллера и маршрута
Создайте контроллер
PostController
, если он не создан ранее:Добавьте метод
index
вapp/Http/Controllers/PostController.php
:Зарегистрируйте маршрут в
routes/web.php
:
2. Создание Blade-шаблона
Шаблон списка постов (
resources/views/posts/index.blade.php
):@extends('layouts.app') @section('content') <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <h1 class="text-3xl font-bold text-gray-900 mb-8">Все посты</h1> <!-- Фильтры и сортировка --> <div class="mb-6 flex justify-between items-center"> <div class="flex space-x-4"> <a href="{{ route('posts.index', ['sort' => 'latest']) }}" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"> Новые </a> <a href="{{ route('posts.index', ['sort' => 'popular']) }}" class="px-4 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300"> Популярные </a> </div> </div> <!-- Список постов --> <div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3"> @foreach ($posts as $post) <div class="bg-white rounded-lg shadow-md overflow-hidden"> @if ($post->image) <img src="{{ asset('storage/' . $post->image) }}" alt="{{ $post->title }}" class="w-full h-48 object-cover"> @endif <div class="p-6"> <div class="flex items-center mb-2"> <span class="text-sm text-gray-600"> {{ $post->created_at->format('d.m.Y') }} </span> <span class="mx-2">•</span> <span class="text-sm text-blue-600"> {{ $post->category->name }} </span> </div> <h2 class="text-xl font-semibold text-gray-900 mb-2"> {{ $post->title }} </h2> <p class="text-gray-600 mb-4">{{ Str::limit($post->content, 150) }}</p> <div class="flex items-center justify-between"> <div class="flex space-x-2"> @foreach ($post->tags as $tag) <span class="px-2 py-1 bg-gray-100 text-gray-700 rounded-full text-sm"> {{ $tag->name }} </span> @endforeach </div> <a href="{{ route('posts.show', $post) }}" class="text-blue-600 hover:text-blue-800"> Читать → </a> </div> </div> </div> @endforeach </div> <!-- Пагинация --> <div class="mt-8"> {{ $posts->links() }} </div> </div> @endsection
3. Кастомизация пагинации
Создайте файл пагинации для Tailwind:
Выберите шаблон
resources/views/vendor/pagination/tailwind.blade.php
.
4. Добавление сортировки в контроллер
Модифицируйте метод index
для поддержки параметров:
public function index(Request $request) {
$sort = $request->query('sort', 'latest');
$query = Post::with(['category', 'tags', 'comments']);
switch ($sort) {
case 'popular':
$query->withCount('comments')->orderBy('comments_count', 'desc');
break;
default:
$query->orderBy('created_at', 'desc');
}
$posts = $query->paginate(10);
return view('posts.index', compact('posts', 'sort'));
}
Индивидуальные задания
1. Фильтрация по категориям
- Добавьте выпадающий список с категориями в шапку страницы.
- Реализуйте фильтрацию постов по выбранной категории через параметр URL.
Пример кода:
<select onchange="window.location.href = '{{ route('posts.index') }}?category=' + this.value">
<option value="">Все категории</option>
@foreach ($categories as $category)
<option value="{{ $category->id }}" {{ $category->id == request('category') ? 'selected' : '' }}>
{{ $category->name }}
</option>
@endforeach
</select>
2. Поиск по заголовкам
Добавьте поле поиска, которое фильтрует посты по вхождению текста в заголовок.
Используйте
LIKE
в SQL-запросе:
3. Бесконечная прокрутка
Установите пакет для AJAX-пагинации:
Добавьте в конец шаблона:
<div id="posts-container"></div> <div id="loading" class="hidden">Загрузка...</div> <script> let page = 1; const loadMore = async () => { page++; const response = await axios.get(`/posts?page=${page}`); document.getElementById('posts-container').innerHTML += response.data; if (!response.data.includes('paginator')) { window.removeEventListener('scroll', handleScroll); } }; const handleScroll = () => { if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 500) { loadMore(); } }; window.addEventListener('scroll', handleScroll); </script>
4. Статистика в сайдбаре
Добавьте блок с общей статистикой:
<div class="bg-white p-6 rounded-lg shadow-md">
<h3 class="font-semibold mb-4">Статистика блога</h3>
<ul class="space-y-2">
<li>Всего постов: {{ Post::count() }}</li>
<li>Всего комментариев: {{ Comment::count() }}</li>
<li>Популярный тег: {{ Tag::withCount('posts')->orderBy('posts_count', 'desc')->first()->name }}</li>
</ul>
</div>
Примечания
- Оптимизация запросов: Используйте
with()
для жадной загрузки связанных данных.
- Tailwind-классы: Для адаптивности применяйте grid-сетки (
md:grid-cols-2
,lg:grid-cols-3
).