Разработка веб-приложений с использованием программных платформ

Тема 4. Продвинутые темы Laravel

Разработка веб-приложений с использованием программных платформ

План лекции

Основные вопросы

  • Аутентификация и стартовые наборы (Starter Kits)
  • Авторизация доступа: механизмы Gates и Policies
  • Изоляция валидации: классы Form Request
  • Создание защищённого RESTful API и Laravel Sanctum
  • Трансформация вывода: Eloquent API Resources
  • Файловые хранилища Storage и ссылка storage:link
  • Стратегии кэширования данных и тегирование
  • Автоматизированное тестирование на базе Pest
  • Чеклист подготовки и развёртывания (Deployment)

Цели лекции

  • Освоить настройку готовой системы входа
  • Разграничить права доступа пользователей к данным
  • Вынести валидацию из контроллеров в запросы форм
  • Спроектировать stateless API со спецификацией JSON
  • Реализовать безопасную загрузку пользовательских файлов
  • Снизить нагрузку на СУБД с помощью кэширования
  • Написать проверяемый Feature-тест для эндпоинта API
  • Освоить регламент оптимизации для боевых серверов
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

От прототипа к production-системе

Учебный прототип (Лекция 3)

  • Все действия доступны любому посетителю
  • Правила валидации записаны прямо в контроллере
  • Интерфейс жестко привязан к Blade-шаблонам
  • Загрузка пользовательских файлов не поддерживается
  • При каждом запросе выполняются прямые запросы к СУБД
  • Отсутствуют автоматические тесты бизнес-логики
  • Нет оптимизации конфигураций под нагрузку

Промышленная система (Лекция 4)

  • Идентификация, аутентификация и верификация
  • Разграничение прав владения ресурсами (Policies)
  • Выделенные классы запросов FormRequest
  • Независимый программный интерфейс RESTful API
  • Абстракция файловых дисков (локальные и облачные)
  • Кэширование тяжелых запросов в Redis
  • Регрессионная защита автотестами на Pest
  • Чеклист компиляции и безопасный режим .env
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Аутентификация: стартовые наборы

Laravel Breeze

  • Официальный легковесный стартовый набор
  • Реализует регистрацию, логин, сброс пароля, email-верификацию
  • Варианты стека: Blade, Inertia (Vue/React) или API-only
  • Код полностью доступен в вашем проекте для правок
  • Идеальный выбор для большинства стандартных систем

Laravel Jetstream

  • Расширенный каркас для сложных корпоративных систем
  • Встроенная двухфакторная аутентификация (2FA / TOTP)
  • Управление командами (teams) и ролевыми приглашениями
  • Интеграция с Sanctum для выпуска личных API-токенов
  • Стек на базе Livewire или Inertia + Tailwind CSS
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Установка и генерация Breeze

Команды развёртывания

# Подключение пакета разработчика
composer require laravel/breeze --dev

# Интерактивная установка каркаса на Blade
php artisan breeze:install blade

# Сборка ассетов и накат миграций пользователей
npm install && npm run build
php artisan migrate
  • Команда breeze:install создаёт структуру «под ключ»

Сгенерированные артефакты

  • Контроллеры: app/Http/Controllers/Auth/
  • Шаблоны форм: resources/views/auth/
  • Маршруты: routes/auth.php
  • Запросы валидации: app/Http/Requests/Auth/
  • Таблицы БД: users, password_reset_tokens, sessions
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Защита маршрутов через Middleware

Назначение встроенных middleware

  • guest — доступ открыт исключительно неавторизованным гостям
  • auth — доступ разрешен только пользователям с активной сессией
  • verified — требует подтверждения email перед доступом к экрану

Пример группировки в routes/web.php

// Только для гостей (логин, регистрация)
Route::middleware('guest')->group(function () {
    Route::get('/login', [AuthController::class, 'create'])->name('login');
    Route::post('/login', [AuthController::class, 'store']);
});

// Только для подтвержденных пользователей
Route::middleware(['auth', 'verified'])->group(function () {
    Route::get('/dashboard', fn() => view('dashboard'))->name('dashboard');
    Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
});
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Аутентификация vs Авторизация

