292 lines
12 KiB
PHP
292 lines
12 KiB
PHP
<?php
|
|
|
|
namespace App\Controllers;
|
|
|
|
use CodeIgniter\HTTP\DownloadResponse;
|
|
use CodeIgniter\HTTP\RedirectResponse;
|
|
use PhpOffice\PhpSpreadsheet\IOFactory;
|
|
use PhpOffice\PhpSpreadsheet\Reader\Html;
|
|
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf;
|
|
use RuntimeException;
|
|
|
|
/**
|
|
* CommonController
|
|
* 목록(index), 일괄작업(batchjob), 일괄삭제, 다운로드 로직을 담당합니다. (SRP: Collection Management)
|
|
*/
|
|
abstract class CommonController extends AbstractCRUDController
|
|
{
|
|
// --- 일괄 작업 (Batch Job) ---
|
|
protected function batchjob_pre_process(array $postDatas): array
|
|
{
|
|
// 1. postDatas에서 선택된 uids 정보 추출
|
|
$uids = $postDatas['batchjob_uids'] ?? [];
|
|
if (empty($uids)) {
|
|
throw new RuntimeException("{$this->getTitle()}에서 일괄작업에 적용할 리스트을 선택하셔야합니다.");
|
|
}
|
|
// 2. 변경할 데이터 추출 및 정리
|
|
unset($postDatas['batchjob_uids'], $postDatas['batchjob_submit']); //formDatas에 포함되지 않게하기위함
|
|
$formDatas = array_filter($postDatas, fn($value) => $value !== "" && $value !== null);
|
|
if (empty($formDatas)) {
|
|
throw new RuntimeException("{$this->getTitle()}에서 일괄작업에 변경할 조건항목을 선택하셔야합니다.");
|
|
}
|
|
// 3. 데이터가 있는 필드 추출
|
|
return array($uids, $formDatas);
|
|
}
|
|
|
|
protected function batchjob_process(array $uids, array $formDatas): array
|
|
{
|
|
return $this->service->batchjob($uids, $formDatas);
|
|
}
|
|
|
|
protected function batchjob_result_process(array $uids, array $entities): string|RedirectResponse
|
|
{
|
|
return $this->action_redirect_process('info', sprintf(
|
|
"%s에서 %s개 처리완료 총:%s개 수정이 완료되었습니다.",
|
|
$this->getTitle(),
|
|
count($entities),
|
|
count($uids)
|
|
));
|
|
}
|
|
final public function batchjob(): string|RedirectResponse
|
|
{
|
|
try {
|
|
$action = __FUNCTION__;
|
|
// 사전작업 및 데이터 추출 초기화
|
|
list($uids, $formDatas) = $this->batchjob_pre_process($this->request->getPost());
|
|
$entities = $this->batchjob_process($uids, $formDatas);
|
|
return $this->batchjob_result_process($uids, $entities);
|
|
} catch (\Throwable $e) {
|
|
return $this->action_redirect_process('error', static::class . '->' . __FUNCTION__ . "에서 {$this->getTitle()} 일괄수정 오류:" . $e->getMessage());
|
|
}
|
|
}
|
|
// --- 일괄 삭제 (Batch Job Delete) ---
|
|
|
|
protected function batchjob_delete_pre_process(array $postDatas): array
|
|
{
|
|
$uids = $postDatas['batchjob_uids'] ?? [];
|
|
if (empty($uids)) {
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 삭제할 리스트을 선택하셔야합니다.");
|
|
}
|
|
return $uids;
|
|
}
|
|
|
|
protected function batchjob_delete_result_process(array $uids, array $entities): string|RedirectResponse
|
|
{
|
|
return $this->action_redirect_process('info', sprintf(
|
|
"%s에서 %s개 처리완료, 총:%s개 일괄삭제가 완료되었습니다.",
|
|
$this->getTitle(),
|
|
count($entities),
|
|
count($uids)
|
|
));
|
|
}
|
|
|
|
/**
|
|
* 단일 삭제 로직을 재사용 (Override 가능)
|
|
*/
|
|
protected function batchjob_delete_process(array $uids): array
|
|
{
|
|
return $this->service->batchjob_delete($uids);
|
|
}
|
|
final public function batchjob_delete(): string|RedirectResponse
|
|
{
|
|
try {
|
|
$uids = $this->batchjob_delete_pre_process($this->request->getPost());
|
|
$entities = $this->batchjob_delete_process($uids);
|
|
return $this->batchjob_delete_result_process($uids, $entities);
|
|
} catch (\Throwable $e) {
|
|
return $this->action_redirect_process('error', static::class . '->' . __FUNCTION__ . "에서 {$this->getTitle()} 일괄삭제 오류:" . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
// --- 목록 (Index / List) 관련 ---
|
|
|
|
/**
|
|
* 조건절(필터, 검색어, 날짜, 정렬)을 처리합니다. (Override 가능)
|
|
*/
|
|
protected function index_condition_process(string $action): void
|
|
{
|
|
// Filter조건절 처리
|
|
$index_filters = [];
|
|
// dd($this->service->getFormService()->getIndexFilters($action));
|
|
foreach ($this->service->getFormService()->getIndexFilters($action) as $field) {
|
|
$value = $this->request->getVar($field) ?? null;
|
|
if ($value) {
|
|
$this->service->setFilter($field, $value);
|
|
}
|
|
$index_filters[$field] = $value;
|
|
}
|
|
$this->addViewDatas('index_filters', $index_filters);
|
|
|
|
// 검색어조건절 처리
|
|
$index_word = $this->request->getVar('index_word');
|
|
if ($index_word !== null && $index_word !== '') {
|
|
$this->service->setSearchWord($index_word);
|
|
}
|
|
$this->addViewDatas('index_word', $index_word);
|
|
|
|
// 날자검색
|
|
$index_start = $this->request->getVar('index_start');
|
|
$index_end = $this->request->getVar('index_end');
|
|
if ($index_start !== null && $index_start !== '' && $index_end !== null && $index_end !== '') {
|
|
$this->service->setDateFilter($index_start, $index_end);
|
|
}
|
|
$this->addViewDatas('index_start', $index_start);
|
|
$this->addViewDatas('index_end', $index_end);
|
|
|
|
// OrderBy처리
|
|
$order_field = $this->request->getVar('order_field');
|
|
$order_value = $this->request->getVar('order_value');
|
|
$this->service->setOrderBy($order_field, $order_value);
|
|
$this->addViewDatas('order_field', $order_field);
|
|
$this->addViewDatas('order_value', $order_value);
|
|
}
|
|
|
|
/**
|
|
* Pagenation Select Box 옵션을 생성합니다. (Override 가능)
|
|
*/
|
|
protected function pagenation_options_process(int $index_totalcount, int $perpage): array
|
|
{
|
|
$page_options = ["" => "줄수선택"];
|
|
// 기존 로직 유지
|
|
for ($i = $perpage; $i <= $index_totalcount; $i += $perpage) {
|
|
$page_options[$i] = $i;
|
|
}
|
|
$page_options[$index_totalcount] = $index_totalcount;
|
|
return $page_options;
|
|
}
|
|
|
|
/**
|
|
* PageNation 링크를 생성하고 뷰 데이터에 추가합니다. (Override 가능)
|
|
*/
|
|
protected function pagenation_process(int $index_totalcount, int $page, int $perpage, $pager_group = 'default', int $segment = 0, $template = 'bootstrap_full'): mixed
|
|
{
|
|
$pager = service("pager");
|
|
$pager->makeLinks($page, $perpage, $index_totalcount, $template, $segment, $pager_group);
|
|
$this->addViewDatas('index_totalpage', $pager->getPageCount($pager_group));
|
|
return $pager->links($pager_group, $template);
|
|
}
|
|
|
|
/**
|
|
* Service에서 엔티티 목록을 가져와 처리합니다. (Override 가능)
|
|
*/
|
|
protected function index_entities_process(array $entities = []): array
|
|
{
|
|
foreach ($this->service->getEntities() as $entity) {
|
|
$entities[] = $entity;
|
|
}
|
|
return $entities;
|
|
}
|
|
|
|
protected function index_result_process(string $action): string
|
|
{
|
|
return $this->action_render_process($action, $this->getViewDatas(), $this->request->getVar('ActionTemplate'));
|
|
}
|
|
|
|
/**
|
|
* 인덱스(목록) 페이지의 메인 로직입니다.
|
|
*/
|
|
protected function index_process(string $action): void
|
|
{
|
|
// 현재 URL을 이전 URL 스택에 저장
|
|
$this->getAuthContext()->pushCurrentUrl($this->request->getUri()->getPath() . ($this->request->getUri()->getQuery() ? "?" . $this->request->getUri()->getQuery() : ""));
|
|
$this->addViewDatas('uri', $this->request->getUri());
|
|
// Paging 설정
|
|
$page = (int) $this->request->getVar('page') ?: 1;
|
|
$perpage = (int) $this->request->getVar('perpage') ?: intval(DEFAULTS['INDEX_PERPAGE'] ?? 10);
|
|
$this->addViewDatas('page', $page);
|
|
$this->addViewDatas('perpage', $perpage);
|
|
// 1. Total Count 계산을 위한 조건절 처리 (오버라이드 가능)
|
|
$this->index_condition_process($action);
|
|
$index_totalcount = $this->service->getTotalCount();
|
|
$this->addViewDatas('index_totalcount', $index_totalcount);
|
|
// Pagination 설정
|
|
$this->addViewDatas('index_pagination', $this->pagenation_process($index_totalcount, $page, $perpage));
|
|
$this->addViewDatas('index_pagination_options', $this->pagenation_options_process($index_totalcount, $perpage));
|
|
// 2. 실제 리스트를 위한 조건절, LIMIT, OFFSET 처리 (오버라이드 가능)
|
|
$this->index_condition_process($action); // 조건절을 다시 호출하여 필터/검색어 유지
|
|
$this->service->setLimit($perpage);
|
|
$this->service->setOffset(($page - 1) * $perpage);
|
|
// Entities 처리
|
|
$this->addViewDatas('entities', $this->index_entities_process());
|
|
helper(['form']);
|
|
$this->addViewDatas('formDatas', $this->request->getVar() ?? []);
|
|
}
|
|
|
|
final public function index(): string
|
|
{
|
|
$action = __FUNCTION__;
|
|
$this->action_init_process($action);
|
|
$this->index_process($action);
|
|
return $this->index_result_process($action);
|
|
}
|
|
|
|
// --- 문서 다운로드 (Download) ---
|
|
protected function downloadByDocumentType(string $document_type, mixed $loaded_data): array
|
|
{
|
|
$full_path = WRITEPATH . DIRECTORY_SEPARATOR . "download";
|
|
switch ($document_type) {
|
|
case 'excel':
|
|
$file_name = sprintf("%s_%s.xlsx", $this->service->getClassPaths(false, "_"), date('Y-m-d_Hm'));
|
|
$writer = IOFactory::createWriter($loaded_data, 'Xlsx');
|
|
$writer->save($full_path . DIRECTORY_SEPARATOR . $file_name);
|
|
break;
|
|
case 'pdf':
|
|
$file_name = sprintf("%s_%s.pdf", $this->service->getClassPaths(false, "_"), date('Y-m-d_Hm'));
|
|
$writer = new Mpdf($loaded_data);
|
|
$writer->save($full_path . DIRECTORY_SEPARATOR . $file_name);
|
|
break;
|
|
default:
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 지원하지 않는 다운로드 타입입니다: {$document_type}");
|
|
}
|
|
return array($full_path, $file_name);
|
|
}
|
|
|
|
protected function download_process(string $action, string $output_type, mixed $uid = null): DownloadResponse|RedirectResponse|string
|
|
{
|
|
switch ($output_type) {
|
|
case 'excel':
|
|
case 'pdf':
|
|
helper(['form']);
|
|
// 전체 목록을 다운로드하므로, 목록 조건절을 처리합니다.
|
|
$this->index_condition_process($action);
|
|
$this->addViewDatas('entities', $this->index_entities_process());
|
|
|
|
// HTML로 렌더링된 내용을 가져옵니다.
|
|
$html = $this->action_render_process($action, $this->getViewDatas(), $this->request->getVar('ActionTemplate'));
|
|
|
|
// HTML을 PhpSpreadsheet 객체로 로드합니다.
|
|
$reader = new Html();
|
|
$loaded_data = $reader->loadFromString($html);
|
|
|
|
// 파일 저장 및 정보 가져오기
|
|
list($full_path, $file_name) = $this->downloadByDocumentType($output_type, $loaded_data);
|
|
$full_path .= DIRECTORY_SEPARATOR . $file_name;
|
|
break;
|
|
default:
|
|
// 개별 파일 다운로드 로직
|
|
if (!$uid) {
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 {$output_type}은 반드시 uid의 값이 필요합니다.");
|
|
}
|
|
$entity = $this->service->getEntity($uid);
|
|
if (!$entity) {
|
|
throw new RuntimeException(static::class . '->' . __FUNCTION__ . "에서 {$uid}에 대한 정보를 찾을수 없습니다.");
|
|
}
|
|
$this->addViewDatas('entity', $entity);
|
|
list($file_name, $uploaded_filename) = $entity->getDownlaodFile();
|
|
$full_path = WRITEPATH . DIRECTORY_SEPARATOR . "uploads" . DIRECTORY_SEPARATOR . $uploaded_filename;
|
|
break;
|
|
}
|
|
return $this->response->download($full_path, null)->setFileName($file_name);
|
|
}
|
|
final public function download(string $output_type, mixed $uid = false): DownloadResponse|RedirectResponse|string
|
|
{
|
|
try {
|
|
$action = __FUNCTION__;
|
|
$this->action_init_process($action);
|
|
return $this->download_process($action, $output_type, $uid);
|
|
} catch (\Throwable $e) {
|
|
return $this->action_redirect_process('error', static::class . '->' . __FUNCTION__ . "에서 {$this->getTitle()} 다운로드 오류:" . $e->getMessage());
|
|
}
|
|
}
|
|
}
|