Создание каталога товаров
Студент разработает публичную часть магазина с выводом товаров, фильтрацией по категориям и постраничной навигацией.
Архитектура каталога товаров
Каталог — это лицо любого интернет-магазина. Применяя метод Chunking, мы разобьем задачу на три этапа: получение данных из БД (Модель), обработка логики (Контроллер) и рендеринг HTML (Представление). Для начала вспомним структуру нашей базы данных. В архивных упражнениях мы создавали таблицу 'products' с полями 'id', 'category_id', 'name', 'description' и 'price'. Модель Product связана с моделью Category отношением belongsTo. Чтобы вывести каталог, нам нужно получить все записи из таблицы products. Однако, если в магазине 10 000 товаров, загрузка всех записей разом приведет к исчерпанию оперативной памяти сервера (Out of Memory) и долгой загрузке страницы. Решение — постраничная навигация (Pagination). Laravel предоставляет встроенный метод paginate(), который автоматически формирует SQL-запросы с LIMIT и OFFSET, а также генерирует ссылки для переключения страниц в HTML.
Фильтрация по категориям и Query Builder
Следующий важный функционал — фильтрация. Пользователь должен иметь возможность кликнуть на категорию (например, 'Ноутбуки') и увидеть только соответствующие товары. Для этого мы передаем параметр в URL, например: /products?category=2. В контроллере мы используем класс Request для получения этого параметра. Используя Eloquent ORM, мы можем динамически строить запрос (Query Builder). Мы начинаем запрос с Product::query(). Затем, если параметр category существует, мы добавляем условие where('category_id', $categoryId). Важно использовать метод when(), предоставляемый Laravel, который позволяет добавлять условия в запрос без сложных конструкций if-else. Это делает код элегантным и легко читаемым. Также мы будем использовать жадную загрузку (Eager Loading) с помощью метода with('category'), чтобы избежать проблемы N+1 запросов при выводе названия категории для каждого товара.
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class ProductController extends Controller {
public function index(Request $request) {
$categoryId = $request->input('category');
$products = Product::query()
->with('category') // Жадная загрузка категории (решение проблемы N+1)
->when($categoryId, function ($query, $categoryId) {
return $query->where('category_id', $categoryId);
})
->paginate(12) // Постраничная навигация (12 товаров на страницу)
->withQueryString(); // Сохраняем параметры GET в ссылках пагинации
return view('products.index', compact('products'));
}
}
Отображение данных в шаблонах Blade
После того как контроллер сформировал коллекцию $products, она передается в представление 'products.index'. Blade — это мощный шаблонизатор Laravel. Мы используем директиву @foreach для обхода коллекции и генерации HTML-карточек товаров. Внутри цикла мы имеем доступ к объекту товара и можем вызывать его свойства: {{ $product->name }}, {{ $product->price }}. Вспомните Упражнение 1.1 из первого блока, где мы создавали метод getFormattedPrice(). Если вы реализовали его в модели Product, вы можете использовать {{ $product->getFormattedPrice() }} для красивого вывода цены со знаком валюты. Для вывода ссылок постраничной навигации достаточно добавить {{ $products->links() }} под сеткой товаров. Laravel автоматически сгенерирует HTML-код, совместимый с фреймворком Tailwind CSS (или Bootstrap, в зависимости от настроек вашего проекта).
Флеш-карточки
Что такое проблема N+1 запросов в ORM?
Нажмите, чтобы увидеть ответ
Ситуация, когда ORM выполняет 1 запрос для получения списка из N объектов, а затем N дополнительных запросов для получения связанных данных каждого объекта. Решается жадной загрузкой (Eager Loading).
Нажмите, чтобы вернуться
Какой метод Eloquent используется для жадной загрузки связей?
Нажмите, чтобы увидеть ответ
Метод with('название_связи'). Например: Product::with('category')->get();
Нажмите, чтобы вернуться
Какой метод в Eloquent используется для добавления условия в запрос только в том случае, если первое переданное в него значение истинно (true)?
Задание
Практическое задание: Реализация каталога.
- Создайте ProductController с помощью команды php artisan make:controller ProductController.
- Реализуйте метод index, добавив в него логику фильтрации через when() и пагинацию paginate().
- В файле routes/web.php создайте GET-маршрут '/products', указывающий на этот метод.
- Создайте файл resources/views/products/index.blade.php.
- В Blade-файле создайте цикл @foreach ($products as $product) и сверстайте карточку товара.
- Добавьте под циклом вывод пагинации: {{ $products->links() }}.