addActionPaths($this->_layout); $this->layouts = LAYOUTS[$this->_layout]; } protected function action_init_process(string $action, array $formDatas = []): void { parent::action_init_process($action, $formDatas); $this->addViewDatas('layout', $this->layouts); $this->addViewDatas('title', $this->getTitle()); $this->addViewDatas('helper', $this->service->getHelper()); $this->service->getActionForm()->action_init_process($action, $formDatas); $this->addViewDatas('formFields', $this->service->getActionForm()->getFormFields()); $this->addViewDatas('formRules', $this->service->getActionForm()->getFormRules()); $this->addViewDatas('formFilters', $this->service->getActionForm()->getFormFilters()); $this->addViewDatas('formOptions', $this->service->getActionForm()->getFormOptions()); $this->addViewDatas('index_actionButtons', $this->service->getActionForm()->getActionButtons()); $this->addViewDatas('index_batchjobFields', $this->service->getActionForm()->getBatchjobFilters()); $this->addViewDatas('index_batchjobButtons', $this->service->getActionForm()->getBatchjobButtons()); } protected function ok(array $data = [], int $status = 200): ResponseInterface { return $this->response->setStatusCode($status)->setJSON([ 'ok' => true, ...$data, ]); } protected function fail(string $message, int $status = 400, array $extra = []): ResponseInterface { return $this->response->setStatusCode($status)->setJSON([ 'ok' => false, 'message' => $message, ...$extra, ]); } protected function requireAjax() { // fetch + X-Requested-With 로 들어오는 경우 if (!$this->request->isAJAX()) { return $this->fail('Invalid request', 400); } return null; } protected function handleException(\Throwable $e): ResponseInterface { if ($e instanceof FormValidationException) { // ✅ 필드별 + 전역 메시지 return $this->fail( $e->getMessage() ?: '입력값을 확인해 주세요.', 422, ['errors' => $e->getErrors()] ); } log_message('error', '[AJAX] ' . $e->getMessage()); return $this->fail('처리 중 오류가 발생했습니다.', 500); } }