Аутентификация (Authentication)

  • Вопрос: «Кто вы такой?»
  • Идентификация субъекта и проверка подлинности пароля
  • Выполняется на входе в систему (логин, токен)
  • Фиксирует состояние пользователя в Auth::user()
  • При ошибке возвращается HTTP-код:
    401 Unauthorized

Авторизация (Authorization)

  • Вопрос: «Имеете ли вы право на это действие?»
  • Проверка полномочий на изменение конкретного ресурса
  • Применяется к сущностям: «может ли User #5 удалить Post #12?»
  • Реализуется через Gates и объектные Policies
  • При отказе возвращается HTTP-код:
    403 Forbidden
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Простые проверки: механизм Gates

Регистрация в AppServiceProvider

namespace App\Providers;

use App\Models\User;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Gate::define('access-admin-panel', function (User $user) {
            return $user->is_admin === true;
        });
    }
}

Проверка в коде приложения

// Проверка условия в контроллере
if (Gate::allows('access-admin-panel')) {
    // Выполнить административное действие
}

// Запрет выполнения
if (Gate::denies('access-admin-panel')) {
    abort(403);
}

// Автоматический выброс HTTP 403 при отказе
Gate::authorize('access-admin-panel');
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Объектные политики (Policies)

Назначение и создание политики

# Генерация класса политики с привязкой к модели
php artisan make:policy PostPolicy --model=Post
  • Создаётся файл app/Policies/PostPolicy.php
  • Методы политики соответствуют типовым действиям:
    viewAny, view, create, update, delete
  • Автоматически связывается с моделью по соглашению имен

Реализация метода проверки

namespace App\Policies;

use App\Models\Post;
use App\Models\User;

class PostPolicy
{
    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id;
    }

    public function delete(User $user, Post $post): bool
    {
        return $user->id === $post->user_id || $user->is_admin;
    }
}
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Вызов политик в контроллере и Blade

Проверка в PostController

class PostController extends Controller
{
    public function edit(Post $post): View
    {
        // Вызывает PostPolicy::update(Auth::user(), $post)
        $this->authorize('update', $post);

        return view('posts.edit', compact('post'));
    }

    public function destroy(Post $post): RedirectResponse
    {
        $this->authorize('delete', $post);
        $post->delete();

        return redirect()->route('posts.index');
    }
}

Отображение кнопок в Blade-шаблоне

@can('update', $post)
    <a href="{{ route('posts.edit', $post) }}" class="btn-edit">
        Редактировать
    </a>
@endcan

@can('delete', $post)
    <form method="POST" action="{{ route('posts.destroy', $post) }}">
        @csrf
        @method('DELETE')
        <button type="submit">Удалить</button>
    </form>
@endcan
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Проблема валидации в контроллерах

«Толстый» контроллер (Антипаттерн)

  • Метод store разрастается до десятков строк
  • Правила валидации смешаны с координацией запроса
  • Дублирование правил при наличии Web и API контроллеров
  • Невозможность изолированного повторного использования
  • Затруднено модульное тестирование логики валидации

Архитектурное решение: Form Request

  • Создание отдельного класса запроса для каждой формы
  • Валидация выполняется до попадания управления в контроллер
  • Встроенная проверка прав авторизации на отправку формы
  • Контроллер получает исключительно проверенный массив данных
  • Соблюдение принципа единственной ответственности (SRP)
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Анатомия класса Form Request

Создание класса через Artisan

php artisan make:request StorePostRequest
  • Создаётся файл app/Http/Requests/StorePostRequest.php
  • Наследует Illuminate\Foundation\Http\FormRequest
  • Внедряется в контроллер через внедрение зависимостей

Метод проверки прав authorize()

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StorePostRequest extends FormRequest
{
    public function authorize(): bool
    {
        // Проверка: имеет ли клиент право отправлять форму
        return $this->user() !== null;
    }
}
  • Если вернуть false, Laravel немедленно вернёт HTTP 403 Forbidden
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Правила и локализация ошибок

Метод rules()

