Phase 6 zamknięta po 2 planach. Pełny fundament dla Phase 7-13 (migracja 17 admin controllers do Admin\ namespace). 06-01 (Forms infrastructure): - Admin\ViewModels\Forms\* — 5 ViewModeli (687 L) - Admin\Validation\FormValidator (196 L) - composer.json: php >=7.4, PSR-4 paths cross-platform safe (Admin\ → autoload/admin/, Frontend\ → autoload/front/) 06-02 (Support layer): - Admin\Support\TableListRequestFactory (99 L) — parser list z $_GET - Admin\Support\Forms\FormRequestHandler (159 L) — POST + CSRF + walidacja + persist - Admin\Support\Forms\FormFieldRenderer (494 L) — renderer HTML pól Decyzje: - Brak BaseController — Phase 7+ kontrolery jako POJOs z DI (jak shopPRO) - PSR-4 filename fix: TableListRequestFactory.php (bez shopPRO 'class.' prefix) - PascalCase namespace (Admin\Support) na lowercase folder admin/ ze względu na Windows fs case-insensitivity vs legacy admin/controls/ Pliki: 8 nowych klas, 1635 L kodu PHP 7.4-kompatybilnego, zero regresji. Smoke test: walidacja e-maila zwraca PL komunikat, factory parsuje ?page=&per_page=&sort=&filter=, Domain/Shared nadal ładują się. PHPUnit: 37/37 OK. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
160 lines
4.7 KiB
PHP
160 lines
4.7 KiB
PHP
<?php
|
|
namespace Admin\Support\Forms;
|
|
|
|
use Admin\ViewModels\Forms\FormEditViewModel;
|
|
use Admin\ViewModels\Forms\FormFieldType;
|
|
use Admin\Validation\FormValidator;
|
|
|
|
/**
|
|
* Obsługa żądań formularza (POST, persist, walidacja)
|
|
*/
|
|
class FormRequestHandler
|
|
{
|
|
private FormValidator $validator;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->validator = new FormValidator();
|
|
}
|
|
|
|
/**
|
|
* Przetwarza żądanie POST formularza
|
|
*
|
|
* @param FormEditViewModel $formViewModel
|
|
* @param array $postData Dane z $_POST
|
|
* @return array Wynik przetwarzania ['success' => bool, 'errors' => array, 'data' => array]
|
|
*/
|
|
public function handleSubmit(FormEditViewModel $formViewModel, array $postData): array
|
|
{
|
|
$result = [
|
|
'success' => false,
|
|
'errors' => [],
|
|
'data' => []
|
|
];
|
|
|
|
// Walidacja CSRF
|
|
$csrfToken = isset($postData['_csrf_token']) ? (string) $postData['_csrf_token'] : '';
|
|
if (!\Shared\Security\CsrfToken::validate($csrfToken)) {
|
|
$result['errors'] = ['csrf' => 'Nieprawidłowy token bezpieczeństwa. Odśwież stronę i spróbuj ponownie.'];
|
|
return $result;
|
|
}
|
|
|
|
// Walidacja
|
|
$errors = $this->validator->validate($postData, $formViewModel->fields, $formViewModel->languages);
|
|
|
|
if (!empty($errors)) {
|
|
$result['errors'] = $errors;
|
|
// Zapisz dane do persist przy błędzie walidacji
|
|
if ($formViewModel->persist) {
|
|
$formViewModel->saveToPersist($postData);
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
// Przetwórz dane (np. konwersja typów)
|
|
$processedData = $this->processData($postData, $formViewModel->fields);
|
|
|
|
$result['success'] = true;
|
|
$result['data'] = $processedData;
|
|
|
|
// Wyczyść persist po sukcesie
|
|
if ($formViewModel->persist) {
|
|
$formViewModel->clearPersist();
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Przetwarza dane z formularza (konwersja typów)
|
|
*/
|
|
private function processData(array $postData, array $fields): array
|
|
{
|
|
$processed = [];
|
|
|
|
foreach ($fields as $field) {
|
|
$value = $postData[$field->name] ?? null;
|
|
|
|
// Konwersja typów
|
|
switch ($field->type) {
|
|
case FormFieldType::SWITCH:
|
|
$processed[$field->name] = $value ? 1 : 0;
|
|
break;
|
|
|
|
case FormFieldType::NUMBER:
|
|
$processed[$field->name] = $value !== null && $value !== '' ? (float)$value : null;
|
|
break;
|
|
|
|
case FormFieldType::LANG_SECTION:
|
|
if ($field->langFields !== null) {
|
|
$processed[$field->name] = $this->processLangSection($postData, $field);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
$processed[$field->name] = $value;
|
|
}
|
|
}
|
|
|
|
return $processed;
|
|
}
|
|
|
|
/**
|
|
* Przetwarza sekcję językową
|
|
*/
|
|
private function processLangSection(array $postData, $section): array
|
|
{
|
|
$result = [];
|
|
|
|
if ($section->langFields === null) {
|
|
return $result;
|
|
}
|
|
|
|
foreach ($section->langFields as $field) {
|
|
$fieldName = $field->name;
|
|
$langData = $postData[$fieldName] ?? [];
|
|
|
|
foreach ($langData as $langId => $value) {
|
|
if (!isset($result[$langId])) {
|
|
$result[$langId] = [];
|
|
}
|
|
|
|
// Konwersja typów dla pól językowych
|
|
switch ($field->type) {
|
|
case FormFieldType::SWITCH:
|
|
$result[$langId][$fieldName] = $value ? 1 : 0;
|
|
break;
|
|
case FormFieldType::NUMBER:
|
|
$result[$langId][$fieldName] = $value !== null && $value !== '' ? (float)$value : null;
|
|
break;
|
|
default:
|
|
$result[$langId][$fieldName] = $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Przywraca dane z persist do POST (przy błędzie walidacji)
|
|
*/
|
|
public function restoreFromPersist(FormEditViewModel $formViewModel): ?array
|
|
{
|
|
if (!$formViewModel->persist) {
|
|
return null;
|
|
}
|
|
|
|
return $_SESSION['form_persist'][$formViewModel->formId] ?? null;
|
|
}
|
|
|
|
/**
|
|
* Sprawdza czy żądanie jest submitowaniem formularza
|
|
*/
|
|
public function isFormSubmit(string $formId): bool
|
|
{
|
|
return $_SERVER['REQUEST_METHOD'] === 'POST' &&
|
|
(isset($_POST['_form_id']) && $_POST['_form_id'] === $formId);
|
|
}
|
|
}
|