trafficmonitor init...2

This commit is contained in:
choi.jh 2025-11-06 16:51:52 +09:00
parent f430183704
commit 65dff253d8
32 changed files with 615 additions and 557 deletions

View File

@ -28,32 +28,29 @@ $routes->group('', ['namespace' => 'App\Controllers'], function ($routes) {
$routes->group('admin', ['namespace' => 'App\Controllers\Admin', 'filter' => 'authFilter:manager'], function ($routes) { $routes->group('admin', ['namespace' => 'App\Controllers\Admin', 'filter' => 'authFilter:manager'], function ($routes) {
$routes->get('/', 'Home::index'); $routes->get('/', 'Home::index');
$routes->group('user', ['namespace' => 'App\Controllers\Admin'], function ($routes) { $routes->group('user', ['namespace' => 'App\Controllers\Admin'], function ($routes) {
$routes->get('/', 'UserController::index', ['filter' => 'authFilter:master']); $routes->get('/', 'UserController::index');
$routes->get('create', 'UserController::create_form', ['filter' => 'authFilter:master']); $routes->get('create', 'UserController::create_form');
$routes->post('create', 'UserController::create', ['filter' => 'authFilter:master']); $routes->post('create', 'UserController::create');
$routes->get('modify/(:num)', 'UserController::modify_form/$1', ['filter' => 'authFilter:master']); $routes->get('modify/(:num)', 'UserController::modify_form/$1');
$routes->post('modify/(:num)', 'UserController::modify/$1', ['filter' => 'authFilter:master']); $routes->post('modify/(:num)', 'UserController::modify/$1');
$routes->get('view/(:num)', 'UserController::view/$1', ['filter' => 'authFilter:manager']); $routes->get('view/(:num)', 'UserController::view/$1');
$routes->get('delete/(:num)', 'UserController::delete/$1', ['filter' => 'authFilter:master']); $routes->get('delete/(:num)', 'UserController::delete/$1', ['filter' => 'authFilter:master']);
$routes->get('toggle/(:num)/(:any)', 'UserController::toggle/$1/$2', ['filter' => 'authFilter:master']); $routes->get('toggle/(:num)/(:any)', 'UserController::toggle/$1/$2', ['filter' => 'authFilter:master']);
$routes->post('batchjob', 'UserController::batchjob', ['filter' => 'authFilter:master']); $routes->post('batchjob', 'UserController::batchjob', ['filter' => 'authFilter:master']);
$routes->post('batchjob_delete', 'UserController::batchjob_delete', ['filter' => 'authFilter:master']); $routes->post('batchjob_delete', 'UserController::batchjob_delete', ['filter' => 'authFilter:master']);
$routes->get('download/(:alpha)', 'UserController::download/$1', ['filter' => 'authFilter:master']); $routes->get('download/(:alpha)', 'UserController::download/$1');
$routes->get('profile/(:num)', 'UserController::profile_form/$1', ['filter' => 'authFilter:manager']); });
$routes->post('profile/(:num)', 'UserController::profile/$1', ['filter' => 'authFilter:manager']); $routes->group('traffic', ['namespace' => 'App\Controllers\Admin'], function ($routes) {
$routes->get('/', 'TrafficController::index');
$routes->group('traffic', ['namespace' => 'App\Controllers\Admin'], function ($routes) { $routes->get('create', 'TrafficController::create_form');
$routes->get('/', 'TrafficController::index'); $routes->post('create', 'TrafficController::create');
$routes->get('create', 'TrafficController::create_form'); $routes->get('modify/(:num)', 'TrafficController::modify_form/$1');
$routes->post('create', 'TrafficController::create'); $routes->post('modify/(:num)', 'TrafficController::modify/$1');
$routes->get('modify/(:num)', 'TrafficController::modify_form/$1'); $routes->get('view/(:num)', 'TrafficController::view/$1');
$routes->post('modify/(:num)', 'TrafficController::modify/$1'); $routes->get('delete/(:num)', 'TrafficController::delete/$1');
$routes->get('view/(:num)', 'TrafficController::view/$1'); $routes->get('toggle/(:num)/(:any)', 'TrafficController::toggle/$1/$2');
$routes->get('delete/(:num)', 'TrafficController::delete/$1'); $routes->post('batchjob', 'TrafficController::batchjob');
$routes->get('toggle/(:num)/(:any)', 'TrafficController::toggle/$1/$2'); $routes->post('batchjob_delete', 'TrafficController::batchjob_delete');
$routes->post('batchjob', 'TrafficController::batchjob'); $routes->get('download/(:alpha)', 'TrafficController::download/$1');
$routes->post('batchjob_delete', 'TrafficController::batchjob_delete');
$routes->get('download/(:alpha)', 'TrafficController::download/$1');
});
}); });
}); });

View File

@ -40,8 +40,7 @@ class Services extends BaseService
return static::getSharedInstance(__FUNCTION__); return static::getSharedInstance(__FUNCTION__);
} else { } else {
return new LocalService( return new LocalService(
new \App\Models\UserModel(), new \App\Models\UserModel()
new \App\Forms\Auth\LocalForm()
); );
} }
} }
@ -52,8 +51,7 @@ class Services extends BaseService
return static::getSharedInstance(__FUNCTION__); return static::getSharedInstance(__FUNCTION__);
} else { } else {
return new LocalService( return new LocalService(
new \App\Models\UserModel(), new \App\Models\UserModel()
new \App\Forms\Auth\LocalForm()
); );
} }
} }
@ -64,7 +62,6 @@ class Services extends BaseService
} }
return new GoogleService( return new GoogleService(
new \App\Models\USerModel(), new \App\Models\USerModel(),
new \App\Forms\Auth\GoogleForm(),
new \App\Libraries\MySocket\GoogleSocket\CURL() new \App\Libraries\MySocket\GoogleSocket\CURL()
); );
} }
@ -75,8 +72,7 @@ class Services extends BaseService
return static::getSharedInstance(__FUNCTION__); return static::getSharedInstance(__FUNCTION__);
} }
return new UserService( return new UserService(
new \App\Models\USerModel(), new \App\Models\USerModel()
new \App\Forms\UserForm()
); );
} }
@ -87,7 +83,6 @@ class Services extends BaseService
} }
return new TrafficService( return new TrafficService(
new \App\Models\TrafficModel(), new \App\Models\TrafficModel(),
new \App\Forms\TrafficForm()
); );
} }
} }

View File

@ -15,4 +15,8 @@ abstract class AdminController extends CommonController
parent::initController($request, $response, $logger); parent::initController($request, $response, $logger);
$this->addActionPaths(self::PATH); $this->addActionPaths(self::PATH);
} }
final protected function getLayout(): string
{
return self::PATH;
}
} }

View File

@ -23,9 +23,9 @@ class UserController extends AdminController
{ {
parent::initController($request, $response, $logger); parent::initController($request, $response, $logger);
if ($this->service === null) { if ($this->service === null) {
$this->service = service('localauth'); $this->service = service('userservice');
} }
$this->addActionPaths(self::PATH); $this->addActionPaths($this::PATH);
} }
protected function getFormRule(string $action, string $field, string $rule): array protected function getFormRule(string $action, string $field, string $rule): array
{ {
@ -37,13 +37,10 @@ class UserController extends AdminController
return parent::getFormRule($action, $field, $rule); return parent::getFormRule($action, $field, $rule);
} }
//Index,FieldForm관련. //Index,FieldForm관련.
protected function create_process(string $action, array $viewDatas): string|RedirectResponse protected function create_process(): UserEntity
{ {
//요청 데이터를 DTO 객체로 변환
$dto = new UserDTO($this->request->getPost()); $dto = new UserDTO($this->request->getPost());
$this->doValidation($action); return $this->service->create($dto);
$entity = $this->service->create($dto);
return redirect()
->route('admin/user/view', [$entity->getPK()])
->with('message', "{$entity->getTitle()} 계정이 등록되었습니다.");
} }
} }

View File