public function rules(): array
{
    return [
        'title'    => ['required', 'string', 'min:5', 'max:255'],
        'body'     => ['required', 'string', 'min:20'],
        'category' => ['required', 'exists:categories,id'],
    ];
}
  • Поддерживаются массивы правил или строковые разделители |
  • Правило exists проверяет существование записи в БД

Метод кастомных сообщений messages()

public function messages(): array
{
    return [
        'title.required' => 'Укажите заголовок статьи.',
        'title.min'      => 'Заголовок должен быть не короче 5 символов.',
        'body.required'  => 'Текст статьи обязателен к заполнению.',
    ];
}
  • Позволяет задать дружественные понятные сообщения на русском языке
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Безопасная обработка в контроллере

Очищенный контроллер

namespace App\Http\Controllers;

use App\Http\Requests\StorePostRequest;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;

class PostController extends Controller
{
    public function store(StorePostRequest $request): RedirectResponse
    {
        // Извлекаем ТОЛЬКО валидированные поля
        $validated = $request->validated();
        $validated['user_id'] = $request->user()->id;

        $post = Post::create($validated);

        return redirect()->route('posts.show', $post)
            ->with('status', 'Статья успешно опубликована!');
    }
}

Гарантии безопасности

  • $request->validated() защищает от Mass Assignment
  • Посторонние ключи из формы отбрасываются
  • При ошибке валидации метод контроллера даже не начинает выполняться:
    • Для браузера: редирект назад с ошибками
    • Для API: ответ HTTP 422 с JSON-ошибками
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Архитектура RESTful API

Базовые принципы REST

  • Stateless: сервер не хранит сессионное состояние между запросами
  • Клиент передаёт токен авторизации в каждом HTTP-запросе
  • Вся необходимая метаинформация передается в заголовках
  • Стандартные HTTP-глаголы соответствуют операциям над ресурсом
  • Обмен данными выполняется в нейтральном формате JSON

Маршруты web.php vs api.php

  • routes/web.php
    • Подключает группу middleware web
    • Сессии, cookies, CSRF-токены, HTML-ответы
  • routes/api.php
    • Подключает группу middleware api
    • Префикс URL /api/, rate limiting (throttle), токены
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Аутентификация API: Laravel Sanctum

Механизм работы Sanctum

  • Легковесная подсистема выпуска токенов личного доступа
  • Токены хешируются (SHA-256) в таблице personal_access_tokens
  • Клиент передает токен в заголовке Authorization: Bearer <token>
  • Поддерживает установку прав (abilities) и срока жизни токенов

Контроллер выпуска токена

Route::post('/tokens/create', function (Request $request) {
    $request->validate([
        'email'    => ['required', 'email'],
        'password' => ['required'],
    ]);

    $user = User::where('email', $request->email)->first();

    if (! $user || ! Hash::check($request->password, $user->password)) {
        return response()->json(['message' => 'Неверные данные входа'], 401);
    }

    $token = $user->createToken('mobile-app')->plainTextToken;
    return response()->json(['token' => $token], 200);
});
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Ресурсные маршруты API

Регистрация apiResource

// routes/api.php
use App\Http\Controllers\Api\PostApiController;

Route::middleware('auth:sanctum')->group(function () {
    Route::apiResource('posts', PostApiController::class);
});
  • В отличие от Route::resource(), метод apiResource() исключает маршруты отображения HTML-форм: create и edit

Спецификация эндпоинтов

Метод URI Метод контроллера Код успешного ответа
GET /api/posts index 200 OK
POST /api/posts store 201 Created
GET /api/posts/{id} show 200 OK
PUT /api/posts/{id} update 200 OK
DELETE /api/posts/{id} destroy 204 No Content
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Трансформация данных: Eloquent Resources

Зачем нужны ресурсы API?

  • Прямой возврат моделей Eloquent в JSON раскрывает скрытые поля
  • Риск утечки чувствительных атрибутов (remember_token, хеши паролей)
  • Необходимость форматирования дат в ISO 8601 для фронтенда
  • Добавление вычисляемых атрибутов и ссылок без изменения модели БД

Генерация класса ресурса

