fix : 컨트롤러 검증 → FormRequest 분리

This commit is contained in:
2025-09-08 02:28:14 +09:00
parent d9563c96cb
commit 4bf02b7424
9 changed files with 204 additions and 26 deletions

View File

@@ -5,7 +5,9 @@
use App\Helpers\ApiResponse;
use App\Http\Controllers\Controller;
use App\Services\Design\ModelService;
use Illuminate\Http\Request;
use App\Http\Requests\Common\PaginateRequest;
use App\Http\Requests\Design\Model\StoreRequest;
use App\Http\Requests\Design\Model\UpdateRequest;
class DesignModelController extends Controller
{
@@ -13,48 +15,35 @@ public function __construct(
protected ModelService $service
) {}
public function index(Request $request)
public function index(PaginateRequest $request)
{
return ApiResponse::handle(function () use ($request) {
$q = $request->query('q', '');
$page = (int) $request->query('page', 1);
$size = (int) $request->query('size', 20);
$p = $request->validatedOrDefaults();
$q = $p['q'] ?? '';
$page = (int) $p['page'];
$size = (int) $p['size'];
// 현재 서비스 시그니처가 list($q, $page, $size)이므로 정합 유지
return $this->service->list($q, $page, $size);
}, __('message.fetched'));
}
public function store(Request $request)
public function store(StoreRequest $request)
{
return ApiResponse::handle(function () use ($request) {
$payload = $request->validate([
'code' => 'required|string|max:100',
'name' => 'required|string|max:200',
'category_id' => 'nullable|integer',
'lifecycle' => 'nullable|string|max:30',
'description' => 'nullable|string',
'is_active' => 'boolean',
]);
return $this->service->create($payload);
return $this->service->create($request->validated());
}, __('message.created'));
}
public function show(int $id)
{
return ApiResponse::handle(fn() => $this->service->find($id), __('message.fetched'));
return ApiResponse::handle(fn () => $this->service->find($id), __('message.fetched'));
}
public function update(Request $request, int $id)
public function update(UpdateRequest $request, int $id)
{
return ApiResponse::handle(function () use ($request, $id) {
$payload = $request->validate([
'code' => 'sometimes|string|max:100',
'name' => 'sometimes|string|max:200',
'category_id' => 'nullable|integer',
'lifecycle' => 'nullable|string|max:30',
'description' => 'nullable|string',
'is_active' => 'boolean',
]);
return $this->service->update($id, $payload);
return $this->service->update($id, $request->validated());
}, __('message.updated'));
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Http\Requests\Common;
use Illuminate\Foundation\Http\FormRequest;
class PaginateRequest extends FormRequest
{
public function authorize(): bool { return true; }
public function rules(): array
{
return [
'page' => 'nullable|integer|min:1',
'size' => 'nullable|integer|min:1|max:100',
'q' => 'nullable|string|max:100',
'sort' => 'nullable|string|in:id,code,name,created_at',
'order' => 'nullable|string|in:asc,desc',
];
}
public function validatedOrDefaults(): array
{
$v = $this->validated();
$v['page'] = $v['page'] ?? 1;
$v['size'] = $v['size'] ?? 20;
$v['order'] = $v['order'] ?? 'desc';
return $v;
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Http\Requests\Design\BomTemplate;
use Illuminate\Foundation\Http\FormRequest;
use App\Support\Validation\BomItemRules;
class ReplaceItemsRequest extends FormRequest
{
public function authorize(): bool { return true; }
public function rules(): array
{
$itemRules = collect(BomItemRules::base())
->mapWithKeys(fn($rule, $key) => ["items.*.$key" => $rule])
->all();
return ['items' => 'required|array|min:1'] + $itemRules;
}
public function messages(): array
{
return [
'items.required' => __('validation.required', ['attribute' => 'items']),
'items.array' => __('validation.array', ['attribute' => 'items']),
'items.min' => __('validation.min.array', ['attribute' => 'items', 'min' => 1]),
];
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Http\Requests\Design\BomTemplate;
use Illuminate\Foundation\Http\FormRequest;
class UpsertRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'name' => 'required|string|max:100',
'is_primary' => 'nullable|boolean',
'notes' => 'nullable|string',
];
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Http\Requests\Design\Model;
use Illuminate\Foundation\Http\FormRequest;
class StoreRequest extends FormRequest
{
public function authorize(): bool { return true; }
public function rules(): array
{
return [
'code' => 'required|string|max:100',
'name' => 'required|string|max:200',
'category_id' => 'nullable|integer',
'lifecycle' => 'nullable|string|max:50',
'description' => 'nullable|string',
'is_active' => 'boolean',
];
}
public function messages(): array
{
return [
'code.required' => __('validation.required', ['attribute' => '모델코드']),
'name.required' => __('validation.required', ['attribute' => '모델명']),
];
}
protected function prepareForValidation(): void
{
if ($this->has('code')) {
$this->merge(['code' => trim($this->input('code'))]);
}
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Http\Requests\Design\Model;
use Illuminate\Foundation\Http\FormRequest;
class UpdateRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'code' => 'sometimes|string|max:100',
'name' => 'sometimes|string|max:200',
'category_id' => 'nullable|integer',
'lifecycle' => 'nullable|string|max:50',
'description' => 'nullable|string',
'is_active' => 'boolean',
];
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Design\ModelVersion;
use Illuminate\Foundation\Http\FormRequest;
class CreateDraftRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'version_no' => 'nullable|integer|min:1',
'notes' => 'nullable|string',
'effective_from' => 'nullable|date',
'effective_to' => 'nullable|date|after_or_equal:effective_from',
];
}
public function messages(): array
{
return [
'effective_to.after_or_equal' => __('validation.after_or_equal', ['attribute' => 'effective_to', 'date' => 'effective_from']),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Support\Validation;
class BomItemRules
{
public static function base(): array
{
return [
'ref_type' => 'required|string|in:MATERIAL,PRODUCT',
'ref_id' => 'required|integer|min:1',
'qty' => 'required|numeric|gt:0',
'waste_rate' => 'nullable|numeric|min:0',
'uom_id' => 'nullable|integer|min:1',
'notes' => 'nullable|string|max:255',
'sort_order' => 'nullable|integer',
'category_id'=> 'nullable|integer', // 선택: 카테고리 분류 사용 시
];
}
}