_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 (\Exception $e) {
$message = sprintf(
"\n------%s SQL오류-----
\n%s\n%s\n------------------------------\n",
__FUNCTION__,
$this->model->getLastQuery(),
$e->getMessage()
);
throw new \Exception($message);
}
}
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 (\Exception $e) {
$message = sprintf(
"\n------%s SQL오류-----
\n%s\n%s\n------------------------------\n",
__FUNCTION__,
$this->model->getLastQuery(),
$e->getMessage()
);
throw new \Exception($message);
}
} //
final public function getLatestPK(): int
{
$row = $this->model->selectMax($this->model->getPKField())->get()->getRow();
return isset($row->uid) ? ((int)$row->uid + 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 = [];
foreach ($this->model->select(implode(',', $columns))->findAll() as $entity) {
$entities[$entity->getPK()] = $this->getEntity_process($entity);
}
return $entities;
}
//Validation용
final protected function getValidationRules(string $action, array $rules): array
{
$dynamicRules = [];
foreach ($rules as $field => $rule) {
//field별 추가 커스텀 룰 적용
list($field, $rule) = $this->getValidationRule($field, $rule);
$dynamicRules[$field] = $rule;
}
return $dynamicRules;
}
protected function getValidationRule(string $field, string $rule): array
{
return array($field, $rule);
}
//CURD 결과처리용
//DB 결과 처리 로직 통합 및 개선
protected function handle_save_result(mixed $result, CommonEntity $entity): CommonEntity
{
if (!$result) {
throw new RuntimeException(static::class . "에서 " . __FUNCTION__ . "오류발생:" . $this->model->getLastQuery());
}
// 2. 최종 PK 값 결정 (insert/update 공통)
$pk = $this->model->useAutoIncrement() && is_numeric($result) && (int)$result > 0
? (int)$result
: $entity->{$this->model->primaryKey};
if (empty($pk)) {
throw new RuntimeException("{$entity->getTitle()} 저장 후 Primary Key를 확인할 수 없습니다.");
}
// 3. Entity 재조회 (수정 및 생성 모두 최신 DB 상태 반영)
$savedEntity = $this->model->find($pk);
if (!$savedEntity) {
throw new RuntimeException("등록/수정된 데이터를 찾을 수 없습니다. (PK: {$pk})");
}
return $savedEntity;
}
//생성용
abstract protected function create_process(array $formDatas): CommonEntity;
public function create(object $dto): CommonEntity
{
$formDatas = (array)$dto;
//입력값 검증
$validation = service('validation')->setRules($this->getValidationRules(__FUNCTION__,));
if (!$validation->run($formDatas)) {
throw new ValidationException(implode("\n", $validation->getErrors()));
}
$entity = $this->create_process($formDatas);
$result = $this->model->insert($entity, $this->model->useAutoIncrement());
return $this->handle_save_result($result, $entity);
}
//수정용
abstract protected function modify_process($uid, array $formDatas): CommonEntity;
public function modify($uid, object $dto): CommonEntity
{
$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($uid, $formDatas);
$result = $this->model->save($updatedEntity);
if (!$result) {
throw new RuntimeException(static::class . "에서 " . __FUNCTION__ . "오류발생:" . $this->model->getLastQuery());
}
return $this->handle_save_result($result, $updatedEntity);
}
protected function delete_process($uid): bool
{
return $this->model->delete($uid);
}
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));
}
}
// //단일작업
// protected function toggle_process(mixed $entity, array $formDatas): mixed
// {
// return $this->model->modify($entity, $formDatas);
// }
// public function toggle(mixed $entity, array $formDatas): mixed
// {
// $db = \Config\Database::connect();
// try {
// //트랜잭션 도중 DB 오류가 발생하면 DatabaseException을 던지도록 설정
// $db->transException(true)->transStart();
// $entity = $this->toggle_process($entity, $formDatas);
// $db->transComplete();
// return $entity;
// } catch (DatabaseException $e) { //DB 오류시 발생
// throw new RuntimeException(sprintf(
// "\n----[%s]에서 트랜잭션 실패: DB 오류----\n%s\n%s\n------------------------------\n",
// __METHOD__,
// $this->model->getLastQuery(),
// $e->getMessage()
// ), $e->getCode(), $e);
// } catch (\Throwable $e) { // 그 외 다른 종류의 예외 처리
// $db->transRollback(); // 예외 발생 시 수동으로 롤백
// throw new RuntimeException($e->getMessage(), 0, $e);
// }
// }
// //일괄처리작업
// protected function batchjob_process(mixed $entity, array $formDatas): mixed
// {
// return $this->model->modify($entity, $formDatas);
// }
// public function batchjob(mixed $entity, array $formDatas): mixed
// {
// $db = \Config\Database::connect();
// try {
// //트랜잭션 도중 DB 오류가 발생하면 DatabaseException을 던지도록 설정
// $db->transException(true)->transStart();
// $entity = $this->batchjob_process($entity, $formDatas);
// $db->transComplete();
// return $entity;
// } catch (DatabaseException $e) { //DB 오류시 발생
// throw new RuntimeException(sprintf(
// "\n----[%s]에서 트랜잭션 실패: DB 오류----\n%s\n%s\n------------------------------\n",
// __METHOD__,
// $this->model->getLastQuery(),
// $e->getMessage()
// ), $e->getCode(), $e);
// } catch (\Throwable $e) { // 그 외 다른 종류의 예외 처리
// $db->transRollback(); // 예외 발생 시 수동으로 롤백
// throw new RuntimeException($e->getMessage(), 0, $e);
// }
// }
// //삭제
// protected function delete_process(string $uid): void
// {
// if (!$this->model->delete($uid)) {
// // delete() 메서드 실패 시 모델의 errors()를 통해 상세 정보 확인
// $errors = $this->model->errors();
// throw new RuntimeException("모델 삭제 실패: " . var_export($errors, true));
// }
// }
// public function delete(mixed $entity): mixed
// {
// $db = \Config\Database::connect();
// $db->transStart();
// try {
// //트랜잭션 도중 DB 오류가 발생하면 DatabaseException을 던지도록 설정
// $db->transException(true)->transStart();
// $this->delete_process($entity->getPK());
// $db->transComplete();
// return $entity;
// } catch (DatabaseException $e) { //DB 오류시 발생
// throw new RuntimeException(sprintf(
// "\n----[%s]에서 트랜잭션 실패: DB 오류----\n%s\n%s\n------------------------------\n",
// __METHOD__,
// $this->model->getLastQuery(),
// $e->getMessage()
// ), $e->getCode(), $e);
// } catch (\Throwable $e) { // 그 외 다른 종류의 예외 처리
// $db->transRollback(); // 예외 발생 시 수동으로 롤백
// throw new RuntimeException($e->getMessage(), 0, $e);
// }
// }
}