220 lines
6.5 KiB
PHP
220 lines
6.5 KiB
PHP
<?php
|
|
// =========================================================
|
|
// AbstractWebController.php (FINAL)
|
|
// - runAction / okResponse / failResponse 내장
|
|
// - action_redirect_process: AJAX 방어 + 상태코드 정책 고정
|
|
// * warning/error => 400
|
|
// * critical/alert/emergency => 500
|
|
// * info/notice/debug/default => 200
|
|
// - RedirectResponse|ResponseInterface로 엄격 정리
|
|
// =========================================================
|
|
|
|
namespace App\Controllers;
|
|
|
|
use App\Libraries\AuthContext;
|
|
use App\Traits\LogTrait;
|
|
use CodeIgniter\Controller;
|
|
use CodeIgniter\HTTP\RedirectResponse;
|
|
use CodeIgniter\HTTP\RequestInterface;
|
|
use CodeIgniter\HTTP\ResponseInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
use App\Exceptions\FormValidationException;
|
|
|
|
abstract class AbstractWebController extends Controller
|
|
{
|
|
use LogTrait;
|
|
|
|
private array $_action_paths = [];
|
|
private array $_viewDatas = [];
|
|
private ?string $_title = null;
|
|
|
|
protected $layouts = [];
|
|
protected $service = null;
|
|
|
|
// --- 초기화 및 DI ---
|
|
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
|
|
{
|
|
parent::initController($request, $response, $logger);
|
|
helper('util');
|
|
}
|
|
|
|
final protected function getAuthContext(): AuthContext
|
|
{
|
|
return service('myauth')->getAuthContext();
|
|
}
|
|
|
|
protected function getTitle(): string
|
|
{
|
|
if ($this->_title === null) {
|
|
$this->_title = lang("{$this->service->getClassPaths(false)}.title");
|
|
}
|
|
return $this->_title;
|
|
}
|
|
|
|
// --- 경로 및 뷰 데이터 관리 ---
|
|
final protected function addActionPaths(string $path): void
|
|
{
|
|
$this->_action_paths[] = $path;
|
|
}
|
|
|
|
final protected function getActionPaths($isArray = true, $delimeter = DIRECTORY_SEPARATOR): array|string
|
|
{
|
|
return $isArray ? $this->_action_paths : implode($delimeter, $this->_action_paths);
|
|
}
|
|
|
|
final protected function addViewDatas(string $key, mixed $value): void
|
|
{
|
|
$this->_viewDatas[$key] = $value;
|
|
}
|
|
|
|
final protected function getViewDatas(?string $key = null): mixed
|
|
{
|
|
if ($key === null)
|
|
return $this->_viewDatas;
|
|
return $this->_viewDatas[$key] ?? null;
|
|
}
|
|
|
|
// --- 공통 처리 로직 (Override 가능) ---
|
|
protected function action_init_process(string $action, array $formDatas = []): void
|
|
{
|
|
$this->addViewDatas('action', $action);
|
|
$this->addViewDatas('authContext', $this->getAuthContext());
|
|
$this->addViewDatas('classPath', $this->service->getClassPaths(false));
|
|
$this->addViewDatas('uri', $this->request->getUri());
|
|
}
|
|
|
|
/**
|
|
* action_redirect_process
|
|
* ✅ AJAX 요청이면 RedirectResponse 대신 JSON으로 변환(방어)
|
|
*
|
|
* 상태코드 정책(고정):
|
|
* - warning/error => 400
|
|
* - critical/alert/emergency => 500
|
|
* - info/notice/debug/default => 200
|
|
*/
|
|
protected function action_redirect_process(string $type, string $message, ?string $redirect_url = null): RedirectResponse|ResponseInterface
|
|
{
|
|
$resolvedRedirect = $redirect_url
|
|
?? $this->getAuthContext()->popPreviousUrl()
|
|
?? implode(DIRECTORY_SEPARATOR, $this->getActionPaths());
|
|
|
|
if ($this->request->isAJAX()) {
|
|
$error400 = ['warning', 'error'];
|
|
$error500 = ['critical', 'alert', 'emergency'];
|
|
|
|
if (in_array($type, $error400, true)) {
|
|
log_message($type, $message);
|
|
return $this->response->setStatusCode(400)->setJSON([
|
|
'ok' => false,
|
|
'message' => $message,
|
|
'redirect' => $resolvedRedirect,
|
|
]);
|
|
}
|
|
|
|
if (in_array($type, $error500, true)) {
|
|
log_message($type, $message);
|
|
return $this->response->setStatusCode(500)->setJSON([
|
|
'ok' => false,
|
|
'message' => $message,
|
|
'redirect' => $resolvedRedirect,
|
|
]);
|
|
}
|
|
|
|
return $this->response->setStatusCode(200)->setJSON([
|
|
'ok' => true,
|
|
'message' => $message,
|
|
'redirect' => $resolvedRedirect,
|
|
]);
|
|
}
|
|
|
|
switch ($type) {
|
|
case 'warning':
|
|
case 'error':
|
|
case 'critical':
|
|
case 'alert':
|
|
case 'emergency':
|
|
log_message($type, $message);
|
|
return redirect()->back()->withInput()->with('message', $message);
|
|
|
|
case 'debug':
|
|
case 'info':
|
|
case 'notice':
|
|
default:
|
|
return redirect()->to($resolvedRedirect)->with('message', $message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 뷰 렌더링
|
|
*/
|
|
protected function action_render_process(string $view_file, array $viewDatas, ?string $template_path = null): string
|
|
{
|
|
helper(['form', 'utility']);
|
|
|
|
$baseViewPath = trim($viewDatas['layout']['path'], '/');
|
|
if ($template_path)
|
|
$baseViewPath .= '/' . trim($template_path, '/');
|
|
|
|
$viewName = $baseViewPath . '/' . ltrim($view_file, '/');
|
|
|
|
return view($viewName, [
|
|
'viewDatas' => [
|
|
...$viewDatas,
|
|
'forms' => [
|
|
'attributes' => ['method' => 'post'],
|
|
'hiddens' => [],
|
|
],
|
|
],
|
|
]);
|
|
}
|
|
|
|
// =========================================================
|
|
// 공통화: runAction / okResponse / failResponse
|
|
// =========================================================
|
|
|
|
protected function runAction(string $action, callable $core): mixed
|
|
{
|
|
try {
|
|
return $core();
|
|
} catch (FormValidationException $e) {
|
|
return $this->failResponse($action, $e);
|
|
} catch (\Throwable $e) {
|
|
return $this->failResponse($action, $e);
|
|
}
|
|
}
|
|
|
|
protected function okResponse(string $message, array $payload = [], ?string $redirectUrl = null): RedirectResponse|ResponseInterface
|
|
{
|
|
if ($this->request->isAJAX()) {
|
|
return $this->response->setStatusCode(200)->setJSON(array_merge(
|
|
['ok' => true, 'message' => $message],
|
|
$payload
|
|
));
|
|
}
|
|
return $this->action_redirect_process('info', $message, $redirectUrl);
|
|
}
|
|
|
|
protected function failResponse(string $action, \Throwable $e, ?string $humanPrefix = null): RedirectResponse|ResponseInterface
|
|
{
|
|
if ($e instanceof FormValidationException) {
|
|
if ($this->request->isAJAX()) {
|
|
return $this->response->setStatusCode(422)->setJSON([
|
|
'ok' => false,
|
|
'errors' => $e->errors,
|
|
]);
|
|
}
|
|
return $this->action_redirect_process('error', dev_exception($e->getMessage()));
|
|
}
|
|
|
|
if ($this->request->isAJAX()) {
|
|
return $this->response->setStatusCode(500)->setJSON([
|
|
'ok' => false,
|
|
'message' => static::class . '->' . $action . "에서 오류:" . $e->getMessage(),
|
|
]);
|
|
}
|
|
|
|
$msg = $humanPrefix ? ($humanPrefix . $e->getMessage()) : $e->getMessage();
|
|
return $this->action_redirect_process('error', dev_exception($msg));
|
|
}
|
|
}
|