Уроки курса
1 Основы синтаксиса PHP 8
60 мин
2 Функции и управляющие конструкции
60 мин
3 Объектно-ориентированное программирование на PHP
60 мин
4 Наследование, интерфейсы и полиморфизм
60 мин
5 Основы баз данных MySQL и работа через PDO
60 мин
6 Архитектурный паттерн MVC
60 мин
7 Введение в Laravel и настройка окружения
60 мин
8 Маршрутизация и контроллеры в Laravel
60 мин
9 Шаблонизатор Blade и создание интерфейса
60 мин
10 Миграции баз данных и Eloquent ORM
60 мин
11 Связи моделей в Eloquent — Настройка связей 'один …
60 мин
12 Аутентификация и защита маршрутов
60 мин
13 Разработка каталога товаров и категорий
60 мин
14 Реализация корзины покупок через сессии
60 мин
15 Оформление заказа и транзакции базы данных
60 мин
16 Интеграция платежной системы Stripe
60 мин
17 Интеграция платежной системы Vipps
60 мин
18 Разработка панели администратора
60 мин
19 Оптимизация и подготовка к production
60 мин
20 Деплой Laravel-приложения на сервер
60 мин
21 Основы PHP 8: Синтаксис, переменные и управляющие конструкции
60 мин
22 Функции и массивы в PHP 8
60 мин
23 Объектно-ориентированное программирование: Классы и объекты
60 мин
24 Продвинутое ООП: Наследование, интерфейсы и полиморфизм
60 мин
25 Основы баз данных: Проектирование БД и работа с …
60 мин
26 Взаимодействие PHP с MySQL через PDO
60 мин
27 Архитектура MVC и введение в фреймворк Laravel
60 мин
28 Маршрутизация и контроллеры в Laravel
60 мин
29 Шаблонизатор Blade: Создание пользовательского интерфейса
60 мин
30 Миграции и Eloquent ORM: Создание таблиц товаров
60 мин
31 Связи в Eloquent ORM: Отношения между моделями
60 мин
32 Аутентификация и авторизация пользователей
60 мин
33 Разработка каталога товаров: Вывод, фильтрация и пагинация
60 мин
34 Реализация корзины покупок с использованием сессий
60 мин
35 Оформление заказа: Работа с формами и валидация
60 мин
36 Транзакции базы данных: Сохранение заказа
60 мин
37 Интеграция платежной системы Stripe
60 мин
38 Интеграция платежной системы Vipps
60 мин
39 Создание панели администратора
60 мин
40 Подготовка к production и деплой приложения
60 мин
41 Основы PHP 8 и синтаксис
60 мин
42 Объектно-ориентированное программирование на PHP
60 мин
43 Продвинутое ООП и интерфейсы
60 мин
44 Основы баз данных и MySQL
60 мин
45 Архитектурный паттерн MVC
60 мин
46 Введение в Laravel и маршрутизация
60 мин
47 Шаблонизатор Blade и верстка интерфейса
60 мин
48 Миграции и структура базы данных
60 мин
49 Eloquent ORM и модели
60 мин
50 Отношения в Eloquent ORM
60 мин
51 Авторизация и защита маршрутов
60 мин
52 Создание каталога товаров
60 мин
53 Реализация корзины покупок
60 мин
54 Оформление заказа и транзакции БД
60 мин
55 Интеграция платежной системы Stripe
60 мин
56 Интеграция платежной системы Vipps
60 мин
57 Панель администратора: управление товарами
60 мин
58 Панель администратора: управление заказами
60 мин
59 Подготовка к production и деплой
60 мин
60 Запуск и тестирование готового интернет-магазина
60 мин

Панель администратора: управление заказами

Студент добавит интерфейс для просмотра списка заказов пользователей и изменения их статусов, решая проблему N+1 запроса.

Прогресс урока: 0%

Отображение заказов и проблема N+1

