From c95b8c8dac0a09072da37eb6fd7450a0a742b5fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=A4=80=ED=9D=A0?= Date: Wed, 11 Mar 2026 12:43:39 +0900 Subject: [PATCH] dbmsv4 init...5 --- app/Entities/BoardEntity.php | 6 +- app/Entities/Customer/CustomerEntity.php | 2 +- app/Entities/Customer/ServiceEntity.php | 4 +- app/Entities/Customer/Wallet/WalletEntity.php | 2 +- app/Entities/Equipment/CHASSISEntity.php | 8 +- app/Entities/Equipment/ServerEntity.php | 8 +- app/Entities/Equipment/ServerPartEntity.php | 8 +- app/Entities/MylogEntity.php | 2 +- app/Entities/Part/CSEntity.php | 6 +- app/Entities/Part/DISKEntity.php | 2 +- app/Entities/Part/IPEntity.php | 10 +- app/Entities/Part/PartType1Entity.php | 2 +- app/Entities/Part/SWITCHEntity.php | 6 +- app/Entities/PaymentEntity.php | 25 +- app/Forms/CommonForm.php | 105 ++++---- app/Services/CommonService.php | 226 ++++++++++++------ app/Services/Customer/ServiceService.php | 5 - app/Services/Part/PartType1Service.php | 4 +- app/Services/Part/PartType2Service.php | 8 +- 19 files changed, 237 insertions(+), 202 deletions(-) diff --git a/app/Entities/BoardEntity.php b/app/Entities/BoardEntity.php index 2fac782..02437d9 100644 --- a/app/Entities/BoardEntity.php +++ b/app/Entities/BoardEntity.php @@ -25,11 +25,11 @@ class BoardEntity extends CommonEntity } public function getUserUid(): ?int { - return $this->user_uid; + return $this->user_uid === null ? null : (int) $this->user_uid; } public function getWorkerUid(): ?int { - return $this->worker_uid; + return $this->worker_uid === null ? null : (int) $this->worker_uid; } public function getCaregory(): string { @@ -37,6 +37,6 @@ class BoardEntity extends CommonEntity } public function getContent(): ?string { - return $this->category; + return $this->content; } } diff --git a/app/Entities/Customer/CustomerEntity.php b/app/Entities/Customer/CustomerEntity.php index 1a55f16..343c3ac 100644 --- a/app/Entities/Customer/CustomerEntity.php +++ b/app/Entities/Customer/CustomerEntity.php @@ -17,6 +17,6 @@ abstract class CustomerEntity extends CommonEntity final public function getUserUid(): ?int { - return $this->user_uid; + return $this->user_uid === null ? null : (int) $this->user_uid; } } diff --git a/app/Entities/Customer/ServiceEntity.php b/app/Entities/Customer/ServiceEntity.php index bcee89a..6f44de9 100644 --- a/app/Entities/Customer/ServiceEntity.php +++ b/app/Entities/Customer/ServiceEntity.php @@ -29,11 +29,11 @@ class ServiceEntity extends CustomerEntity } public function getClientInfoUid(): ?int { - return $this->clientinfo_uid; + return $this->clientinfo_uid === null ? null : (int) $this->clientinfo_uid; } public function getServerInfoUid(): ?int { - return $this->serverinfo_uid; + return $this->serverinfo_uid === null ? null : (int) $this->serverinfo_uid; } //기본기능용 public function getCode(): string diff --git a/app/Entities/Customer/Wallet/WalletEntity.php b/app/Entities/Customer/Wallet/WalletEntity.php index 21d96ee..16c204e 100644 --- a/app/Entities/Customer/Wallet/WalletEntity.php +++ b/app/Entities/Customer/Wallet/WalletEntity.php @@ -27,7 +27,7 @@ abstract class WalletEntity extends CustomerEntity final public function getClientInfoUid(): ?int { - return $this->clientinfo_uid; + return $this->clientinfo_uid === null ? null : (int) $this->clientinfo_uid; } final public function getAmount(): int diff --git a/app/Entities/Equipment/CHASSISEntity.php b/app/Entities/Equipment/CHASSISEntity.php index e561d66..ef26bd0 100644 --- a/app/Entities/Equipment/CHASSISEntity.php +++ b/app/Entities/Equipment/CHASSISEntity.php @@ -21,15 +21,15 @@ class CHASSISEntity extends EquipmentEntity } public function getCPUInfoUid(): ?int { - return $this->cpuinfo_uid; + return $this->cpuinfo_uid === null ? null : (int) $this->cpuinfo_uid; } public function getRAMInfoUid(): ?int { - return $this->raminfo_uid; + return $this->raminfo_uid === null ? null : (int) $this->raminfo_uid; } public function getDISKInfoUid(): ?int { - return $this->diskinfo_uid; + return $this->diskinfo_uid === null ? null : (int) $this->diskinfo_uid; } //기본기능 public function getPrice(): int @@ -46,7 +46,7 @@ class CHASSISEntity extends EquipmentEntity } public function getAvailable(): int { - return $this->getStock() - $this->getUsed(); + return (int) ($this->getStock() - $this->getUsed()); } public function getCPUCnt(): int { diff --git a/app/Entities/Equipment/ServerEntity.php b/app/Entities/Equipment/ServerEntity.php index cf3f0bc..1a98637 100644 --- a/app/Entities/Equipment/ServerEntity.php +++ b/app/Entities/Equipment/ServerEntity.php @@ -25,19 +25,19 @@ class ServerEntity extends EquipmentEntity } final public function getClientInfoUid(): ?int { - return $this->clientinfo_uid; + return $this->clientinfo_uid === null ? null : (int) $this->clientinfo_uid; } final public function getServiceInfoUid(): ?int { - return $this->serviceinfo_uid; + return $this->serviceinfo_uid === null ? null : (int) $this->serviceinfo_uid; } final public function getChassisInfoUid(): int { - return $this->chassisinfo_uid; + return $this->chassisinfo_uid === null ? null : (int) $this->chassisinfo_uid; } final public function getSwitchInfoUid(): ?int { - return $this->switchinfo_uid; + return $this->switchinfo_uid === null ? null : (int) $this->switchinfo_uid; } //기본기능용 diff --git a/app/Entities/Equipment/ServerPartEntity.php b/app/Entities/Equipment/ServerPartEntity.php index e804b77..c6d8bdc 100644 --- a/app/Entities/Equipment/ServerPartEntity.php +++ b/app/Entities/Equipment/ServerPartEntity.php @@ -29,19 +29,19 @@ class ServerPartEntity extends EquipmentEntity } public function getClientInfoUid(): ?int { - return $this->clientinfo_uid; + return $this->clientinfo_uid === null ? null : (int) $this->clientinfo_uid; } public function getServiceInfoUid(): ?int { - return $this->serviceinfo_uid; + return $this->serviceinfo_uid === null ? null : (int) $this->serviceinfo_uid; } public function getServerInfoUid(): int { - return $this->serverinfo_uid; + return $this->serverinfo_uid === null ? null : (int) $this->serverinfo_uid; } public function getPartUid(): ?int { - return $this->part_uid; + return $this->part_uid === null ? null : (int) $this->part_uid; } //기본기능용 public function getCustomTitle(): string diff --git a/app/Entities/MylogEntity.php b/app/Entities/MylogEntity.php index 567a5d8..37d00a4 100644 --- a/app/Entities/MylogEntity.php +++ b/app/Entities/MylogEntity.php @@ -19,6 +19,6 @@ class MylogEntity extends CommonEntity //Common Function public function getUserUid(): ?int { - return $this->user_uid; + return $this->user_uid === null ? null : (int) $this->user_uid; } } diff --git a/app/Entities/Part/CSEntity.php b/app/Entities/Part/CSEntity.php index ef1990c..8e7f0e3 100644 --- a/app/Entities/Part/CSEntity.php +++ b/app/Entities/Part/CSEntity.php @@ -24,15 +24,15 @@ class CSEntity extends PartType2Entity //기본기능 final public function getClientInfoUid(): ?int { - return $this->clientinfo_uid; + return $this->clientinfo_uid === null ? null : (int) $this->clientinfo_uid; } final public function getServiceInfoUid(): ?int { - return $this->serviceinfo_uid; + return $this->serviceinfo_uid === null ? null : (int) $this->serviceinfo_uid; } final public function getServerInfoUid(): ?int { - return $this->serverinfo_uid; + return $this->serverinfo_uid === null ? null : (int) $this->serverinfo_uid; } public function getIP(): string { diff --git a/app/Entities/Part/DISKEntity.php b/app/Entities/Part/DISKEntity.php index aaec151..35e3dc3 100644 --- a/app/Entities/Part/DISKEntity.php +++ b/app/Entities/Part/DISKEntity.php @@ -17,6 +17,6 @@ class DISKEntity extends PartType1Entity public function getFormat(): int { - return $this->format ?? 0; + return (int) $this->format ?? 0; } } diff --git a/app/Entities/Part/IPEntity.php b/app/Entities/Part/IPEntity.php index afdcc68..3156021 100644 --- a/app/Entities/Part/IPEntity.php +++ b/app/Entities/Part/IPEntity.php @@ -23,23 +23,23 @@ class IPEntity extends PartType3Entity } public function getLineInfoUID(): int { - return $this->lineinfo_uid; + return $this->lineinfo_uid === null ? null : (int) $this->lineinfo_uid; } public function getOldClientInfoUID(): ?int { - return $this->old_clientinfo_uid; + return $this->old_clientinfo_uid === null ? null : (int) $this->old_clientinfo_uid; } final public function getClientInfoUid(): ?int { - return $this->clientinfo_uid; + return $this->clientinfo_uid === null ? null : (int) $this->clientinfo_uid; } final public function getServiceInfoUid(): ?int { - return $this->serviceinfo_uid; + return $this->serviceinfo_uid === null ? null : (int) $this->serviceinfo_uid; } final public function getServerInfoUid(): ?int { - return $this->serverinfo_uid; + return $this->serverinfo_uid === null ? null : (int) $this->serverinfo_uid; } //기본기능 public function getIP(): string diff --git a/app/Entities/Part/PartType1Entity.php b/app/Entities/Part/PartType1Entity.php index c7c399f..dd84112 100644 --- a/app/Entities/Part/PartType1Entity.php +++ b/app/Entities/Part/PartType1Entity.php @@ -19,6 +19,6 @@ class PartType1Entity extends PartEntity } final public function getAvailable(): int { - return $this->getStock() - $this->getUsed(); + return (int) ($this->getStock() - $this->getUsed()); } } diff --git a/app/Entities/Part/SWITCHEntity.php b/app/Entities/Part/SWITCHEntity.php index 586253e..ca44819 100644 --- a/app/Entities/Part/SWITCHEntity.php +++ b/app/Entities/Part/SWITCHEntity.php @@ -21,15 +21,15 @@ class SWITCHEntity extends PartType3Entity } final public function getClientInfoUid(): ?int { - return $this->clientinfo_uid; + return $this->clientinfo_uid === null ? null : (int) $this->clientinfo_uid; } final public function getServiceInfoUid(): ?int { - return $this->serviceinfo_uid; + return $this->serviceinfo_uid === null ? null : (int) $this->serviceinfo_uid; } final public function getServerInfoUid(): ?int { - return $this->serverinfo_uid; + return $this->serverinfo_uid === null ? null : (int) $this->serverinfo_uid; } public function getCode(): string { diff --git a/app/Entities/PaymentEntity.php b/app/Entities/PaymentEntity.php index 11f392c..a9f2563 100644 --- a/app/Entities/PaymentEntity.php +++ b/app/Entities/PaymentEntity.php @@ -9,22 +9,7 @@ class PaymentEntity extends CommonEntity { const PK = PaymentModel::PK; const TITLE = PaymentModel::TITLE; - protected array $nullableFields = [ - 'serviceinfo_uid', - 'serverpartinfo_uid', - ]; - protected $attributes = [ - 'serviceinfo_uid' => null, - 'serverpartinfo_uid' => null, - 'title' => '', - 'amount' => 0, - 'billing' => "", - 'billing_at' => "", - 'billing_month' => 0, - 'pay' => "", - 'status' => '', - 'content' => '' - ]; + public function __construct(array|null $data = null) { parent::__construct($data); @@ -39,19 +24,19 @@ class PaymentEntity extends CommonEntity } public function getUserUid(): ?int { - return $this->user_uid; + return $this->user_uid === null ? null : (int) $this->user_uid; } public function getClientInfoUid(): ?int { - return $this->clientinfo_uid; + return $this->clientinfo_uid === null ? null : (int) $this->clientinfo_uid; } public function getServiceInfoUid(): ?int { - return $this->serviceinfo_uid; + return $this->serviceinfo_uid === null ? null : (int) $this->serviceinfo_uid; } public function getServerPartInfoUid(): ?int { - return $this->serverpartinfo_uid; + return $this->serverpartinfo_uid === null ? null : (int) $this->serverpartinfo_uid; } //기본기능 public function getCustomTitle(): string diff --git a/app/Forms/CommonForm.php b/app/Forms/CommonForm.php index 6418249..6d4b97a 100644 --- a/app/Forms/CommonForm.php +++ b/app/Forms/CommonForm.php @@ -28,6 +28,7 @@ abstract class CommonForm private array $_batchjobButtons = ['batchjob' => '일괄처리', 'batchjob_delete' => '일괄삭제']; protected $formAction = null; + protected $isDebug = false; protected function __construct() { @@ -239,94 +240,78 @@ abstract class CommonForm * 데이터를 검증하고 유효하지 않을 경우 예외를 발생시킵니다. * 2025 CI4 표준: 규칙 배열 내에 label을 포함하여 한글 메시지 출력을 보장합니다. */ - public function validate_process(array &$formDatas, $isDebug = false): array - { - // 1) 전체 라벨/룰 - $allFormFields = $this->getFormFields(); // ['field' => '라벨', ...] - $allFormRules = $this->getFormRules(); // ['field' => 'rules', ...] - if (empty($allFormRules)) { - throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 지정된 Form RULE이 없습니다."); - } - - if ($this->formAction === 'modify') { - // (1) formDatas에 실제로 넘어온 필드만 - $targetFields = array_keys($formDatas); - if ($isDebug) { - log_message('debug', static::class . '->' . __FUNCTION__ . "에서 Validate targetFields Begin DEBUG"); - log_message('debug', var_export($targetFields, true)); - } - // // (2) 내부 제어용 키 제거(프로젝트에 맞게 추가/삭제) - // $exclude = ['_method', 'csrf_test_name', 'submit', 'token', 'action']; - // $targetFields = array_values(array_diff($targetFields, $exclude)); - // // (3) wildcard(role.*) 같은 규칙이 있으면 부모 기반으로 같이 포함 - // // - formDatas에 role이 있으면 role.* 규칙도 함께 검사되도록 추가 - // foreach ($allFormRules as $ruleField => $_ruleStr) { - // $ruleField = (string) $ruleField; - // if (!str_contains($ruleField, '.*')) { - // continue; - // } - // $parent = str_replace('.*', '', $ruleField); - // if (in_array($parent, $targetFields, true)) { - // $targetFields[] = $ruleField; // e.g. 'role.*' - // } - // } - // // (4) 실제로 룰이 정의된 필드만 남김 - // $targetFields = array_values(array_intersect($targetFields, array_keys($allFormRules))); - if ($isDebug) { - log_message('debug', static::class . '->' . __FUNCTION__ . "에서 Validate targetFields End DEBUG"); - log_message('debug', var_export($targetFields, true)); - } - // 최종: modify에서는 "타겟만" 룰/라벨 세팅 - $formFields = $this->getFormFields($targetFields); - $formRules = $this->getFormRules($targetFields); - // throw new RuntimeException(static::class . "->targetFields" . implode(",", $targetFields) . "\nformRules:" . implode(",", array_keys($formRules)) . "\nformFields:" . implode(",", array_keys($formFields))); - }//modify - // 2) 액션별 "검증 대상 필드" 결정 - // $formFields = $allFormFields; - // $formRules = $allFormRules; - return array($formFields, $formRules, $allFormFields); - } - final public function validate(array &$formDatas, $isDebug = false): void + final public function validate(array &$formDatas): void { log_message('debug', '>>> CommonForm::validate CALLED: ' . static::class . ', formAction:' . $this->formAction); + try { // 0) 데이터 구조 정리 (null 변환 X) $formDatas = $this->sanitizeFormDatas($formDatas); - list($formFields, $formRules, $allFormFields) = $this->validate_process($formDatas, $isDebug); - if (empty($formRules)) { - throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: 검증할 대상 RULE이 없습니다."); + + // 1) 검증 대상 라벨/룰 결정 + // 1) 전체 라벨/룰 + $allFormFields = $this->getFormFields(); // ['field' => '라벨', ...] + $allFormRules = $this->getFormRules(); // ['field' => 'rules', ...] + + if (empty($allFormRules)) { + throw new RuntimeException( + static::class . '->' . __FUNCTION__ . "에서 오류발생: 지정된 Form RULE이 없습니다." + ); } - // 3) wildcard(role.*) 부모 배열 보정 + + // modify/create 공통: 전체 룰 기준 + $formFields = $allFormFields; + $formRules = $allFormRules; + + if ($this->isDebug) { + log_message('debug', static::class . '->' . __FUNCTION__ . "에서 Validate ALL Begin DEBUG"); + log_message('debug', 'formAction=' . (string) $this->formAction); + log_message('debug', 'formDatas keys=' . var_export(array_keys($formDatas), true)); + log_message('debug', 'formRules keys=' . var_export(array_keys($formRules), true)); + log_message('debug', static::class . '->' . __FUNCTION__ . "에서 Validate ALL End DEBUG"); + } + + if (empty($formRules)) { + throw new RuntimeException( + static::class . '->' . __FUNCTION__ . "에서 오류발생: 검증할 대상 RULE이 없습니다." + ); + } + + // 2) wildcard(role.*) 부모 배열 보정 $this->ensureParentArrayForWildcardRules($formDatas, $formRules); - // 5) dynamicRules 구성 + // 3) dynamicRules 구성 $dynamicRules = []; foreach ($formRules as $field => $rule) { [$fieldName, $ruleStr] = $this->getValidationRule((string) $field, (string) $rule); + // label 결정 if (isset($formFields[$fieldName])) { $label = $formFields[$fieldName]; } elseif (str_contains($fieldName, '.*')) { $parentField = str_replace('.*', '', $fieldName); - $label = ($allFormFields[$parentField] ?? $formFields[$parentField] ?? $fieldName) . " 항목"; + $label = ($allFormFields[$parentField] ?? $formFields[$parentField] ?? $fieldName) . ' 항목'; } else { $label = $fieldName; } + $dynamicRules[$fieldName] = [ 'label' => $label, 'rules' => $ruleStr, ]; } - if ($isDebug) { + if ($this->isDebug) { log_message('debug', static::class . '->' . __FUNCTION__ . "에서 Validate dynamicRules DEBUG"); - log_message('debug', var_export($formDatas, true)); - log_message('debug', var_export($dynamicRules, true)); + log_message('debug', 'formDatas=' . var_export($formDatas, true)); + log_message('debug', 'dynamicRules=' . var_export($dynamicRules, true)); } $this->_validation->setRules($dynamicRules); + if (!$this->_validation->run($formDatas)) { $errors = $this->_validation->getErrors(); + throw new RuntimeException(sprintf( "%s->%s작업 필수항목\nformDatas->%s\ndynamicRules->%s\n%s", static::class, @@ -336,12 +321,14 @@ abstract class CommonForm implode("\n", $errors) )); } - } catch (\Throwable $e) { if ($e instanceof RuntimeException) { throw $e; } - // throw new RuntimeException("유효성 검사 중 시스템 오류 발생: " . $e->getMessage()); + + throw new RuntimeException( + static::class . '->' . __FUNCTION__ . "에서 유효성 검사 중 시스템 오류 발생: " . $e->getMessage() + ); } } diff --git a/app/Services/CommonService.php b/app/Services/CommonService.php index 4858b65..c7e0afc 100644 --- a/app/Services/CommonService.php +++ b/app/Services/CommonService.php @@ -42,15 +42,16 @@ abstract class CommonService return $result; } catch (FormValidationException $e) { - // ✅ 검증 에러는 감싸지 말고 그대로 던져야 Ajax가 422 + errors 받음 + // 검증 에러는 감싸지 말고 그대로 던져야 Ajax가 422 + errors 받음 $db->transRollback(); throw $e; } catch (DatabaseException $e) { + $db->transRollback(); $errorMessage = sprintf( "\n----[%s]에서 트랜잭션 실패: DB 오류----\n%s\n%s\n------------------------------\n", static::class . '->' . ($functionName ?: 'dbTransaction'), - $this->model->getLastQuery() ?? "No Query Available", + $this->model->getLastQuery() ?? 'No Query Available', $e->getMessage() ); log_message('error', $errorMessage); @@ -58,7 +59,6 @@ abstract class CommonService } catch (\Throwable $e) { $db->transRollback(); - // ✅ 여기서 FormValidationException까지 RuntimeException으로 바뀌던게 문제였음 throw new RuntimeException($e->getMessage(), $e->getCode(), $e); } } @@ -73,7 +73,7 @@ abstract class CommonService 'title_field' => $this->getTitleField(), 'table' => $this->model->getTable(), 'useAutoIncrement' => $this->model->useAutoIncrement(), - 'class_path' => $this->getClassPaths(false) + 'class_path' => $this->getClassPaths(false), ]); } } @@ -90,12 +90,13 @@ abstract class CommonService 'title_field' => $this->getTitleField(), 'table' => $this->model->getTable(), 'useAutoIncrement' => $this->model->useAutoIncrement(), - 'class_path' => $this->getClassPaths(false) + 'class_path' => $this->getClassPaths(false), ]); } } return $this->_helper; } + final public function getAuthContext(): AuthContext { if ($this->_authContext === null) { @@ -103,14 +104,17 @@ abstract class CommonService } return $this->_authContext; } + final protected function addClassPaths(string $path): void { $this->_classPaths[] = $path; } + final public function getPKField(): string { return $this->model->getPKField(); } + final public function getTitleField(): string { return $this->model->getTitleField(); @@ -120,16 +124,19 @@ abstract class CommonService { return $isArray ? $this->_classPaths : implode($delimeter, $this->_classPaths); } + final public function getNextPK(): int { $pkField = $this->getPKField(); $row = $this->model->selectMax($pkField)->get()->getRow(); return isset($row->{$pkField}) ? ((int) $row->{$pkField} + 1) : 1; } + /** * 단일 엔티티를 조회합니다. */ - abstract protected function getEntity_process(CommonEntity $entity): CommonEntity; + abstract protected function getEntity_process($entity): CommonEntity; + final public function getEntity($where = null, ?string $message = null): ?CommonEntity { try { @@ -137,134 +144,163 @@ abstract class CommonService if ($where !== null) { $entity = is_array($where) ? $this->model->where($where)->first() : $this->model->find($where); } + if ($entity === null) { return null; } - // 💡 동적으로 가져온 Entity 클래스 이름으로 instanceof 검사 + $entityClass = $this->getEntityClass(); if (!$entity instanceof $entityClass) { - throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 {$entityClass}만 가능:" . get_class($entity)); + throw new RuntimeException( + static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 {$entityClass}만 가능:" . get_class($entity) + ); } + return $this->getEntity_process($entity); + } catch (DatabaseException $e) { $errorMessage = sprintf( "\n------DB Query 오류 (%s)-----\nQuery: %s\nError: %s\n------------------------------\n", static::class . '->' . __FUNCTION__, - $this->model->getLastQuery() ?? "No Query Available", + $this->model->getLastQuery() ?? 'No Query Available', $e->getMessage() ); log_message('error', $errorMessage); throw new RuntimeException($errorMessage, $e->getCode(), $e); - } catch (\Exception $e) { + + } catch (\Throwable $e) { $errorMessage = sprintf( "\n------일반 오류 (%s)-----\nError: %s\n------------------------------\n", static::class . '->' . __FUNCTION__, $e->getMessage() ); - throw new \Exception($errorMessage, $e->getCode(), $e); + throw new RuntimeException($errorMessage, $e->getCode(), $e); } } + /** * 엔티티 배열 조회합니다. - * @return CommonEntity|null CommonEntity 인스턴스 또는 찾지 못했을 경우 null + * @return CommonEntity[] CommonEntity 인스턴스 배열 */ protected function getEntities_process(mixed $where = null, array $columns = ['*'], array $entities = []): array { if ($where) { $this->model->where($where); } - //기본 Order By 이용하기위해 + + // 기본 Order By 이용 $this->setOrderBy(); + + if (!empty($columns) && $columns !== ['*']) { + $this->model->select(implode(',', $columns)); + } + /** @var array<\App\Entities\CommonEntity> $results */ - $results = $this->model->select(implode(',', $columns))->findAll(); - log_message('debug', $this->model->getLastQuery()); + $results = $this->model->findAll(); + log_message('debug', (string) $this->model->getLastQuery()); + foreach ($results as $entity) { $entities[] = $entity; } + return $entities; } + public function getEntities(?array $where = null, array $columns = ['*'], array $entities = []): array { try { /** @var array<\App\Entities\CommonEntity> $entities */ $entities = $this->getEntities_process($where, $columns, $entities); return $entities; + } catch (DatabaseException $e) { $errorMessage = sprintf( "\n------DB Query 오류 (%s)-----\nQuery: %s\nError: %s\n------------------------------\n", static::class . '->' . __FUNCTION__, - $this->model->getLastQuery() ?? "No Query Available", + $this->model->getLastQuery() ?? 'No Query Available', $e->getMessage() ); log_message('error', $errorMessage); throw new RuntimeException($errorMessage, $e->getCode(), $e); - } catch (\Exception $e) { + + } catch (\Throwable $e) { $errorMessage = sprintf( "\n------일반 오류 (%s)-----\nError: %s\n------------------------------\n", static::class . '->' . __FUNCTION__, $e->getMessage() ); - throw new \Exception($errorMessage, $e->getCode(), $e); + throw new RuntimeException($errorMessage, $e->getCode(), $e); } } - //CURD 결과처리용 - protected function save_process(CommonEntity $entity): CommonEntity + // CURD 결과처리용 + protected function save_process($entity): CommonEntity { try { if (!$this->model->save($entity)) { $errors = $this->model->errors(); - $errorMsg = is_array($errors) ? implode(", ", $errors) : "DB 저장 작업이 실패했습니다."; - throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: " . $errorMsg); + $errorMsg = is_array($errors) ? implode(', ', $errors) : 'DB 저장 작업이 실패했습니다.'; + throw new RuntimeException(static::class . '->' . __FUNCTION__ . '에서 오류발생: ' . $errorMsg); } return $entity; + } catch (\Throwable $e) { - log_message('debug', __FUNCTION__ . ":" . var_export($entity, true)); - log_message('debug', __FUNCTION__ . ":" . $this->model->getLastQuery()); - throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:" . $e->getMessage()); + log_message('debug', __FUNCTION__ . ':' . var_export($entity, true)); + log_message('debug', __FUNCTION__ . ':' . (string) $this->model->getLastQuery()); + throw new RuntimeException(static::class . '->' . __FUNCTION__ . '에서 오류발생:' . $e->getMessage()); } } - //Action 작업시 field에따른 Hook처리(각 Service에서 override); + // Action 작업시 field에따른 Hook처리(각 Service에서 override) protected function fieldhook_process(string $field, $value, array $formDatas): array { return $formDatas; } - //생성용 - protected function create_process_validate(CommonForm &$actionForm, array $formDatas) - { - $actionForm->validate($formDatas); // ✅ 여기서 검증 - } + // 생성용 protected function create_process(array $formDatas): CommonEntity { try { $actionForm = $this->getActionForm(); if (!$actionForm instanceof CommonForm) { - throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: actionForm이 정의되지 않았습니다."); + throw new RuntimeException(static::class . '->' . __FUNCTION__ . '에서 오류발생: actionForm이 정의되지 않았습니다.'); } + + // create 폼 초기화 $actionForm->form_init_process('create', $formDatas); - $this->create_process_validate($actionForm, $formDatas); - // 검증 통과 후 엔티티 반영용 - foreach ($formDatas as $field => $value) { - $formDatas = $this->fieldhook_process($field, $value, $formDatas); + + // 검증 + $actionForm->validate($formDatas); + + // 후처리 + $processedDatas = $formDatas; + foreach (array_keys($processedDatas) as $field) { + $value = $processedDatas[$field] ?? null; + $processedDatas = $this->fieldhook_process($field, $value, $processedDatas); } + $entityClass = $this->getEntityClass(); - $entity = new $entityClass($formDatas); + $entity = new $entityClass($processedDatas); + + if (!$entity instanceof CommonEntity) { + throw new RuntimeException('Return Type은 CommonEntity만 가능'); + } if (!$entity instanceof $entityClass) { throw new RuntimeException("Return Type은 {$entityClass}만 가능"); } - $entity->fill($formDatas); $entity = $this->save_process($entity); - //생성PK 설정 + + // 생성 PK 설정 if ($this->model->useAutoIncrement()) { $entity->{$this->getPKField()} = $this->model->getInsertID(); } + return $entity; + } catch (FormValidationException $e) { - throw $e; // ✅ 감싸지 말고 그대로 + throw $e; } catch (\Throwable $e) { - throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:" . $e->getMessage()); + throw new RuntimeException(static::class . '->' . __FUNCTION__ . '에서 오류발생:' . $e->getMessage()); } } @@ -276,38 +312,50 @@ abstract class CommonService }, __FUNCTION__); } - //수정용 - protected function modify_process_validate(CommonForm &$actionForm, array $formDatas) - { - $actionForm->validate($formDatas); // ✅ 여기서 검증 - } + // 수정용 protected function modify_process($entity, array $formDatas): CommonEntity { try { $actionForm = $this->getActionForm(); if (!$actionForm instanceof CommonForm) { - throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: actionForm이 정의되지 않았습니다."); + throw new RuntimeException( + static::class . '->' . __FUNCTION__ . '에서 오류발생: actionForm이 정의되지 않았습니다.' + ); } - $actionForm->form_init_process('modify', $formDatas); - $this->modify_process_validate($actionForm, $formDatas); - // 검증 통과 후 엔티티 반영 - foreach ($formDatas as $field => $value) { - $formDatas = $this->fieldhook_process($field, $value, $formDatas); + + // 기존 엔티티 데이터 + 수정 데이터 병합 + $validateFormDatas = $entity->toArray(); + foreach ($formDatas as $key => $value) { + $validateFormDatas[$key] = $value; } - $entity->fill($formDatas); - if (!$entity->hasChanged()) { - return $entity; + + // 병합 데이터 기준으로 modify 폼 초기화 + $actionForm->form_init_process('modify', $validateFormDatas); + + // 검증 + $actionForm->validate($validateFormDatas); + + // 후처리 + $processedDatas = $validateFormDatas; + foreach (array_keys($processedDatas) as $field) { + $value = $processedDatas[$field] ?? null; + $processedDatas = $this->fieldhook_process($field, $value, $processedDatas); + } + + $entity->fill($processedDatas); + if ($entity->hasChanged()) { + $entity = $this->save_process($entity); } - $entity = $this->save_process($entity); return $entity; } catch (FormValidationException $e) { - throw $e; // ✅ 감싸지 말고 그대로 + throw $e; } catch (\Throwable $e) { - throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:" . $e->getMessage()); + throw new RuntimeException( + static::class . '->' . __FUNCTION__ . '에서 오류발생:' . $e->getMessage() + ); } } - final public function modify(string|int $uid, array $formDatas): CommonEntity { return $this->dbTransaction(function () use ($uid, $formDatas) { @@ -315,68 +363,78 @@ abstract class CommonService if (!$entity) { throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$uid}에 해당하는 정보을 찾을수 없습니다."); } + $formDatas['user_uid'] = (int) $this->getAuthContext()->getUID(); return $this->modify_process($entity, $formDatas); }, __FUNCTION__); } - //배치 작업용 수정 + // 배치 작업용 수정 protected function batchjob_process($entity, array $formDatas): CommonEntity { $entity = $this->modify_process($entity, $formDatas); return $entity; } + final public function batchjob(array $uids, array $formDatas): array { return $this->dbTransaction(function () use ($uids, $formDatas) { $entities = []; + foreach ($uids as $uid) { $entity = $this->getEntity($uid); if (!$entity) { throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$uid}에 해당하는 정보을 찾을수 없습니다."); } + $entityClass = $this->getEntityClass(); if (!$entity instanceof $entityClass) { throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 {$entityClass}만 가능"); } - $formDatas['user_uid'] = $this->getAuthContext()->getUID(); + + $formDatas['user_uid'] = (int) $this->getAuthContext()->getUID(); $entities[] = $this->batchjob_process($entity, $formDatas); } + return $entities; }, __FUNCTION__); } - //삭제용 (일반) + // 삭제용 (일반) protected function delete_process($entity): CommonEntity { $result = $this->model->delete($entity->getPK()); - log_message('debug', $this->model->getLastQuery()); if ($result === false) { $errors = $this->model->errors(); - $errorMsg = is_array($errors) ? implode(", ", $errors) : "삭제 작업이 실패했습니다."; - throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: " . $errorMsg); + $errorMsg = is_array($errors) ? implode(', ', $errors) : '삭제 작업이 실패했습니다.'; + throw new RuntimeException(static::class . '->' . __FUNCTION__ . '에서 오류발생: ' . $errorMsg); } + return $entity; } + final public function delete(string|int $uid): CommonEntity { return $this->dbTransaction(function () use ($uid) { if (!$uid) { - throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 삭제에 필요한 PrimaryKey 가 정의 되지 않았습니다."); + throw new RuntimeException(static::class . '->' . __FUNCTION__ . '에서 삭제에 필요한 PrimaryKey 가 정의 되지 않았습니다.'); } + $entity = $this->getEntity($uid); if (!$entity) { throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$uid}에 해당하는 정보을 찾을수 없습니다."); } + $entityClass = $this->getEntityClass(); if (!$entity instanceof $entityClass) { throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 {$entityClass}만 가능"); } + return $this->delete_process($entity); }, __FUNCTION__); } - //삭제용 (배치 작업) + // 삭제용 (배치 작업) protected function batchjob_delete_process($entity): CommonEntity { $entity = $this->delete_process($entity); @@ -387,36 +445,43 @@ abstract class CommonService { return $this->dbTransaction(function () use ($uids) { $entities = []; + foreach ($uids as $uid) { $entity = $this->getEntity($uid); if (!$entity) { throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: {$uid}에 해당하는 정보을 찾을수 없습니다."); } + $entityClass = $this->getEntityClass(); if (!$entity instanceof $entityClass) { throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생:Return Type은 {$entityClass}만 가능"); } + $entities[] = $this->batchjob_delete_process($entity); } + return $entities; }, __FUNCTION__); } - //Index용 + // Index용 final public function getTotalCount(): int { return $this->model->countAllResults(); } - //Limit처리 + + // Limit처리 final public function setLimit(int $perpage): void { $this->model->limit($perpage); } - //Offset처리 + + // Offset처리 final public function setOffset(int $offset): void { $this->model->offset($offset); } + public function setFilter(string $field, mixed $filter_value): void { switch ($field) { @@ -425,24 +490,27 @@ abstract class CommonService break; } } - //검색어조건절처리 + + // 검색어조건절처리 public function setSearchWord(string $word): void { - $this->model->orLike($this->model->getTable() . "." . $this->getTitleField(), $word, 'both'); + $this->model->orLike($this->model->getTable() . '.' . $this->getTitleField(), $word, 'both'); } - //날자검색 + + // 날짜검색 public function setDateFilter(string $start, string $end): void { - $this->model->where(sprintf("%s.created_at >= '%s 00:00:00'", $this->model->getTable(), $start)); - $this->model->where(sprintf("%s.created_at <= '%s 23:59:59'", $this->model->getTable(), $end)); + $this->model->where("{$this->model->getTable()}.created_at >=", $start . ' 00:00:00'); + $this->model->where("{$this->model->getTable()}.created_at <=", $end . ' 23:59:59'); } - //OrderBy 처리 + + // OrderBy 처리 public function setOrderBy(mixed $field = null, mixed $value = null): void { if ($field !== null && $value !== null) { - $this->model->orderBy(sprintf("%s.%s %s", $this->model->getTable(), $field, $value)); + $this->model->orderBy($this->model->getTable() . '.' . $field, (string) $value); } else { - $this->model->orderBy(sprintf("%s.%s %s", $this->model->getTable(), $this->getPKField(), "DESC")); + $this->model->orderBy($this->model->getTable() . '.' . $this->getPKField(), 'DESC'); } } -} +} \ No newline at end of file diff --git a/app/Services/Customer/ServiceService.php b/app/Services/Customer/ServiceService.php index 7ed19d0..8c434e4 100644 --- a/app/Services/Customer/ServiceService.php +++ b/app/Services/Customer/ServiceService.php @@ -4,7 +4,6 @@ namespace App\Services\Customer; use App\Entities\CommonEntity; use App\Entities\Customer\ServiceEntity; -use App\Forms\CommonForm; use App\Forms\Customer\ServiceForm; use App\Helpers\Customer\ServiceHelper; use App\Models\Customer\ServiceModel; @@ -120,10 +119,6 @@ class ServiceService extends CustomerService return $entity; } - protected function modify_process_validate(CommonForm &$actionForm, array $formDatas) - { - $actionForm->validate($formDatas, true); // ✅ 여기서 검증 - } protected function modify_process($entity, array $formDatas): ServiceEntity { if (empty($formDatas['serverinfo_uid'])) { diff --git a/app/Services/Part/PartType1Service.php b/app/Services/Part/PartType1Service.php index f566172..42fb29f 100644 --- a/app/Services/Part/PartType1Service.php +++ b/app/Services/Part/PartType1Service.php @@ -22,10 +22,10 @@ abstract class PartType1Service extends PartService /** @var PartEntity $entity IDE에 entity type알려주기*/ $entity = $this->getPartEntityByServerPart($serverPartEntity); //파트정보의 사용가능한 갯수 , 사용갯수 비교 - if ($entity->getAvailable() < $serverPartEntity->getCnt()) { + if ($entity->getAvailable() < $serverPartEntity->getCnt()) { throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 현재 {$entity->getTitle()}는 사용가능 갯수[{$entity->getAvailable()}]보다 지정하신 갯수({$serverPartEntity->getCnt()})가 더 많습니다."); } - $formDatas = []; + $formDatas = []; $formDatas['used'] = $entity->getUsed() + $serverPartEntity->getCnt(); return parent::modify_process($entity, $formDatas); } diff --git a/app/Services/Part/PartType2Service.php b/app/Services/Part/PartType2Service.php index d514458..e80cfed 100644 --- a/app/Services/Part/PartType2Service.php +++ b/app/Services/Part/PartType2Service.php @@ -16,9 +16,9 @@ abstract class PartType2Service extends PartService //서버파트관련 작업 public function attachToServerPart(ServerPartEntity $serverPartEntity, array $formDatas = []): PartEntity { - $formDatas['clientinfo_uid'] = $serverPartEntity->getClientInfoUid(); + $formDatas['clientinfo_uid'] = $serverPartEntity->getClientInfoUid(); $formDatas['serviceinfo_uid'] = $serverPartEntity->getServiceInfoUid(); - $formDatas['serverinfo_uid'] = $serverPartEntity->getServerInfoUid(); + $formDatas['serverinfo_uid'] = $serverPartEntity->getServerInfoUid(); $formDatas['status'] = STATUS['OCCUPIED']; //파트정보가져오기 $entity = $this->getPartEntityByServerPart($serverPartEntity); @@ -40,9 +40,9 @@ abstract class PartType2Service extends PartService } public function detachFromServerPart(ServerPartEntity $serverPartEntity, array $formDatas = []): PartEntity { - $formDatas['clientinfo_uid'] = null; + $formDatas['clientinfo_uid'] = null; $formDatas['serviceinfo_uid'] = null; - $formDatas['serverinfo_uid'] = null; + $formDatas['serverinfo_uid'] = null; $formDatas['status'] = STATUS['AVAILABLE']; //파트정보가져오기 $entity = $this->getPartEntityByServerPart($serverPartEntity);