@ -8,6 +8,7 @@ use App\Entities\UserEntity;
use CodeIgniter\HTTP\RedirectResponse; use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface; use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Validation\Exceptions\ValidationException;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
abstract class AuthController extends CommonController abstract class AuthController extends CommonController
@ -20,35 +21,44 @@ abstract class AuthController extends CommonController
} }
abstract protected function login_process(): UserEntity; abstract protected function login_process(): UserEntity;
abstract protected function logout_process(): void; abstract protected function logout_process(): void;
//로그인화면 //로그인화면
public function login_form_process(array $viewDatas = []): array public function login_form_process(): void {}
{ final public function login_form(): string|RedirectResponse
return $viewDatas;
}
public function login_form(): string|RedirectResponse
{ {
$action = __FUNCTION__;
try { try {
//초기화 //초기화
$action = __FUNCTION__; $this->action_init_process($action);
$viewDatas = $this->action_init_process($action); $this->login_form_process();
$viewDatas = $this->login_form_process($viewDatas); $this->action_render_process($action);
return $this->action_post_process($action, $viewDatas); // dd($this->getViewDatas());
} catch (\Exception $e) { } catch (\Exception $e) {
$viewDatas[self::ACTION_RESULT] = 'error'; $this->addViewDatas(self::ACTION_RESULT, 'error');
$viewDatas[self::ACTION_MESSAGE] = $e->getMessage(); $this->addViewDatas(self::ACTION_MESSAGE, $e->getMessage());
return $this->action_post_process($action, $viewDatas); //오류발생시 리디렉션 대신 폼 뷰를 다시 렌더링하도록 action_view_process 호출
} }
return $this->action_result_process(
$this->getActionPaths(),
$action,
$this->getViewDatas()
);
} }
//로그인처리 //로그인처리
public function login(): RedirectResponse final public function login(): RedirectResponse
{ {
$action = __FUNCTION__;
try { try {
$action = __FUNCTION__; $this->action_init_process($action);
$viewDatas = $this->action_init_process($action);
$this->login_process(); $this->login_process();
return redirect()->to($this->authService->popPreviousUrl())->with('success', '로그인이 완료되었습니다.'); $redirect_url = $this->authService->popPreviousUrl() ?? implode(DIRECTORY_SEPARATOR, $this->getActionPaths());
return redirect()->to($redirect_url)->with('success', MESSAGES['LOGIN']);
} catch (ValidationException $e) {
// 검증 실패 시 폼으로 돌아가서 오류 메시지 표시
log_message('error', $e->getMessage());
return redirect()->back()->withInput()->with('errors', $e->getMessage());
} catch (\Exception $e) { } catch (\Exception $e) {
log_message('error', $e->getMessage());
return redirect()->back()->withInput()->with('error', $e->getMessage()); return redirect()->back()->withInput()->with('error', $e->getMessage());
// return redirect()->to($this->getMyAuth()->popPreviousUrl())->with('error', $e->getMessage()); // return redirect()->to($this->getMyAuth()->popPreviousUrl())->with('error', $e->getMessage());
} }
@ -59,10 +69,11 @@ abstract class AuthController extends CommonController
try { try {
$this->logout_process(); $this->logout_process();
// 홈페이지로 리다이렉트 // 홈페이지로 리다이렉트
return redirect()->route('/')->with('error', MESSAGES['LOGOUT']); $redirect_url = $this->authService->popPreviousUrl() ?? "/";
return redirect()->route($redirect_url)->with('error', MESSAGES['LOGOUT']);
} catch (\Exception $e) { } catch (\Exception $e) {
log_message("error", $e->getMessage()); log_message("error", $e->getMessage());
return redirect()->back()->with('error', "로그아웃 중 오류가 발생했습니다."); return redirect()->back()->withInput()->with('error', "로그아웃 중 오류가 발생했습니다.");
} }
} }
} }

View File