Управление заказами — сердце любого интернет-магазина. Администратор должен видеть список всех заказов, информацию о покупателе, состав заказа (товары) и иметь возможность менять статус (например, с 'Новый' на 'Отправлен'). При выводе списка заказов разработчики часто сталкиваются с классической проблемой производительности, известной как «Проблема N+1 запроса» (Direct Instruction).

Представьте, что вы выводите на страницу 50 заказов. Для каждого заказа вам нужно показать имя пользователя, который его сделал. Если вы напишете цикл и внутри вызовете `$order->user->name`, Laravel будет делать отдельный SQL-запрос к таблице `users` для каждого из 50 заказов. Итого: 1 запрос для получения заказов + 50 запросов для получения пользователей = 51 запрос. Это сильно замедляет работу приложения. Решение — использовать Eager Loading (Жадная загрузка) с помощью метода `with()`.

php
<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Order;
use Illuminate\Http\Request;

class AdminOrderController extends Controller {
    public function index() {
        // Использование Eager Loading (Жадной загрузки) для решения проблемы N+1
        // Загружаем заказы вместе с пользователями и позициями заказа
        $orders = Order::with(['user', 'items.product'])
                       ->orderBy('created_at', 'desc')
                       ->paginate(20);

        return view('admin.orders.index', compact('orders'));
    }

    public function show(Order $order) {
        // Для одного заказа подгружаем связи
        $order->load(['user', 'items.product']);
        return view('admin.orders.show', compact('order'));
    }
}

Изменение статуса заказа с использованием PHP 8

Статус заказа определяет, на каком этапе находится покупка. Обычно это набор фиксированных значений: `pending` (ожидает оплаты), `paid` (оплачен), `shipped` (отправлен), `completed` (завершен), `cancelled` (отменен). Для изменения статуса мы создадим отдельный метод `updateStatus` в нашем контроллере.

Для вывода человекопонятного названия статуса в интерфейсе, мы можем использовать новую возможность PHP 8 — выражение `match` (взято из архивных материалов). Конструкция `match` работает аналогично `switch`, но возвращает значение, имеет более строгий синтаксис (сравнивает по типу `===`) и не требует использования `break`. Это делает код более коротким, безопасным и легко читаемым.

php
<?php
// Пример использования выражения match (PHP 8) в модели Order или Хелпере

function getStatusName(string $statusCode): string {
    return match($statusCode) {
        'pending' => 'Ожидает оплаты',
        'paid' => 'Оплачен',
        'shipped' => 'Отправлен',
        'completed' => 'Доставлен',
        'cancelled' => 'Отменен',
        default => throw new InvalidArgumentException('Неизвестный статус: ' . $statusCode),
    };
}

// Метод в AdminOrderController для обновления статуса
public function updateStatus(Request $request, Order $order) {
    $request->validate([
        'status' => 'required|in:pending,paid,shipped,completed,cancelled'
    ]);

    $order->status = $request->status;
    $order->save();

    return back()->with('success', 'Статус заказа обновлен на: ' . getStatusName($order->status));
}

Детализация заказа и связи Eloquent

Давайте подробнее рассмотрим конструкцию `with(['user', 'items.product'])`. Здесь мы видим силу Eloquent ORM. Мы не просто загружаем связанные позиции заказа (`items`), мы используем «точечную нотацию» (`items.product`), чтобы сказать Laravel: «Загрузи позиции заказа, а для каждой позиции сразу загрузи связанный с ней товар». Это позволяет нам в Blade-шаблоне свободно выводить название товара и его картинку: `{{ $item->product->name }}`, не опасаясь дополнительных SQL-запросов.

В шаблоне `admin.orders.show` мы выведем таблицу с составом заказа. Важно отображать цену товара на момент покупки (которая сохранена в таблице `order_items`), а не текущую цену из таблицы `products`. Цена товара может измениться, но история заказа должна оставаться неизменной (Mastery Learning).

Как называется проблема производительности, при которой ORM выполняет множество дополнительных SQL-запросов в цикле, и как ее решить в Laravel?

Какая конструкция, появившаяся в PHP 8, является более строгой и лаконичной альтернативой оператору switch и возвращает значение?