dbmsv4 init...4
This commit is contained in:
parent
cba596fa0a
commit
298e498cf5
@ -15,8 +15,8 @@ class ClientEntity extends CustomerEntity
|
|||||||
'email' => '',
|
'email' => '',
|
||||||
'role' => [],
|
'role' => [],
|
||||||
'account_balance' => 0,
|
'account_balance' => 0,
|
||||||
'coupon_balance' => 0,
|
'coupon_balance' => 0,
|
||||||
'point_balance' => 0,
|
'point_balance' => 0,
|
||||||
'status' => '',
|
'status' => '',
|
||||||
'history' => ''
|
'history' => ''
|
||||||
];
|
];
|
||||||
@ -79,8 +79,8 @@ class ClientEntity extends CustomerEntity
|
|||||||
}
|
}
|
||||||
// 2-b. JSON이 아니면 CSV로 가정하고 변환
|
// 2-b. JSON이 아니면 CSV로 가정하고 변환
|
||||||
$parts = explode(DEFAULTS["DELIMITER_ROLE"], $role);
|
$parts = explode(DEFAULTS["DELIMITER_ROLE"], $role);
|
||||||
// 각 요소의 불필요한 공백과 따옴표 제거
|
// 각 요소의 불필요한 공백과 따옴표 제거. null 가능성에 대비해 string 형변환 추가
|
||||||
$cleanedRoles = array_map(fn($item) => trim($item, " \t\n\r\0\x0B\""), $parts);
|
$cleanedRoles = array_map(fn($item) => trim((string) ($item ?? ''), " \t\n\r\0\x0B\""), $parts);
|
||||||
return array_filter($cleanedRoles);
|
return array_filter($cleanedRoles);
|
||||||
}
|
}
|
||||||
// 3. 변환에 실패했거나 데이터가 없는 경우 빈 배열 반환
|
// 3. 변환에 실패했거나 데이터가 없는 경우 빈 배열 반환
|
||||||
@ -109,8 +109,8 @@ class ClientEntity extends CustomerEntity
|
|||||||
elseif (is_array($role)) {
|
elseif (is_array($role)) {
|
||||||
$roleArray = $role;
|
$roleArray = $role;
|
||||||
}
|
}
|
||||||
// 배열의 각 요소를 정리
|
// 배열의 각 요소를 정리. null이나 scalar 타입이 섞여있을 경우에 대비해 string으로 명시적 형변환 후 trim 수행
|
||||||
$cleanedRoles = array_map(fn($item) => trim($item, " \t\n\r\0\x0B\""), $roleArray);
|
$cleanedRoles = array_map(fn($item) => trim((string) ($item ?? ''), " \t\n\r\0\x0B\""), $roleArray);
|
||||||
$roleArray = array_filter($cleanedRoles);
|
$roleArray = array_filter($cleanedRoles);
|
||||||
// 최종적으로 DB에 삽입될 단일 CSV 문자열로 변환하여 저장합니다.
|
// 최종적으로 DB에 삽입될 단일 CSV 문자열로 변환하여 저장합니다.
|
||||||
$this->attributes['role'] = implode(DEFAULTS["DELIMITER_ROLE"], $roleArray);
|
$this->attributes['role'] = implode(DEFAULTS["DELIMITER_ROLE"], $roleArray);
|
||||||
|
|||||||
@ -57,8 +57,8 @@ class UserEntity extends CommonEntity
|
|||||||
}
|
}
|
||||||
// 2-b. JSON이 아니면 CSV로 가정하고 변환
|
// 2-b. JSON이 아니면 CSV로 가정하고 변환
|
||||||
$parts = explode(DEFAULTS["DELIMITER_ROLE"], $role);
|
$parts = explode(DEFAULTS["DELIMITER_ROLE"], $role);
|
||||||
// 각 요소의 불필요한 공백과 따옴표 제거
|
// 각 요소의 불필요한 공백과 따옴표 제거. null 가능성에 대비해 string 형변환 추가
|
||||||
$cleanedRoles = array_map(fn($item) => trim($item, " \t\n\r\0\x0B\""), $parts);
|
$cleanedRoles = array_map(fn($item) => trim((string) ($item ?? ''), " \t\n\r\0\x0B\""), $parts);
|
||||||
return array_filter($cleanedRoles);
|
return array_filter($cleanedRoles);
|
||||||
}
|
}
|
||||||
// 3. 변환에 실패했거나 데이터가 없는 경우 빈 배열 반환
|
// 3. 변환에 실패했거나 데이터가 없는 경우 빈 배열 반환
|
||||||
@ -95,8 +95,8 @@ class UserEntity extends CommonEntity
|
|||||||
elseif (is_array($role)) {
|
elseif (is_array($role)) {
|
||||||
$roleArray = $role;
|
$roleArray = $role;
|
||||||
}
|
}
|
||||||
// 배열의 각 요소를 정리
|
// 배열의 각 요소를 정리. null이나 scalar 타입이 섞여있을 경우에 대비해 string으로 명시적 형변환 후 trim 수행
|
||||||
$cleanedRoles = array_map(fn($item) => trim($item, " \t\n\r\0\x0B\""), $roleArray);
|
$cleanedRoles = array_map(fn($item) => trim((string) ($item ?? ''), " \t\n\r\0\x0B\""), $roleArray);
|
||||||
$roleArray = array_filter($cleanedRoles);
|
$roleArray = array_filter($cleanedRoles);
|
||||||
// 최종적으로 DB에 삽입될 단일 CSV 문자열로 변환하여 저장합니다.
|
// 최종적으로 DB에 삽입될 단일 CSV 문자열로 변환하여 저장합니다.
|
||||||
$this->attributes['role'] = implode(DEFAULTS["DELIMITER_ROLE"], $roleArray);
|
$this->attributes['role'] = implode(DEFAULTS["DELIMITER_ROLE"], $roleArray);
|
||||||
|
|||||||
@ -132,7 +132,7 @@ abstract class CommonForm
|
|||||||
* @param array $formDatas 검증할 데이터
|
* @param array $formDatas 검증할 데이터
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
*/
|
*/
|
||||||
final public function validate(array $formDatas): void
|
final public function validate(array &$formDatas): void
|
||||||
{
|
{
|
||||||
if ($this->_validation === null) {
|
if ($this->_validation === null) {
|
||||||
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: Validation 서비스가 초기화되지 않았습니다.");
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 오류발생: Validation 서비스가 초기화되지 않았습니다.");
|
||||||
@ -141,12 +141,23 @@ abstract class CommonForm
|
|||||||
try {
|
try {
|
||||||
$dynamicRules = [];
|
$dynamicRules = [];
|
||||||
|
|
||||||
// 0. Ensure all scalar inputs are strings to prevent trim() error on PHP 8.1+
|
// 0. Ensure all scalar/null inputs are strings to prevent trim() error on PHP 8.1+
|
||||||
foreach ($formDatas as $key => $value) {
|
$castToString = function (&$data, $path = '') use (&$castToString) {
|
||||||
if (is_scalar($value) && !is_string($value)) {
|
foreach ($data as $key => &$value) {
|
||||||
$formDatas[$key] = (string) $value;
|
$currentField = $path ? "{$path}.{$key}" : $key;
|
||||||
|
try {
|
||||||
|
if (is_array($value)) {
|
||||||
|
$castToString($value, $currentField);
|
||||||
|
} elseif ($value === null || (is_scalar($value) && !is_string($value))) {
|
||||||
|
$data[$key] = (string) ($value ?? '');
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
throw new RuntimeException("데이터 정제 중 오류 발생 (필드: {$currentField}): " . $e->getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
$castToString($formDatas);
|
||||||
|
|
||||||
// 1. 현재 서비스의 필드 라벨 정보 로드 (언어 파일 기반)
|
// 1. 현재 서비스의 필드 라벨 정보 로드 (언어 파일 기반)
|
||||||
$formFields = $this->getFormFields();
|
$formFields = $this->getFormFields();
|
||||||
$formRules = $this->getFormRules();
|
$formRules = $this->getFormRules();
|
||||||
@ -156,48 +167,94 @@ abstract class CommonForm
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($formRules as $field => $rule) {
|
foreach ($formRules as $field => $rule) {
|
||||||
// 2. 필드명과 규칙 추출
|
try {
|
||||||
list($field, $rule) = $this->getValidationRule($field, $rule);
|
// 2. 필드명과 규칙 추출
|
||||||
|
list($field, $rule) = $this->getValidationRule($field, $rule);
|
||||||
|
|
||||||
// 3. 라벨 결정 로직 (한글 라벨 매핑)
|
// 3. 라벨 결정 로직 (한글 라벨 매핑)
|
||||||
if (isset($formFields[$field])) {
|
if (isset($formFields[$field])) {
|
||||||
$label = $formFields[$field];
|
$label = $formFields[$field];
|
||||||
} elseif (str_contains($field, '.*')) {
|
} elseif (str_contains($field, '.*')) {
|
||||||
// 배열 검증(role.* 등)의 경우 부모 필드의 라벨을 활용
|
// 배열 검증(role.* 등)의 경우 부모 필드의 라벨을 활용
|
||||||
$parentField = str_replace('.*', '', $field);
|
$parentField = str_replace('.*', '', $field);
|
||||||
$label = ($formFields[$parentField] ?? $field) . " 항목";
|
$label = ($formFields[$parentField] ?? $field) . " 항목";
|
||||||
} else {
|
} else {
|
||||||
$label = $field; // 언어 파일에 정의가 없는 경우 필드명 유지
|
$label = $field; // 언어 파일에 정의가 없는 경우 필드명 유지
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. [핵심 해결책] 규칙 배열 자체에 label을 포함시킴
|
||||||
|
// 이렇게 하면 CI4 엔진이 {field} 자리에 이 label 값을 최우선으로 사용합니다.
|
||||||
|
$dynamicRules[$field] = [
|
||||||
|
'label' => $label,
|
||||||
|
'rules' => $rule
|
||||||
|
];
|
||||||
|
|
||||||
|
// 4.5. Ensure the field exists in formDatas to prevent trim(null) in the engine
|
||||||
|
if (!array_key_exists($field, $formDatas) && !str_contains($field, '.*')) {
|
||||||
|
$formDatas[$field] = '';
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
throw new RuntimeException("유효성 검사 규칙 준비 중 오류 발생 (필드: {$field}): " . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. [핵심 해결책] 규칙 배열 자체에 label을 포함시킴
|
|
||||||
// 이렇게 하면 CI4 엔진이 {field} 자리에 이 label 값을 최우선으로 사용합니다.
|
|
||||||
$dynamicRules[$field] = [
|
|
||||||
'label' => $label,
|
|
||||||
'rules' => $rule
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 검증 규칙 설정 (인자를 하나만 전달하여 설정 충돌 방지)
|
// 5. 검증 규칙 설정 (인자를 하나만 전달하여 설정 충돌 방지)
|
||||||
$this->_validation->setRules($dynamicRules);
|
$this->_validation->setRules($dynamicRules);
|
||||||
|
|
||||||
// 6. 검증 실행
|
// 6. 검증 실행
|
||||||
if (!$this->_validation->run($formDatas)) {
|
try {
|
||||||
// 한글 라벨이 적용된 에러 메시지들을 배열로 가져와 한 줄씩 합침
|
if (!$this->_validation->run($formDatas)) {
|
||||||
$errors = $this->_validation->getErrors();
|
// 한글 라벨이 적용된 에러 메시지들을 배열로 가져와 한 줄씩 합침
|
||||||
throw new RuntimeException(implode("\n", $errors));
|
$errors = $this->_validation->getErrors();
|
||||||
|
throw new RuntimeException(implode("\n", $errors));
|
||||||
|
}
|
||||||
|
} catch (\TypeError $e) {
|
||||||
|
// TypeError(예: trim(null) 등) 발생 시 범인(field) 찾기 시도
|
||||||
|
$culpritField = "알 수 없음";
|
||||||
|
$culpritValue = "null";
|
||||||
|
|
||||||
|
foreach ($dynamicRules as $f => $r) {
|
||||||
|
if (str_contains($r['rules'], 'trim')) {
|
||||||
|
// 중첩 필드(.*)와 일반 필드 구분하여 null 체크
|
||||||
|
if (str_contains($f, '.*')) {
|
||||||
|
$parentKey = str_replace('.*', '', $f);
|
||||||
|
if (isset($formDatas[$parentKey]) && is_array($formDatas[$parentKey])) {
|
||||||
|
foreach ($formDatas[$parentKey] as $k => $v) {
|
||||||
|
if ($v === null) {
|
||||||
|
$culpritField = "{$parentKey}.{$k} ({$r['label']})";
|
||||||
|
break 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isset($formDatas[$f]) || $formDatas[$f] === null) {
|
||||||
|
$culpritField = "{$f} ({$r['label']})";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$errorMsg = $e->getMessage();
|
||||||
|
// "trim(): Argument #1 ($string) must be of type string, null given" 문구에서 Argument #1을 필드명으로 교체
|
||||||
|
$errorMsg = str_replace("Argument #1 (\$string)", "데이터(필드: {$culpritField}, 값: {$culpritValue})", $errorMsg);
|
||||||
|
throw new RuntimeException("검증 도중 타입 오류 발생: " . $errorMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 검증 성공 시 추가 로직 없이 종료
|
// 검증 성공 시 추가 로직 없이 종료
|
||||||
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
// 이미 RuntimeException으로 포장된 경우 그대로 던짐
|
||||||
|
if ($e instanceof RuntimeException) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
// 오류 발생 시 디버깅을 위해 로그 기록
|
// 오류 발생 시 디버깅을 위해 로그 기록
|
||||||
log_message('debug', '--- Validation Error Detail ---');
|
log_message('debug', '--- Validation Error Detail ---');
|
||||||
log_message('debug', 'Rules: ' . var_export($this->getFormRules(), true));
|
log_message('debug', 'Rules: ' . var_export($this->getFormRules(), true));
|
||||||
log_message('debug', 'Data: ' . var_export($formDatas, true));
|
log_message('debug', 'Data: ' . var_export($formDatas, true));
|
||||||
log_message('debug', 'Message: ' . $e->getMessage());
|
log_message('debug', 'Message: ' . $e->getMessage());
|
||||||
|
|
||||||
throw new RuntimeException($e->getMessage());
|
throw new RuntimeException("유효성 검사 중 시스템 오류 발생: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@ class ClientHelper extends CustomerHelper
|
|||||||
break;
|
break;
|
||||||
case 'role':
|
case 'role':
|
||||||
$currentRoles = is_array($value)
|
$currentRoles = is_array($value)
|
||||||
? array_map('strtolower', array_map('trim', $value))
|
? array_map('strtolower', array_map(fn($item) => trim((string) ($item ?? ''), " \t\n\r\0\x0B\""), $value))
|
||||||
: [];
|
: [];
|
||||||
$form = '';
|
$form = '';
|
||||||
//Form페이지에서는 맨앞에것 제외하기 위함
|
//Form페이지에서는 맨앞에것 제외하기 위함
|
||||||
@ -60,7 +60,7 @@ class ClientHelper extends CustomerHelper
|
|||||||
"data-src" => "/admin/customer/wallet/account?clientinfo_uid={$viewDatas['entity']->getPK()}&ActionTemplate=popup",
|
"data-src" => "/admin/customer/wallet/account?clientinfo_uid={$viewDatas['entity']->getPK()}&ActionTemplate=popup",
|
||||||
"data-bs-toggle" => "modal",
|
"data-bs-toggle" => "modal",
|
||||||
"data-bs-target" => "#modal_action_form",
|
"data-bs-target" => "#modal_action_form",
|
||||||
"class" => "text-primary",
|
"class" => "text-primary",
|
||||||
...$extras,
|
...$extras,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@ -73,7 +73,7 @@ class ClientHelper extends CustomerHelper
|
|||||||
"data-src" => "/admin/customer/wallet/coupon?clientinfo_uid={$viewDatas['entity']->getPK()}&ActionTemplate=popup",
|
"data-src" => "/admin/customer/wallet/coupon?clientinfo_uid={$viewDatas['entity']->getPK()}&ActionTemplate=popup",
|
||||||
"data-bs-toggle" => "modal",
|
"data-bs-toggle" => "modal",
|
||||||
"data-bs-target" => "#modal_action_form",
|
"data-bs-target" => "#modal_action_form",
|
||||||
"class" => "text-primary",
|
"class" => "text-primary",
|
||||||
...$extras,
|
...$extras,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@ -86,7 +86,7 @@ class ClientHelper extends CustomerHelper
|
|||||||
"data-src" => "/admin/customer/wallet/point?clientinfo_uid={$viewDatas['entity']->getPK()}&ActionTemplate=popup",
|
"data-src" => "/admin/customer/wallet/point?clientinfo_uid={$viewDatas['entity']->getPK()}&ActionTemplate=popup",
|
||||||
"data-bs-toggle" => "modal",
|
"data-bs-toggle" => "modal",
|
||||||
"data-bs-target" => "#modal_action_form",
|
"data-bs-target" => "#modal_action_form",
|
||||||
"class" => "text-primary",
|
"class" => "text-primary",
|
||||||
...$extras,
|
...$extras,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@ -107,7 +107,7 @@ class ClientHelper extends CustomerHelper
|
|||||||
case 'batchjob':
|
case 'batchjob':
|
||||||
case 'batchjob_delete':
|
case 'batchjob_delete':
|
||||||
//역활이 보안관리자가 아니면 사용불가
|
//역활이 보안관리자가 아니면 사용불가
|
||||||
$action = $this->getAuthContext()->isAccessRole([ROLE['USER']['SECURITY']]) ? parent::getListButton($action, $label, $viewDatas, $extras) : "";
|
$action = $this->getAuthContext()->isAccessRole([ROLE['USER']['SECURITY']]) ? parent::getListButton($action, $label, $viewDatas, $extras) : "";
|
||||||
break;
|
break;
|
||||||
case 'modify':
|
case 'modify':
|
||||||
//역활이 보안관리자가 아니면 수정불가
|
//역활이 보안관리자가 아니면 수정불가
|
||||||
@ -133,7 +133,7 @@ class ClientHelper extends CustomerHelper
|
|||||||
$label,
|
$label,
|
||||||
$action,
|
$action,
|
||||||
[
|
[
|
||||||
"data-src" => "/admin/customer/wallet/{$action}?clientinfo_uid={$viewDatas['entity']->getPK()}&ActionTemplate=popup",
|
"data-src" => "/admin/customer/wallet/{$action}?clientinfo_uid={$viewDatas['entity']->getPK()}&ActionTemplate=popup",
|
||||||
"data-bs-toggle" => "modal",
|
"data-bs-toggle" => "modal",
|
||||||
"data-bs-target" => "#modal_action_form",
|
"data-bs-target" => "#modal_action_form",
|
||||||
"class" => "text-primary",
|
"class" => "text-primary",
|
||||||
@ -169,10 +169,10 @@ class ClientHelper extends CustomerHelper
|
|||||||
$action = "{$label} 0원";
|
$action = "{$label} 0원";
|
||||||
if (array_key_exists($viewDatas['entity']->getPK(), $viewDatas['unPaids'])) {
|
if (array_key_exists($viewDatas['entity']->getPK(), $viewDatas['unPaids'])) {
|
||||||
$action = form_label(
|
$action = form_label(
|
||||||
sprintf("%s건/%s원", $viewDatas['unPaids'][$viewDatas['entity']->getPK()]['cnt'], number_format($viewDatas['unPaids'][$viewDatas['entity']->getPK()]['amount'])),
|
sprintf("%s건/%s원", $viewDatas['unPaids'][$viewDatas['entity']->getPK()]['cnt'], number_format($viewDatas['unPaids'][$viewDatas['entity']->getPK()]['amount'])),
|
||||||
'payment_unpaid',
|
'payment_unpaid',
|
||||||
[
|
[
|
||||||
"data-src" => "/admin/payment?clientinfo_uid={$viewDatas['entity']->getPK()}&status=unpaid&ActionTemplate=popup",
|
"data-src" => "/admin/payment?clientinfo_uid={$viewDatas['entity']->getPK()}&status=unpaid&ActionTemplate=popup",
|
||||||
"data-bs-toggle" => "modal",
|
"data-bs-toggle" => "modal",
|
||||||
"data-bs-target" => "#modal_action_form",
|
"data-bs-target" => "#modal_action_form",
|
||||||
"class" => "text-primary form-label-sm",
|
"class" => "text-primary form-label-sm",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user