# Symfony Serializer: девять практических сценариев

Самостоятельный PHP-проект без полного Symfony Framework. PHP 8.2+, Symfony Serializer 7.4.23, Bootstrap 5.3.8. Собственный код MIT. Все данные учебные.

## Что здесь можно попробовать

1. JSON → Customer DTO → JSON: обязательные поля и значения по умолчанию.
2. snake_case во внешнем контракте и camelCase в PHP.
3. Группы public/admin при формировании ответа.
4. DateTimeImmutable и перевод отображения даты в UTC/Europe/Moscow. В этом сценарии принимается только существующая календарная дата YYYY-MM-DDTHH:MM:SS с поясом ±HH:MM или Z; доли секунд, относительные выражения и отсутствующий пояс отклоняются до normalizer. Невозможные даты не нормализуются в следующий месяц.
5. Вложенный Address и массив объектов Item. Конструктор Order требует id, address и items; неполный заказ возвращает 422, а не обращается к неинициализированному свойству.
6. Отсутствие поля, явный null, false и пустая строка.
7. Ошибки типов, лишние поля, сбор нескольких ошибок.
8. Циклическая связь → ссылка с ID; отдельный пример MaxDepth.
9. Десериализация Signup и отдельная проверка Symfony Validator.

Классы и настройки разрешены заранее. Через мастерскую нельзя передать PHP-код, имя своего класса, путь файла или внешний URL. У введённых данных нет постоянного хранилища. Не отправляйте реальные контакты, пароли и документы.

## Windows (PowerShell)

Установите PHP 8.2+ и Composer, проверьте PATH. Node.js нужен только для пересборки CSS и клиентских проверок; готовая папка public уже включена.

```powershell
php --version
composer --version
composer install --no-interaction --no-plugins --no-scripts
composer check-platform-reqs
composer test
composer verify
php bin/run.php nested fixtures/nested.json
php -S 127.0.0.1:8191 -t public
```

Откройте http://127.0.0.1:8191/ . Встроенный сервер предназначен для разработки. Остановка: Ctrl+C в его терминале. Не открывайте этот сервер в Интернет.

Необязательная пересборка интерфейса:

```powershell
npm.cmd ci --ignore-scripts
npm.cmd run build
npm.cmd test
npm.cmd audit --audit-level=low
```

## Linux: локальный запуск и CLI

Для Ubuntu 24.04 подойдёт PHP 8.3 из стандартного репозитория. Для другой версии дистрибутива сначала проверьте доступные пакеты и фактическую версию PHP. Установку Composer выполните по официальной инструкции с проверкой подписи установщика: https://getcomposer.org/download/ . Не используйте случайные curl | sh.

```bash
sudo apt update
sudo apt install php8.3-cli php8.3-mbstring php8.3-xml unzip
php --version
composer install --no-interaction --no-plugins --no-scripts
composer check-platform-reqs
composer test
composer verify
php bin/run.php validate fixtures/validate.json
php -S 127.0.0.1:8191 -t public
```

CLI возвращает 0 при успешном сценарии, 2 при ожидаемой ошибке данных, 1 при ошибке запуска. В примере validate исходные данные специально не проходят бизнес-проверки; код 2 здесь ожидаем.

```bash
php bin/run.php groups fixtures/groups.json '{"group":"admin"}'
php bin/run.php dates fixtures/dates.json '{"timezone":"Europe/Moscow"}'
php bin/run.php relations fixtures/relations.json '{"relationMode":"depth"}'
```

В PowerShell проще скачать PHP-рецепт из мастерской или создать JSON параметров в отдельной переменной; избегайте переноса bash-кавычек без проверки оболочки. Рецепт кладут в корень проекта и запускают `php recipe.php`. Данные внутри рецепта закодированы base64; они не интерполируются в PHP-код.

## API и честные записи выполнения

`GET /api.php` сообщает готовность runtime. `POST /api.php` выполняет настоящий PHP с Content-Type application/json. Тело:

```json
{"scenario":"roundtrip","input":"{\"name\":\"Анна\",\"email\":\"demo@example.test\",\"active\":true}","options":{}}
```

Внешний input — строка с JSON выбранного примера. options — объект, даже если он пуст. Разрешены только group, timezone, relationMode, collectErrors, skipNull с ограниченными значениями. Ответ 200 означает успешное преобразование, 422 — ошибку данных выбранного примера. Ошибка самого конверта даёт 400; неверный метод — 405, media type — 415, слишком большое тело — 413, недоступный PHP runtime — 503. Неожиданный сбой даёт 500 без стека и путей сервера.

Лимиты учебного endpoint: тело запроса 32 КиБ, input 16 КиБ, строка 2000 байт, ключ 100 байт, 30 элементов в коллекции, 250 узлов, 8 уровней структуры, время PHP до 3 секунд. `set_time_limit` не заменяет таймауты FPM и reverse proxy. Endpoint не пишет введённые данные в базу или файлы. Веб-сервер при этом может вести обычный журнал обращений; не включайте логирование тел запросов с личными данными.

