344 lines
11 KiB
PHP
344 lines
11 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Services\Design;
|
||
|
|
|
||
|
|
use App\Models\Design\ModelParameter;
|
||
|
|
use App\Models\Design\DesignModel;
|
||
|
|
use App\Services\Service;
|
||
|
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||
|
|
use Illuminate\Support\Facades\DB;
|
||
|
|
use Illuminate\Validation\ValidationException;
|
||
|
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||
|
|
|
||
|
|
class ModelParameterService extends Service
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* 모델의 매개변수 목록 조회
|
||
|
|
*/
|
||
|
|
public function listByModel(int $modelId, string $q = '', int $page = 1, int $size = 20): LengthAwarePaginator
|
||
|
|
{
|
||
|
|
$tenantId = $this->tenantId();
|
||
|
|
|
||
|
|
// 모델 존재 확인
|
||
|
|
$model = DesignModel::where('tenant_id', $tenantId)->where('id', $modelId)->first();
|
||
|
|
if (!$model) {
|
||
|
|
throw new NotFoundHttpException(__('error.not_found'));
|
||
|
|
}
|
||
|
|
|
||
|
|
$query = ModelParameter::query()
|
||
|
|
->where('tenant_id', $tenantId)
|
||
|
|
->where('model_id', $modelId);
|
||
|
|
|
||
|
|
if ($q !== '') {
|
||
|
|
$query->where(function ($w) use ($q) {
|
||
|
|
$w->where('parameter_name', 'like', "%{$q}%")
|
||
|
|
->orWhere('description', 'like', "%{$q}%");
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
return $query->orderBy('sort_order')->orderBy('id')->paginate($size, ['*'], 'page', $page);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 매개변수 조회
|
||
|
|
*/
|
||
|
|
public function show(int $parameterId): ModelParameter
|
||
|
|
{
|
||
|
|
$tenantId = $this->tenantId();
|
||
|
|
|
||
|
|
$parameter = ModelParameter::where('tenant_id', $tenantId)->where('id', $parameterId)->first();
|
||
|
|
if (!$parameter) {
|
||
|
|
throw new NotFoundHttpException(__('error.not_found'));
|
||
|
|
}
|
||
|
|
|
||
|
|
return $parameter;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 매개변수 생성
|
||
|
|
*/
|
||
|
|
public function create(array $data): ModelParameter
|
||
|
|
{
|
||
|
|
$tenantId = $this->tenantId();
|
||
|
|
$userId = $this->apiUserId();
|
||
|
|
|
||
|
|
// 모델 존재 확인
|
||
|
|
$model = DesignModel::where('tenant_id', $tenantId)->where('id', $data['model_id'])->first();
|
||
|
|
if (!$model) {
|
||
|
|
throw new NotFoundHttpException(__('error.not_found'));
|
||
|
|
}
|
||
|
|
|
||
|
|
// 같은 모델 내에서 매개변수명 중복 체크
|
||
|
|
$exists = ModelParameter::query()
|
||
|
|
->where('tenant_id', $tenantId)
|
||
|
|
->where('model_id', $data['model_id'])
|
||
|
|
->where('parameter_name', $data['parameter_name'])
|
||
|
|
->exists();
|
||
|
|
|
||
|
|
if ($exists) {
|
||
|
|
throw ValidationException::withMessages(['parameter_name' => __('error.duplicate')]);
|
||
|
|
}
|
||
|
|
|
||
|
|
return DB::transaction(function () use ($tenantId, $userId, $data) {
|
||
|
|
// sort_order가 없으면 자동 설정
|
||
|
|
if (!isset($data['sort_order'])) {
|
||
|
|
$maxOrder = ModelParameter::where('tenant_id', $tenantId)
|
||
|
|
->where('model_id', $data['model_id'])
|
||
|
|
->max('sort_order') ?? 0;
|
||
|
|
$data['sort_order'] = $maxOrder + 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
$payload = array_merge($data, [
|
||
|
|
'tenant_id' => $tenantId,
|
||
|
|
'created_by' => $userId,
|
||
|
|
'updated_by' => $userId,
|
||
|
|
]);
|
||
|
|
|
||
|
|
return ModelParameter::create($payload);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 매개변수 수정
|
||
|
|
*/
|
||
|
|
public function update(int $parameterId, array $data): ModelParameter
|
||
|
|
{
|
||
|
|
$tenantId = $this->tenantId();
|
||
|
|
$userId = $this->apiUserId();
|
||
|
|
|
||
|
|
$parameter = ModelParameter::where('tenant_id', $tenantId)->where('id', $parameterId)->first();
|
||
|
|
if (!$parameter) {
|
||
|
|
throw new NotFoundHttpException(__('error.not_found'));
|
||
|
|
}
|
||
|
|
|
||
|
|
// 매개변수명 변경 시 중복 체크
|
||
|
|
if (isset($data['parameter_name']) && $data['parameter_name'] !== $parameter->parameter_name) {
|
||
|
|
$exists = ModelParameter::query()
|
||
|
|
->where('tenant_id', $tenantId)
|
||
|
|
->where('model_id', $parameter->model_id)
|
||
|
|
->where('parameter_name', $data['parameter_name'])
|
||
|
|
->where('id', '!=', $parameterId)
|
||
|
|
->exists();
|
||
|
|
|
||
|
|
if ($exists) {
|
||
|
|
throw ValidationException::withMessages(['parameter_name' => __('error.duplicate')]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return DB::transaction(function () use ($parameter, $userId, $data) {
|
||
|
|
$payload = array_merge($data, ['updated_by' => $userId]);
|
||
|
|
$parameter->update($payload);
|
||
|
|
|
||
|
|
return $parameter->fresh();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 매개변수 삭제
|
||
|
|
*/
|
||
|
|
public function delete(int $parameterId): bool
|
||
|
|
{
|
||
|
|
$tenantId = $this->tenantId();
|
||
|
|
$userId = $this->apiUserId();
|
||
|
|
|
||
|
|
$parameter = ModelParameter::where('tenant_id', $tenantId)->where('id', $parameterId)->first();
|
||
|
|
if (!$parameter) {
|
||
|
|
throw new NotFoundHttpException(__('error.not_found'));
|
||
|
|
}
|
||
|
|
|
||
|
|
return DB::transaction(function () use ($parameter, $userId) {
|
||
|
|
$parameter->update(['deleted_by' => $userId]);
|
||
|
|
return $parameter->delete();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 매개변수 순서 변경
|
||
|
|
*/
|
||
|
|
public function reorder(int $modelId, array $parameterIds): array
|
||
|
|
{
|
||
|
|
$tenantId = $this->tenantId();
|
||
|
|
$userId = $this->apiUserId();
|
||
|
|
|
||
|
|
// 모델 존재 확인
|
||
|
|
$model = DesignModel::where('tenant_id', $tenantId)->where('id', $modelId)->first();
|
||
|
|
if (!$model) {
|
||
|
|
throw new NotFoundHttpException(__('error.not_found'));
|
||
|
|
}
|
||
|
|
|
||
|
|
return DB::transaction(function () use ($tenantId, $userId, $modelId, $parameterIds) {
|
||
|
|
$order = 1;
|
||
|
|
$updated = [];
|
||
|
|
|
||
|
|
foreach ($parameterIds as $parameterId) {
|
||
|
|
$parameter = ModelParameter::query()
|
||
|
|
->where('tenant_id', $tenantId)
|
||
|
|
->where('model_id', $modelId)
|
||
|
|
->where('id', $parameterId)
|
||
|
|
->first();
|
||
|
|
|
||
|
|
if ($parameter) {
|
||
|
|
$parameter->update([
|
||
|
|
'sort_order' => $order,
|
||
|
|
'updated_by' => $userId,
|
||
|
|
]);
|
||
|
|
$updated[] = $parameter->fresh();
|
||
|
|
$order++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $updated;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 매개변수 대량 저장 (upsert)
|
||
|
|
*/
|
||
|
|
public function bulkUpsert(int $modelId, array $parameters): array
|
||
|
|
{
|
||
|
|
$tenantId = $this->tenantId();
|
||
|
|
$userId = $this->apiUserId();
|
||
|
|
|
||
|
|
// 모델 존재 확인
|
||
|
|
$model = DesignModel::where('tenant_id', $tenantId)->where('id', $modelId)->first();
|
||
|
|
if (!$model) {
|
||
|
|
throw new NotFoundHttpException(__('error.not_found'));
|
||
|
|
}
|
||
|
|
|
||
|
|
return DB::transaction(function () use ($tenantId, $userId, $modelId, $parameters) {
|
||
|
|
$result = [];
|
||
|
|
|
||
|
|
foreach ($parameters as $index => $paramData) {
|
||
|
|
$paramData['model_id'] = $modelId;
|
||
|
|
|
||
|
|
// ID가 있으면 업데이트, 없으면 생성
|
||
|
|
if (isset($paramData['id']) && $paramData['id']) {
|
||
|
|
$parameter = ModelParameter::query()
|
||
|
|
->where('tenant_id', $tenantId)
|
||
|
|
->where('model_id', $modelId)
|
||
|
|
->where('id', $paramData['id'])
|
||
|
|
->first();
|
||
|
|
|
||
|
|
if ($parameter) {
|
||
|
|
$parameter->update(array_merge($paramData, ['updated_by' => $userId]));
|
||
|
|
$result[] = $parameter->fresh();
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
// 새로운 매개변수 생성
|
||
|
|
$exists = ModelParameter::query()
|
||
|
|
->where('tenant_id', $tenantId)
|
||
|
|
->where('model_id', $modelId)
|
||
|
|
->where('parameter_name', $paramData['parameter_name'])
|
||
|
|
->exists();
|
||
|
|
|
||
|
|
if (!$exists) {
|
||
|
|
if (!isset($paramData['sort_order'])) {
|
||
|
|
$paramData['sort_order'] = $index + 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
$payload = array_merge($paramData, [
|
||
|
|
'tenant_id' => $tenantId,
|
||
|
|
'created_by' => $userId,
|
||
|
|
'updated_by' => $userId,
|
||
|
|
]);
|
||
|
|
|
||
|
|
$result[] = ModelParameter::create($payload);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $result;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 매개변수 값 검증
|
||
|
|
*/
|
||
|
|
public function validateParameters(int $modelId, array $values): array
|
||
|
|
{
|
||
|
|
$tenantId = $this->tenantId();
|
||
|
|
|
||
|
|
// 모델의 모든 매개변수 조회
|
||
|
|
$parameters = ModelParameter::query()
|
||
|
|
->where('tenant_id', $tenantId)
|
||
|
|
->where('model_id', $modelId)
|
||
|
|
->orderBy('sort_order')
|
||
|
|
->get();
|
||
|
|
|
||
|
|
$errors = [];
|
||
|
|
$validated = [];
|
||
|
|
|
||
|
|
foreach ($parameters as $parameter) {
|
||
|
|
$paramName = $parameter->parameter_name;
|
||
|
|
$value = $values[$paramName] ?? null;
|
||
|
|
|
||
|
|
// 필수 매개변수 체크
|
||
|
|
if ($parameter->is_required && ($value === null || $value === '')) {
|
||
|
|
$errors[$paramName] = __('error.required');
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 값이 없고 필수가 아니면 기본값 사용
|
||
|
|
if ($value === null || $value === '') {
|
||
|
|
$validated[$paramName] = $parameter->default_value;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 타입별 검증
|
||
|
|
if (!$parameter->validateValue($value)) {
|
||
|
|
$errors[$paramName] = __('error.invalid_value');
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 형변환 후 저장
|
||
|
|
$validated[$paramName] = $parameter->castValue($value);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!empty($errors)) {
|
||
|
|
throw ValidationException::withMessages($errors);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $validated;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 모델의 매개변수 스키마 조회 (API용)
|
||
|
|
*/
|
||
|
|
public function getParameterSchema(int $modelId): array
|
||
|
|
{
|
||
|
|
$tenantId = $this->tenantId();
|
||
|
|
|
||
|
|
// 모델 존재 확인
|
||
|
|
$model = DesignModel::where('tenant_id', $tenantId)->where('id', $modelId)->first();
|
||
|
|
if (!$model) {
|
||
|
|
throw new NotFoundHttpException(__('error.not_found'));
|
||
|
|
}
|
||
|
|
|
||
|
|
$parameters = ModelParameter::query()
|
||
|
|
->where('tenant_id', $tenantId)
|
||
|
|
->where('model_id', $modelId)
|
||
|
|
->orderBy('sort_order')
|
||
|
|
->get();
|
||
|
|
|
||
|
|
return [
|
||
|
|
'model' => [
|
||
|
|
'id' => $model->id,
|
||
|
|
'code' => $model->code,
|
||
|
|
'name' => $model->name,
|
||
|
|
],
|
||
|
|
'parameters' => $parameters->map(function ($param) {
|
||
|
|
return [
|
||
|
|
'name' => $param->parameter_name,
|
||
|
|
'type' => $param->parameter_type,
|
||
|
|
'required' => $param->is_required,
|
||
|
|
'default' => $param->default_value,
|
||
|
|
'min' => $param->min_value,
|
||
|
|
'max' => $param->max_value,
|
||
|
|
'unit' => $param->unit,
|
||
|
|
'options' => $param->options,
|
||
|
|
'description' => $param->description,
|
||
|
|
];
|
||
|
|
})->toArray(),
|
||
|
|
];
|
||
|
|
}
|
||
|
|
}
|