php artisan make:resource PostResource
  • Создаётся файл app/Http/Resources/PostResource.php
  • Определяет метод toArray(), описывающий структуру JSON
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Реализация класса PostResource

Код PostResource

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class PostResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id'         => $this->id,
            'title'      => $this->title,
            'content'    => $this->body,
            'author'     => [
                'id'   => $this->user->id,
                'name' => $this->user->name,
            ],
            'created_at' => $this->created_at->toISOString(),
        ];
    }
}

Формат итогового ответа

{
  "data": {
    "id": 15,
    "title": "Новая архитектура",
    "content": "Текст статьи...",
    "author": {
      "id": 3,
      "name": "Иван Иванов"
    },
    "created_at": "2026-10-02T11:00:00.000000Z"
  }
}
  • Laravel автоматически упаковывает результат в корневой ключ data
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Использование ресурсов в контроллере

Отдача единичных записей и коллекций

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Resources\PostResource;
use App\Models\Post;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;

class PostApiController extends Controller
{
    public function index(): AnonymousResourceCollection
    {
        $posts = Post::with('user')->latest()->paginate(10);
        return PostResource::collection($posts);
    }

    public function show(Post $post): PostResource
    {
        return new PostResource($post->load('user'));
    }
}

Автоматическая пагинация

  • Метод PostResource::collection() с paginate() автоматически добавляет в ответ служебные мета-данные:
    links, meta, current_page, last_page, per_page
  • Не требует ручного вычисления ссылок пагинации для клиента API
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Работа с файлами: фасад Storage

Архитектура Flysystem

  • Фасад Storage построен на базе универсальной библиотеки Flysystem
  • Предоставляет единый программный API для любых типов файловых хранилищ
  • Смена локального диска на облачный Amazon S3 требует только изменения конфигурации .env без переписывания контроллеров

Базовые методы фасада Storage

use Illuminate\Support\Facades\Storage;

// Запись содержимого в файл
Storage::disk('public')->put('reports/summary.txt', $data);

// Чтение и проверка существования
$content = Storage::disk('public')->get('reports/summary.txt');
$exists  = Storage::disk('public')->exists('reports/summary.txt');

// Удаление файла
Storage::disk('public')->delete('reports/summary.txt');
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Конфигурация дисков (config/filesystems.php)

  • local — каталог storage/app/private/
    • Доступ закрыт от прямого просмотра через браузер
    • Используется для закрытых документов, чеков, отчётов
  • public — каталог storage/app/public/
    • Публичные пользовательские файлы (аватары, фото товаров)
    • Доступны через веб-сервер после создания ссылки
php artisan storage:link
  • Создаёт символическую ссылку:
    public/storage →\rightarrow storage/app/public
  • Браузер обращается по URL: https://example.com/storage/avatars/image.jpg
  • Выполняется один раз при первичной настройке проекта
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Контроллер загрузки файлов

Контроллер сохранения аватара

public function updateAvatar(Request $request): RedirectResponse
{
    $request->validate([
        'avatar' => ['required', 'image', 'mimes:jpeg,png,webp', 'max:2048'],
    ]);

    if ($request->hasFile('avatar')) {
        // Удаляем старый файл пользователя
        if ($request->user()->avatar_path) {
            Storage::disk('public')->delete($request->user()->avatar_path);
        }

        // Сохраняем новый с уникальным хеш-именем
        $path = $request->file('avatar')->store('avatars', 'public');
        $request->user()->update(['avatar_path' => $path]);
    }

    return back()->with('status', 'Аватар успешно обновлён!');
}

Правила безопасной загрузки

  • Никогда не использовать исходное имя файла (getClientOriginalName)
  • Метод store() автоматически генерирует уникальный хеш
  • Строгая проверка типа image, списка mimes и лимита max в КБ
  • Генерация URL: Storage::url($user->avatar_path)
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Кэширование данных: фасад Cache

Цели применения кэша

  • Снижение нагрузки на сервер баз данных при частых запросах
  • Сокращение времени отдачи ответа клиенту (TTFB) до единиц миллисекунд
  • Временное сохранение тяжелых агрегированных выборок данных

Основные операции кэширования

