trafficmonitor init...2

This commit is contained in:
choi.jh 2025-11-10 11:29:00 +09:00
parent 34bba22949
commit 155b7d5137
14 changed files with 122 additions and 150 deletions

View File

@ -39,31 +39,28 @@ abstract class AdminController extends CommonController
$this->addViewDatas('formRules', $this->service->getFormService()->getFormRules($action, array_keys($formFields)));
$this->addViewDatas('formOptions', $this->service->getFormService()->getFormOptions($action, $formFilters));
}
protected function create_form_process(array $formDatas = []): array
{
return $formDatas;
}
abstract protected function create_form_process(string $action): void;
final public function create_form(): string
{
$action = __FUNCTION__;
try {
//초기화
$this->action_init_process($action);
$this->addViewDatas('formDatas', $this->create_form_process());
$this->create_form_process($action);
} catch (\Exception $e) {
log_message('error', $e->getMessage());
session()->setFlashdata('message', $e->getMessage());
}
return $this->action_render_process($this->getActionPaths(), $action, $this->getViewDatas());
}
abstract protected function create_process(): RedirectResponse;
final public function create(): RedirectResponse
abstract protected function create_process(string $action): string|RedirectResponse;
final public function create(): string|RedirectResponse
{
$action = __FUNCTION__;
try {
//초기화
$this->action_init_process($action);
return $this->create_process();
return $this->create_process($action);
} catch (ValidationException $e) {
// 검증 실패 시 폼으로 돌아가서 오류 메시지 표시
log_message('error', $e->getMessage());
@ -73,7 +70,38 @@ abstract class AdminController extends CommonController
return redirect()->back()->withInput()->with('message', $e->getMessage());
}
}
protected function modify_form_process($uid): CommonEntity
abstract protected function modify_form_process(string $action, $uid): void;
final public function modify_form($uid): string
{
$action = __FUNCTION__;
try {
//초기화
$this->action_init_process($action);
$this->modify_form_process($action, $uid);
} catch (\Exception $e) {
log_message('error', $e->getMessage());
session()->setFlashdata('message', $e->getMessage());
}
return $this->action_render_process($this->getActionPaths(), $action, $this->getViewDatas());
}
abstract protected function modify_process(string $action, $uid): string|RedirectResponse;
final public function modify($uid): string|RedirectResponse
{
$action = __FUNCTION__;
try {
//초기화
$this->action_init_process($action);
return $this->modify_process($action, $uid);
} catch (ValidationException $e) {
// 검증 실패 시 폼으로 돌아가서 오류 메시지 표시
log_message('error', $e->getMessage());
return redirect()->back()->withInput()->with('message', $e->getMessage());
} catch (\Exception $e) {
log_message('error', $e->getMessage());
return redirect()->back()->withInput()->with('message', $e->getMessage());
}
}
protected function delete_process($uid): RedirectResponse
{
if (!$uid) {
throw new \Exception("계정 번호가 정의 되지 않았습니다.");
@ -82,30 +110,17 @@ abstract class AdminController extends CommonController
if (!$entity instanceof CommonEntity) {
throw new \Exception("{$uid}에 해당하는 계정을 찾을수 없습니다.");
}
return $entity;
$this->service->delete($uid);
$redirect_url = $this->getAuthContext()->popPreviousUrl() ?? implode(DIRECTORY_SEPARATOR, $this->getActionPaths());
return redirect()->to($redirect_url)->with('message', "{$entity->getTitle()} 계정 생성이 완료되었습니다.");
}
final public function modify_form($uid): string
final public function delete($uid): RedirectResponse
{
$action = __FUNCTION__;
try {
//초기화
$this->action_init_process($action);
$entity = $this->modify_form_process($uid);
$this->addViewDatas('entity', $entity);
} catch (\Exception $e) {
log_message('error', $e->getMessage());
session()->setFlashdata('message', $e->getMessage());
}
return $this->action_render_process($this->getActionPaths(), $action, $this->getViewDatas());
}
abstract protected function modify_process($uid): RedirectResponse;
final public function modify($uid): RedirectResponse
{
$action = __FUNCTION__;
try {
//초기화
$this->action_init_process($action);
return $this->modify_process($uid);
return $this->delete_process($uid);
} catch (ValidationException $e) {
// 검증 실패 시 폼으로 돌아가서 오류 메시지 표시
log_message('error', $e->getMessage());

View File

@ -30,19 +30,21 @@ class UserController extends AdminController
return parent::getFormRule($action, $field, $rule);
}
//Action작업관련
protected function create_process(): RedirectResponse
protected function create_form_process(string $action): void
{
//Form Default값 설정
$formDatas = ['role' => [ROLE['USER']['MANAGER']]];
$this->addViewDatas('formDatas', $formDatas);
}
protected function create_process(string $action): string|RedirectResponse
{
//요청 데이터를 DTO 객체로 변환
$dto = new UserDTO($this->request->getPost());
$entity = $this->service->create($dto);
$dto = new UserDTO($this->request->getPost());
$entity = $this->service->create($dto);
$redirect_url = $this->getAuthContext()->popPreviousUrl() ?? implode(DIRECTORY_SEPARATOR, $this->getActionPaths());
return redirect()->to($redirect_url)->with('message', "{$entity->getTitle()} 계정 생성이 완료되었습니다.");
}
protected function modify_form_process($uid): UserEntity
{
return parent::modify_form_process($uid);
}
protected function modify_process($uid): RedirectResponse
protected function modify_form_process(string $action, $uid): void
{
if (!$uid) {
throw new \Exception("계정 번호가 정의 되지 않았습니다.");
@ -51,13 +53,17 @@ class UserController extends AdminController
if (!$entity instanceof UserEntity) {
throw new \Exception("{$uid}에 해당하는 계정을 찾을수 없습니다.");
}
$this->addViewDatas('entity', $entity);
}
protected function modify_process(string $action, $uid): string|RedirectResponse
{
//요청 데이터를 DTO 객체로 변환
$dto = new UserDTO($this->request->getPost());
$entity = $this->service->modify($entity, $dto);
$entity = $this->service->modify($uid, $dto);
$redirect_url = $this->getAuthContext()->popPreviousUrl() ?? implode(DIRECTORY_SEPARATOR, $this->getActionPaths());
return redirect()->to($redirect_url)->with('message', "{$entity->getTitle()} 계정 수정이 완료되었습니다.");
}
protected function view_process($uid): UserEntity
{
return parent::view_process($uid);

View File

@ -3,9 +3,9 @@
namespace App\Controllers;
use App\Controllers\BaseController;
use App\DTOs\CertificationDTO;
use App\Libraries\AuthContext;
use App\Traits\LogTrait;
use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Psr\Log\LoggerInterface;
@ -74,6 +74,11 @@ abstract class CommonController extends BaseController
$this->addViewDatas('authContext', $this->getAuthContext());
$this->addViewDatas('classPath', $this->service->getClassPaths(false));
}
protected function action_rediect_process(string $message): RedirectResponse
{
$redirect_url = $this->getAuthContext()->popPreviousUrl() ?? implode(DIRECTORY_SEPARATOR, $this->getActionPaths());
return redirect()->to($redirect_url)->with('message', $message);
}
protected function action_render_process(array $view_paths, string $view_file, array $viewDatas): string
{
$lastest_path = array_pop($view_paths); //paths는 마지막을 뺀 앞단까지만 남음

View File

@ -37,7 +37,7 @@ CREATE TABLE `user` (
PRIMARY KEY (`uid`),
UNIQUE KEY `UQ_id` (`id`),
UNIQUE KEY `UQ_email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=46 DEFAULT CHARSET=utf8 COMMENT='관리자정보';
) ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=utf8 COMMENT='관리자정보';
/*!40101 SET character_set_client = @saved_cs_client */;
--
@ -59,4 +59,4 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2025-11-05 21:33:38
-- Dump completed on 2025-11-10 8:58:23

View File

@ -77,24 +77,19 @@ class UserEntity extends CommonEntity
public function setRole(mixed $role)
{
$roleArray = [];
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);
$role = explode(DEFAULTS["DELIMITER_ROLE"], $cleanRoleString);
}
} else if (is_array($role)) {
// 이미 배열인 경우에도 데이터 정리를 한 번 거칩니다.
}
if (is_array($role)) {
//배열에도 불필요한 따옴표와 공백을 제거
$cleanedRoles = array_map(fn($item) => trim($item, " \t\n\r\0\x0B\""), $role);
$roleArray = array_filter($cleanedRoles);
}
// 💡 핵심: 최종적으로 DB에 삽입될 단일 CSV 문자열로 변환하여 저장합니다.
$this->attributes['role'] = implode(',', $roleArray);
$this->attributes['role'] = implode(DEFAULTS["DELIMITER_ROLE"], $roleArray);
}
}

View File

@ -22,51 +22,6 @@ class CommonHelper
}
return $this->_attributes[$key];
}
// final public function form_dropdown_common(string $field, mixed $value, array $viewDatas, array $extras = [], array $attributes = [], bool $isAll = false): string
// {
// // 필터 옵션이 없으면 빈 배열로 초기화
// if (!array_key_exists($field, $viewDatas['formOptions'])) {
// return ""; // 필터 옵션이 없으면 빈 문자열 반환
// }
// $extra = "";
// foreach ($extras as $extra_tag => $extra_value) {
// $extra .= sprintf(" %s=\"%s\"", $extra_tag, $extra_value);
// }
// // $formOptions는 필터 옵션 배열로, key는 필터 엔티티의 PK, value는 필터 엔티티 객체
// $html = sprintf("<select name=\"%s\" %s>", $field, $extra);
// $html .= "<option value=\"\">" . lang("{$this->getAttribute('class_path')}.label.{$field}") . " 선택" . "</option>";
// $html .= $this->form_dropdown_common_process($field, $value, $viewDatas, $extras, $attributes, $isAll);
// $html .= '</select>';
// return $html;
// }
// //필수함수
// protected function form_dropdown_common_process(string $field, mixed $value, array $viewDatas, array $extras = [], array $attributes = [], bool $isAll = false): string
// {
// $html = "";
// switch ($field) {
// default:
// foreach ($viewDatas['formOptions'][$field]['options'] as $option_key => $option_value) {
// $isSelected = $option_key == $value ? ' selected' : '';
// $isDisabled = "";
// $attribute = "";
// $label = "";
// if ($option_value instanceof CommonEntity) {
// if ($option_key != $value && $option_value->getStatus() != DEFAULTS['STATUS'] && !$isAll) {
// continue;
// }
// foreach ($attributes as $attribute_name => $attribute_value) {
// $attribute .= sprintf(" %s=\"%s\"", $attribute_name, $option_value->$attribute_value);
// }
// $label = $option_value->getCustomTitle();
// } else {
// $label = $option_value;
// }
// $html .= sprintf("<option value=\"%s\"%s%s%s>%s</option>", $option_key, $isSelected, $isDisabled, $attribute, $label);
// }
// break;
// }
// return $html;
// }
public function getFieldLabel(string $field, string $label, array $viewDatas, array $extras = []): string
{
switch ($field) {
@ -81,21 +36,17 @@ class CommonHelper
{
switch ($field) {
case 'email':
$form = form_input($field, $value ?? "", [
"class" => "form-control",
'style' => 'width:100%;',
"placeholder" => "예)test@example.com",
...$extras
]);
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' form-control' : 'form-control';
$extras['style'] = 'width:100%;';
$extras['placeholder'] = '예)test@example.co.kr';
$form = form_input($field, $value ?? "", $extras);
break;
case 'mobile':
case 'phone':
$form = form_input($field, $value ?? "", [
"class" => "form-control",
'style' => 'width:100%;',
"placeholder" => "예)010-0010-0010",
...$extras
]);
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' form-control' : 'form-control';
$extras['style'] = 'width:100%;';
$extras['placeholder'] = '예)010-0010-0010';
$form = form_input($field, $value ?? "", $extras);
break;
case 'issue_at':
case 'expired_at':
@ -105,30 +56,25 @@ class CommonHelper
case 'updated_at':
case 'created_at':
case 'deleted_at':
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' calender' : 'calender';
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' form-control calender' : 'form-control calender';
$extras['style'] = 'width:100%;';
$form = form_input($field, $value ?? "", $extras);
break;
case 'description':
case 'content':
case 'detail':
case 'history':
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' tinymce' : 'tinymce';
$form = form_textarea($field, html_entity_decode($value ?? "", ENT_QUOTES, 'UTF-8'), [
"class" => "form-control",
'style' => 'width:100%;',
...$extras
]);
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' form-control tinymce' : 'form-control tinymce';
$extras['style'] = 'width:100%;';
$form = form_textarea($field, html_entity_decode($value ?? "", ENT_QUOTES, 'UTF-8'), $extras);
break;
default:
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' form-control' : 'form-control';
if (in_array($field, $viewDatas['formFilters'])) {
$form = form_dropdown($field, $viewDatas['formOptions'][$field]['options'], $value, $viewDatas['formOptions'][$field]['extras']);
// $form = $this->form_dropdown_common($field, $value, $viewDatas, $extras);
$form = form_dropdown($field, $viewDatas['formOptions'][$field]['options'], $value, [...$extras, ...$viewDatas['formOptions'][$field]['extras']]);
} else {
$form = form_input($field, $value ?? "", [
"class" => "form-control",
'style' => 'width:100%;',
...$extras
]);
$extras['style'] = 'width:100%;';
$form = form_input($field, $value ?? "", $extras);
}
break;
}

View File

@ -15,7 +15,9 @@ class UserHelper extends CommonHelper
switch ($field) {
case 'passwd':
case 'confirmpassword':
$form = form_password($field, "", [...$extras]);
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' form-control' : 'form-control';
$extras['style'] = 'width:100%;';
$form = form_password($field, "", $extras);
break;
case 'role':
$currentRoles = is_array($value)
@ -27,7 +29,7 @@ class UserHelper extends CommonHelper
foreach ($viewDatas['formOptions'][$field]['options'] as $key => $label) {
$checked = in_array(strtolower(trim($key)), $currentRoles);
$form .= '<label class="me-3">';
$form .= form_checkbox('role[]', $key, $checked, array_merge(['id' => "role_{$key}"], $extras));
$form .= form_checkbox('role[]', $key, $checked, ['id' => "role_{$key}", ...$extras]);
$form .= " {$label}";
$form .= '</label>';
}

View File

@ -85,7 +85,7 @@ abstract class AuthService
}
final protected function getValidationRules(string $action, array $allRules = []): array
{
foreach ($this->getFormService()->getFormFields($action) as $field) {
foreach ($this->getFormService()->getFormFields($action) as $field => $label) {
$allRules = array_merge($allRules, $this->getValidationRule($action, $field, $allRules));
}
return $allRules;

View File

@ -91,7 +91,7 @@ abstract class CommonService
//Validation용
final protected function getValidationRules(string $action, array $allRules = []): array
{
foreach ($this->getFormService()->getFormFields($action) as $field) {
foreach ($this->getFormService()->getFormFields($action) as $field => $label) {
$allRules = array_merge($allRules, $this->getValidationRule($action, $field, $allRules));
}
return $allRules;
@ -131,7 +131,7 @@ abstract class CommonService
abstract protected function create_process(array $formDatas): CommonEntity;
public function create(object $dto): CommonEntity
{
$formDatas = (array) $dto;
$formDatas = (array)$dto;
//입력값 검증
$validation = service('validation')->setRules($this->getValidationRules(__FUNCTION__));
if (!$validation->run($formDatas)) {
@ -142,23 +142,20 @@ abstract class CommonService
return $this->handle_save_result($result, $entity);
}
//수정용
abstract protected function modify_process(CommonEntity $entity, array $formDatas): CommonEntity;
public function modify(CommonEntity $entity, object $dto): CommonEntity
abstract protected function modify_process($uid, array $formDatas): CommonEntity;
public function modify($uid, object $dto): CommonEntity
{
$formDatas = (array) $dto;
$formDatas = (array)$dto;
//입력값 검증
$validation = service('validation')->setRules($this->getValidationRules(__FUNCTION__));
if (!$validation->run($formDatas)) {
throw new ValidationException(implode("\n", $validation->getErrors()));
}
$updatedEntity = $this->modify_process($entity, $formDatas);
// 2. 💡 model->save() 사용: Primary Key가 있으므로 UPDATE를 수행하며,
// Dirty Tracking에 의해 변경된 필드만 업데이트합니다.
$updatedEntity = $this->modify_process($uid, $formDatas);
$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

@ -61,24 +61,29 @@ class UserService extends CommonService
}
return parent::create($dto);
}
protected function modify_process(CommonEntity $entity, array $formDatas): UserEntity
protected function modify_process($uid, array $formDatas): UserEntity
{
// CommonEntity 타입을 UserEntity로 형 변환합니다. (타입 힌트가 CommonEntity지만 실제로는 UserEntity 객체입니다.)
$userEntity = $entity;
if (!$uid) {
throw new \Exception("계정 번호가 정의 되지 않았습니다.");
}
$entity = $this->getEntity($uid);
if (!$entity instanceof UserEntity) {
throw new \Exception("{$uid}에 해당하는 계정을 찾을수 없습니다.");
}
if (isset($formDatas['confirmpassword'])) {
unset($formDatas['confirmpassword']);
}
// 변경 사항을 Entity에 적용합니다. (Dirty Tracking 활성화)
$userEntity->fill($formDatas);
$entity->fill($formDatas);
// 💡 부모 호출 제거: 변경된 Entity 객체를 반환합니다.
return $userEntity;
return $entity;
}
public function modify($entity, object $dto): UserEntity
public function modify($uid, object $dto): UserEntity
{
if (!$dto instanceof UserDTO) {
throw new RuntimeException(__METHOD__ . "에서 오류발생:" . get_class($dto) . "는 사용할수 없습니다.");
}
return parent::modify($entity, $dto);
return parent::modify($uid, $dto);
}
//List 검색용
//FormFilter 조건절 처리

View File

@ -1,4 +1,5 @@
<?= $this->extend(LAYOUTS[$viewDatas['layout']]['path']) ?>
<?= session('message') ? $viewDatas['helper']->alertTrait(session('message')) : "" ?>
<?= $this->section('content') ?>
<div id="container" class="content">
<div class="form_top"><?= $this->include("templates/{$viewDatas['layout']}/form_content_top"); ?></div>
@ -6,17 +7,16 @@
<table class="table table-bordered">
<?php foreach ($viewDatas['formFields'] as $field => $label): ?>
<tr>
<th nowrap class="text-end"><?= $viewDatas['helper']->getFieldLabel($field, $label, $viewDatas) ?></th>
<th nowrap class="text-end bg-light" width="20%"><?= $viewDatas['helper']->getFieldLabel($field, $label, $viewDatas) ?></th>
<td nowrap class="text-start">
<?= $viewDatas['helper']->getFieldForm($field, old($field) ?? ($viewDatas['formDatas'][$field] ?? null), $viewDatas) ?>
<span><?= validation_show_error($field); ?></span>
<div><?= validation_show_error($field); ?></div>
</td>
</tr>
<?php endforeach; ?>
</table>
<div class="text-center"><?= form_submit('', '입력', array("class" => "btn btn-outline btn-primary")); ?></div>
<?= form_close(); ?>
<?php if (session('message')): ?><div class="alert alert-danger text-start"><?= nl2br(session('message')) ?></div><?php endif; ?>
<div class="form_bottom"><?= $this->include("templates/{$viewDatas['layout']}/form_content_bottom"); ?></div>
</div>
<?= $this->endSection() ?>

View File

@ -19,11 +19,11 @@ $template = "templates" . DIRECTORY_SEPARATOR . "{$viewDatas['layout']}";
<table class="index_table data table table-bordered table-hover table-striped" data-rtc-resizable-table="reisze_table">
<thead>
<tr>
<th class="index_head_short_column">번호</th>
<th class="text-center bg-light">번호</th>
<?php foreach ($viewDatas['formFields'] as $field => $label): ?>
<th data-rtc-resizable="<?= $field ?>"><?= $viewDatas['helper']->getListLabel($field, $label, $viewDatas) ?></th>
<th class="text-center bg-light"><?= $viewDatas['helper']->getListLabel($field, $label, $viewDatas) ?></th>
<?php endforeach ?>
<th class="index_head_short_column">작업</th>
<th class="text-center bg-light">작업</th>
</tr>
</thead>
<tbody>

View File

@ -1,4 +1,5 @@
<?= $this->extend(LAYOUTS[$viewDatas['layout']]['path']) ?>
<?= session('message') ? $viewDatas['helper']->alertTrait(session('message')) : "" ?>
<?= $this->section('content') ?>
<div id="container" class="content">
<div class="form_top"><?= $this->include("templates/{$viewDatas['layout']}/form_content_top"); ?></div>
@ -6,17 +7,16 @@
<table class="table table-bordered">
<?php foreach ($viewDatas['formFields'] as $field => $label): ?>
<tr>
<th nowrap class="text-end"><?= $viewDatas['helper']->getFieldLabel($field, $label, $viewDatas) ?></th>
<th nowrap class="text-end bg-light" width="20%"><?= $viewDatas['helper']->getFieldLabel($field, $label, $viewDatas) ?></th>
<td nowrap class="text-start">
<?= $viewDatas['helper']->getFieldForm($field, old($field) ?? ($viewDatas['entity']->$field ?? null), $viewDatas) ?>
<span><?= validation_show_error($field); ?></span>
<div><?= validation_show_error($field); ?></div>
</td>
</tr>
<?php endforeach; ?>
</table>
<div class="text-center"><?= form_submit('', '수정', array("class" => "btn btn-outline btn-primary")); ?></div>
<?= form_close(); ?>
<?php if (session('message')): ?><div class="alert alert-danger text-start"><?= nl2br(session('message')) ?></div><?php endif; ?>
<div class="form_bottom"><?= $this->include("templates/{$viewDatas['layout']}/form_content_bottom"); ?></div>
</div>
<?= $this->endSection() ?>

View File

@ -1,11 +1,12 @@
<?= $this->extend(LAYOUTS[$viewDatas['layout']]['path']) ?>
<?= session('message') ? $viewDatas['helper']->alertTrait(session('message')) : "" ?>
<?= $this->section('content') ?>
<div id="container" class="content">
<div class="form_top"><?= $this->include("templates/{$viewDatas['layout']}/form_content_top"); ?></div>
<table class="table table-bordered">
<?php foreach ($viewDatas['formFields'] as $field => $label): ?>
<tr>
<th nowrap class="text-end"><?= $viewDatas['helper']->getFieldLabel($field, $label, $viewDatas) ?></th>
<th nowrap class="text-end bg-light" width="20%"><?= $viewDatas['helper']->getFieldLabel($field, $label, $viewDatas) ?></th>
<td nowrap class="text-start"><?= $viewDatas['helper']->getFieldView($field, old($field) ?? ($viewDatas['entity']->$field ?? null), $viewDatas) ?></td>
</tr>
<?php endforeach; ?>