diff --git a/app/Entities/Customer/ClientEntity.php b/app/Entities/Customer/ClientEntity.php index 7722ff4..6dca574 100644 --- a/app/Entities/Customer/ClientEntity.php +++ b/app/Entities/Customer/ClientEntity.php @@ -28,14 +28,19 @@ class ClientEntity extends CustomerEntity return sprintf("%s/%s", $this->getSite(), $title ? $title : $this->getTitle()); } + public function getSite(): string + { + return $this->site; + } + public function getName(): string { return $this->name; } - public function getSite(): string + public function getRole(): string { - return $this->site; + return $this->role; } public function getAccountBalance(): int @@ -57,69 +62,4 @@ class ClientEntity extends CustomerEntity { return $this->history; } - - /** - * role을 배열로 반환 - */ - public function getRole(): array - { - $role = $this->attributes['role'] ?? null; - - if (is_array($role)) { - return array_values(array_filter($role, fn($v) => (string) $v !== '')); - } - - if (is_string($role) && $role !== '') { - $decoded = json_decode($role, true); - if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) { - $clean = array_map( - fn($item) => trim((string) ($item ?? ''), " \t\n\r\0\x0B\""), - $decoded - ); - return array_values(array_filter($clean, fn($v) => $v !== '')); - } - - $parts = explode(DEFAULTS["DELIMITER_COMMA"], $role); - $clean = array_map( - fn($item) => trim((string) ($item ?? ''), " \t\n\r\0\x0B\""), - $parts - ); - return array_values(array_filter($clean, fn($v) => $v !== '')); - } - - return []; - } - - /** - * ✅ role은 DB 저장용 CSV 문자열로 반환 - */ - public function setRole($role): string - { - $roleArray = []; - - if (is_string($role)) { - $clean = trim($role, " \t\n\r\0\x0B\""); - if ($clean !== '') { - $decoded = json_decode($clean, true); - if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) { - $roleArray = $decoded; - } else { - $roleArray = explode(DEFAULTS["DELIMITER_COMMA"], $clean); - } - } - } elseif (is_array($role)) { - $roleArray = $role; - } else { - $roleArray = []; - } - - $cleaned = array_map( - fn($item) => trim((string) ($item ?? ''), " \t\n\r\0\x0B\""), - $roleArray - ); - - $roleArray = array_values(array_filter($cleaned, fn($v) => $v !== '')); - - return implode(DEFAULTS["DELIMITER_COMMA"], $roleArray); - } } diff --git a/app/Entities/UserEntity.php b/app/Entities/UserEntity.php index 34d524c..93dee44 100644 --- a/app/Entities/UserEntity.php +++ b/app/Entities/UserEntity.php @@ -28,7 +28,10 @@ class UserEntity extends CommonEntity { return $this->passwd; } - + public function getRole(): string + { + return $this->role; + } public function getEmail(): string { return $this->email; @@ -37,87 +40,4 @@ class UserEntity extends CommonEntity { return $this->mobile; } - /** - * role을 "배열"로 반환 (DB에는 CSV/JSON/배열 무엇이든 복구) - */ - public function getRole(): array - { - $role = $this->attributes['role'] ?? null; - - if (is_array($role)) { - return array_values(array_filter($role, fn($v) => (string) $v !== '')); - } - - if (is_string($role) && $role !== '') { - // JSON 시도 - $decoded = json_decode($role, true); - if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) { - $clean = array_map( - fn($item) => trim((string) ($item ?? ''), " \t\n\r\0\x0B\""), - $decoded - ); - return array_values(array_filter($clean, fn($v) => $v !== '')); - } - - // CSV fallback - $parts = explode(DEFAULTS["DELIMITER_COMMA"], $role); - $clean = array_map( - fn($item) => trim((string) ($item ?? ''), " \t\n\r\0\x0B\""), - $parts - ); - return array_values(array_filter($clean, fn($v) => $v !== '')); - } - - return []; - } - - /** - * ✅ CI4 뮤테이터: "return 값"이 attributes에 저장됨 - * - 빈값이면 기존값 유지 (create에서 required면 validate에서 걸러짐) - */ - public function setPasswd($password): string - { - // null/'' 이면 기존값 유지 - if (!is_string($password) || $password === '') { - return (string) ($this->attributes['passwd'] ?? ''); - } - - return password_hash($password, PASSWORD_BCRYPT); - } - - /** - * ✅ role은 최종적으로 "CSV 문자열"로 저장 (DB 안전) - */ - public function setRole($role): string - { - $roleArray = []; - - if (is_string($role)) { - $clean = trim($role, " \t\n\r\0\x0B\""); - if ($clean !== '') { - // JSON 문자열 가능성도 있어서 먼저 JSON 시도 - $decoded = json_decode($clean, true); - if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) { - $roleArray = $decoded; - } else { - $roleArray = explode(DEFAULTS["DELIMITER_COMMA"], $clean); - } - } - } elseif (is_array($role)) { - $roleArray = $role; - } else { - // 그 외 타입은 안전하게 빈값 처리 - $roleArray = []; - } - - $cleaned = array_map( - fn($item) => trim((string) ($item ?? ''), " \t\n\r\0\x0B\""), - $roleArray - ); - - $roleArray = array_values(array_filter($cleaned, fn($v) => $v !== '')); - - // ✅ 무조건 문자열 반환 (빈 배열이면 '') - return implode(DEFAULTS["DELIMITER_COMMA"], $roleArray); - } -} +} \ No newline at end of file diff --git a/app/Models/CommonModel.php b/app/Models/CommonModel.php index 2c60d32..8052fd3 100644 --- a/app/Models/CommonModel.php +++ b/app/Models/CommonModel.php @@ -14,12 +14,10 @@ abstract class CommonModel extends Model protected $useSoftDeletes = false; protected $protectFields = true; protected $allowedFields = []; - // $allowEmptyInserts = false (기본값): 삽입할 데이터가 전혀 없는 경우, CI4는 오류를 발생시키며 쿼리 실행을 막습니다. (보안 및 데이터 무결성 목적) // $allowEmptyInserts = true: 삽입할 데이터가 없어도 INSERT INTO table_name () VALUES () 같은 빈 쿼리 실행을 허용합니다 (극히 드문 경우에 사용). protected bool $allowEmptyInserts = false; protected bool $updateOnlyChanged = true; - // protected $useEmptyStringIfNull = true; (기본값) // 이 기본 설정 때문에 PHP의 null 값이 데이터베이스로 전달될 때 실제 SQL의 NULL 키워드가 아닌 **빈 문자열 ('')**로 변환되고 있습니다. // 그리고 데이터베이스(MySQL 등)의 설정에 따라 빈 문자열이 업데이트 쿼리에서 무시되거나, 해당 컬럼의 기존 값이 유지되는 현상이 발생합니다. @@ -43,16 +41,15 @@ abstract class CommonModel extends Model // Callbacks protected $allowCallbacks = true; - protected $beforeInsert = ['emptyStringToNull']; //Field 값이 NULL일 경우 DB Default값 적용용 + protected $beforeInsert = []; //Field 값이 NULL일 경우 DB Default값 적용용 protected $afterInsert = []; - protected $beforeUpdate = ['emptyStringToNull']; //Field 값이 NULL일 경우 DB Default값 적용용 + protected $beforeUpdate = []; //Field 값이 NULL일 경우 DB Default값 적용용 protected $afterUpdate = []; protected $beforeFind = []; protected $afterFind = []; protected $beforeDelete = []; protected $afterDelete = []; - protected array $nullableFields = []; // 모델별로 override protected function __construct() { parent::__construct(); @@ -77,35 +74,4 @@ abstract class CommonModel extends Model { return $this->allowedFields; } - - protected function emptyStringToNull(array $data): array - { - if (!isset($data['data']) || !is_array($data['data'])) { - return $data; - } - - // 공통 모델에서는 아무 필드도 강제하지 않음 (안전) - if (empty($this->nullableFields)) { - return $data; - } - - foreach ($this->nullableFields as $field) { - if (array_key_exists($field, $data['data'])) { - $v = $data['data'][$field]; - - // 문자열이면 trim 후, 빈문자면 null - if (is_string($v)) { - $v = trim($v); - $data['data'][$field] = ($v === '') ? null : $v; - } else { - // 문자열이 아닌데도 '' 같은 케이스 방어 (거의 없음) - if ($v === '') - $data['data'][$field] = null; - } - } - } - - return $data; - } - } diff --git a/app/Services/CommonService.php b/app/Services/CommonService.php index e856248..3deb670 100644 --- a/app/Services/CommonService.php +++ b/app/Services/CommonService.php @@ -246,7 +246,7 @@ abstract class CommonService } //Action 작업시 field에따른 Hook처리(각 Service에서 override); - protected function validation_fieldhook(string $field, $value, array $formDatas): array + protected function fieldhook_process(string $field, $value, array $formDatas): array { return $formDatas; } @@ -256,21 +256,21 @@ abstract class CommonService { try { $actionForm = $this->getActionForm(); - if ($actionForm instanceof CommonForm) { - $actionForm->action_init_process('create', $formDatas); - // log_message('debug', 'BEFORE hook CREATE FORMDATA:' . print_r($formDatas ?? null, true)); - foreach ($formDatas as $field => $value) { - $formDatas = $this->validation_fieldhook($field, $value, $formDatas); - } - // log_message('debug', 'AFTER hook CREATE FORMDATA:' . print_r($formDatas ?? null, true)); - $actionForm->validate($formDatas); // ✅ 여기서 검증 + if (!$actionForm instanceof CommonForm) { + throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: actionForm이 정의되지 않았습니다."); + } + $actionForm->action_init_process('create', $formDatas); + $actionForm->validate($formDatas); // ✅ 여기서 검증 + // 검증 통과 후 엔티티 반영용 + foreach ($formDatas as $field => $value) { + $formDatas = $this->fieldhook_process($field, $value, $formDatas); } - $entityClass = $this->getEntityClass(); $entity = new $entityClass($formDatas); if (!$entity instanceof $entityClass) { throw new RuntimeException("Return Type은 {$entityClass}만 가능"); } + $entity->fill($formDatas); return $this->save_process($entity); } catch (FormValidationException $e) { throw $e; // ✅ 감싸지 말고 그대로 @@ -288,10 +288,6 @@ abstract class CommonService } //수정용 - protected function modify_process_fieldhook(array $formDatas): array - { - return $formDatas; - } protected function modify_process($entity, array $formDatas): CommonEntity { try { @@ -300,17 +296,12 @@ abstract class CommonService throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: actionForm이 정의되지 않았습니다."); } $actionForm->action_init_process('modify', $formDatas); - log_message('debug', 'BEFORE hook MODIFY FORMDATA:' . print_r($formDatas ?? null, true)); - foreach ($formDatas as $field => $value) { - $formDatas = $this->validation_fieldhook($field, $value, $formDatas); - } - log_message('debug', 'AFTER hook MODIFY FORMDATA:' . print_r($formDatas ?? null, true)); $actionForm->validate($formDatas); // ✅ 여기서 검증 // 검증 통과 후 엔티티 반영 - $formDatas = $this->modify_process_fieldhook($formDatas); - log_message('debug', 'BEFORE MODIFY fill Entity:' . print_r($formDatas ?? null, true)); + foreach ($formDatas as $field => $value) { + $formDatas = $this->fieldhook_process($field, $value, $formDatas); + } $entity->fill($formDatas); - log_message('debug', 'AFTER MODIFY fill Entity:' . print_r($entity ?? null, true)); if (!$entity->hasChanged()) { return $entity; } diff --git a/app/Services/Customer/ClientService.php b/app/Services/Customer/ClientService.php index 3af9559..e6810a4 100644 --- a/app/Services/Customer/ClientService.php +++ b/app/Services/Customer/ClientService.php @@ -38,50 +38,44 @@ class ClientService extends CustomerService parent::setOrderBy($field, $value); } - protected function validation_fieldhook(string $field, $value, array $formDatas): array + protected function fieldhook_process(string $field, $value, array $formDatas): array { switch ($field) { case 'role': - if (is_string($value)) { - $value = ($value === '') ? [] : explode(DEFAULTS["DELIMITER_COMMA"], $value); - } elseif (!is_array($value)) { - $value = []; - } - $value = array_values(array_filter(array_map( - fn($v) => trim((string) ($v ?? ''), " \t\n\r\0\x0B\""), - $value - ))); - $formDatas[$field] = $value; + $arr = is_array($value) ? $value : explode(',', (string) $value); + $arr = array_values(array_filter(array_map('trim', $arr))); + sort($arr); + $formDatas[$field] = implode(',', $arr); break; default: - $formDatas = parent::validation_fieldhook($field, $value, $formDatas); + $formDatas = parent::fieldhook_process($field, $value, $formDatas); break; } return $formDatas; } - protected function modify_process_fieldhook(array $formDatas): array - { - // 1) DB 컬럼 아닌 값 제거 - unset($formDatas['confirmpassword']); + // protected function modify_process_fieldhook(array $formDatas): array + // { + // // 1) DB 컬럼 아닌 값 제거 + // unset($formDatas['confirmpassword']); - // 2) role은 무조건 문자열로 - if (array_key_exists('role', $formDatas)) { - $arr = is_array($formDatas['role']) - ? $formDatas['role'] - : explode(',', (string) $formDatas['role']); + // // 2) role은 무조건 문자열로 + // if (array_key_exists('role', $formDatas)) { + // $arr = is_array($formDatas['role']) + // ? $formDatas['role'] + // : explode(',', (string) $formDatas['role']); - $arr = array_values(array_filter(array_map('trim', $arr))); - sort($arr); - $formDatas['role'] = implode(',', $arr); - } + // $arr = array_values(array_filter(array_map('trim', $arr))); + // sort($arr); + // $formDatas['role'] = implode(',', $arr); + // } - // 3) passwd는 빈 값이면 업데이트 제외 (원하면) - if (array_key_exists('passwd', $formDatas) && $formDatas['passwd'] === '') { - unset($formDatas['passwd']); - } + // // 3) passwd는 빈 값이면 업데이트 제외 (원하면) + // if (array_key_exists('passwd', $formDatas) && $formDatas['passwd'] === '') { + // unset($formDatas['passwd']); + // } - return $formDatas; - } + // return $formDatas; + // } public function history(string|int $uid, string $history): CommonEntity { return $this->dbTransaction(function () use ($uid, $history) { diff --git a/app/Services/UserService.php b/app/Services/UserService.php index 2d28161..aa2ce52 100644 --- a/app/Services/UserService.php +++ b/app/Services/UserService.php @@ -26,51 +26,31 @@ class UserService extends CommonService { return $entity; } - protected function validation_fieldhook(string $field, $value, array $formDatas): array + protected function fieldhook_process(string $field, $value, array $formDatas): array { switch ($field) { case 'role': - if (is_string($value)) { - $value = ($value === '') ? [] : explode(DEFAULTS["DELIMITER_COMMA"], $value); - } elseif (!is_array($value)) { - $value = []; + $arr = is_array($value) ? $value : explode(',', (string) $value); + $arr = array_values(array_filter(array_map('trim', $arr))); + sort($arr); + $formDatas[$field] = implode(',', $arr); + break; + case 'passwd': + if ($formDatas[$field] !== '') { + $formDatas[$field] = password_hash($value, PASSWORD_BCRYPT); + } else { + unset($formDatas[$field]); } - $value = array_values(array_filter(array_map( - fn($v) => trim((string) ($v ?? ''), " \t\n\r\0\x0B\""), - $value - ))); - $formDatas[$field] = $value; + break; + case 'confirmpassword': + unset($formDatas['confirmpassword']); break; default: - $formDatas = parent::validation_fieldhook($field, $value, $formDatas); + $formDatas = parent::fieldhook_process($field, $value, $formDatas); break; } return $formDatas; } - - protected function modify_process_fieldhook(array $formDatas): array - { - // 1) DB 컬럼 아닌 값 제거 - unset($formDatas['confirmpassword']); - - // 2) role은 무조건 문자열로 - if (array_key_exists('role', $formDatas)) { - $arr = is_array($formDatas['role']) - ? $formDatas['role'] - : explode(',', (string) $formDatas['role']); - - $arr = array_values(array_filter(array_map('trim', $arr))); - sort($arr); - $formDatas['role'] = implode(',', $arr); - } - - // 3) passwd는 빈 값이면 업데이트 제외 (원하면) - if (array_key_exists('passwd', $formDatas) && $formDatas['passwd'] === '') { - unset($formDatas['passwd']); - } - - return $formDatas; - } //List 검색용 //FormFilter 조건절 처리 public function setFilter(string $field, mixed $filter_value): void