@ -22,17 +22,16 @@ class GoogleController extends AuthController
} }
$this->addActionPaths(self::PATH); $this->addActionPaths(self::PATH);
} }
public function login_form_process(array $viewDatas = []): array public function login_form_process(): void
{ {
//구글 로그인 BUTTON용 //구글 로그인 BUTTON용
$viewDatas['SNSButton'] = anchor($this->service->socket->createAuthUrl(), ICONS['GOOGLE'] . 'Google 로그인', ["class" => "btn-google"]); $this->addViewDatas('SNSButton', anchor($this->service->socket->createAuthUrl(), ICONS['GOOGLE'] . 'Google 로그인', ["class" => "btn-google"]));
return $viewDatas;
} }
//로그인처리 //로그인처리
protected function login_process(): UserEntity protected function login_process(): UserEntity
{ {
$formDatas = $this->doValidation(__FUNCTION__); $formDatas = $this->doValidation($this->getViewDatas('action'));
if (!array_key_exists('access_code', $formDatas) || !$formDatas['access_code']) { if (!array_key_exists('access_code', $formDatas) || !$formDatas['access_code']) {
throw new \Exception("구글 로그인 실패"); throw new \Exception("구글 로그인 실패");
} }

View File

@ -2,6 +2,7 @@
namespace App\Controllers\Auth; namespace App\Controllers\Auth;
use App\DTOs\Auth\LocalDTO;
use App\Entities\UserEntity; use App\Entities\UserEntity;
use App\Services\Auth\LocalService; use App\Services\Auth\LocalService;
use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\RequestInterface;
@ -26,8 +27,9 @@ class LocalController extends AuthController
//로그인처리 //로그인처리
protected function login_process(): UserEntity protected function login_process(): UserEntity
{ {
$formDatas = $this->doValidation(__FUNCTION__); //요청 데이터를 DTO 객체로 변환
return $this->service->login($formDatas); $dto = new LocalDTO($this->request->getPost());
return $this->service->login($dto);
} }
protected function logout_process(): void protected function logout_process(): void
{ {

View File

@ -3,14 +3,13 @@
namespace App\Controllers; namespace App\Controllers;
use App\Controllers\BaseController; use App\Controllers\BaseController;
use App\DTOs\AuthDTO; use App\DTOs\CertificationDTO;
use App\Services\CommonService;
use App\Traits\LogTrait; use App\Traits\LogTrait;
use CodeIgniter\HTTP\DownloadResponse; use CodeIgniter\HTTP\DownloadResponse;
use CodeIgniter\HTTP\RedirectResponse; use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface; use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Validation\Validation; use CodeIgniter\Validation\Exceptions\ValidationException;
use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Html; use PhpOffice\PhpSpreadsheet\Reader\Html;
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf; use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf;
@ -19,30 +18,45 @@ use Psr\Log\LoggerInterface;
abstract class CommonController extends BaseController abstract class CommonController extends BaseController
{ {
use LogTrait; use LogTrait;
protected const ACTION_PATH = "action_path"; const ACTION_RESULT = "action_result";
protected const ACTION_VIEW_FILE = "action_view_file"; const ACTION_MESSAGE = "action_message";
protected const ACTION_RESULT = "action_result";
protected const ACTION_MESSAGE = "action_message";
private array $_action_paths = []; private array $_action_paths = [];
protected $authService = null; private array $_viewDatas = [];
protected $service = null; protected $service = null;
protected $myAuth = null; protected $authService = null;
protected $myCertification = null;
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger) public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
{ {
parent::initController($request, $response, $logger); parent::initController($request, $response, $logger);
//로그인관련 //로그인관련
$this->authService = service('myauth'); $this->authService = service('myauth');
$this->myAuth = AuthDTO::fromByAuthService($this->authService); $this->myCertification = CertificationDTO::fromByAuthService($this->authService);
}
protected function getLayout(): string
{
return 'empty';
} }
final public function addActionPaths(string $path) final public function addActionPaths(string $path)
{ {
$this->_action_paths[] = $path; $this->_action_paths[] = $path;
} }
final public function getActionPaths(): array final public function getActionPaths($isArray = true, $delimeter = DIRECTORY_SEPARATOR): array|string
{ {
return $this->_action_paths; return $isArray ? $this->_action_paths : implode($delimeter, $this->_action_paths);
} }
final protected function doValidation(string $action): array final public function addViewDatas(string $key, mixed $value)
{
$this->_viewDatas[$key] = $value;
}
final public function getViewDatas(?string $key = null): mixed
{
if ($key === null) {
return $this->_viewDatas;
}
return $this->_viewDatas[$key] ?? null;
}
//공통 필수기능
protected function doValidation(string $action): array
{ {
$dynamicRules = []; $dynamicRules = [];
foreach ($this->service->getFormRules($action) as $field => $rule) { foreach ($this->service->getFormRules($action) as $field => $rule) {
@ -58,7 +72,6 @@ abstract class CommonController extends BaseController
} }
return $this->validator->getValidated(); return $this->validator->getValidated();
} }
//공통 필수기능
protected function getFormRule(string $action, string $field, string $rule): array protected function getFormRule(string $action, string $field, string $rule): array
{ {
switch ($field) { switch ($field) {
@ -67,85 +80,83 @@ abstract class CommonController extends BaseController
} }
return array($field, $rule); return array($field, $rule);
} }
protected function action_init_process(string $action, array $viewDatas = []): array protected function action_init_process(string $action): void
{ {
$viewDatas['action'] = $action; $this->addViewDatas('action', $action);
$viewDatas[self::ACTION_PATH] = $this->getActionPaths(); $this->addViewDatas('myCertification', $this->myCertification);
$viewDatas[self::ACTION_VIEW_FILE] = $this->request->getVar('ActionTemplate') ?? $viewDatas['action']; $this->addViewDatas('layout', $this->getLayout());
$viewDatas['formFields'] = $this->service->getFormFields(); $this->addViewDatas('serviceForm', $this->service->getFormService());
$viewDatas['formFilters'] = $this->service->getFormFilters(); $this->addViewDatas('formFields', $this->service->getFormFields());
$viewDatas['formRules'] = $this->service->getFormRules($viewDatas['action']); $this->addViewDatas('formFilters', $this->service->getFormFilters());
$viewDatas['formOptions'] = $this->service->getFormOptions($viewDatas['action']); $this->addViewDatas('formRules', $this->service->getFormRules($action));
return $viewDatas; $this->addViewDatas('formOptions', $this->service->getFormOptions($action));
} }
protected function action_post_process(string $action, array $viewDatas): string|RedirectResponse protected function action_render_process(string $action): void
{
$this->addViewDatas('helper', $this->service->getHelper($action, $this->getViewDatas()));
}
protected function action_result_process(array $view_paths, string $view_file, array $viewDatas): string
{ {
$view_paths = array_key_exists(self::ACTION_PATH, $viewDatas) ? $viewDatas[self::ACTION_PATH] : $this->getActionPaths();
$lastest_path = array_pop($view_paths); //paths는 마지막을 뺀 앞단까지만 남음 $lastest_path = array_pop($view_paths); //paths는 마지막을 뺀 앞단까지만 남음
switch ($action) { // ✅ 중간 안내 화면으로
case 'create_form': // return view('posts/success_redirect', [
case 'modify_form': // 'message' => '게시글이 성공적으로 등록되었습니다.',
case 'login_form': // 'redirectUrl' => route_to('posts_list')
// ✅ 중간 안내 화면으로 // ]);
// return view('posts/success_redirect', [ // 중요한 작업 (결제 완료, 오류 등) → “로딩 페이지(View)”로 안내 후 JS redirect
// 'message' => '게시글이 성공적으로 등록되었습니다.', $full_path = implode(DIRECTORY_SEPARATOR, [
// 'redirectUrl' => route_to('posts_list') ...$view_paths,
// ]); $this->request->getVar('ActionTemplate') ?? $lastest_path,
// 중요한 작업 (결제 완료, 오류 등) → “로딩 페이지(View)”로 안내 후 JS redirect $view_file
$full_path = implode(DIRECTORY_SEPARATOR, [ ]);
...$view_paths, $view_datas = [
$this->request->getVar('ActionTemplate') ?? $lastest_path, 'control' => $viewDatas,
array_key_exists(self::ACTION_VIEW_FILE, $viewDatas) ? $viewDatas[self::ACTION_VIEW_FILE] : $action 'forms' => ['attributes' => ['method' => "post",], 'hiddens' => []],
]); ];
$view_datas = [ helper(['form', __FUNCTION__]);
'control' => $viewDatas, return view($full_path, ['viewDatas' => $view_datas]);
'forms' => ['attributes' => ['method' => "post",], 'hiddens' => []],
];
helper(['form', __FUNCTION__]);
$result = view($full_path, ['viewDatas' => $view_datas]);
break;
default:
// ✅ Flashdata로 성공 메시지 저장
// 일반 CRUD (create/update/delete) → Flashdata + redirect()
$message = array_key_exists(self::ACTION_MESSAGE, $viewDatas) ?: static::class . "/{$action}이 완료되었습니다.";
session()->setFlashdata($viewDatas[self::ACTION_RESULT], $message);
$result = redirect()->route(implode(DIRECTORY_SEPARATOR, $view_paths))->with('message', $message);
break;
}
return $result;
} }
protected function create_form_process(array $viewDatas): array protected function create_form_process(): void {}
{ final public function create_form(): string|RedirectResponse
return $viewDatas;
}
public function create_form(): string|RedirectResponse
{ {
$action = __FUNCTION__;
try { try {
//초기화 //초기화
$action = __FUNCTION__; $this->action_init_process($action);
$viewDatas = $this->action_init_process($action); $this->create_form_process();
$viewDatas = $this->create_form_process($viewDatas); $this->action_render_process($action);
return $this->action_post_process($action, $viewDatas); // dd($this->getViewDatas());
} catch (\Exception $e) { } catch (\Exception $e) {
$viewDatas[self::ACTION_RESULT] = 'error'; log_message('error', $e->getMessage());
$viewDatas[self::ACTION_MESSAGE] = $e->getMessage(); $this->addViewDatas(self::ACTION_RESULT, 'error');
//리디렉션 대신 폼 뷰를 다시 렌더링하도록 form_post_process 호출 $this->addViewDatas(self::ACTION_MESSAGE, $e->getMessage());
return $this->action_post_process($action, $viewDatas); //오류발생시 리디렉션 대신 폼 뷰를 다시 렌더링하도록 action_view_process 호출
} }
return $this->action_result_process(
$this->getActionPaths(),
$action,
$this->getViewDatas()
);
} }
protected function create_process(string $action, array $viewDatas): string|RedirectResponse protected function create_process(): mixed
{ {
$this->doValidation($action); return $this->service->create();
return $this->action_post_process($action, $viewDatas);
} }
public function create(): string|RedirectResponse final public function create(): RedirectResponse
{ {
$action = __FUNCTION__;
try { try {
//초기화 //초기화
$action = __FUNCTION__; $this->action_init_process($action);
$viewDatas = $this->action_init_process($action); $this->create_process();
return $this->create_process($action, $viewDatas); $redirect_url = $this->authService->popPreviousUrl() ?? implode(DIRECTORY_SEPARATOR, $this->getActionPaths());
return redirect()->to($redirect_url)->with('success', static::class . "/{$action}이 완료되었습니다.");
} catch (ValidationException $e) {
// 검증 실패 시 폼으로 돌아가서 오류 메시지 표시
log_message('error', $e->getMessage());
return redirect()->back()->withInput()->with('errors', $e->getMessage());
} catch (\Exception $e) { } catch (\Exception $e) {
log_message('error', $e->getMessage());
return redirect()->back()->withInput()->with('error', $e->getMessage()); return redirect()->back()->withInput()->with('error', $e->getMessage());
} }
} }

13
app/DTOs/Auth/AuthDTO.php Normal file
View File

@ -0,0 +1,13 @@
<?php
namespace App\DTOs\Auth;
use App\DTOs\CommonDTO;
abstract class AuthDTO extends CommonDTO
{
public function __construct()
{
parent::__construct();
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\DTOs\Auth;
class GoogleDTO extends AuthDTO
{
public $access_code = null;
public function __construct(array $datas = [])
{
parent::__construct();
foreach ($datas as $key => $value) {
if (property_exists($this, $key)) {
$this->{$key} = $value;
}
}
}
public function toArray(): array
{
return [
'access_code' => $this->access_code,
];
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\DTOs\Auth;
class LocalDTO extends AuthDTO
{
public ?string $id = null;
public ?string $passwd = null;
public function __construct(array $datas = [])
{
parent::__construct();
foreach ($datas as $key => $value) {
if (property_exists($this, $key)) {
$this->{$key} = $value;
}
}
}
public function toArray(): array
{
return [
'id' => $this->id,
'passwd' => $this->passwd,
];
}
}

View File

@ -1,26 +0,0 @@
<?php
namespace App\DTOs;
use App\Services\Auth\AuthService;
class AuthDTO extends CommonDTO
{
public function __construct(
public bool $isLogin,
public ?int $uid = null,
public ?string $name = null,
public ?string $role = null
) {
parent::__construct();
}
public static function fromByAuthService(AuthService $service): self
{
return new self(
$service->isLoggedIn(),
$service->getUID(),
$service->getName(),
$service->getRole(),
);
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\DTOs;
use App\Services\Auth\AuthService;
class CertificationDTO extends CommonDTO
{
public bool $isLogin = false;
public ?int $uid = null;
public ?string $name = null;
public ?string $role = null;
public function __construct(array $datas = [])
{
parent::__construct();
foreach ($datas as $key => $value) {
if (property_exists($this, $key)) {
$this->{$key} = $value;
}
}
}
public static function fromByAuthService(AuthService $service): self
{
return new self(
[
'isLogin' => $service->isLoggedIn(),
'uid' => $service->getUID(),
'name' => $service->getName(),
'role' => $service->getRole(),
]
);
}
}

View File

@ -5,24 +5,34 @@ namespace App\DTOs;
class UserDTO extends CommonDTO class UserDTO extends CommonDTO
{ {
public ?int $uid = null; public ?int $uid = null;
public ?string $name = null; public ?string $id = null;
public ?string $passwd = null;
public ?string $passwd_confirm = null;
public ?string $email = null;
public ?string $mobile = null;
public ?string $role = null; public ?string $role = null;
public ?string $status = null;
public function __construct(array $datas = []) public function __construct(array $datas = [])
{ {
parent::__construct();
foreach ($datas as $key => $value) { foreach ($datas as $key => $value) {
if (property_exists($this, $key)) { if (property_exists($this, $key)) {
$this->{$key} = $value; $this->{$key} = $value;
} }
} }
} }
public function toArray(): array public function toArray(): array
{ {
return [ return [
'uid' => $this->uid, 'uid' => $this->uid,
'title' => $this->name, 'id' => $this->id,
'passwd' => $this->passwd,
'passwd_confirm' => $this->passwd_confirm,
'email' => $this->email,
'mobile' => $this->mobile,
'role' => $this->role, 'role' => $this->role,
'status' => $this->status,
]; ];
} }
} }

View File

@ -28,30 +28,13 @@ abstract class CommonForm
} }
return $rules; return $rules;
} }
final public function getFormOptions(string $class_path, string $action, array $fields, array $options = []): array final public function getFormOptions(string $action, array $fields, array $options = []): array
{ {
foreach ($fields as $field) { foreach ($fields as $field) {
$options = $this->getFormOption($class_path, $action, $field, $options); $options = $this->getFormOption($action, $field, $options);
} }
return $options; return $options;
} }
final public function form_dropdown_common(string $field, mixed $value, array $viewDatas, array $extras = [], array $attributes = [], bool $isAll = false): string
{
// 필터 옵션이 없으면 빈 배열로 초기화
if (!array_key_exists($field, $viewDatas['control']['formOptions'])) {
return ""; // 필터 옵션이 없으면 빈 문자열 반환
}
$extra = "";
foreach ($extras as $extra_tag => $extra_value) {
$extra .= sprintf(" %s=\"%s\"", $extra_tag, $extra_value);
}
// $formOptions는 필터 옵션 배열로, key는 필터 엔티티의 PK, value는 필터 엔티티 객체
$html = sprintf("<select name=\"%s\" %s>", $field, $extra);
$html .= "<option value=\"\">" . lang("{$viewDatas['class_path']}.label.{$field}") . " 선택" . "</option>";
$html .= $this->form_dropdown_common_process($field, $value, $viewDatas, $extras, $attributes, $isAll);
$html .= '</select>';
return $html;
}
//필수함수 //필수함수
public function getFormFilters(): array public function getFormFilters(): array
{ {
@ -119,7 +102,7 @@ abstract class CommonForm
} }
return $rules; return $rules;
} }
public function getFormOption(string $class_path, string $action, string $field, array $options = []): array public function getFormOption(string $action, string $field, array $options = []): array
{ {
switch ($field) { switch ($field) {
case 'user_uid': case 'user_uid':
@ -131,118 +114,13 @@ abstract class CommonForm
$option = $clientService->getEntities(); $option = $clientService->getEntities();
break; break;
default: default:
$option = lang($class_path . "." . strtoupper($field)); $option = lang($this->getAttribute('class_path') . "." . strtoupper($field));
break; break;
} }
if (!is_array($option)) { if (!is_array($option)) {
throw new \Exception(__FUNCTION__ . "에서 {$field}의 options 값들이 배열이 아닙니다.\n" . var_export($option, true)); throw new \Exception(static::class . DIRECTORY_SEPARATOR . __FUNCTION__ . "에서 {$field}의 options 값들이 배열이 아닙니다.\n" . var_export($option, true));
} }
$options[$field] = $option; $options[$field] = $option;
return $options; return $options;
} }
protected function form_dropdown_common_process(string $field, mixed $value, array $viewDatas, array $extras = [], array $attributes = [], bool $isAll = false): string
{
$html = "";
switch ($field) {
default:
foreach ($viewDatas['control']['formOptions'][$field] as $option_key => $option_value) {
$isSelected = $option_key == $value ? ' selected' : '';
$isDisabled = "";
$attribute = "";
$label = "";
if ($option_value instanceof CommonEntity) {
if ($option_key != $value && $option_value->getStatus() != $option_value::DEFAULT_STATUS && !$isAll) {
continue;
}
foreach ($attributes as $attribute_name => $attribute_value) {
$attribute .= sprintf(" %s=\"%s\"", $attribute_name, $option_value->$attribute_value);
}
$label = $option_value->getCustomTitle();
} else {
$label = $option_value;
}
$html .= sprintf("<option value=\"%s\"%s%s%s>%s</option>", $option_key, $isSelected, $isDisabled, $attribute, $label);
}
break;
}
return $html;
}
public function getFieldForm(string $field, mixed $value, array $viewDatas, array $extras = []): string
{
switch ($field) {
case 'email':
$form = form_input($field, $value ?? "", [
"class" => "form-control",
'style' => 'width:100%;',
"placeholder" => "예)test@example.com",
...$extras
]);
break;
case 'mobile':
case 'phone':
$form = form_input($field, $value ?? "", [
"class" => "form-control",
'style' => 'width:100%;',
"placeholder" => "예)010-0010-0010",
...$extras
]);
break;
case 'role':
if (!is_array($viewDatas['control']['formOptions'][$field])) {
throw new \Exception(__METHOD__ . "에서 {$field}의 field_options가 array형태가 아닙니다.");
}
// create, modify, create_form, modify_form일때 checkbox로 표시
if (in_array($viewDatas['control']['action'], ['create_form', 'modify_form'])) {
$forms = [];
foreach ($viewDatas['control']['formOptions'][$field] as $key => $label) {
if ($key !== '') { // 빈값은 제외
$values = is_array($value) ? $value : explode(DEFAULTS["DELIMITER_ROLE"], $value);
//form_check에는 "class" => "form-control" 쓰면 않되거나 form-check를 써야함
$forms[] = form_checkbox("{$field}[]", $key, in_array($key, $values), $extras) . $label;
}
}
$form = implode(" ", $forms);
} else {
$form = form_dropdown($field, $value, $viewDatas, $extras);
}
break;
case 'issue_at':
case 'expired_at':
case 'billing_at':
case 'start_at':
case 'end_at':
case 'updated_at':
case 'created_at':
case 'deleted_at':
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' calender' : 'calender';
$form = form_input($field, $value ?? "", $extras);
break;
case 'description':
case 'content':
case 'detail':
case 'history':
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' tinymce' : 'tinymce';
$form = form_textarea($field, html_entity_decode($value ?? "", ENT_QUOTES, 'UTF-8'), [
"class" => "form-control",
'style' => 'width:100%;',
...$extras
]);
break;
default:
if (in_array($field, $viewDatas['control']['formFilters'])) {
if (str_contains($field, "_uid")) {
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' select-field' : 'select-field';
}
$form = $this->form_dropdown_common($field, $value, $viewDatas, $extras);
} else {
$form = form_input($field, $value ?? "", [
"class" => "form-control",
'style' => 'width:100%;',
...$extras
]);
}
break;
}
return $form;
}
} }

View File

@ -105,25 +105,4 @@ class TrafficForm extends CommonForm
$options[$field] = $option; $options[$field] = $option;
return $options; return $options;
} }
public function getFieldForm(string $field, mixed $value, array $viewDatas, array $extras = []): string
{
switch ($field) {
case 'site':
$extras['onChange'] = "$('select[name=\'clientinfo_uid\']').select2('open')";
$form = $this->form_dropdown_common($field, $value, $viewDatas, $extras);
break;
case 'serverinfo_uid':
$extras['class'] = array_key_exists('class', $extras) ? $extras['class'] . ' select-field' : 'select-field';
$attributes = ['data-price' => 'price'];
$form = $this->form_dropdown_common($field, $value, $viewDatas, $extras, $attributes);
break;
case 'amount':
$form = form_input($field, 0, ["readonly" => "readonly", ...$extras]);
break;
default:
$form = parent::getFieldForm($field, $value, $viewDatas, $extras);
break;
}
return $form;
}
} }