use Illuminate\Support\Facades\Cache;

// Записать на 1 час (3600 секунд)
Cache::put('popular_tags', $tags, now()->addHour());

// Извлечь или вычислить (паттерн Cache-Aside)
$posts = Cache::remember('posts.recent', 600, function () {
    return Post::with('user')->latest()->take(10)->get();
});

// Принудительное удаление ключа из кэша
Cache::forget('posts.recent');
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Драйверы кэша и тегирование

Сравнение драйверов кэша

Драйвер Хранилище Скорость Тегирование
file storage/framework/cache/ Средняя Нет
database Таблица cache в БД Средняя Нет
redis In-memory key-value СУБД Экстремальная Да
memcached In-memory key-value Экстремальная Да

Тегирование кэша в Redis

// Сохранение с метками тегов
Cache::tags(['posts', 'category.4'])->put('post.12', $post, 3600);

// Сброс всех записей, помеченных тегом 'posts'
Cache::tags(['posts'])->flush();
  • Позволяет гранулярно сбрасывать связанные группы записей без очистки всего кэша приложения
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Автоматизированное тестирование

Пирамида тестирования

  • Unit-тесты: тестирование изолированных функций и вспомогательных классов без запуска приложения
  • Feature-тесты: интеграционные тесты полных HTTP-запросов (роутинг, middleware, контроллер, БД)
  • Browser-тесты: сквозное тестирование интерфейса в реальном браузере через Laravel Dusk

Pest vs PHPUnit

  • PHPUnit: классический стандарт объектно-ориентированного тестирования на базе классов
  • Pest: современный выразительный DSL для тестирования с лаконичным синтаксисом функций
  • Pest полностью совместим с PHPUnit и предустановлен в Laravel
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Создание Feature-теста для API

Создание файла теста через Artisan

# Создание Feature-теста с синтаксисом Pest
php artisan make:test Api/PostApiTest --pest
  • Создаётся файл tests/Feature/Api/PostApiTest.php

Проверка запрета неавторизованного доступа

use App\Models\Post;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('unauthenticated user cannot create post via API', function () {
    $response = $this->postJson('/api/posts', [
        'title' => 'Тестовая статья',
        'body'  => 'Содержимое тестовой статьи',
    ]);

    $response->assertStatus(401);
});
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Тестирование аутентификации и состояния БД

Проверка успешного сценария с токеном

test('authorized user creates post through API', function () {
    $user = User::factory()->create();

    $payload = [
        'title' => 'Промышленная разработка',
        'body'  => 'Детальный текст статьи о тестировании',
    ];

    $response = $this->actingAs($user, 'sanctum')
        ->postJson('/api/posts', $payload);

    $response->assertStatus(201)
        ->assertJsonPath('data.title', 'Промышленная разработка');

    // Проверка фактического наличия записи в таблице БД
    $this->assertDatabaseHas('posts', [
        'title'   => 'Промышленная разработка',
        'user_id' => $user->id,
    ]);
});

Ключевые утверждения

  • actingAs($user, 'sanctum') имитирует валидный токен Bearer
  • assertDatabaseHas() проверяет транзакционную запись в СУБД
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Запуск и анализ тестов

Команды консоли

# Запуск полного набора тестов
php artisan test

# Параллельный запуск для максимального ускорения
php artisan test --parallel

# Формирование отчёта о покрытии кода (Code Coverage)
php artisan test --coverage --min=80

Изоляция тестового окружения (phpunit.xml)

<php>
    <env name="APP_ENV" value="testing"/>
    <env name="BCRYPT_ROUNDS" value="4"/>
    <env name="CACHE_STORE" value="array"/>
    <env name="DB_CONNECTION" value="sqlite"/>
    <env name="DB_DATABASE" value=":memory:"/>
</php>
  • Тесты работают в оперативной памяти SQLite без затрагивания рабочей базы данных разработки
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Развёртывание приложения (Deployment)

Регламент подготовки к эксплуатации

  1. Установка только боевых зависимостей без dev-пакетов
  2. Предварительная компиляция и кэширование метаинформации
  3. Применение миграций базы данных без ручного подтверждения
  4. Сборка клиентских ассетов через Vite для production