Кнопка «Показать запись исходного примера» читает `public/records.json`: это результаты реального PHP, созданные `composer build`. Они относятся только к fixtures и явно отмечены как запись. Изменённые данные требуют работающего PHP; JavaScript не имитирует Serializer. `composer verify` повторяет все девять запусков и сравнивает результаты побайтно. Обновляйте записи осознанно после изменения поведения.

## Linux/VPS: отдельный сайт с PHP-FPM и Nginx

Ниже пример для Ubuntu 24.04, PHP 8.3, отдельного домена serializer.example.test и проекта `/var/www/serializer`. Замените домен своим. Файлы проекта принадлежат пользователю деплоя; FPM достаточно чтения. Writable-каталог приложению не нужен. `public` — единственный document root; vendor и src не публикуются как статические файлы.

```bash
sudo apt install php8.3-fpm nginx
cd /var/www/serializer
composer install --no-dev --no-interaction --prefer-dist --no-plugins --no-scripts
composer check-platform-reqs
sudo systemctl enable --now php8.3-fpm nginx
```

В контексте `http` Nginx (например, `/etc/nginx/conf.d/serializer-limits.conf`):

```nginx
limit_req_zone $binary_remote_addr zone=serializer_api:10m rate=2r/s;
```

В отдельном server-блоке:

```nginx
server {
    listen 80;
    server_name serializer.example.test;
    root /var/www/serializer/public;
    index index.html;
    client_max_body_size 32k;
    location / { try_files $uri $uri/ =404; }
    location = /api.php {
        limit_req zone=serializer_api burst=5 nodelay;
        limit_req_status 429;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root/api.php;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_read_timeout 5s;
    }
    location ~ \.php$ { return 404; }
    location ~ /\. { deny all; }
}
```

```bash
sudo nginx -t
sudo systemctl reload nginx
curl -i http://127.0.0.1/api.php -H 'Host: serializer.example.test'
```

Этот фрагмент HTTP подходит для первоначальной проверки. До публичной работы настройте HTTPS для своего домена. Пул FPM должен иметь `request_terminate_timeout = 5s`, разумный `pm.max_children` под память VPS и `php_admin_value[memory_limit] = 64M`; проверяйте фактический расход, а не переносите число процессов без расчёта. Для одного публичного учебного endpoint ограничивайте частоту на reverse proxy. В PHP-коде нет распределённого rate limiter. Если Nginx стоит за доверенным прокси, корректно настройте real IP только для его адресов; иначе все посетители могут делить один лимит. Не доверяйте произвольному X-Forwarded-For.

## Вариант Caddy + PHP-FPM

На сервере с установленным Caddy и PHP-FPM используйте отдельный домен с корректными DNS и открытыми 80/443. Caddy сможет обслужить HTTPS. Socket и права пользователя caddy на него должны соответствовать фактическому пулу FPM.

```caddyfile
serializer.example.com {
    root * /var/www/serializer/public
    request_body {
        max_size 32KiB
    }
    @api path /api.php
    handle @api {
        php_fastcgi unix//run/php/php8.3-fpm.sock
    }
    handle {
        @php path *.php
        respond @php 404
        file_server
    }
}
```

```bash
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
curl -i https://serializer.example.com/api.php
```

В стандартном Caddy нет встроенного эквивалента указанного `limit_req`. Для публичной интенсивной нагрузки поставьте ограничение частоты на внешнем прокси/CDN или добавьте отдельно выбранное и проверенное решение. Ограничение размера тела и FPM-ресурсов оставьте в любом случае. Не копируйте директивы стороннего модуля без его установки.

## Публикация на WordPress

Пакет мастерской может содержать public, src и vendor; api.php использует свой Composer autoload и не загружает WordPress. Наличие vendor внутри плагина требуется только для готового endpoint. В исходном ZIP vendor и node_modules отсутствуют: восстановите их по lock-файлам. При установке в WordPress сначала проверьте PHP хостинга; версии до 8.2 получают ясное сообщение 503, а доступ к записанным опытам сохраняется. PHP исходников не предназначен для включения в текст записи или редактор PHP-сниппетов.

## Проверки и структура

```bash
composer test
composer verify
composer audit
npm ci --ignore-scripts
npm run build
npm test
npm audit --audit-level=low
```

`src/Models.php` — DTO и атрибуты. `Workshop.php` — преобразования и ограничения. `Endpoint.php` — HTTP-контракт без сети. `public/api.php` — тонкая HTTP-обвязка. `fixtures` — входы. `tests/run.php` — PHP-проверки, `tests/client.test.mjs` — проверки ограничений клиента, рецептов и защиты от устаревших результатов. Эти тесты не являются нагрузочным испытанием или проверкой вашего FPM; браузер и эксплуатацию проверяйте отдельно.

Официальные материалы: https://symfony.com/doc/7.4/serializer.html · https://symfony.com/releases/7.4 · https://getcomposer.org/doc/ · https://symfony.com/doc/7.4/validation.html .
