From a07b0f238a59c05165707c11723203835ef9213a Mon Sep 17 00:00:00 2001 From: "choi.jh" Date: Mon, 17 Nov 2025 14:34:23 +0900 Subject: [PATCH] trafficmonitor init...2 --- app/Controllers/CommonController.php | 168 ++++++++++++++++++++++----- 1 file changed, 138 insertions(+), 30 deletions(-) diff --git a/app/Controllers/CommonController.php b/app/Controllers/CommonController.php index 6efd1db..b5c1ef7 100644 --- a/app/Controllers/CommonController.php +++ b/app/Controllers/CommonController.php @@ -15,41 +15,52 @@ use CodeIgniter\HTTP\DownloadResponse; use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\Reader\Html; use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf; +use CodeIgniter\API\ResponseTrait; abstract class CommonController extends BaseController { use LogTrait; + use ResponseTrait; + protected $request; + private array $_action_paths = []; private array $_viewDatas = []; protected $service = null; private ?string $_title = null; + public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger) { parent::initController($request, $response, $logger); } + final protected function getAuthContext(): AuthContext { return service('myauth')->getAuthContext(); } + final protected function addActionPaths(string $path) { $this->_action_paths[] = $path; } + final protected function getActionPaths($isArray = true, $delimeter = DIRECTORY_SEPARATOR): array|string { return $isArray ? $this->_action_paths : implode($delimeter, $this->_action_paths); } + final protected function addViewDatas(string $key, mixed $value) { $this->_viewDatas[$key] = $value; } + final protected function getViewDatas(?string $key = null): mixed { if ($key === null) { return $this->_viewDatas; } - return $this->_viewDatas[$key] ?? null; + return $this->_viewDatas[$key] ?? null; } + protected function getTitle(): string { if ($this->_title === null) { @@ -57,6 +68,7 @@ abstract class CommonController extends BaseController } return $this->_title; } + //공통 필수기능 //필수함수 //사용자정의 함수 @@ -66,11 +78,13 @@ abstract class CommonController extends BaseController $this->addViewDatas('authContext', $this->getAuthContext()); $this->addViewDatas('classPath', $this->service->getClassPaths(false)); } + protected function action_modal_process(string $message): string { return " "; } + protected function action_redirect_process(string $type, string $message, ?string $redirect_url = null): RedirectResponse { switch ($type) { @@ -115,40 +130,41 @@ abstract class CommonController extends BaseController } return $result; } + protected function action_render_process(array $view_paths, string $view_file, array $viewDatas): string { $lastest_path = array_pop($view_paths); //paths는 마지막을 뺀 앞단까지만 남음 - // ✅ 중간 안내 화면으로 - // return view('posts/success_redirect', [ - // 'message' => '게시글이 성공적으로 등록되었습니다.', - // 'redirectUrl' => route_to('posts_list') - // ]); - // 중요한 작업 (결제 완료, 오류 등) → “로딩 페이지(View)”로 안내 후 JS redirect + $full_path = implode(DIRECTORY_SEPARATOR, $view_paths); + + // GET/POST/JSON 데이터에서 'ActionTemplate' 파라미터를 가져옵니다. $final_path = $this->request->getVar('ActionTemplate'); + if ($final_path) { $full_path .= DIRECTORY_SEPARATOR . $final_path; } - // else { - // $full_path .= DIRECTORY_SEPARATOR. $lastest_path; - // } + $view_datas = [ ...$viewDatas, 'forms' => ['attributes' => ['method' => "post",], 'hiddens' => []], ]; + helper(['form', __FUNCTION__]); return view($full_path . DIRECTORY_SEPARATOR . $view_file, ['viewDatas' => $view_datas]); } + //생성 protected function create_form_process(array $formDatas = []): array { //Form Default값 설정 return $formDatas; } + protected function create_form_result_process(string $action): string|RedirectResponse { return $this->action_render_process($this->getActionPaths(), $action, $this->getViewDatas()); } + final public function create_form(): string|RedirectResponse { try { @@ -160,16 +176,19 @@ abstract class CommonController extends BaseController return $this->action_redirect_process('error', "{$this->getTitle()}에서 생성폼 오류:" . $e->getMessage()); } } + protected function create_process(): CommonEntity { - //요청 데이터를 DTO 객체로 변환 + // POST 데이터를 DTO 객체로 변환 (getPost()는 POST 요청 본문만 가져옵니다.) $dto = $this->service->createDTO($this->request->getPost()); return $this->service->create($dto); } + protected function create_result_process(CommonEntity $entity): string|RedirectResponse { return $this->action_modal_process("{$this->getTitle()}에서 {$entity->getTitle()} 생성이 완료되었습니다."); } + final public function create(): string|RedirectResponse { try { @@ -181,11 +200,12 @@ abstract class CommonController extends BaseController return $this->action_redirect_process('error', "{$this->getTitle()}에서 생성 오류:" . $e->getMessage()); } } + //수정 protected function modify_form_process($uid): CommonEntity { if (!$uid) { - throw new \Exception("{$this->getTitle()}에 번호가 정의 되지 않았습니다."); + throw new \Exception("{$this->getTitle()}에 번호가 정의 되지 않았습니다."); } $entity = $this->service->getEntity($uid); if (!$entity instanceof CommonEntity) { @@ -193,10 +213,12 @@ abstract class CommonController extends BaseController } return $entity; } + protected function modify_form_result_process(string $action): string|RedirectResponse { return $this->action_render_process($this->getActionPaths(), $action, $this->getViewDatas()); } + final public function modify_form($uid): string|RedirectResponse { try { @@ -208,16 +230,19 @@ abstract class CommonController extends BaseController return $this->action_redirect_process('error', "{$this->getTitle()}에서 {$uid} 수정폼 오류:" . $e->getMessage()); } } + protected function modify_process($uid): CommonEntity { - //요청 데이터를 DTO 객체로 변환 + // POST 데이터를 DTO 객체로 변환 $dto = $this->service->createDTO($this->request->getPost()); return $this->service->modify($uid, $dto); } + protected function modify_result_process(CommonEntity $entity): string|RedirectResponse { return $this->action_modal_process("{$this->getTitle()}에서 {$entity->getTitle()} 수정이 완료되었습니다."); } + final public function modify($uid): string|RedirectResponse { try { @@ -229,9 +254,11 @@ abstract class CommonController extends BaseController return $this->action_redirect_process('error', "{$this->getTitle()}에서 {$uid} 수정 오류:" . $e->getMessage()); } } + //일괄처리 protected function batchjob_pre_process(array $postDatas = []): array { + // POST 데이터 전체를 가져옵니다. foreach ($this->request->getPost() as $field => $value) { $postDatas[$field] = $value; } @@ -260,10 +287,12 @@ abstract class CommonController extends BaseController $selectedFields = array_keys($formDatas); return array($uids, $selectedFields, $formDatas); } + protected function batchjob_process($uid, array $formDatas): CommonEntity { return $this->service->batchjob($uid, $formDatas); } + protected function batchjob_result_process(array $uids, array $entities, array $errors): string|RedirectResponse { return $this->action_redirect_process('info', sprintf( @@ -274,6 +303,7 @@ abstract class CommonController extends BaseController count($uids) )); } + final public function batchjob(): string|RedirectResponse { try { @@ -302,15 +332,18 @@ abstract class CommonController extends BaseController return $this->action_redirect_process('error', "{$this->getTitle()}에서 일괄작업처리 오류:" . $e->getMessage()); } } + //삭제 protected function delete_process($uid): CommonEntity { return $this->service->delete($uid); } + protected function delete_result_process(CommonEntity $entity): string|RedirectResponse { return $this->action_redirect_process('info', "{$this->getTitle()}에서 {$entity->getTitle()} 삭제가 완료되었습니다."); } + final public function delete($uid): RedirectResponse { try { @@ -319,9 +352,11 @@ abstract class CommonController extends BaseController return $this->action_redirect_process('error', "{$this->getTitle()}에서 {$uid} 삭제 오류:" . $e->getMessage()); } } + //일괄삭제 protected function batchjob_delete_pre_process(): array { + // POST 데이터 전체를 가져옵니다. $postDatas = $this->request->getPost(); //1. postDatas에서 선택된 uids 정보 추출 $uids = []; @@ -334,6 +369,7 @@ abstract class CommonController extends BaseController } return array($uids); } + protected function batchjob_delete_result_process(array $uids, array $entities, array $errors): string|RedirectResponse { return $this->action_redirect_process('info', sprintf( @@ -344,10 +380,12 @@ abstract class CommonController extends BaseController count($uids) )); } + protected function batchjob_delete_process($uid): CommonEntity { return $this->service->delete($uid); } + final public function batchjob_delete(): string|RedirectResponse { try { @@ -367,11 +405,12 @@ abstract class CommonController extends BaseController return $this->action_redirect_process('error', "{$this->getTitle()}에서 일괄삭제 오류:" . $e->getMessage()); } } + //상세보기 protected function view_process($uid): CommonEntity { if (!$uid) { - throw new \Exception("{$this->getTitle()}에 번호가 정의 되지 않았습니다."); + throw new \Exception("{$this->getTitle()}에 번호가 정의 되지 않았습니다."); } $entity = $this->service->getEntity($uid); if (!$entity instanceof CommonEntity) { @@ -379,10 +418,12 @@ abstract class CommonController extends BaseController } return $entity; } + protected function view_result_process(string $action): string { return $this->action_render_process($this->getActionPaths(), $action, $this->getViewDatas()); } + final public function view($uid): string|RedirectResponse { try { @@ -394,6 +435,7 @@ abstract class CommonController extends BaseController return $this->action_redirect_process('error', "{$this->getTitle()}에서 {$uid} 상세보기 오류:" . $e->getMessage()); } } + //리스트관련 //조건절 처리 protected function index_condition_process(string $action): void @@ -401,19 +443,22 @@ abstract class CommonController extends BaseController //Filter조건절 처리 $index_filters = []; foreach ($this->service->getFormService()->getFormFilters($action) as $field) { - $value = $this->request->getVar(index: $field) ?? null; + // getVar()를 사용하여 GET, POST, JSON 입력을 통합하여 가져옵니다. + $value = $this->request->getVar($field) ?? null; if ($value) { $this->service->setFilter($field, $value); $index_filters[$field] = $value; } } $this->addViewDatas('index_filters', $index_filters); + //검색어조건절 처리 $index_word = $this->request->getVar('index_word'); if ($index_word !== null && $index_word !== '') { $this->service->setSearchWord($index_word); } $this->addViewDatas('index_word', $index_word); + //날자검색 $index_start = $this->request->getVar('index_start'); $index_end = $this->request->getVar('index_end'); @@ -430,6 +475,7 @@ abstract class CommonController extends BaseController $this->addViewDatas('order_field', $order_field); $this->addViewDatas('order_value', $order_value); } + //Index Option출력용 protected function pagenation_options_process(int $index_totalcount, int $perpage): array { @@ -440,6 +486,7 @@ abstract class CommonController extends BaseController $page_options[$index_totalcount] = $index_totalcount; return $page_options; } + //PageNation 처리 protected function pagenation_process(int $index_totalcount, int $page, int $perpage, $pager_group = 'default', int $segment = 0, $template = 'bootstrap_full'): mixed { @@ -449,11 +496,11 @@ abstract class CommonController extends BaseController $pager = service("pager"); $pager->makeLinks($page, $perpage, $index_totalcount, $template, $segment, $pager_group); // $page = $pager->getCurrentPage($pager_group); - $this->addViewDatas('index_totalpage', $pager->getPageCount($pager_group)); + $this->addViewDatas('index_totalpage', $pager->getPageCount($pager_group)); return $pager->links($pager_group, $template); } - // //Page출력 처리 - //Entities처리 + + //Entities처리 (하위 클래스에서 오버라이드 가능) protected function index_process(array $entities = []): array { foreach ($this->service->getEntities() as $entity) { @@ -461,41 +508,100 @@ abstract class CommonController extends BaseController } return $entities; } + + // HTML View 출력 처리 (기존 로직) protected function index_result_process(string $action): string { return $this->action_render_process($this->getActionPaths(), $action, $this->getViewDatas()); } - public function index(): string + + protected function index_api_result_process(string $action): ResponseInterface + { + $viewDatas = $this->getViewDatas(); + + // 필요한 핵심 데이터만 추출 + $data = [ + 'entities' => $viewDatas['entities'] ?? [], + 'total_count' => $viewDatas['index_totalcount'] ?? 0, + 'page' => $viewDatas['page'] ?? 1, + 'perpage' => $viewDatas['perpage'] ?? (DEFAULTS['INDEX_PERPAGE'] ?? 10), // DEFAULTS 확인 필요 + 'filters' => $viewDatas['index_filters'] ?? [], + 'index_word' => $viewDatas['index_word'] ?? null, + 'index_start' => $viewDatas['index_start'] ?? null, + 'index_end' => $viewDatas['index_end'] ?? null, + ]; + + // CodeIgniter의 ResponseTrait의 respond() 메서드를 사용하여 JSON으로 응답 + return $this->respond([ + 'status' => 'success', + 'message' => "{$this->getTitle()} 목록 API 조회 성공", + 'data' => $data, + ]); + } + + public function index(): string|ResponseInterface { $action = __FUNCTION__; + + // API 요청 여부를 확인합니다. + // is_api 또는 RequestTemplate 파라미터를 getVar()로 통합하여 확인합니다. + $isApiRequest = $this->request->getVar('is_api') === '1' || + $this->request->getVar('RequestTemplate') === 'api'; + try { //초기화 $this->action_init_process($action); $this->addViewDatas('uri', $this->request->getUri()); - //Page, Per_page필요부분 + + // Page, Per_page 설정 $page = (int) $this->request->getVar('page') ?: 1; - $perpage = (int) $this->request->getVar('perpage') ?: intval(DEFAULTS['INDEX_PERPAGE']); + $perpage = (int) $this->request->getVar('perpage') ?: intval(DEFAULTS['INDEX_PERPAGE'] ?? 10); $this->addViewDatas('page', $page); $this->addViewDatas('perpage', $perpage); - //index_totalcount - //조건절 처리 index_totalcount용 + + // index_totalcount를 위한 조건절 처리 (오버라이드 가능) $this->index_condition_process($action); $index_totalcount = $this->service->getTotalCount(); $this->addViewDatas('index_totalcount', $index_totalcount); - $this->addViewDatas('index_pagination', $this->pagenation_process($index_totalcount, $page, $perpage)); - $this->addViewDatas('index_pagination_options', $this->pagenation_options_process($index_totalcount, $perpage)); - //조건절 LIMIT , OFFSET 처리 List용 + + // API 요청이 아닌 경우에만 HTML 뷰를 위한 페이지네이션 링크와 옵션을 준비 + if (!$isApiRequest) { + $this->addViewDatas('index_pagination', $this->pagenation_process($index_totalcount, $page, $perpage)); + $this->addViewDatas('index_pagination_options', $this->pagenation_options_process($index_totalcount, $perpage)); + } + + // 조건절 LIMIT , OFFSET 처리 List용 (기존 로직 유지) $this->index_condition_process($action); $this->service->setLimit($perpage); $this->service->setOffset(($page - 1) * $perpage); + + // Entities 처리 (API든 View든 공통적으로 필요하며, 하위 클래스에서 오버라이드 가능) $this->addViewDatas('entities', $this->index_process()); + helper(['form']); - $this->addViewDatas('formDatas', $this->request->getGet()); + + // 인자 없이 getVar() 호출 시, GET, POST, JSON 등 모든 데이터를 가져오며, 없을 경우 빈 배열을 사용합니다. + $this->addViewDatas('formDatas', $this->request->getVar() ?? []); } catch (\Exception $e) { + // API 요청인 경우 JSON 오류 메시지를 반환 + if ($isApiRequest) { + return $this->failServerError($e->getMessage()); + } + // 일반 요청인 경우 세션 오류 메시지를 설정 session()->setFlashdata('message', $e->getMessage()); } - //현재 URL을 세션에 저장 + + // --- 결과 분기 처리 --- + + if ($isApiRequest) { + // API 요청에 대한 JSON 렌더링 + return $this->index_api_result_process($action); + } + + // 현재 URL을 세션에 저장 (일반 View 요청 시에만) $this->getAuthContext()->pushCurrentUrl($this->request->getUri()->getPath() . ($this->request->getUri()->getQuery() ? "?" . $this->request->getUri()->getQuery() : "")); + + // HTML 뷰 렌더링 return $this->index_result_process($action); } @@ -517,6 +623,7 @@ abstract class CommonController extends BaseController } return array($full_path, $file_name); } + protected function download_process(string $action, string $output_type, mixed $uid = null): DownloadResponse|RedirectResponse|string { switch ($output_type) { @@ -525,7 +632,7 @@ abstract class CommonController extends BaseController helper(['form']); $this->index_condition_process($action); $this->addViewDatas('entities', $this->index_process()); - $html = $this->action_render_process($this->getActionPaths(), $action, $this->getViewDatas()); + $html = $this->action_render_process($this->getActionPaths(), $action, $this->getViewDatas()); //data loading $reader = new Html(); $loaded_data = $reader->loadFromString($html); @@ -547,6 +654,7 @@ abstract class CommonController extends BaseController } return $this->response->download($full_path, null)->setFileName($file_name); } + // Download final public function download(string $output_type, mixed $uid = false): DownloadResponse|RedirectResponse|string {