Оптимизация Composer

# Установка библиотек для боевого сервера
composer install --no-dev --optimize-autoloader --no-interaction
  • --no-dev отсекает тестовые утилиты (Pest, Faker, Mockery)
  • --optimize-autoloader формирует монолитную карту классов classmap, ускоряя поиск файлов PHP
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Производственное кэширование Laravel

Обязательные команды кэширования

# 1. Кэширование всех конфигурационных файлов в единый массив
php artisan config:cache

# 2. Компиляция таблицы маршрутов в быстрый код сопоставления
php artisan route:cache

# 3. Предкомпиляция всех Blade-шаблонов
php artisan view:cache

# 4. Кэширование событий и слушателей
php artisan event:cache

Критическое правило config:cache!

  • После выполнения config:cache вызовы функции env('KEY') возвращают null во всех прикладных файлах проекта!
  • Обращаться к настройкам разрешено только через хелпер config('services.stripe.key')
  • Для отката кэша в процессе отладки: php artisan optimize:clear
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Чеклист безопасности окружения (.env)

Параметры боевого файла .env

  • APP_ENV=production
  • APP_DEBUG=false
    • Категорически запрещено включать отладку на сервере!
    • APP_DEBUG=true раскрывает пароли к СУБД, API-ключи и пути на диске при любой ошибке
  • APP_KEY=base64:... (уникальный ключ шифрования сессий и токенов)
  • APP_URL=https://myproject.by (обязательно протокол HTTPS)

Команды на сервере

# Безопасный накат миграций в production
php artisan migrate --force

# Настройка прав на каталоги записи
chmod -R 775 storage bootstrap/cache
  • Флаг --force принудительно подтверждает миграцию без запроса в интерактивном терминале
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Инфраструктура и серверное окружение

Архитектура стека Nginx + PHP-FPM

  • Запросы принимает обратный прокси-сервер Nginx
  • Документ-рут Nginx (root) строго указывает на каталог /public!
  • Прямой доступ клиентов к ядру, каталогу app и файлу .env физически невозможен
  • Статические ассеты (CSS, JS, картинки) Nginx отдаёт напрямую
  • Запросы к PHP передаются через сокет сервиса php8.3-fpm

Платформы развёртывания

  • PaaS / Managed: Laravel Cloud, Laravel Forge, Render
    • Автоматизация деплоя из Git, автонастройка SSL Let's Encrypt
  • Классический VPS: Ubuntu Server 24.04 LTS
    • Ручная настройка Nginx, демонов Supervisor для очередей и планировщика задач php artisan schedule:run в Cron
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Резюме лекции

Безопасность и валидация

  • Аутентификация: официальный стартовый набор Laravel Breeze обеспечивает проверенный каркас входа
  • Авторизация: разделение логики на процедурные Gates и объектные Policies для контроля ресурсов
  • Валидация: изоляция бизнес-правил в классах FormRequest и отсечение мусорных полей через validated()

API, данные и инфраструктура

  • RESTful API: токенизация через Laravel Sanctum и стандартизация JSON через API Resources
  • Хранилище: единый фасад Storage, абстракция Flysystem и раздача публичных файлов через storage:link
  • Производительность: кэширование через Cache::remember() и инвалидация тегов в Redis
  • Качество: регрессионные Feature-тесты на Pest с проверкой статусов, структуры JSON и БД
  • Развёртывание: компиляция конфигураций и строгое отключение отладки APP_DEBUG=false
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Вопросы для контроля знаний

  1. В чём состоит принципиальное отличие HTTP 401 Unauthorized от HTTP 403 Forbidden?
  2. В каких сценариях целесообразно использовать Gate, а в каких — Policy?
  3. Какую угрозу безопасности несёт передача $request->all() в метод Post::create()?
  4. Зачем в кодовой базе RESTful API используется слой Eloquent API Resources?
  5. Какую практическую задачу решает консольная команда php artisan storage:link?
  6. Почему в боевой рабочей среде критически важно выставить APP_DEBUG=false?
  7. Что произойдет при попытке вызова функции env('KEY') после команды config:cache?
  8. Чем отличается запуск Feature-теста с трейтом RefreshDatabase от обычного теста?
