_classPaths[] = $path; } final public function getClassPaths($isArray = true, $delimeter = DIRECTORY_SEPARATOR): array|string { return $isArray ? $this->_classPaths : implode($delimeter, $this->_classPaths); } final public function getEntity(string|int|array $where, ?string $message = null): mixed { try { $entity = is_array($where) ? $this->model->where($where)->first() : $this->model->find($where); if (!$entity) { return null; } if (is_array($entity)) { throw new \Exception(__METHOD__ . "에서 결과값 Array 오류발생:\n" . var_export($entity, true)); } return $this->getEntity_process($entity); } catch (DatabaseException $e) { // 💡 DB 오류를 명시적으로 잡음 $errorMessage = sprintf( "\n------DB Query 오류 (%s)-----\nQuery: %s\nError: %s\n------------------------------\n", __FUNCTION__, $this->model->getLastQuery() ?? "No Query Available", $e->getMessage() ); log_message('error', $errorMessage); throw new RuntimeException($errorMessage, $e->getCode(), $e); } catch (\Exception $e) { // 기타 일반적인 예외 처리 $errorMessage = sprintf( "\n------일반 오류 (%s)-----\nError: %s\n------------------------------\n", __FUNCTION__, $e->getMessage() ); throw new \Exception($errorMessage, $e->getCode(), $e); } } final public function getEntities(mixed $where = null, array $columns = ['*']): array { try { $entities = $this->getEntities_process($where, $columns); // echo static::class . DIRECTORY_SEPARATOR . __FUNCTION__ . " Query:" . $this->model->getLastQuery(); return $entities; } catch (DatabaseException $e) { // 💡 DB 오류를 명시적으로 잡음 $errorMessage = sprintf( "\n------DB Query 오류 (%s)-----\nQuery: %s\nError: %s\n------------------------------\n", __FUNCTION__, $this->model->getLastQuery() ?? "No Query Available", $e->getMessage() ); log_message('error', $errorMessage); throw new RuntimeException($errorMessage, $e->getCode(), $e); } catch (\Exception $e) { // 기타 일반적인 예외 처리 $errorMessage = sprintf( "\n------일반 오류 (%s)-----\nError: %s\n------------------------------\n", __FUNCTION__, $e->getMessage() ); throw new \Exception($errorMessage, $e->getCode(), $e); } } // final public function getLatestPK(): int { $pkField = $this->model->getPKField(); // $this->model->selectMax($pkField)->get()->getRow() 대신 row() 사용 권장 $row = $this->model->selectMax($pkField)->get()->getRow(); // uid 대신 PK 필드명을 동적으로 사용 return isset($row->{$pkField}) ? ((int)$row->{$pkField} + 1) : 1; } //Entity관련 protected function getEntity_process(mixed $entity): mixed { return $entity; } //entities를 가져오는 조건 protected function getEntities_process(mixed $where = null, array $columns = ['*']): array { if ($where) { $this->model->where($where); } //출력순서 정의 $this->setOrderBy(); $entities = []; // findAll()이 DB 오류 없이 실행되었다면 문제 없음 foreach ($this->model->select(implode(',', $columns))->findAll() as $entity) { $entities[$entity->getPK()] = $this->getEntity_process($entity); } return $entities; } //CURD 결과처리용 //DB 결과 처리 로직 통합 및 개선 protected function handle_save_result(mixed $result, ?CommonEntity $entity = null): CommonEntity { //최종 PK 값 결정 (insert/update 공통) $pk = $this->model->useAutoIncrement() && is_numeric($result) && (int)$result > 0 ? (int)$result : ($entity->{$this->model->primaryKey} ?? null); // PK가 없는 경우 null 처리 if (empty($pk)) { // 모델의 insert/update가 실패했을 경우 에러 메시지를 포함하여 RuntimeException을 던집니다. $errors = $this->model->errors(); $errorMsg = is_array($errors) && !empty($errors) ? implode(", ", $errors) : "DB 작업 성공 후 PK를 확인할 수 없거나 모델 오류 발생."; throw new RuntimeException(__METHOD__ . "에서 오류발생: " . $errorMsg); } return $this->getEntity($pk); } //생성용 protected function create_process(array $formDatas): CommonEntity { $result = $this->model->insert($formDatas, $this->model->useAutoIncrement()); if ($result === false) { $errors = $this->model->errors(); $errorMsg = is_array($errors) ? implode(", ", $errors) : "삽입 작업이 실패했습니다."; throw new RuntimeException(__METHOD__ . "에서 오류발생: " . $errorMsg); } return $this->handle_save_result($result); } public function create(object $dto): CommonEntity { $formDatas = (array)$dto; //입력값 검증 if (!$this->getFormService()->validate($formDatas)) { throw new ValidationException(implode("\n", service('validation')->getErrors())); } return $this->create_process($formDatas); } //수정용 protected function modify_process($uid, array $formDatas): CommonEntity { if (!$uid) { throw new \Exception("수정에 필요한 PrimaryKey 가 정의 되지 않았습니다."); } $entity = $this->getEntity($uid); if (!$entity instanceof CommonEntity) { throw new \Exception(__METHOD__ . "에서 오류발생: {$uid}에 해당하는 정보을 찾을수 없습니다."); } $result = $this->model->update($uid, $formDatas); if ($result === false) { $errors = $this->model->errors(); $errorMsg = is_array($errors) ? implode(", ", $errors) : "업데이트 작업이 실패했습니다."; throw new RuntimeException(__METHOD__ . "에서 오류발생: " . $errorMsg); } return $this->handle_save_result($result, $entity); } public function modify($uid, object $dto): CommonEntity { $formDatas = (array)$dto; //입력값 검증 if (!$this->getFormService()->validate($formDatas)) { throw new ValidationException(implode("\n", service('validation')->getErrors())); } return $this->modify_process($uid, $formDatas); } protected function delete_process($uid): bool { if (!$uid) { throw new \Exception("삭제에 필요한 PrimaryKey 가 정의 되지 않았습니다."); } $entity = $this->getEntity($uid); if (!$entity instanceof CommonEntity) { throw new \Exception(__METHOD__ . "에서 오류발생: {$uid}에 해당하는 정보을 찾을수 없습니다."); } $result = $this->model->delete($uid); if ($result === false) { $errors = $this->model->errors(); $errorMsg = is_array($errors) ? implode(", ", $errors) : "모델 삭제 작업이 실패했습니다."; throw new RuntimeException(__METHOD__ . "에서 오류발생: " . $errorMsg); } return $result; } final public function delete($uid): bool { return $this->delete_process($uid); } //Index용 final public function getTotalCount(): int { return $this->model->countAllResults(); } //Limit처리 final public function setLimit(int $perpage): void { $this->model->limit($perpage); } //Offset처리 final public function setOffset(int $offset): void { $this->model->offset($offset); } public function setFilter(string $field, mixed $filter_value): void { switch ($field) { default: $this->model->where("{$this->model->getTable()}.{$field}", $filter_value); break; } } //검색어조건절처리 public function setSearchWord(string $word): void { $this->model->orLike($this->model->getTable() . "." . $this->model->getTitleField(), $word, 'both'); } //날자검색 public function setDateFilter(string $start, string $end): void { $this->model->where(sprintf("%s.created_at >= '%s 00:00:00'", $this->model->getTable(), $start)); $this->model->where(sprintf("%s.created_at <= '%s 23:59:59'", $this->model->getTable(), $end)); } //OrderBy 처리 public function setOrderBy(mixed $field = null, mixed $value = null): void { if ($field !== null && $value !== null) { $this->model->orderBy(sprintf(" %s.%s %s", $this->model->getTable(), $field, $value)); } } }