Уроки курса
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 мин

Транзакции базы данных: Сохранение заказа

Изучение концепции транзакций БД (ACID). Применение DB::transaction для атомарного сохранения заказа и позиций корзины. Очистка сессии.

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

Добро пожаловать в шестнадцатый урок нашего курса! До этого момента мы научились формировать корзину пользователя, сохраняя выбранные товары в сессии, а также подготовили форму для ввода данных доставки. Теперь перед нами стоит критически важная задача: перенести данные из временного хранилища (сессии) в постоянное (базу данных). Этот процесс таит в себе серьезную опасность. Представьте ситуацию: пользователь оформляет заказ на 5 разных товаров. Наш код успешно создает запись в таблице orders, затем начинает в цикле добавлять товары в таблицу order_items. Первый товар добавлен успешно, второй тоже, но на третьем происходит сбой (например, отключилось электричество на сервере или база данных на секунду стала недоступна). Что произойдет? В базе останется «оборванный» заказ. Деньги с клиента могут быть списаны, но мы не будем знать, что именно он купил, так как часть товаров не сохранилась. Это катастрофа для любого интернет-магазина. Чтобы избежать таких ситуаций, в программировании и базах данных используется механизм транзакций.

Транзакция — это последовательность операций с базой данных, которая воспринимается СУБД как единое целое. Для транзакций действует принцип ACID: Atomicity (Атомарность), Consistency (Согласованность), Isolation (Изолированность), Durability (Надежность). Для нас сейчас важнее всего Атомарность. Этот принцип звучит так: «Или всё, или ничего». Если мы оборачиваем наши действия по сохранению заказа в транзакцию, база данных гарантирует, что либо все записи (и сам заказ, и все его позиции) будут успешно сохранены, либо, если на любом этапе возникнет ошибка, база данных откатит (Rollback) все изменения к первоначальному состоянию. В Laravel для работы с транзакциями предоставляется невероятно удобный фасад DB и метод transaction(). Метод принимает замыкание (анонимную функцию), внутри которого мы пишем наш код сохранения. Если код выполняется без выброса исключений, Laravel автоматически делает commit (фиксирует изменения). Если происходит ошибка — делает rollback.

php
use Illuminate\Support\Facades\DB;
use App\Models\Order;
use App\Models\OrderItem;
use Illuminate\Http\Request;

public function process(Request $request) {
    $cart = session('cart', []);
    if (empty($cart)) {
        return redirect()->route('cart.index')->with('error', 'Корзина пуста');
    }

    // Оборачиваем логику сохранения в транзакцию
    DB::transaction(function () use ($cart) {
        // 1. Считаем общую сумму
        $total = array_sum(array_map(fn($item) => $item['price'] * $item['quantity'], $cart));
        
        // 2. Создаем главную запись заказа
        $order = Order::create([
            'user_id' => auth()->id(),
            'total_price' => $total,
            'status' => 'pending'
        ]);

        // 3. Сохраняем каждый товар заказа
        foreach ($cart as $id => $item) {
            OrderItem::create([
                'order_id' => $order->id,
                'product_id' => $id,
                'quantity' => $item['quantity'],
                'price' => $item['price']
            ]);
        }
    });

    // 4. Очищаем корзину после успешного сохранения
    session()->forget('cart');
    
    return redirect()->route('orders.success');
}

Давайте детально разберем представленный выше код контроллера CheckoutController. Во-первых, мы извлекаем корзину из сессии: $cart = session('cart', []);. Если корзина пуста, мы немедленно прерываем выполнение и возвращаем пользователя обратно. Далее мы вызываем DB::transaction(). Обратите внимание на конструкцию use ($cart). В PHP анонимные функции имеют свою собственную область видимости. Они не видят переменные, созданные вне их. Конструкция use позволяет «пробросить» переменную $cart внутрь транзакции. Внутри функции мы сначала вычисляем общую сумму заказа, используя комбинацию функций array_sum и array_map (это современный и лаконичный подход в PHP 8). Затем мы создаем запись в модели Order. Статус по умолчанию устанавливаем как pending (в ожидании оплаты). Получив объект $order, мы используем его ID ($order->id) для связывания товаров в цикле foreach. Мы создаем записи OrderItem. Только после того, как транзакция успешно завершится (выход из замыкания), мы вызываем session()->forget('cart'), навсегда удаляя оформленные товары из сессии пользователя.

Задание

Вам необходимо реализовать процесс оформления заказа в вашем проекте, используя транзакции.

  • Создайте метод process() в CheckoutController.
  • Импортируйте фасад Illuminate\Support\Facades\DB.
  • Получите данные корзины из сессии.
  • Реализуйте DB::transaction с замыканием, передав в него корзину.
  • Внутри транзакции создайте Order и в цикле OrderItem.
  • После блока транзакции добавьте очистку сессии и редирект.
10 баллов

Зачем использовать DB::transaction при сохранении заказа?

Какой метод фасада session используется для полного удаления ключа 'cart' из сессии? Напишите только название метода.