Лекция 4. Продвинутые темы Laravel
Разработка веб-приложений с использованием программных платформ

Полезные ресурсы и документация

Безопасность и архитектура

  • Laravel Starter Kits — laravel.com/docs/starter-kits
  • Laravel Authorization — laravel.com/docs/authorization
  • Laravel Validation — laravel.com/docs/validation
  • Laravel Sanctum — laravel.com/docs/sanctum

Хранилище, тесты и деплой

  • Laravel File Storage — laravel.com/docs/filesystem
  • Laravel Cache — laravel.com/docs/cache
  • Pest PHP Testing Framework — pestphp.com
  • Laravel Deployment Guide — laravel.com/docs/deployment
Лекция 4. Продвинутые темы Laravel

Лекция 4, 2 академических часа. Цель: сформировать у студентов практические навыки реализации защищённых корпоративных веб-систем: комплексная аутентификация и авторизация, чистая валидация входных данных через Form Request, проектирование stateless RESTful API с токенами Sanctum, безопасная работа с файловыми хранилищами, оптимизация через кэширование, написание автоматических тестов и регламент подготовки к промышленному развёртыванию (production deployment). Связь с предыдущими темами: продолжает лекцию 3 («Основы Laravel: архитектура, маршрутизация, Blade и Eloquent») и базируется на протоколе HTTP и принципах безопасности из лекций 1 и 2. Материал завершает блок изучения Laravel перед переходом к компонентам Symfony. Методика: 50 минут лекционный разбор архитектуры, 25 минут живая демонстрация ключевых сценариев в консоли и API-клиенте, 15 минут разбор типовых ошибок и контрольные вопросы.

Докладчик: Подчеркните, что предыдущая лекция дала базовый работающий макет, но реальная промышленная веб-разработка начинается именно на этом этапе, когда в проект закладываются безопасность, тестирование и масштабируемость.

Докладчик: Сравните два подхода. Покажите, что учебный макет хорош для первого знакомства, но отдавать его в промышленную эксплуатацию категорически запрещено из-за уязвимостей и архитектурного долга.

Докладчик: Отметьте, что в Laravel не нужно вручную писать хеширование паролей и обработчики сессий входа. Официальные стартовые наборы экономят сотни часов рутины и закрывают векторы атак.

Докладчик: Обратите внимание студентов на то, что Breeze не прячет код внутри vendor-директории, а генерирует чистые контроллеры и шаблоны прямо в проекте.

Докладчик: Покажите, как middleware перенаправляет неавторизованного пользователя на страницу /login и сохраняет URL намерения (intended URL) для возврата после успешного входа.

Докладчик: Подчеркните эту границу! Студенты постоянно путают 401 и 403. 401 означает «мы вас не знаем, представьтесь», а 403 — «мы знаем, кто вы, но вам сюда нельзя».

Докладчик: Gates отлично подходят для общих глобальных действий, не привязанных к конкретной модели Eloquent (доступ в панель управления, просмотр отчетов за месяц).

Докладчик: Политики группируют правила вокруг конкретной бизнес-сущности. Обратите внимание, что первым аргументом Laravel всегда автоматически передаёт текущего аутентифицированного пользователя.

Докладчик: Обязательно укажите, что сокрытие кнопки в интерфейсе через @can не заменяет проверку $this->authorize() в контроллере! Злоумышленник может отправить запрос вручную через cURL.

Докладчик: Объясните, что контроллер должен быть тонким дирижером. Его задача — принять запрос, вызвать сервис или модель и вернуть ответ, а не валидировать массивы.

Докладчик: Подчеркните, что если проверка прав не нужна внутри Form Request (например, маршрут уже защищен middleware auth), метод authorize() должен явно возвращать true.

Докладчик: Расскажите о правилах валидации exists и unique. Они автоматически делают SQL-запрос к базе для подтверждения валидности внешних ключей.

Докладчик: Категорически запретите использовать $request->all() при создании моделей. Злоумышленник может дописать в HTTP-запрос 'is_admin' => 1 и получить права суперпользователя.

