refactor ClientWidgetFormController; replace validation logic with SubmitWidgetFormAction for improved maintainability and clarity
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Containers\Widget\Actions;
|
||||
|
||||
use App\Containers\Widget\Tasks\GenerateWidgetFormValidationRulesTask;
|
||||
use App\Containers\Widget\Tasks\GenerateWidgetFormValidationMessagesTask;
|
||||
use App\Containers\Widget\Tasks\StoreWidgetFormResponseTask;
|
||||
use App\Containers\Widget\Tasks\FindWidgetFormByIdTask;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class SubmitWidgetFormAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly FindWidgetFormByIdTask $findWidgetFormByIdTask,
|
||||
private readonly GenerateWidgetFormValidationRulesTask $generateWidgetFormValidationRulesTask,
|
||||
private readonly GenerateWidgetFormValidationMessagesTask $generateWidgetFormValidationMessagesTask,
|
||||
private readonly StoreWidgetFormResponseTask $storeWidgetFormResponseTask,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function run(int $id, array $requestData): array
|
||||
{
|
||||
$formData = $this->findWidgetFormByIdTask->run($id);
|
||||
|
||||
$rules = $this->generateWidgetFormValidationRulesTask->run($formData['columns'], $formData['id']);
|
||||
$messages = $this->generateWidgetFormValidationMessagesTask->run($formData['columns']);
|
||||
|
||||
$validator = Validator::make($requestData, $rules, $messages);
|
||||
|
||||
if ($validator->fails()) {
|
||||
throw new ValidationException($validator);
|
||||
}
|
||||
|
||||
$this->storeWidgetFormResponseTask->run($id, $validator->validated());
|
||||
|
||||
return [
|
||||
'message' => $formData['send_message'],
|
||||
'status' => 'ok'
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Containers\Widget\Tasks;
|
||||
|
||||
use App\Containers\Widget\Models\CustomForm;
|
||||
|
||||
class FindWidgetFormByIdTask
|
||||
{
|
||||
public function run(int $id): CustomForm
|
||||
{
|
||||
return CustomForm::findOrFail($id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Containers\Widget\Tasks;
|
||||
|
||||
class GenerateWidgetFormValidationMessagesTask
|
||||
{
|
||||
public function run(array $columns): array
|
||||
{
|
||||
$messages = [];
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$name = $column['data']['name_field'];
|
||||
|
||||
if (!empty($column['data']['rules']['required'])) {
|
||||
$messages[$name . '.required'] = 'Поле обязательно для заполнения.';
|
||||
}
|
||||
|
||||
if (!empty($column['data']['rules']['min'])) {
|
||||
$messages[$name . '.min'] = 'Минимальная длина поля должна быть ' . $column['data']['rules']['min'] . ' символов.';
|
||||
}
|
||||
|
||||
if (!empty($column['data']['rules']['max'])) {
|
||||
$messages[$name . '.max'] = 'Максимальная длина поля должна быть ' . $column['data']['rules']['max'] . ' символов.';
|
||||
}
|
||||
|
||||
if (!empty($column['data']['rules']['unique'])) {
|
||||
$messages[$name . '.unique'] = 'Поле должно быть уникальным';
|
||||
}
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Containers\Widget\Tasks;
|
||||
|
||||
use App\Containers\Widget\Data\Rules\UniqueJsonField;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class GenerateWidgetFormValidationRulesTask
|
||||
{
|
||||
/**
|
||||
* Генерирует массив правил валидации для полей формы на основе их конфигурации.
|
||||
*
|
||||
* @param array $columns Конфигурация полей
|
||||
* @param int $formId ID формы для правила 'unique'
|
||||
* @return array Массив правил валидации в формате Laravel
|
||||
*/
|
||||
public function run(array $columns, int $formId): array
|
||||
{
|
||||
return collect($columns)
|
||||
->mapWithKeys(fn(array $column) => [
|
||||
// Ключом будет название поля, значением - массив его правил
|
||||
$column['data']['name_field'] => $this->resolveRulesForColumn($column, $formId)
|
||||
])
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Определяет и делегирует создание правил в зависимости от типа поля.
|
||||
*/
|
||||
private function resolveRulesForColumn(array $column, int $formId): array
|
||||
{
|
||||
$type = $column['type'] ?? 'default';
|
||||
|
||||
return match ($type) {
|
||||
'multiple_choice' => ['required', 'array', 'min:1'],
|
||||
default => $this->buildRulesFromConfig($column, $formId),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Собирает стандартный набор правил валидации из конфигурации поля.
|
||||
*/
|
||||
private function buildRulesFromConfig(array $column, int $formId): array
|
||||
{
|
||||
$configRules = $column['data']['rules'] ?? [];
|
||||
$validationRules = [];
|
||||
|
||||
// Правила, которые просто включаются по флагу true
|
||||
if (!empty($configRules['required'])) {
|
||||
$validationRules[] = 'required';
|
||||
}
|
||||
|
||||
// Правила, требующие значения (min, max, и т.д.)
|
||||
foreach (['min', 'max'] as $rule) {
|
||||
// Используем isset для корректной обработки значения '0'
|
||||
if (isset($configRules[$rule])) {
|
||||
$validationRules[] = "{$rule}:{$configRules[$rule]}";
|
||||
}
|
||||
}
|
||||
|
||||
// Сложные правила, требующие инстанцирования объектов
|
||||
if (!empty($configRules['unique'])) {
|
||||
$fieldName = $column['data']['name_field'];
|
||||
$validationRules[] = new UniqueJsonField($formId, $fieldName);
|
||||
}
|
||||
|
||||
return $validationRules;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Containers\Widget\Tasks;
|
||||
|
||||
use App\Containers\Widget\Models\CustomFormResponse;
|
||||
|
||||
class StoreWidgetFormResponseTask
|
||||
{
|
||||
public function run(int $formId, array $validatedData): void
|
||||
{
|
||||
CustomFormResponse::create([
|
||||
'custom_form_id' => $formId,
|
||||
'answers' => $validatedData,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,20 @@
|
||||
|
||||
namespace App\Containers\Widget\UI\API\Controllers;
|
||||
|
||||
use App\Containers\Widget\Data\Rules\UniqueJsonField;
|
||||
use App\Containers\Widget\Actions\SubmitWidgetFormAction;
|
||||
use App\Containers\Widget\Enums\CustomFormStatus;
|
||||
use App\Containers\Widget\Models\CustomForm;
|
||||
use App\Containers\Widget\Models\CustomFormResponse;
|
||||
use App\Containers\Widget\UI\API\Transformers\FormResource;
|
||||
use App\Ship\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class ClientWidgetFormController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly SubmitWidgetFormAction $submitWidgetFormAction,
|
||||
) {}
|
||||
|
||||
public function single(string $id)
|
||||
{
|
||||
return new FormResource(CustomForm::query()->where('status', CustomFormStatus::PUBLISHED)->where('form_id', $id)->firstOrFail());
|
||||
@@ -20,103 +23,12 @@ class ClientWidgetFormController extends Controller
|
||||
|
||||
public function submit(int $id, Request $request)
|
||||
{
|
||||
$data = CustomForm::findOrFail($id);
|
||||
|
||||
|
||||
$rules = $this->generateValidationRules($data['columns'], $data['id']);
|
||||
|
||||
|
||||
$messages = $this->generateValidationMessages($data['columns']);
|
||||
|
||||
|
||||
$validateData = Validator::make($request->all(), $rules, $messages);
|
||||
|
||||
|
||||
if ($validateData->fails()) {
|
||||
return response()->json($validateData->errors(), 422);
|
||||
try {
|
||||
$result = $this->submitWidgetFormAction->run($id, $request->all());
|
||||
} catch (ValidationException $exception) {
|
||||
return response()->json($exception->errors(), 422);
|
||||
}
|
||||
|
||||
$this->storeResponse($id, $validateData->validated());
|
||||
|
||||
|
||||
return response()->json([
|
||||
'message' => $data['send_message'],
|
||||
'status' => 'ok'
|
||||
]);
|
||||
}
|
||||
|
||||
private function generateValidationRules(array $columns, int $id): array
|
||||
{
|
||||
$rules = [];
|
||||
|
||||
foreach ($columns as $column) {
|
||||
// Извлекаем информацию о поле
|
||||
$name = $column['data']['name_field'];
|
||||
$rulesForField = [];
|
||||
|
||||
// Проверяем, является ли поле массивом (множественный выбор)
|
||||
if ($column['type'] === 'multiple_choice') {
|
||||
$rulesForField[] = 'required'; // Обязательно для множественного выбора
|
||||
$rulesForField[] = 'array'; // Указывает, что это массив
|
||||
$rulesForField[] = 'min:1'; // Минимум один элемент
|
||||
$rules[$name] = $rulesForField; // Правила для каждого элемента массива
|
||||
} else {
|
||||
// Обработка обычных полей
|
||||
if (!empty($column['data']['rules']['required'])) {
|
||||
$rulesForField[] = 'required';
|
||||
}
|
||||
|
||||
if (!empty($column['data']['rules']['min'])) {
|
||||
$rulesForField[] = 'min:' . $column['data']['rules']['min'];
|
||||
}
|
||||
|
||||
if (!empty($column['data']['rules']['max'])) {
|
||||
$rulesForField[] = 'max:' . $column['data']['rules']['max'];
|
||||
}
|
||||
|
||||
if (!empty($column['data']['rules']['unique']) && $column['data']['rules']['unique'] === true) {
|
||||
$rulesForField[] = new UniqueJsonField($id, $name);
|
||||
}
|
||||
|
||||
$rules[$name] = $rulesForField; // Добавляем правила для обычного поля
|
||||
}
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
private function generateValidationMessages(array $columns): array
|
||||
{
|
||||
$messages = [];
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$name = $column['data']['name_field'];
|
||||
|
||||
if (!empty($column['data']['rules']['required'])) {
|
||||
$messages[$name . '.required'] = 'Поле обязательно для заполнения.';
|
||||
}
|
||||
|
||||
if (!empty($column['data']['rules']['min'])) {
|
||||
$messages[$name . '.min'] = 'Минимальная длина поля должна быть ' . $column['data']['rules']['min'] . ' символов.';
|
||||
}
|
||||
|
||||
if (!empty($column['data']['rules']['max'])) {
|
||||
$messages[$name . '.max'] = 'Максимальная длина поля должна быть ' . $column['data']['rules']['max'] . ' символов.';
|
||||
}
|
||||
|
||||
if (!empty($column['data']['rules']['unique'])) {
|
||||
$messages[$name . '.max'] = 'Поле должно быть уникальным';
|
||||
}
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
private function storeResponse(int $id, array $validateData): void
|
||||
{
|
||||
CustomFormResponse::create([
|
||||
'custom_form_id' => $id,
|
||||
'answers' => $validateData,
|
||||
]);
|
||||
return response()->json($result);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user