diff --git a/app/Controllers/Auth/GoogleController.php b/app/Controllers/Auth/GoogleController.php index 118d126..cf6c45e 100644 --- a/app/Controllers/Auth/GoogleController.php +++ b/app/Controllers/Auth/GoogleController.php @@ -2,18 +2,15 @@ namespace App\Controllers\Auth; +use App\DTOs\Auth\GoogleDTO; +use App\Entities\UserEntity; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface; use Psr\Log\LoggerInterface; -use App\Libraries\MySocket\GoogleSocket\API as GoogleSocket; -use App\Entities\UserEntity; - class GoogleController extends AuthController { public const PATH = 'login'; - private ?GoogleSocket $_socket = null; - private $_service = null; public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger) { parent::initController($request, $response, $logger); @@ -27,15 +24,12 @@ class GoogleController extends AuthController //구글 로그인 BUTTON용 $this->addViewDatas('SNSButton', anchor($this->service->socket->createAuthUrl(), ICONS['GOOGLE'] . 'Google 로그인', ["class" => "btn-google"])); } - //로그인처리 protected function login_process(): UserEntity { - $formDatas = $this->doValidation($this->getViewDatas('action')); - if (!array_key_exists('access_code', $formDatas) || !$formDatas['access_code']) { - throw new \Exception("구글 로그인 실패"); - } - return $this->service->login($formDatas); + //요청 데이터를 DTO 객체로 변환 + $dto = new GoogleDTO($this->request->getPost()); + return $this->service->login($dto); } protected function logout_process(): void { diff --git a/app/Controllers/Auth/LocalController.php b/app/Controllers/Auth/LocalController.php index d1c368c..5e9ad34 100644 --- a/app/Controllers/Auth/LocalController.php +++ b/app/Controllers/Auth/LocalController.php @@ -27,7 +27,6 @@ class LocalController extends AuthController //로그인처리 protected function login_process(): UserEntity { - //요청 데이터를 DTO 객체로 변환 $dto = new LocalDTO($this->request->getPost()); return $this->service->login($dto); } diff --git a/app/Controllers/CommonController.php b/app/Controllers/CommonController.php index 7d682a5..0efaf09 100644 --- a/app/Controllers/CommonController.php +++ b/app/Controllers/CommonController.php @@ -23,14 +23,11 @@ abstract class CommonController extends BaseController private array $_action_paths = []; private array $_viewDatas = []; protected $service = null; - protected $authService = null; protected $myCertification = null; public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger) { parent::initController($request, $response, $logger); - //로그인관련 - $this->authService = service('myauth'); - $this->myCertification = CertificationDTO::fromByAuthService($this->authService); + $this->myCertification = CertificationDTO::byAuthContext(service('myauth')->getAuthContext()); } protected function getLayout(): string { diff --git a/app/DTOs/CertificationDTO.php b/app/DTOs/CertificationDTO.php index adc9e76..01795c7 100644 --- a/app/DTOs/CertificationDTO.php +++ b/app/DTOs/CertificationDTO.php @@ -2,7 +2,7 @@ namespace App\DTOs; -use App\Services\Auth\AuthService; +use App\Libraries\AuthContext; use CodeIgniter\Entity\Entity; // DTO가 Entity를 상속받지 않는 경우, 필요한 경우 CommonDTO 또는 Entity 상속을 유지합니다. class CertificationDTO extends Entity // DTO가 Entity를 상속받는 것으로 가정합니다. @@ -22,15 +22,15 @@ class CertificationDTO extends Entity // DTO가 Entity를 상속받는 것으로 } } } - - public static function fromByAuthService(AuthService $service): self + //인증 정보 + public static function byAuthContext(AuthContext $authContext): self { return new self( [ - 'isLogin' => $service->isLoggedIn(), - 'uid' => $service->getUID(), - 'name' => $service->getName(), - 'role' => $service->getRole(), //배열(array|null)을 반환합니다. + 'isLogin' => $authContext->isLoggedIn(), + 'uid' => $authContext->getUID(), + 'name' => $authContext->getName(), + 'role' => $authContext->getRole(), //배열(array|null)을 반환합니다. ] ); } diff --git a/app/Filters/AuthFilter.php b/app/Filters/AuthFilter.php index ef8fcb7..d343720 100644 --- a/app/Filters/AuthFilter.php +++ b/app/Filters/AuthFilter.php @@ -26,20 +26,20 @@ class AuthFilter implements FilterInterface */ public function before(RequestInterface $request, $arguments = null) { - $auth = service('myauth'); + $authContext = service('myauth')->getAuthContext(); // var_dump($arguments); // log_message("debug", var_export($arguments, true)); // exit; // 로그인 않했으면 - if (!$auth->isLoggedIn()) { - $auth->pushCurrentUrl($request->getUri()->getPath() . ($request->getUri()->getQuery() ? "?" . $request->getUri()->getQuery() : "")); + if (!$authContext->isLoggedIn()) { + $authContext->pushCurrentUrl($request->getUri()->getPath() . ($request->getUri()->getQuery() ? "?" . $request->getUri()->getQuery() : "")); return redirect()->to(URLS['LOGIN'])->with('error', '로그인을하셔야합니다.'); } //User Role 비교 // 회원 ROLES이 필요ROLE($arguments) 목록에 존재하지 않으면(ACL) - if (!$auth->isAccessRole($arguments)) { + if (!$authContext->isAccessRole($arguments)) { return redirect()->back()->with( 'error', - "회원[{$auth->getName()}]님은 접속에 필요한 권한이 없습니다. " + "회원[{$authContext->getName()}]님은 접속에 필요한 권한이 없습니다. " ); } } diff --git a/app/Helpers/TrafficHelper.php b/app/Helpers/TrafficHelper.php index cd73ea1..f769eb3 100644 --- a/app/Helpers/TrafficHelper.php +++ b/app/Helpers/TrafficHelper.php @@ -9,7 +9,6 @@ class TrafficHelper extends CommonHelper public function __construct() { parent::__construct(); - $this->setTitleField(TrafficModel::TITLE); } public function getFieldForm(string $field, mixed $value, array $viewDatas, array $extras = []): string { diff --git a/app/Libraries/AuthContext.php b/app/Libraries/AuthContext.php new file mode 100644 index 0000000..4506ed3 --- /dev/null +++ b/app/Libraries/AuthContext.php @@ -0,0 +1,137 @@ +session = \Config\Services::session(); + } + + private function getAuthInfo(string $key = ""): array|string|null + { + $authInfo = $this->session->get(self::SESSION_AUTH_INFO); + if ($key) { + return $authInfo[$key] ?? null; + } + return $authInfo; + } + + // ---------------------------------------------------- + // Public Accessors (AuthService에서 이동) + // ---------------------------------------------------- + + public function getUID(): string|null + { + return $this->getAuthInfo('uid'); + } + + public function getID(): string|null + { + return $this->getAuthInfo('id'); + } + + public function getName(): string|null + { + return $this->getAuthInfo('name'); + } + + public function getRole(): array|null + { + return $this->getAuthInfo('role'); + } + + public function isLoggedIn(): bool + { + return $this->session->has(self::SESSION_IS_LOGIN); + } + + public function isAccessRole(array $roles): bool + { + $userRoles = $this->getRole(); + if (empty($userRoles) || !is_array($userRoles)) { + return false; + } + return !empty(array_intersect($userRoles, $roles)); + } + + public function pushCurrentUrl(string $url): void + { + $this->session->set($this->urlStackName, $url); + } + + public function popPreviousUrl(): string + { + $url = $this->session->get($this->urlStackName) ?? ""; + if (!empty($url)) { + $this->session->set($this->urlStackName, ""); // 세션에서 제거 + return $url; + } + return '/'; + } + + // ---------------------------------------------------- + // Session Writers (Login/Logout Process) + // ---------------------------------------------------- + + /** + * 인증 성공 후 세션에 사용자 정보를 기록합니다. + */ + public function setAuthSession(UserEntity $entity): void + { + $this->session->set(self::SESSION_IS_LOGIN, true); + $this->session->set(self::SESSION_AUTH_INFO, [ + 'uid' => $entity->getPK(), + 'id' => $entity->getID(), + 'name' => $entity->getTitle(), + 'role' => $entity->getRole() + ]); + } + + /** + * 로그아웃 시 세션 및 쿠키를 파괴합니다. + */ + public function destroyAuthSession(): void + { + // 세션 데이터 삭제 + $this->session->remove(self::SESSION_IS_LOGIN); + $this->session->remove(self::SESSION_AUTH_INFO); + + // 모든 세션 데이터 삭제 + $this->session->destroy(); + + // 세션 쿠키 삭제 (AuthService에서 가져온 로직) + if (ini_get("session.use_cookies")) { + $params = session_get_cookie_params(); + setcookie( + session_name(), + '', + time() - 42000, + $params["path"], + $params["domain"], + $params["secure"], + $params["httponly"] + ); + } + // 세션 재생성 + session_start(); + $this->session->regenerate(true); + } +} diff --git a/app/Models/TrafficModel.php b/app/Models/TrafficModel.php index b17a35e..8c057ae 100644 --- a/app/Models/TrafficModel.php +++ b/app/Models/TrafficModel.php @@ -9,7 +9,7 @@ class TrafficModel extends CommonModel { const TABLE = "trafficinfo"; const PK = "uid"; - const TITLE = "title"; + const TITLE = "switch"; protected $table = self::TABLE; // protected $useAutoIncrement = false; protected $primaryKey = self::PK; @@ -17,21 +17,10 @@ class TrafficModel extends CommonModel protected $allowedFields = [ "uid", "user_uid", - "clientinfo_uid", - "serverinfo_uid", - "payment_uid", - "code", - "title", - "site", - "location", - "rack", - "line", - "billing_at", - "sale", - "amount", - "start_at", - "end_at", - "history", + "switch", + "index", + "in", + "out", "status", "updated_at" ]; @@ -39,11 +28,4 @@ class TrafficModel extends CommonModel { parent::__construct(); } - public function getFormRule(string $action, string $field): string - //입력전 코드처리 - final public function create(array $formDatas): ServiceEntity - { - $formDatas['code'] = $formDatas['site'] . "_s" . uniqid(); - return parent::create($formDatas); - } } diff --git a/app/Services/Auth/AuthService.php b/app/Services/Auth/AuthService.php index 5a5f5b8..07bd173 100644 --- a/app/Services/Auth/AuthService.php +++ b/app/Services/Auth/AuthService.php @@ -5,148 +5,117 @@ namespace App\Services\Auth; use App\Entities\UserEntity; use App\Helpers\AuthHelper; use App\Models\CommonModel; -use App\Services\CommonService; -use CodeIgniter\Session\Session; +use App\Libraries\AuthContext; +use CodeIgniter\Validation\Exceptions\ValidationException; - -// 참고:https://github.com/SyntaxPhoenix/iloclient -abstract class AuthService extends CommonService +/** + * AuthService + * 인증(로그인) 워크플로우를 정의하는 템플릿 클래스입니다. + * CommonService를 상속받지 않아 불필요한 CRUD 구현을 요구하지 않습니다. + */ +abstract class AuthService { - private ?Session $_session = null; - private $url_stack_name = "url_stack"; + private ?AuthContext $_authContext = null; + private array $_classPaths = []; + protected $formServiceInstance = null; + protected ?CommonModel $model = null; + protected ?AuthHelper $helperInstance = null; + protected function __construct(CommonModel $model) { - parent::__construct($model); + $this->model = $model; // 모델을 직접 주입받아 자식에게 전달 $this->addClassPaths('Auth'); } - abstract public function login(mixed $dto): UserEntity; + abstract public function getFormService(): mixed; final public function getHelper(): AuthHelper { if ($this->helperInstance === null) { $this->helperInstance = new AuthHelper(); + // AuthHelper에 필요한 기본 메타데이터만 설정합니다. (CRUD 제거) $this->helperInstance->setAttributes([ 'pk_field' => $this->model->getPKField(), 'title_field' => $this->model->getTitleField(), - 'table' => $this->model->getTable(), - 'useAutoIncrement' => $this->model->useAutoIncrement(), - 'class_path' => $this->getClassPaths(false) + 'class_path' => $this->getClassPaths(false) ]); } return $this->helperInstance; } - //Index,FieldForm관련 - final public function getSession(): Session + //인증세션용 + final public function getAuthContext(): AuthContext { - if ($this->_session === null) { - $this->_session = \Config\Services::session(); + if ($this->_authContext === null) { + $this->_authContext = new AuthContext(); } - return $this->_session; + return $this->_authContext; } - private function getAuthInfo(string $key = ""): array|string|null + final protected function addClassPaths(string $path): void { - $authInfo = $this->getSession()->get(SESSION_NAMES['AUTH']); - if ($key) { - return $authInfo[$key] ?? null; - } - return $authInfo; + $this->_classPaths[] = $path; } - public function getFormFields(): array + final public function getClassPaths($isArray = true, $delimeter = DIRECTORY_SEPARATOR): array|string { - return ['id', 'passwd']; + return $isArray ? $this->_classPaths : implode($delimeter, $this->_classPaths); } - final public function getUID(): string|null + protected function getEntity_process(mixed $entity): mixed { - return $this->getAuthInfo('uid'); - } - final public function getID(): string|null - { - return $this->getAuthInfo('id'); - } - final public function getName(): string|null - { - return $this->getAuthInfo('name'); - } - - /** - * 현재 로그인된 사용자의 역할을 배열 형태로 반환합니다. - * UserEntity::getRole()의 반환 타입과 일치시킵니다. - * @return array|null - */ - final public function getRole(): array|null // <-- 타입 힌트를 array|null로 변경 - { - // getAuthInfo는 UserEntity에서 배열을 받아옵니다. - return $this->getAuthInfo('role'); - } - - final public function isLoggedIn(): bool - { - return $this->getSession()->has(SESSION_NAMES['ISLOGIN']); - } - - /** - * 사용자가 필요한 접근 권한($roles)을 가지고 있는지 확인합니다. - * @param array $roles 요구되는 권한 목록 - * @return bool - */ - final public function isAccessRole(array $roles): bool - { - // (1) getRole()의 반환 타입이 이제 배열이므로 바로 받습니다. - $userRoles = $this->getRole(); - // 역할 정보 자체가 없거나 빈 배열인 경우 접근 불가 - if (empty($userRoles) || !is_array($userRoles)) { - return false; - } - // (2) 문자열 explode() 대신 array_intersect를 사용하여 배열 간의 공통점을 찾습니다. - // 교집합이 없으면 false - return !empty(array_intersect($userRoles, $roles)); - } - - final public function pushCurrentUrl(string $url): void - { - $this->getSession()->set($this->url_stack_name, $url); - } - final public function popPreviousUrl(): string - { - $url = $this->getSession()->get($this->url_stack_name) ?? ""; - if (!empty($url)) { - $this->pushCurrentUrl(""); - return $url; - } - return '/'; // 기본 URL - } - final protected function login_process(UserEntity $entity): UserEntity - { - $this->getSession()->set(SESSION_NAMES['ISLOGIN'], true); - $this->getSession()->set(SESSION_NAMES['AUTH'], [ - 'uid' => $entity->getPK(), - 'id' => $entity->getID(), - 'name' => $entity->getTitle(), - 'role' => $entity->getRole() - ]); return $entity; } + 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 protected function getValidationRules(string $action, array $allRules = []): array + { + foreach ($this->getFormService()->getFormFields($action) as $field) { + $allRules = array_merge($allRules, $this->getValidationRule($action, $field, $allRules)); + } + return $allRules; + } + protected function getValidationRule(string $action, string $field, array $rules = []): array + { + switch ($field) { + default: + $rules[$field] = $this->getFormService()->getValidationRule($action, $field); + break; + } + return $rules; + } + + //로그인 + abstract protected function login_process(array $formDatas): UserEntity; + public function login(object $dto): UserEntity + { + //입력값 검증 + $formDatas = (array) $dto; + if (!service('validation')->setRules($this->getValidationRules(__FUNCTION__))->run($formDatas)) { + throw new ValidationException(implode("\n", service('validation')->getErrors())); + } + //인증처리 + $entity = $this->login_process($formDatas); + //세션처리 + $this->getAuthContext()->setAuthSession($entity); + return $entity; + } + //로그아웃 final public function logout(): void { - // 세션 데이터 삭제 - $this->getSession()->remove(SESSION_NAMES['ISLOGIN']); - $this->getSession()->remove(SESSION_NAMES['AUTH']); - // 모든 세션 데이터 삭제 - $this->getSession()->destroy(); - // 세션 쿠키 삭제 - if (ini_get("session.use_cookies")) { - $params = session_get_cookie_params(); - setcookie( - session_name(), - '', - time() - 42000, - $params["path"], - $params["domain"], - $params["secure"], - $params["httponly"] - ); - } - // 세션 재생성 - session_start(); - $this->getSession()->regenerate(true); + $this->getAuthContext()->destroyAuthSession(); } } diff --git a/app/Services/Auth/GoogleService.php b/app/Services/Auth/GoogleService.php index 20b5bcc..d32962e 100644 --- a/app/Services/Auth/GoogleService.php +++ b/app/Services/Auth/GoogleService.php @@ -33,39 +33,18 @@ class GoogleService extends AuthService } return $this->formServiceInstance; } - public function getFormFields(): array - { - return ["access_code"]; - } - public function getFormFilters(): array - { - return ["access_code"]; - } - public function getBatchjobButtons(): array - { - return []; - } //기본기능 - public function login(mixed $dto): UserEntity + protected function login_process(array $formDatas): UserEntity { try { - if (!$dto instanceof GoogleDTO) { - throw new RuntimeException(__METHOD__ . "에서 오류발생: GoogleDTO만 사용하실수 있습니다"); - } - // DTO 객체를 배열로 변환하여 검증기에 전달 - $formDatas = (array) $dto; - if (!service('validation')->setRules($this->getFormRules(__FUNCTION__))->run($formDatas)) { - // 검증 실패 시, ValidationException을 던집니다. - throw new ValidationException(service('validation')->getErrors()); - } - $this->socket->setToken($dto->access_code); + $this->socket->setToken($formDatas['access_code']); $sns_entity = $this->socket->signup(); // local db 사용와의 연결 확인 $entity = $this->getEntity($sns_entity->getParent()); if (!$entity instanceof UserEntity) { throw new PageNotFoundException("회원[{$sns_entity->getTitle()}]님은 아직 로컬사용자 연결이 이루어지지 않았습니다."); } - return $this->login_process($entity);; + return $entity; } catch (\Google_Service_Exception $e) { log_message('error', '구글 서비스 예외발생: ' . $e->getMessage()); throw new PageNotFoundException("구글 로그인 중 오류가 발생했습니다. 다시 시도해 주세요."); @@ -74,4 +53,13 @@ class GoogleService extends AuthService throw new PageNotFoundException("관리자에게 문의하시기 바랍니다.\n{$e->getMessage()}"); } } + public function login(mixed $dto): UserEntity + { + if (!$dto instanceof GoogleDTO) { + throw new RuntimeException(__METHOD__ . "에서 오류발생: GoogleDTO만 사용하실수 있습니다"); + } + return parent::login($dto); + // DTO 객체를 배열로 변환하여 검증기에 전달 + $formDatas = (array) $dto; + } } diff --git a/app/Services/Auth/LocalService.php b/app/Services/Auth/LocalService.php index a8bc2fb..f8f5809 100644 --- a/app/Services/Auth/LocalService.php +++ b/app/Services/Auth/LocalService.php @@ -6,7 +6,6 @@ use App\DTOs\Auth\LocalDTO; use App\Entities\UserEntity; use App\Forms\Auth\LocalForm; use App\Models\UserModel; -use CodeIgniter\Validation\Exceptions\ValidationException; use RuntimeException; class LocalService extends AuthService @@ -16,6 +15,7 @@ class LocalService extends AuthService parent::__construct($model); $this->addClassPaths('Local'); } + public function getFormService(): LocalForm { if ($this->formServiceInstance === null) { @@ -25,42 +25,28 @@ class LocalService extends AuthService 'title_field' => $this->model->getTitleField(), 'table' => $this->model->getTable(), 'useAutoIncrement' => $this->model->useAutoIncrement(), - 'class_path' => $this->getClassPaths(false) + 'class_path' => $this->getClassPaths(false), ]); } return $this->formServiceInstance; } - public function getFormFields(): array + protected function login_process(array $formDatas): UserEntity { - return ["id", "passwd",]; - } - public function getFormFilters(): array - { - return []; - } - public function getBatchjobButtons(): array - { - return []; - } - //기본기능 - public function login(mixed $dto): UserEntity - { - if (!$dto instanceof LocalDTO) { - throw new RuntimeException(__METHOD__ . "에서 오류발생: LcoalDTO만 사용하실수 있습니다"); - } - // DTO 객체를 배열로 변환하여 검증기에 전달 - $formDatas = (array) $dto; - if (!service('validation')->setRules($this->getFormRules(__FUNCTION__))->run($formDatas)) { - // 검증 실패 시, ValidationException을 던집니다. - throw new ValidationException(implode("\n", service('validation')->getErrors())); - } - $entity = $this->getEntity(['id' => $dto->id, 'status' => STATUS['AVAILABLE']], false); + $entity = $this->getEntity(['id' => $formDatas['id'], 'status' => 'AVAILABLE'], true); if (!$entity instanceof UserEntity) { - throw new \Exception("{$dto->id}에 대한 로그인 정보를 찾을수 없습니다."); + throw new \Exception("{$formDatas['id']}에 대한 로그인 정보를 찾을수 없습니다."); } - if (!password_verify($dto->passwd, $entity->getPassword())) { + if (!password_verify($formDatas['passwd'], $entity->getPassword())) { throw new \Exception("암호가 맞지 않습니다."); } - return $this->login_process($entity); + return $entity; + } + + public function login(object $dto): UserEntity + { + if (!$dto instanceof LocalDTO) { + throw new RuntimeException(__METHOD__ . "에서 오류발생:" . get_class($dto) . "는 사용할수 없습니다."); + } + return parent::login($dto); } } diff --git a/app/Services/CommonService.php b/app/Services/CommonService.php index 9f3c28f..237111b 100644 --- a/app/Services/CommonService.php +++ b/app/Services/CommonService.php @@ -2,7 +2,10 @@ namespace App\Services; +use App\Entities\CommonEntity; use App\Models\CommonModel; +use CodeIgniter\Validation\Exceptions\ValidationException; +use RuntimeException; abstract class CommonService { @@ -96,6 +99,62 @@ abstract class CommonService } return $rules; } + //CURD 결과처리용 + //DB 결과 처리 로직 통합 및 개선 + protected function handle_save_result(mixed $result, $entity): CommonEntity + { + if (!$result) { + // static::class는 현재 호출된 자식 클래스 이름 반환 + throw new RuntimeException(static::class . "에서 {$entity->getTitle()} 등록/수정 중 DB 오류가 발생하였습니다."); + } + // 2. 최종 PK 값 결정 (insert/update 공통) + $pkValue = $this->model->useAutoIncrement() && is_numeric($result) && (int)$result > 0 + ? (int)$result + : $entity->{$this->model->primaryKey}; + + if (empty($pkValue)) { + throw new RuntimeException("{$entity->getTitle()} 저장 후 Primary Key를 확인할 수 없습니다."); + } + // 3. Entity 재조회 (수정 및 생성 모두 최신 DB 상태 반영) + $savedEntity = $this->model->find($pkValue); + if (!$savedEntity) { + throw new RuntimeException("등록/수정된 데이터를 찾을 수 없습니다. (PK: {$pkValue})"); + } + return $savedEntity; + } + //생성용 + abstract protected function create_process(array $formDatas): CommonEntity; + public function create(object $dto): CommonEntity + { + $formDatas = (array) $dto; + if (!service('validation')->setRules($this->getValidationRules(__FUNCTION__))->run($formDatas)) { + throw new ValidationException(implode("\n", service('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(array $formDatas): array; + public function modify(object $dto): CommonEntity + { + $formDatas = (array) $dto; + if (!service('validation')->setRules($this->getValidationRules(__FUNCTION__))->run($formDatas)) { + throw new ValidationException(implode("\n", service('validation')->getErrors())); + } + list($pk, $updateData) = $this->modify_process($formDatas); + $entity = new ($this->model->returnType)($updateData); // 재조회에 필요한 PK를 얻기 위함 + $result = $this->model->update($pk, $updateData); + return $this->handle_save_result($result, $entity); + } + 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 { diff --git a/app/Services/UserService.php b/app/Services/UserService.php index 6aed284..71b41fe 100644 --- a/app/Services/UserService.php +++ b/app/Services/UserService.php @@ -3,6 +3,7 @@ namespace App\Services; use App\DTOs\UserDTO; +use App\Entities\CommonEntity; use App\Entities\UserEntity; use App\Forms\UserForm; use App\Helpers\UserHelper; @@ -46,93 +47,53 @@ class UserService extends CommonService return $this->helperInstance; } //기본 기능부분 - public function create(UserDTO $dto): UserEntity + protected function create_process(array $formDatas): UserEntity { - // DTO 객체를 배열로 변환하여 검증기에 전달 - $formDatas = (array) $dto; - // dd($formDatas); - if (!service('validation')->setRules($this->getValidationRules(__FUNCTION__))->run($formDatas)) { - throw new ValidationException(implode("\n", service('validation')->getErrors())); - } - $entity = new UserEntity($formDatas); - $result = $this->model->insert($entity); - if (!$result) { - throw new \Exception("{$entity->getTitle()} 등록 중 DB 오류가 발생하였습니다."); - } - // 💡 PK 타입에 따른 최종 Entity 반환 로직 분기 - if ($this->model->useAutoIncrement) { //정수 PK인 경우 - $savedEntity = $this->model->find($result); - } else { //문자열 PK인 경우 - $pkValue = $entity->{$this->model->primaryKey}; - $savedEntity = $this->model->find($pkValue); - } - if (!$savedEntity instanceof UserEntity) { - throw new \Exception("등록된 데이터를 찾을 수 없습니다."); - } - return $savedEntity; + return new UserEntity($formDatas); } - public function modify(UserDTO $dto): UserEntity + public function create(object $dto): UserEntity { - // DTO 객체를 배열로 변환하여 검증기에 전달 - $formDatas = (array) $dto; - // dd($formDatas); - if (!service('validation')->setRules($this->getValidationRules(__FUNCTION__))->run($formDatas)) { - throw new ValidationException(implode("\n", service('validation')->getErrors())); + if (!$dto instanceof UserDTO) { + throw new RuntimeException(__METHOD__ . "에서 오류발생:" . get_class($dto) . "는 사용할수 없습니다."); } - $entity = new UserEntity($formDatas); - $result = $this->model->update($entity->getPK(), $formDatas); - if (!$result) { - throw new \Exception("{$entity->getTitle()} 등록 중 DB 오류가 발생하였습니다."); - } - // 💡 PK 타입에 따른 최종 Entity 반환 로직 분기 - if ($this->model->useAutoIncrement) { //정수 PK인 경우 - $savedEntity = $this->model->find($result); - } else { //문자열 PK인 경우 - $pkValue = $entity->{$this->model->primaryKey}; - $savedEntity = $this->model->find($pkValue); - } - if (!$savedEntity instanceof UserEntity) { - throw new \Exception("등록된 데이터를 찾을 수 없습니다."); - } - return $savedEntity; + return parent::create($dto); + } + protected function modify_process(array $formDatas): array + { + // DTO에 PK가 포함되어 있다고 가정. 필요 시 데이터 가공 + return [ + $formDatas[$this->model->primaryKey], // PK + $formDatas // Update Data + ]; + } + public function modify(object $dto): UserEntity + { + if (!$dto instanceof UserDTO) { + throw new RuntimeException(__METHOD__ . "에서 오류발생:" . get_class($dto) . "는 사용할수 없습니다."); + } + return parent::modify($dto); + } + //List 검색용 + //FormFilter 조건절 처리 + public function index_condition_filterField(string $field, mixed $filter_value): void + { + switch ($field) { + case 'role': + $where = "FIND_IN_SET(" . $this->model->escape($filter_value) . ", {$this->model->getTable()}.{$field}) > 0"; + //FIND_IN_SET()은 MySQL 함수이므로 CodeIgniter가 이를 일반 컬럼명으로 착각하고 escape하게 되면 오류가 발생합니다. 따라서 ->where($sql, null, false)로 명시하여 escape를 꺼줘야 정상 작동 + $this->model->where($where, null, false); + break; + default: + parent::index_condition_filterField($field, $filter_value); + break; + } + } + //검색어조건절처리 + public function index_condition_filterWord(string $word): void + { + $this->model->orLike($this->model->getTable() . '.id', $word, 'both'); + $this->model->orLike($this->model->getTable() . "." . $this->model->getTitleField(), $word, 'both'); + $this->model->orLike($this->model->getTable() . '.email', $word, 'both'); + parent::index_condition_filterWord($word); } - // protected function modify_process(mixed $entity, array $formDatas): UserEntity - // { - // // die(var_export($formDatas, true)); - // //암호를 입력하지 않았을시는 변경하기 않게 하기위함 - // if (isset($formDatas['passwd']) && $formDatas['passwd'] == "") { - // unset($formDatas['passwd']); - // unset($formDatas['confirmpassword']); - // } - // //Role을 지정이 있을경우에만 , toggle이나 batcjhjob에서는 없을수도 있으므로 - // if (isset($formDatas['role'])) { - // $formDatas['role'] = implode(DEFAULTS["DELIMITER_ROLE"], $formDatas['role']); - // } - // // die(var_export($formDatas, true)); - // $entity = parent::modify_process($entity, $formDatas); - // return $entity; - // } - // //List 검색용 - // //FormFilter 조건절 처리 - // public function index_condition_filterField(string $field, mixed $filter_value): void - // { - // switch ($field) { - // case 'role': - // $where = "FIND_IN_SET(" . $this->model->escape($filter_value) . ", {$this->model->getTable()}.{$field}) > 0"; - // //FIND_IN_SET()은 MySQL 함수이므로 CodeIgniter가 이를 일반 컬럼명으로 착각하고 escape하게 되면 오류가 발생합니다. 따라서 ->where($sql, null, false)로 명시하여 escape를 꺼줘야 정상 작동 - // $this->model->where($where, null, false); - // break; - // default: - // parent::index_condition_filterField($field, $filter_value); - // break; - // } - // } - // //검색어조건절처리 - // public function index_condition_filterWord(string $word): void - // { - // $this->model->orLike($this->model->getTable() . '.id', $word, 'both'); - // $this->model->orLike($this->model->getTable() . "." . $this->model->getTitleField(), $word, 'both'); - // $this->model->orLike($this->model->getTable() . '.email', $word, 'both'); - // parent::index_condition_filterWord($word); - // } }