View File

@ -75,17 +75,4 @@ class UserForm extends CommonForm
} }
return $rules; return $rules;
} }
public function getFieldForm(string $field, mixed $value, array $viewDatas, array $extras = []): string
{
switch ($field) {
case 'passwd':
case 'confirmpassword':
$form = form_password($field, "", [...$extras]);
break;
default:
$form = parent::getFieldForm($field, $value, $viewDatas, $extras);
break;
}
return $form;
} //
} }

View File

@ -2,14 +2,11 @@
namespace App\Helpers; namespace App\Helpers;
use App\Models\UserModel;
class AuthHelper extends CommonHelper class AuthHelper extends CommonHelper
{ {
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
$this->setTitleField(UserModel::TITLE);
} }
public function getFieldForm(string $field, mixed $value, array $viewDatas, array $extras = []): string public function getFieldForm(string $field, mixed $value, array $viewDatas, array $extras = []): string
{ {

View File

@ -4,44 +4,24 @@ namespace App\Helpers;
use App\Entities\CommonEntity; use App\Entities\CommonEntity;
use App\Traits\UtilTrait; use App\Traits\UtilTrait;
use RuntimeException;
class CommonHelper class CommonHelper
{ {
use UtilTrait; use UtilTrait;
private $_myAuth = null; private array $_attributes = [];
private $_viewDatas = [];
private $_titleField = "";
protected function __construct() {} protected function __construct() {}
final protected function getMyAuth(): mixed final public function setAttributes(array $attributes): void
{ {
if (!$this->_myAuth) { $this->_attributes = $attributes;
$this->_myAuth = service('myauth'); }
final public function getAttribute(string $key): string
{
if (!array_key_exists($key, $this->_attributes)) {
throw new RuntimeException(__METHOD__ . "에서 오류발생: {$key}에 해당하는 속성이 정의되지 않았습니다.");
} }
return $this->_myAuth; return $this->_attributes[$key];
} }
final public function setTitleField(string $field): void
{
$this->_titleField = $field;
}
final public function getTitleField(): string
{
if (!$this->_titleField) {
throw new \Exception("titleField가 지정되지 않았습니다.");
}
return $this->_titleField;
}
final public function setViewDatas(array $viewDatas): void
{
$this->_viewDatas = $viewDatas;
}
final public function getViewDatas(string $key)
{
if (!array_key_exists($key, $this->_viewDatas)) {
throw new \Exception("{$key}에 해당하는 ViewData가 존재하지 않습니다.");
}
return $this->_viewDatas[$key];
}
final public function form_dropdown_common(string $field, mixed $value, array $viewDatas, array $extras = [], array $attributes = [], bool $isAll = false): string final public function form_dropdown_common(string $field, mixed $value, array $viewDatas, array $extras = [], array $attributes = [], bool $isAll = false): string
{ {
// 필터 옵션이 없으면 빈 배열로 초기화 // 필터 옵션이 없으면 빈 배열로 초기화
@ -54,7 +34,7 @@ class CommonHelper
} }
// $formOptions는 필터 옵션 배열로, key는 필터 엔티티의 PK, value는 필터 엔티티 객체 // $formOptions는 필터 옵션 배열로, key는 필터 엔티티의 PK, value는 필터 엔티티 객체
$html = sprintf("<select name=\"%s\" %s>", $field, $extra); $html = sprintf("<select name=\"%s\" %s>", $field, $extra);
$html .= "<option value=\"\">" . lang("{$viewDatas['class_path']}.label.{$field}") . " 선택" . "</option>"; $html .= "<option value=\"\">" . lang("{$this->getAttribute('class_path')}.label.{$field}") . " 선택" . "</option>";
$html .= $this->form_dropdown_common_process($field, $value, $viewDatas, $extras, $attributes, $isAll); $html .= $this->form_dropdown_common_process($field, $value, $viewDatas, $extras, $attributes, $isAll);
$html .= '</select>'; $html .= '</select>';
return $html; return $html;
@ -93,7 +73,7 @@ class CommonHelper
default: default:
// required가 있으면 class 추가 // required가 있으면 class 추가
$extras = (strpos($viewDatas['control']['formRules'][$field], 'required') !== false) ? ["class" => "text-danger", "required" => "", ...$extras] : $extras; $extras = (strpos($viewDatas['control']['formRules'][$field], 'required') !== false) ? ["class" => "text-danger", "required" => "", ...$extras] : $extras;
$label = form_label($label, $field, ['class' => 'form-label-sm', ...$extras]); $label = $label ?: form_label(lang("{$this->getAttribute('class_path')}.label.{$field}"), $field, ['class' => 'form-label-sm', ...$extras]);
break; break;
} }
return $label; return $label;

View File

@ -2,14 +2,11 @@
namespace App\Helpers; namespace App\Helpers;
use App\Models\UserModel;
class UserHelper extends CommonHelper class UserHelper extends CommonHelper
{ {
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
$this->setTitleField(UserModel::TITLE);
} }
public function getFieldForm(string $field, mixed $value, array $viewDatas, array $extras = []): string public function getFieldForm(string $field, mixed $value, array $viewDatas, array $extras = []): string
{ {

View File

@ -1,38 +0,0 @@
<?php
if (! function_exists('render_field_form')) {
/**
* 필드를 렌더링하고 유효성 검사 오류를 포함합니다.
* ServiceService에서 가져오던 로직을 여기로 옮깁니다.
*/
function render_field_form(string $field, $value, array $viewDatas): string
{
$service = $viewDatas['service'] ?? null;
if ($service === null) {
return __FUNCTION__ . "에서 오류발생: ViewDatas에 'service'가 정의되지 않았습니다.";
}
$formHelper = $service->getFormService();
$html = $formHelper->getSpecificFieldHtml($field, $value, $viewDatas);
$error = validation_show_error($field);
return $html . "<span>{$error}</span>";
}
if (! function_exists('render_field_label')) {
function render_field_label(string $field, array $viewDatas): string
{
$classPath = $viewDatas['class_path'];
$baseLabel = lang("{$classPath}.label.{$field}");
// 1. ServiceForm에서 동적 처리(예: 도움말 아이콘, 별도 클래스)를 가져옵니다.
$service = $viewDatas['service'] ?? null;
if ($service === null) {
return __FUNCTION__ . "에서 오류발생: ViewDatas에 'service'가 정의되지 않았습니다.";
}
$formHelper = $service->getFormHelper();
$dynamicHtml = $formHelper->getSpecificLabelAdornment($field);
// 2. 공통 로직: 필수 필드 표시 (*)
// (ServiceForm이 해당 필드가 필수인지 알려줘야 함)
$isRequired = $formHelper->isFieldRequired($field);
$requiredStar = $isRequired ? '<span class="text-danger">*</span>' : '';
return "{$baseLabel}{$requiredStar}{$dynamicHtml}";
}
}
}

View File

@ -3,6 +3,7 @@
namespace App\Services\Auth; namespace App\Services\Auth;
use App\Entities\UserEntity; use App\Entities\UserEntity;
use App\Helpers\AuthHelper;
use App\Models\CommonModel; use App\Models\CommonModel;
use App\Services\CommonService; use App\Services\CommonService;
use CodeIgniter\Session\Session; use CodeIgniter\Session\Session;
@ -16,13 +17,27 @@ abstract class AuthService extends CommonService
protected function __construct(CommonModel $model) protected function __construct(CommonModel $model)
{ {
parent::__construct($model); parent::__construct($model);
$this->addClassPath('Auth'); $this->addClassPaths('Auth');
}
abstract public function login(mixed $dto): UserEntity;
final public function getHelper(): AuthHelper
{
if ($this->helperInstance === null) {
$this->helperInstance = new AuthHelper();
$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)
]);
}
return $this->helperInstance;
} }
abstract public function login(array $formDatas): UserEntity;
//Index,FieldForm관련 //Index,FieldForm관련
final public function getSession(): Session final public function getSession(): Session
{ {
if (!$this->_session) { if ($this->_session === null) {
$this->_session = \Config\Services::session(); $this->_session = \Config\Services::session();
} }
return $this->_session; return $this->_session;

View File

@ -2,31 +2,34 @@
namespace App\Services\Auth; namespace App\Services\Auth;
use App\DTOs\Auth\GoogleDTO;
use App\DTOs\AuthDTO;
use App\Entities\UserEntity; use App\Entities\UserEntity;
use App\Forms\Auth\GoogleForm; use App\Forms\Auth\GoogleForm;
use App\Libraries\MySocket\GoogleSocket\CURL; use App\Libraries\MySocket\GoogleSocket\CURL;
use App\Models\UserModel; use App\Models\UserModel;
use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\Validation\Exceptions\ValidationException;
use RuntimeException;
class GoogleService extends AuthService class GoogleService extends AuthService
{ {
public function __construct(UserModel $model, private GoogleForm $formService, private CURL $socket) public function __construct(UserModel $model, private CURL $socket)
{ {
parent::__construct($model); parent::__construct($model);
$this->formServiceInstance = $this->formService; $this->addClassPaths('Google');
// FormService에 Model 메타데이터를 설정
$this->formServiceInstance->setAttributes([
'pk_field' => $this->model->getPKField(),
'title_field' => $this->model->getTitleField(),
'table' => $this->model->getTable(),
'useAutoIncrement' => $this->model->useAutoIncrement(),
]);
$this->addClassPath('Google');
} }
public function getFormService(): GoogleForm public function getFormService(): GoogleForm
{ {
if ($this->formServiceInstance === null) { if ($this->formServiceInstance === null) {
throw new \RuntimeException('FormService는 ' . static::class . '에서 초기화되어야 합니다.'); $this->formServiceInstance = new GoogleForm();
$this->formServiceInstance->setAttributes([
'pk_field' => $this->model->getPKField(),
'title_field' => $this->model->getTitleField(),
'table' => $this->model->getTable(),
'useAutoIncrement' => $this->model->useAutoIncrement(),
'class_path' => $this->getClassPaths(false)
]);
} }
return $this->formServiceInstance; return $this->formServiceInstance;
} }
@ -43,11 +46,19 @@ class GoogleService extends AuthService
return []; return [];
} }
//기본기능 //기본기능
public function login(array $formDatas): UserEntity public function login(mixed $dto): UserEntity
{ {
try { try {
// Google 서비스 설정 if (!$dto instanceof GoogleDTO) {
$this->socket->setToken($formDatas['access_code']); 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);
$sns_entity = $this->socket->signup(); $sns_entity = $this->socket->signup();
// local db 사용와의 연결 확인 // local db 사용와의 연결 확인
$entity = $this->getEntity($sns_entity->getParent()); $entity = $this->getEntity($sns_entity->getParent());

View File

@ -2,31 +2,31 @@
namespace App\Services\Auth; namespace App\Services\Auth;
use App\DTOs\Auth\LocalDTO;
use App\Entities\UserEntity; use App\Entities\UserEntity;
use App\Forms\Auth\LocalForm; use App\Forms\Auth\LocalForm;
use App\Models\UserModel; use App\Models\UserModel;
use CodeIgniter\Validation\Exceptions\ValidationException;
use RuntimeException;
class LocalService extends AuthService class LocalService extends AuthService
{ {
public function __construct( public function __construct(UserModel $model)
UserModel $model, {
private LocalForm $formService,
) {
parent::__construct($model); parent::__construct($model);
$this->formServiceInstance = $this->formService; $this->addClassPaths('Local');
// FormService에 Model 메타데이터를 설정
$this->formServiceInstance->setAttributes([
'pk_field' => $this->model->getPKField(),
'title_field' => $this->model->getTitleField(),
'table' => $this->model->getTable(),
'useAutoIncrement' => $this->model->useAutoIncrement(),
]);
$this->addClassPath('Local');
} }
public function getFormService(): LocalForm public function getFormService(): LocalForm
{ {
if ($this->formServiceInstance === null) { if ($this->formServiceInstance === null) {
throw new \RuntimeException('FormService는 ' . static::class . '에서 초기화되어야 합니다.'); $this->formServiceInstance = new LocalForm();
$this->formServiceInstance->setAttributes([
'pk_field' => $this->model->getPKField(),
'title_field' => $this->model->getTitleField(),
'table' => $this->model->getTable(),
'useAutoIncrement' => $this->model->useAutoIncrement(),
'class_path' => $this->getClassPaths(false)
]);
} }
return $this->formServiceInstance; return $this->formServiceInstance;
} }
@ -43,17 +43,22 @@ class LocalService extends AuthService
return []; return [];
} }
//기본기능 //기본기능
public function login(array $formDatas): UserEntity public function login(mixed $dto): UserEntity
{ {
$entity = $this->getEntity([ if (!$dto instanceof LocalDTO) {
'id' => $formDatas['id'], throw new RuntimeException(__METHOD__ . "에서 오류발생: LcoalDTO만 사용하실수 있습니다");
'status' => UserEntity::DEFAULT_STATUS
], false);
if (!$entity instanceof UserEntity) {
throw new \Exception("{$formDatas['id']}에 대한 로그인 정보를 찾을수 없습니다.");
} }
if (!password_verify($formDatas['passwd'], $entity->getPassword())) { // DTO 객체를 배열로 변환하여 검증기에 전달
// log_message("error", "암호: {$formDatas['passwd']}, {$entity->passwd}"); $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);
if (!$entity instanceof UserEntity) {
throw new \Exception("{$dto->id}에 대한 로그인 정보를 찾을수 없습니다.");
}
if (!password_verify($dto->passwd, $entity->getPassword())) {
throw new \Exception("암호가 맞지 않습니다."); throw new \Exception("암호가 맞지 않습니다.");
} }
return $this->login_process($entity); return $this->login_process($entity);

View File

@ -2,23 +2,23 @@
namespace App\Services; namespace App\Services;
use CodeIgniter\HTTP\RedirectResponse;
use App\Models\CommonModel; use App\Models\CommonModel;
abstract class CommonService abstract class CommonService
{ {
private $_logService = null; private array $_classPaths = [];
protected array $classPaths = [];
protected $formServiceInstance = null; protected $formServiceInstance = null;
protected $helperInstance = null;
protected function __construct(protected CommonModel $model) {} protected function __construct(protected CommonModel $model) {}
abstract public function getFormService(): mixed; abstract public function getFormService(): mixed;
final protected function addClassPath(string $className): void abstract public function getHelper(): mixed;
final protected function addClassPaths(string $path): void
{ {
$this->classPaths[] = $className; $this->_classPaths[] = $path;
} }
final public function getClassPath($delimeter = DIRECTORY_SEPARATOR): string final public function getClassPaths($isArray = true, $delimeter = DIRECTORY_SEPARATOR): array|string
{ {
return implode($delimeter, $this->classPaths); return $isArray ? $this->_classPaths : implode($delimeter, $this->_classPaths);
} }
final public function getEntity(string|int|array $where, ?string $message = null): mixed final public function getEntity(string|int|array $where, ?string $message = null): mixed
{ {
@ -76,11 +76,7 @@ abstract class CommonService
} }
public function getFormOptions(string $action): array public function getFormOptions(string $action): array
{ {
return $this->getFormService()->getFormOptions( return $this->getFormService()->getFormOptions($action, $this->getFormFilters());
$this->getClassPath(),
$action,
$this->getFormFilters()
);
} }
public function getViewFields(): array public function getViewFields(): array
{ {

View File

@ -12,26 +12,38 @@ class TrafficService extends CommonService
{ {
public function __construct( public function __construct(
TrafficModel $model, TrafficModel $model,
private TrafficForm $formService,
) { ) {
parent::__construct($model); parent::__construct($model);
$this->formServiceInstance = $this->formService; $this->addClassPaths('Traffic');
// FormService에 Model 메타데이터를 설정
$this->formServiceInstance->setAttributes([
'pk_field' => $this->model->getPKField(),
'title_field' => $this->model->getTitleField(),
'table' => $this->model->getTable(),
'useAutoIncrement' => $this->model->useAutoIncrement(),
]);
$this->addClassPath('Service');
} }
public function getFormService(): TrafficForm public function getFormService(): TrafficForm
{ {
if ($this->formServiceInstance === null) { if ($this->formServiceInstance === null) {
throw new \RuntimeException('FormService는 ' . static::class . '에서 초기화되어야 합니다.'); $this->formServiceInstance = new TrafficForm();
$this->formServiceInstance->setAttributes([
'pk_field' => $this->model->getPKField(),
'title_field' => $this->model->getTitleField(),
'table' => $this->model->getTable(),
'useAutoIncrement' => $this->model->useAutoIncrement(),
'class_path' => $this->getClassPaths(false)
]);
} }
return $this->formServiceInstance; return $this->formServiceInstance;
} }
public function getHelper(): TrafficHelper
{
if ($this->helperInstance === null) {
$this->helperInstance = new TrafficHelper();
$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)
]);
}
return $this->helperInstance;
}
//필수함수 //필수함수
// public function getNewServiceEntities(int $interval, string $status = ServiceEntity::DEFAULT_STATUS): array // public function getNewServiceEntities(int $interval, string $status = ServiceEntity::DEFAULT_STATUS): array
// { // {

View File

@ -2,114 +2,99 @@
namespace App\Services; namespace App\Services;
use App\DTOs\UserDTO;
use App\Entities\UserEntity; use App\Entities\UserEntity;
use App\Forms\UserForm; use App\Forms\UserForm;
use App\Helpers\UserHelper;
use App\Models\UserModel; use App\Models\UserModel;
use CodeIgniter\Validation\Exceptions\ValidationException;
use RuntimeException;
class UserService extends CommonService class UserService extends CommonService
{ {
public function __construct( public function __construct(UserModel $model)
UserModel $model, {
private UserForm $formService,
) {
parent::__construct($model); parent::__construct($model);
$this->formServiceInstance = $this->formService; $this->addClassPaths('User');
// FormService에 Model 메타데이터를 설정
$this->formServiceInstance->setAttributes([
'pk_field' => $this->model->getPKField(),
'title_field' => $this->model->getTitleField(),
'table' => $this->model->getTable(),
'useAutoIncrement' => $this->model->useAutoIncrement(),
]);
$this->addClassPath('Service');
} }
public function getFormService(): UserForm public function getFormService(): UserForm
{ {
if ($this->formServiceInstance === null) { if ($this->formServiceInstance === null) {
throw new \RuntimeException('FormService는 ' . static::class . '에서 초기화되어야 합니다.'); $this->formServiceInstance = new UserForm();
$this->formServiceInstance->setAttributes([
'pk_field' => $this->model->getPKField(),
'title_field' => $this->model->getTitleField(),
'table' => $this->model->getTable(),
'useAutoIncrement' => $this->model->useAutoIncrement(),
'class_path' => $this->getClassPaths(false)
]);
} }
return $this->formServiceInstance; return $this->formServiceInstance;
} }
public function getFormFields(): array public function getHelper(): UserHelper
{ {
return [ if ($this->helperInstance === null) {
'id', $this->helperInstance = new UserHelper();
'passwd', $this->helperInstance->setAttributes([
'confirmpassword', 'pk_field' => $this->model->getPKField(),
'name', 'title_field' => $this->model->getTitleField(),
'email', 'table' => $this->model->getTable(),
'mobile', 'useAutoIncrement' => $this->model->useAutoIncrement(),
'role', 'class_path' => $this->getClassPaths(false)
'status', ]);
]; }
} return $this->helperInstance;
public function getFormFilters(): array
{
return [
'role',
'status',
];
}
public function getIndexFields(): array
{
return [
'id',
'name',
'email',
'mobile',
'role',
'status',
];
}
public function getBatchjobFields(): array
{
return ['status'];
} }
//기본 기능부분 //기본 기능부분
public function create(UserDTO $dto): UserEntity
protected function create_process(array $formDatas): UserEntity
{ {
// DTO 객체를 배열로 변환하여 검증기에 전달
$formDatas = (array) $dto;
if (!service('validation')->setRules($this->getFormRules(__FUNCTION__))->run($formDatas)) {
// 검증 실패 시, ValidationException을 던집니다.
throw new ValidationException(implode("\n", service('validation')->getErrors()));
}
$formDatas['role'] = implode(DEFAULTS["DELIMITER_ROLE"], $formDatas['role']); $formDatas['role'] = implode(DEFAULTS["DELIMITER_ROLE"], $formDatas['role']);
$entity = $this->model->create($formDatas); $entity = $this->model->create($formDatas);
return $entity; return $entity;
} }
protected function modify_process(mixed $entity, array $formDatas): UserEntity // protected function modify_process(mixed $entity, array $formDatas): UserEntity
{ // {
// die(var_export($formDatas, true)); // // die(var_export($formDatas, true));
//암호를 입력하지 않았을시는 변경하기 않게 하기위함 // //암호를 입력하지 않았을시는 변경하기 않게 하기위함
if (isset($formDatas['passwd']) && $formDatas['passwd'] == "") { // if (isset($formDatas['passwd']) && $formDatas['passwd'] == "") {
unset($formDatas['passwd']); // unset($formDatas['passwd']);
unset($formDatas['confirmpassword']); // unset($formDatas['confirmpassword']);
} // }
//Role을 지정이 있을경우에만 , toggle이나 batcjhjob에서는 없을수도 있으므로 // //Role을 지정이 있을경우에만 , toggle이나 batcjhjob에서는 없을수도 있으므로
if (isset($formDatas['role'])) { // if (isset($formDatas['role'])) {
$formDatas['role'] = implode(DEFAULTS["DELIMITER_ROLE"], $formDatas['role']); // $formDatas['role'] = implode(DEFAULTS["DELIMITER_ROLE"], $formDatas['role']);
} // }
// die(var_export($formDatas, true)); // // die(var_export($formDatas, true));
$entity = parent::modify_process($entity, $formDatas); // $entity = parent::modify_process($entity, $formDatas);
return $entity; // return $entity;
} // }
//List 검색용 // //List 검색용
//FormFilter 조건절 처리 // //FormFilter 조건절 처리
public function index_condition_filterField(string $field, mixed $filter_value): void // public function index_condition_filterField(string $field, mixed $filter_value): void
{ // {
switch ($field) { // switch ($field) {
case 'role': // case 'role':
$where = "FIND_IN_SET(" . $this->model->escape($filter_value) . ", {$this->model->getTable()}.{$field}) > 0"; // $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를 꺼줘야 정상 작동 // //FIND_IN_SET()은 MySQL 함수이므로 CodeIgniter가 이를 일반 컬럼명으로 착각하고 escape하게 되면 오류가 발생합니다. 따라서 ->where($sql, null, false)로 명시하여 escape를 꺼줘야 정상 작동
$this->model->where($where, null, false); // $this->model->where($where, null, false);
break; // break;
default: // default:
parent::index_condition_filterField($field, $filter_value); // parent::index_condition_filterField($field, $filter_value);
break; // break;
} // }
} // }
//검색어조건절처리 // //검색어조건절처리
public function index_condition_filterWord(string $word): void // public function index_condition_filterWord(string $word): void
{ // {
$this->model->orLike($this->model->getTable() . '.id', $word, 'both'); // $this->model->orLike($this->model->getTable() . '.id', $word, 'both');
$this->model->orLike($this->model->getTable() . "." . $this->model::TITLE, $word, 'both'); // $this->model->orLike($this->model->getTable() . "." . $this->model->getTitleField(), $word, 'both');
$this->model->orLike($this->model->getTable() . '.email', $word, 'both'); // $this->model->orLike($this->model->getTable() . '.email', $word, 'both');
parent::index_condition_filterWord($word); // parent::index_condition_filterWord($word);
} // }
} }

View File

@ -0,0 +1,24 @@
<?= $this->extend(LAYOUTS[$viewDatas['control']['layout']]['path']) ?>
<?= $this->section('content') ?>
<?php if (session('error')): echo $viewDatas['control']['helper']->alertTrait(session('error')) ?><?php endif ?>
<div id="container" class="content">
<div class="form_top"><?= $this->include("templates/{$viewDatas['control']['layout']}/form_content_top"); ?></div>
<?= form_open(current_url(), $viewDatas['forms']['attributes'], $viewDatas['forms']['hiddens']) ?>
<div class="action_form">
<table class="table table-bordered">
<?php foreach ($viewDatas['control']['formFields'] as $field): ?>
<tr>
<th nowrap class="text-end"><?= $viewDatas['control']['helper']->getFieldLabel($field, "", $viewDatas) ?></th>
<td nowrap class="text-start">
<?= $viewDatas['control']['helper']->getFieldForm($field, old($field) ?? ($viewDatas['control']['formDatas'][$field] ?? null), $viewDatas) ?>
<span><?= validation_show_error($field); ?></span>
</td>
</tr>
<?php endforeach; ?>
</table>
<div class="text-center"><?= form_submit('', '입력', array("class" => "btn btn-outline btn-primary")); ?></div>
<?= form_close(); ?>
</div>
<div class="form_bottom"><?= $this->include("templates/{$viewDatas['control']['layout']}/form_content_bottom"); ?></div>
</div>
<?= $this->endSection() ?>

View File

@ -0,0 +1,21 @@
<table>
<thead>
<tr>
<?php foreach ($viewDatas['control']['formFields'] as $field): ?>
<th><?= lang("{$viewDatas['class_path']}.label.{$field}") ?></th>
<?php endforeach ?>
</tr>
</thead>
<tbody>
<?php $cnt = 0 ?>
<?php foreach ($viewDatas['entities'] as $entity): ?>
<?php $viewDatas['entity'] = $entity; ?>
<tr>
<?php foreach ($viewDatas['control']['formFields'] as $field): ?>
<td><?= $viewDatas['service']->getHelper()->getFieldView($field, $entity->$field, $viewDatas) ?></td>
<?php endforeach ?>
</tr>
<?php $cnt++ ?>
<?php endforeach ?>
</tbody>
</table>

View File

@ -0,0 +1,70 @@
<?= $this->extend(LAYOUTS[$viewDatas['control']['layout']]['path']) ?>
<?= $this->section('content') ?>
<?php if ($error = session('error')): echo $viewDatas['service']->getHelper()->alertTrait($error) ?><?php endif ?>
<div class="layout_top"><?= $this->include(LAYOUTS[$viewDatas['control']['layout']]['path'] . '/top'); ?></div>
<!-- Layout Middle Start -->
<table class="layout_middle">
<tr>
<td class="layout_left">
<!-- Layout Left Start -->
<?= $this->include(LAYOUTS[$viewDatas['control']['layout']]['path'] . '/left_menu'); ?>
<!-- Layout Left End -->
</td>
<td class="layout_right">
<!-- Layout Right Start -->
<div class="layout_header"><?= $this->include("templates/{$viewDatas['control']['layout']}/index_header"); ?></div>
<div id="container" class="layout_content">
<link href="/css/<?= $viewDatas['control']['layout'] ?>/index.css" media="screen" rel="stylesheet" type="text/css" />
<div class="index_body">
<?= form_open(current_url(), ["method" => "get"]) ?>
<nav class="index_top navbar navbar-expand-lg">
<div class="container-fluid">
<nav class="condition nav">
조건:
<?php foreach ($viewDatas['control']['formFilters'] as $field): ?>
<?= $viewDatas['service']->getHelper()->getListFilter($field, $viewDatas['control']['index_filters'][$field] ?? old($field), $viewDatas) ?>&nbsp;
<?php endforeach ?>
</nav>
<?= $this->include("templates/{$viewDatas['control']['layout']}/index_content_top"); ?>
</div>
</nav>
<?= form_close() ?>
<?= form_open(current_url(), ['id' => 'batchjob_form', 'method' => "post"]) ?>
<table class="index_table data table table-bordered table-hover table-striped" data-rtc-resizable-table="reisze_table">
<thead>
<tr>
<th class="index_head_short_column">번호</th>
<?php foreach ($viewDatas['control']['formFields'] as $field): ?>
<th data-rtc-resizable="<?= $field ?>"><?= $viewDatas['service']->getHelper()->getListLabel($field, lang("{$viewDatas['class_path']}.label.{$field}"), $viewDatas) ?></th>
<?php endforeach ?>
<th class="index_head_short_column">작업</th>
</thead>
<tbody>
<?php $cnt = 0 ?>
<?php foreach ($viewDatas['entities'] as $entity): ?>
<?php $viewDatas['entity'] = $entity; ?>
<tr <?= $viewDatas['entity']->getStatus() === $viewDatas['entity']::DEFAULT_STATUS ? "" : 'class="table-danger"' ?>>
<?php $num = $viewDatas['total_count'] - (($viewDatas['page'] - 1) * $viewDatas['per_page'] + $cnt); ?>
<td nowrap><?= $viewDatas['service']->getHelper()->getListButton('modify', $num, $viewDatas) ?></td>
<?php foreach ($viewDatas['control']['formFields'] as $field): ?>
<td><?= $viewDatas['service']->getHelper()->getFieldView($field, $entity->$field, $viewDatas) ?></td>
<?php endforeach ?>
<td nowrap>
<?= $viewDatas['service']->getHelper()->getListButton('view', '', $viewDatas) ?>&nbsp;
<?= $viewDatas['service']->getHelper()->getListButton('delete', '', $viewDatas) ?>
</td>
</tr>
<?php $cnt++ ?>
<?php endforeach ?>
</tbody>
</table>
<?= $this->include("templates/{$viewDatas['control']['layout']}/index_content_bottom"); ?>
<?= form_close() ?>
</div>
</div>
<div class="layout_footer"><?= $this->include("templates/{$viewDatas['control']['layout']}/index_footer"); ?></div>
</td>
</tr>
</table>
<div class="layout_bottom"><?= $this->include(LAYOUTS[$viewDatas['control']['layout']]['path'] . '/bottom'); ?></div>
<?= $this->endSection() ?>

View File

@ -0,0 +1,24 @@
<?= $this->extend(LAYOUTS[$viewDatas['control']['layout']]['path']) ?>
<?= $this->section('content') ?>
<?php if ($error = session('error')): echo $viewDatas['service']->getHelper()->alertTrait($error) ?><?php endif ?>
<div id="container" class="content">
<div class="form_top"><?= $this->include("templates/{$viewDatas['control']['layout']}/form_content_top"); ?></div>
<?= form_open(current_url(), ['id' => 'action_form', ...$viewDatas['forms']['attributes']], $viewDatas['forms']['hiddens']) ?>
<div class="action_form">
<table class="table table-bordered">
<?php foreach ($viewDatas['control']['formFields'] as $field): ?>
<tr>
<th nowrap class="text-end"><?= $viewDatas['service']->getHelper()->getFieldLabel($field, lang("{$viewDatas['class_path']}.label.{$field}"), $viewDatas) ?></th>
<td nowrap class="text-start">
<?= $viewDatas['service']->getHelper()->getFieldForm($field, old($field) ?? $viewDatas['entity']->$field ?? null, $viewDatas) ?>
<div><?= validation_show_error($field); ?></div>
</td>
</tr>
<?php endforeach; ?>
</table>
<div class="text-center"><?= form_submit("", '수정', ["class" => "btn btn-outline btn-primary"]) ?></div>
<?= form_close(); ?>
</div>
<div class="form_bottom"><?= $this->include("templates/{$viewDatas['control']['layout']}/form_content_bottom"); ?></div>
</div>
<?= $this->endSection() ?>

View File

@ -0,0 +1,17 @@
<?= $this->extend(LAYOUTS[$viewDatas['control']['layout']]['path']) ?>
<?= $this->section('content') ?>
<?php if ($error = session('error')): echo $viewDatas['service']->getHelper()->alertTrait($error) ?><?php endif ?>
<div id="container" class="content">
<link href="/css/<?= $viewDatas['control']['layout'] ?>/form.css" media="screen" rel="stylesheet" type="text/css" />
<div class="action_form">
<table class="table table-bordered">
<?php foreach ($viewDatas['control']['formFields'] as $field): ?>
<tr>
<th nowrap class="text-end" width="20%"><?= $viewDatas['service']->getHelper()->getFieldLabel($field, lang("{$viewDatas['class_path']}.label.{$field}"), $viewDatas) ?></th>
<td nowrap class="text-start"><?= $viewDatas['service']->getHelper()->getFieldView($field, $viewDatas['entity']->$field, $viewDatas) ?></td>
</tr>
<?php endforeach; ?>
</table>
</div>
</div>
<?= $this->endSection() ?>