Докладчик: Объясните разницу между веб-приложением для браузера и API. Браузеру нужны HTML и сессионные куки. Мобильному приложению или фронтенду на React/Vue нужен только чистый JSON.

Докладчик: Обратите внимание: метод plainTextToken возвращает открытый токен ровно один раз при генерации. В базе хранится только его криптографический хеш.

Докладчик: Подчеркните стандартные коды ответов HTTP. Создание ресурса возвращает 201 Created, удаление без тела — 204 No Content, ошибка валидации — 422 Unprocessable Content.

Докладчик: API Resource — это слой представления (View) для REST API. Он выступает контрактом между внутренней структурой базы данных и внешним миром.

Докладчик: Обратите внимание, что мы переименовали поле 'body' в 'content'. Это наглядно демонстрирует, как API Resource изолирует клиентов API от схемы таблиц базы данных.

Докладчик: Обратите внимание на вызов Post::with('user'). Это предотвращает проблему N+1 запросов при сериализации автора каждого поста в цикле коллекции.

Докладчик: Подчеркните, что в PHP-коде никогда не следует использовать прямые функции вроде file_put_contents() или move_uploaded_file() с жестко заданными абсолютными путями.

Докладчик: Это частая ошибка студентов! Без команды storage:link файлы загружаются в storage/app/public, но браузер получает ошибку 404, пытаясь загрузить картинку по URL.

Докладчик: Объясните опасность сохранения оригинального имени файла: атака Path Traversal, перезапись существующих файлов и выполнение вредоносных скриптов при ошибочной конфигурации веб-сервера.

Докладчик: Метод Cache::remember() — наиболее элегантный инструмент Laravel. Он автоматически проверяет наличие ключа, а если его нет — выполняет замыкание, сохраняет результат и возвращает его.

Докладчик: Для учебных проектов подходит драйвер file. В высоконагруженных промышленных проектах стандартом де-факто является Redis благодаря поддержке атомарных операций и тегов.

Докладчик: Подчеркните студентам, что Feature-тесты в веб-разработке дают максимальную отдачу на затраченное время, так как они эмулируют реальный HTTP-запрос пользователя от начала до конца.

Докладчик: Обратите внимание на трейт RefreshDatabase. Он автоматически применяет миграции к тестовой БД и оборачивает каждый тест в транзакцию с последующим откатом (rollback).

Докладчик: Метод actingAs() избавляет от необходимости вручную выпускать токен через HTTP-запрос логина в каждом тесте, значительно ускоряя прогон тестового набора.

Докладчик: Настройка BCRYPT_ROUNDS=4 для тестирования драматически ускоряет выполнение тестов с пользователями, так как хеширование паролей не тратит процессорное время.

Докладчик: Развертывание PHP-приложений кардинально отличается от локальной разработки. На сервере никогда не должен запускаться npm run dev или composer require --dev.

Докладчик: Подчеркните это правило трижды! 90% начинающих разработчиков при деплое сталкиваются с тем, что env() внезапно возвращает null, если они забыли о config:cache.

Докладчик: Утечка отладочного экрана Ignition при APP_DEBUG=true — одна из самых частых причин взлома веб-приложений. На боевом сервере пользователь должен видеть только нейтральную страницу ошибки 500.

Докладчик: Напомните студентам, что веб-сервер никогда не должен смотреть в корень проекта Laravel. Только в подпапку /public! Иначе весь исходный код и файл .env с паролями окажутся в открытом доступе.

Докладчик: Обобщите изученный блок. Студенты теперь владеют всеми компонентами, которые отделяют студенческую поделку от коммерческого веб-сервиса уровня Middle-разработчика.

Докладчик: Задайте 2-3 вопроса аудитории для оперативной проверки усвоения материала. Разберите логику ответа на вопрос о разнице между 401 и 403, а также опасность $request->all().

Докладчик: Рекомендуйте студентам официальную документацию Laravel как главный источник актуальных стандартов. На следующем занятии мы переходим к фреймворку Symfony и сравним их архитектурные подходы.