trafficmonitor init...2

This commit is contained in:
최준흠 2025-11-07 23:03:24 +09:00
parent d86c64b28e
commit a632153947
7 changed files with 99 additions and 65 deletions

View File

@ -32,7 +32,11 @@ class UserController extends AdminController
}
return parent::getFormRule($action, $field, $rule);
}
//Index,FieldForm관련.
//Action작업관련
protected function create_form_process(): void
{
new UserDTO($this->request->getPost());
}
protected function create_process(): RedirectResponse
{
//요청 데이터를 DTO 객체로 변환
@ -63,7 +67,7 @@ class UserController extends AdminController
}
//요청 데이터를 DTO 객체로 변환
$dto = new UserDTO($this->request->getPost());
$entity = $this->service->modify($dto);
$entity = $this->service->modify($entity, $dto);
$redirect_url = $this->getAuthContext()->popPreviousUrl() ?? implode(DIRECTORY_SEPARATOR, $this->getActionPaths());
return redirect()->to($redirect_url)->with('success', "{$entity->getTitle()} 계정 수정이 완료되었습니다.");
}

View File

@ -6,7 +6,6 @@ use CodeIgniter\Entity\Entity;
abstract class CommonEntity extends Entity
{
const DEFAULT_STATUS = "";
protected $datamap = [];
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
//사용법 : $client->created_at->format('Y-m-d')

View File

@ -8,7 +8,6 @@ class TrafficEntity extends CommonEntity
{
const PK = TrafficModel::PK;
const TITLE = TrafficModel::TITLE;
const DEFAULT_STATUS = STATUS['AVAILABLE'];
final public function getUserUID(): int|null
{
return $this->attributes['user_uid'] ?? null;

View File

@ -4,23 +4,20 @@ namespace App\Entities;
use App\Entities\CommonEntity;
use App\Models\UserModel as Model;
use CodeIgniter\Entity\Entity; // Entity 클래스를 명시적으로 use 하는 것이 좋습니다.
class UserEntity extends CommonEntity
{
const PK = Model::PK;
const TITLE = Model::TITLE;
const DEFAULT_STATUS = STATUS['AVAILABLE'];
/**
* @var array Entity 속성을 DB에 저장하거나 DB에서 로드할 때의 변환 규칙
* @var array DB 컬럼 타입이 VARCHAR(255)이고 CSV 형식으로 통일하기 위해 json-array 캐스팅을 제거합니다.
*/
protected $casts = [
// 'role' 컬럼에 배열을 할당하면 DB에 JSON 문자열로 저장되며,
// DB에서 로드할 때 JSON 문자열이 자동으로 PHP 배열로 변환됩니다.
'role' => 'json-array',
// 'role' => 'json-array', // 🚫 CSV 형식 저장을 위해 제거
];
// --- Getter Methods ---
public function getID(): string
{
return (string) $this->attributes['id'];
@ -31,8 +28,41 @@ class UserEntity extends CommonEntity
return $this->attributes['passwd'];
}
// $formDatas['passwd']에 평문 비밀번호가 들어있으면,
// Model->insert시 Entity 생성자($formDatas)가 setPasswd()를 자동으로 호출합니다.
/**
* 사용자의 역할을 배열 형태로 반환합니다.
* DB의 JSON 또는 CSV 형식 데이터를 모두 배열로 복구할 있는 로직을 포함합니다.
* @return array
*/
public function getRole(): array
{
$role = $this->attributes['role'] ?? null;
// 1. 이미 배열인 경우 (방어적 코딩)
if (is_array($role)) {
return array_filter($role);
}
// 2. 문자열 데이터인 경우 처리
if (is_string($role) && !empty($role)) {
// 2-a. JSON 디코딩 시도 (기존 DB의 JSON 형식 처리)
$decodedRole = json_decode($role, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($decodedRole)) {
return $decodedRole;
}
// 2-b. JSON이 아니면 CSV로 가정하고 변환
$parts = explode(',', $role);
// 각 요소의 불필요한 공백과 따옴표 제거
$cleanedRoles = array_map(fn($item) => trim($item, " \t\n\r\0\x0B\""), $parts);
return array_filter($cleanedRoles);
}
// 3. 변환에 실패했거나 데이터가 없는 경우 빈 배열 반환
return [];
}
// --- Setter Methods ---
public function setPasswd(string $password)
{
// 비밀번호를 암호화하여 저장합니다.
@ -40,35 +70,31 @@ class UserEntity extends CommonEntity
}
/**
* 사용자의 역할을 배열 형태로 반환합니다.
* $casts에 의해 DB에서 읽어올 이미 배열로 변환될 것을 기대합니다.
* @return array
* Role 데이터가 Entity에 설정될 호출되어, 입력된 CSV/JSON 문자열을 정리
* DB에 적합한 CSV 문자열로 최종 저장합니다.
* @param mixed $role 입력 데이터 (문자열 또는 배열)
*/
public function getRole(): array
public function setRole(mixed $role)
{
$role = $this->attributes['role'] ?? [];
$roleArray = [];
// 1. $casts가 성공적으로 작동했거나, 이미 배열인 경우 바로 반환합니다.
if (is_array($role)) {
return $role;
if (is_string($role)) {
// 1. 양쪽의 불필요한 따옴표와 공백을 제거하여 깨끗한 문자열 확보
$cleanRoleString = trim($role, " \t\n\r\0\x0B\"");
if (!empty($cleanRoleString)) {
// 2. 쉼표를 기준으로 분리 후, 각 요소의 공백/따옴표를 다시 제거
$parts = explode(',', $cleanRoleString);
$cleanedRoles = array_map(fn($item) => trim($item, " \t\n\r\0\x0B\""), $parts);
$roleArray = array_filter($cleanedRoles);
}
} else if (is_array($role)) {
// 이미 배열인 경우에도 데이터 정리를 한 번 거칩니다.
$cleanedRoles = array_map(fn($item) => trim($item, " \t\n\r\0\x0B\""), $role);
$roleArray = array_filter($cleanedRoles);
}
// 2. 캐스팅에 실패했으나 원본이 문자열로 남아있는 경우 (JSON 또는 CSV)
if (is_string($role) && !empty($role)) {
// 2-a. JSON 디코딩을 시도합니다.
$decodedRole = json_decode($role, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($decodedRole)) {
return $decodedRole; // 유효한 JSON 배열인 경우
}
// 2-b. JSON이 아니면 레거시 CSV 형식이라고 가정하고 explode로 변환합니다.
if (defined('DEFAULTS') && isset(DEFAULTS['DELIMITER_ROLE'])) {
return explode(DEFAULTS['DELIMITER_ROLE'], $role);
}
}
// 3. 변환에 실패했거나 데이터가 없는 경우 빈 배열 반환
return [];
// 💡 핵심: 최종적으로 DB에 삽입될 단일 CSV 문자열로 변환하여 저장합니다.
$this->attributes['role'] = implode(',', $roleArray);
}
}

View File

@ -22,7 +22,6 @@ class UserHelper extends CommonHelper
if (($viewDatas['control']['entity'] ?? null) instanceof UserEntity) {
$value = $viewDatas['control']['entity']->getRole();
}
dd($value);
$currentRoles = is_array($value)
? array_map('strtolower', array_map('trim', $value))
: [];
@ -30,11 +29,6 @@ class UserHelper extends CommonHelper
//체크박스를 순회하며 생성
foreach ($viewDatas['control']['formOptions']['role'] as $key => $label) {
$checked = in_array(strtolower(trim($key)), $currentRoles);
var_dump($currentRoles);
echo '<HR>';
echo $key;
echo $checked ? "{$key}TRUE" : "FALSE";
dd($viewDatas['control']['formOptions']['role']);
$form .= '<label class="me-3">';
// form_checkbox에 들어가는 값($key)은 원본 값을 유지(저장용).
$form .= form_checkbox('role[]', $key, $checked, array_merge(['id' => "role_{$key}"], $extras));

View File

@ -101,24 +101,23 @@ abstract class CommonService
}
//CURD 결과처리용
//DB 결과 처리 로직 통합 및 개선
protected function handle_save_result(mixed $result, $entity): CommonEntity
protected function handle_save_result(mixed $result, CommonEntity $entity): CommonEntity
{
if (!$result) {
// static::class는 현재 호출된 자식 클래스 이름 반환
throw new RuntimeException(static::class . "에서 {$entity->getTitle()} 등록/수정 중 DB 오류가 발생하였습니다.");
throw new RuntimeException(static::class . "에서 " . __FUNCTION__ . "오류발생:" . $this->model->getLastQuery());
}
// 2. 최종 PK 값 결정 (insert/update 공통)
$pkValue = $this->model->useAutoIncrement() && is_numeric($result) && (int)$result > 0
$pk = $this->model->useAutoIncrement() && is_numeric($result) && (int)$result > 0
? (int)$result
: $entity->{$this->model->primaryKey};
if (empty($pkValue)) {
if (empty($pk)) {
throw new RuntimeException("{$entity->getTitle()} 저장 후 Primary Key를 확인할 수 없습니다.");
}
// 3. Entity 재조회 (수정 및 생성 모두 최신 DB 상태 반영)
$savedEntity = $this->model->find($pkValue);
$savedEntity = $this->model->find($pk);
if (!$savedEntity) {
throw new RuntimeException("등록/수정된 데이터를 찾을 수 없습니다. (PK: {$pkValue})");
throw new RuntimeException("등록/수정된 데이터를 찾을 수 없습니다. (PK: {$pk})");
}
return $savedEntity;
}
@ -137,8 +136,8 @@ abstract class CommonService
return $this->handle_save_result($result, $entity);
}
//수정용
abstract protected function modify_process(array $formDatas): array;
public function modify(object $dto): CommonEntity
abstract protected function modify_process(CommonEntity $entity, array $formDatas): CommonEntity;
public function modify(CommonEntity $entity, object $dto): CommonEntity
{
$formDatas = (array) $dto;
//입력값 검증
@ -146,10 +145,15 @@ abstract class CommonService
if (!$validation->run($formDatas)) {
throw new ValidationException(implode("\n", $validation->getErrors()));
}
list($pk, $updateData) = $this->modify_process($formDatas);
$entity = new ($this->model->returnType)($updateData); // 재조회에 필요한 PK를 얻기 위함
$result = $this->model->update($pk, $updateData);
return $this->handle_save_result($result, $entity);
$updatedEntity = $this->modify_process($entity, $formDatas);
// 2. 💡 model->save() 사용: Primary Key가 있으므로 UPDATE를 수행하며,
// Dirty Tracking에 의해 변경된 필드만 업데이트합니다.
$result = $this->model->save($updatedEntity);
if (!$result) {
throw new RuntimeException(static::class . "에서 " . __FUNCTION__ . "오류발생:" . $this->model->getLastQuery());
}
// 3. handle_save_result에 Entity 객체 전달
return $this->handle_save_result($result, $updatedEntity);
}
protected function delete_process($uid): bool
{

View File

@ -49,6 +49,10 @@ class UserService extends CommonService
//기본 기능부분
protected function create_process(array $formDatas): UserEntity
{
if (isset($formDatas['confirmpassword'])) {
unset($formDatas['confirmpassword']);
}
//UserEntity를 생성하면 Setter가 자동 호출됩니다.
return new UserEntity($formDatas);
}
public function create(object $dto): UserEntity
@ -58,20 +62,24 @@ class UserService extends CommonService
}
return parent::create($dto);
}
protected function modify_process(array $formDatas): array
protected function modify_process(CommonEntity $entity, array $formDatas): UserEntity
{
// DTO에 PK가 포함되어 있다고 가정. 필요 시 데이터 가공
return [
$formDatas[$this->model->primaryKey], // PK
$formDatas // Update Data
];
// CommonEntity 타입을 UserEntity로 형 변환합니다. (타입 힌트가 CommonEntity지만 실제로는 UserEntity 객체입니다.)
$userEntity = $entity;
if (isset($formDatas['confirmpassword'])) {
unset($formDatas['confirmpassword']);
}
// 변경 사항을 Entity에 적용합니다. (Dirty Tracking 활성화)
$userEntity->fill($formDatas);
// 💡 부모 호출 제거: 변경된 Entity 객체를 반환합니다.
return $userEntity;
}
public function modify(object $dto): UserEntity
public function modify($entity, object $dto): UserEntity
{
if (!$dto instanceof UserDTO) {
throw new RuntimeException(__METHOD__ . "에서 오류발생:" . get_class($dto) . "는 사용할수 없습니다.");
}
return parent::modify($dto);
return parent::modify($entity, $dto);
}
//List 검색용
//FormFilter 조건절 처리