본문으로 건너뛰기

엑셀 다운로드 성능 개선 및 통계 기록 확대

PHP 8 · GODO25
변경 파일 수: 4개
변경 파일 목록
총 4개
변경 파일 코드
추가삭제
Component/Excel/ExcelDataConvert.php+3
변경 전ExcelDataConvert.php
* 상품 엑셀 다운
*
* @author artherot
 
 
*/
public function setExcelGoodsDown($setData)
{
// 엑셀 하단
$this->excelFooter;
 
 
}
 
/**
 
변경 후ExcelDataConvert.php
* 상품 엑셀 다운
*
* @author artherot
* @param array $setData 엑셀 다운로드 요청 데이터 (fieldCheck, downType, downRange 등)
* @return bool 다운로드 대상 필드가 없으면 false
*/
public function setExcelGoodsDown($setData)
{
// 엑셀 하단
$this->excelFooter;
 
return true;
}
 
/**
 
Component/Excel/ExcelRequest.php+2-74
변경 전ExcelRequest.php
use Framework\Utility\ComponentUtils;
use Framework\Utility\ArrayUtils;
use Framework\Utility\DateTimeUtils;
use Framework\Utility\ProducerUtils;
use Framework\Utility\StringUtils;
use Framework\Utility\NumberUtils;
use Framework\Security\Token;
use Framework\Debug\Exception\MissingRequiredFieldException;
use LogHandler;
use Origin\DTO\Kafka\ShopDataExtractLogDTO;
use Origin\Enum\Excel\ShopDataExtractTarget;
use Request;
use Session;
use UserFilePath;
$orderDelete->deleteLapseOrderExcelFormUpdate($arrData['requestSno'], $arrData['sno']);
$this->_logger->channel('orderDelete')->info(__METHOD__ . ' ORDER DELETE EXCEL FORM SNO SAVE, DB_EXCEL_REQUEST INSERT NO : ' . $arrData['requestSno'] . ', EXCEL FORM SNO : ', [$arrData['formSno']]);
 
$this->publishExtractLog($formData, true, ShopDataExtractLogDTO::EXTRACT_TYPE_EXCEL);
return $arrData['requestSno'];
}
 
unset($arrBind);
 
$this->publishExtractLog($formData, true, ShopDataExtractLogDTO::EXTRACT_TYPE_EXCEL);
return true;
} else {
$this->publishExtractLog($formData, false, ShopDataExtractLogDTO::EXTRACT_TYPE_EXCEL);
return false;
}
 
 
 
//특정 갯수 이하인 경우 바로 생성
/*
if($arrData[ $arrData['whereFl'].'Count'] <= self::EXCEL_PAGE_NUM ) {
return true;
}
*/
 
}
 
public function makeExcelFile(&$arrData)
 
return ['getData' => $setData, 'totalCount' => '$totalNum'];
}
 
/**
* 상점 데이터 추출 완료 결과를 카프카 토픽으로 발행한다.
*
* @param ?array $formData 엑셀 양식 데이터 (es_excelForm, menu 포함)
* @param bool $isSuccess 추출 성공 여부
* @param string $extractType 추출 유형 (ShopDataExtractLogDTO::EXTRACT_TYPE_* 상수)
* @return void
*/
protected function publishExtractLog(?array $formData, bool $isSuccess, string $extractType): void
{
//10월 정기배포 전까지 발행되지 않도록 임시조치
return;
try {
$godosno = Globals::get('gLicense.godosno');
if (empty($godosno)) {
throw new MissingRequiredFieldException('상점 데이터 추출 로그 발행 실패: 라이선스 상점번호(godosno)가 없습니다.');
}
 
$menu = $formData['menu'] ?? null;
if (empty($menu)) {
throw new MissingRequiredFieldException('상점 데이터 추출 로그 발행 실패: 엑셀 양식 메뉴(menu)가 없습니다.');
}
 
$extractTarget = ShopDataExtractTarget::fromMenu($menu);
// 매핑 미확정 메뉴(orderDraft, plusreview, adminLog)는 발행하지 않고 건너뛴다. (9월 배포 추가작업 예정)
if ($extractTarget === null) {
$this->_logger->channel('excel')->info(
'상점 데이터 추출 로그 발행 생략: 매핑되지 않은 엑셀 양식 메뉴',
[
'godoSno' => (int)$godosno,
'extractType' => $extractType,
'extractTarget' => $extractTarget->value,
'isSuccess' => $isSuccess
]
);
return;
}
 
$producer = new ProducerUtils();
$shopDataExtractLogDto = new ShopDataExtractLogDTO(
[(int)$godosno],
$extractType,
$extractTarget->value,
$isSuccess
);
 
$producer->send(
$producer::TOPIC_SHOP_DATA_EXTRACT_LOG_CREATE,
json_encode($shopDataExtractLogDto->toArray()),
$producer::MODE_RESULT_CALLLBACK
);
} catch (\Throwable $e) {
$this->_logger->channel('excel')->warning(
'상점 데이터 추출 로그 카프카 메시지 발송 실패',
[
'exception' => $e,
'extractType' => $extractType,
'menu' => $formData['menu'] ?? null
]
);
}
}
}
 
변경 후ExcelRequest.php
use Framework\Utility\ComponentUtils;
use Framework\Utility\ArrayUtils;
use Framework\Utility\DateTimeUtils;
 
use Framework\Utility\StringUtils;
use Framework\Utility\NumberUtils;
use Framework\Security\Token;
 
use LogHandler;
 
 
use Request;
use Session;
use UserFilePath;
$orderDelete->deleteLapseOrderExcelFormUpdate($arrData['requestSno'], $arrData['sno']);
$this->_logger->channel('orderDelete')->info(__METHOD__ . ' ORDER DELETE EXCEL FORM SNO SAVE, DB_EXCEL_REQUEST INSERT NO : ' . $arrData['requestSno'] . ', EXCEL FORM SNO : ', [$arrData['formSno']]);
 
 
return $arrData['requestSno'];
}
 
unset($arrBind);
 
 
return true;
 
 
 
}
 
return false;
 
//특정 갯수 이하인 경우 바로 생성
/*
if($arrData[ $arrData['whereFl'].'Count'] <= self::EXCEL_PAGE_NUM ) {
return true;
}
*/
 
}
 
public function makeExcelFile(&$arrData)
 
return ['getData' => $setData, 'totalCount' => '$totalNum'];
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
Controller/Admin/Goods/ExcelGoodsPsController.php+20-3
변경 전ExcelGoodsPsController.php
// 상품 엑셀 다운로드
case 'excel_down':
$this->streamedDownload('상품다운로드.xls');
$excel->setExcelGoodsDown($postValue);
// 상품 엑셀 다운로드 본사 & 전체 일 떄 로깅 처리
if ($postValue['downType'] === 'all' && $postValue['scmFl'] === 'n') {
Churn::detectExcelDownloadTotal('goods');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
exit;
break;
 
변경 후ExcelGoodsPsController.php
// 상품 엑셀 다운로드
case 'excel_down':
$this->streamedDownload('상품다운로드.xls');
 
// 상품 엑셀 다운로드 본사 & 전체 일 떄 로깅 처리
$isTotalDownload = $postValue['downType'] === 'all' && $postValue['scmFl'] === 'n';
try {
$isDownloadSuccess = $excel->setExcelGoodsDown($postValue);
} catch (\Throwable $e) {
// 권한 없음·쿼리 오류 등으로 중단된 경우도 추출 실패로 남긴다
if ($isTotalDownload) {
Churn::detectExcelDownloadFail('goods');
}
throw $e;
}
if ($isTotalDownload) {
// 튜닝 소스가 반환값 없이 오버라이드한 경우(null)를 실패로 오인하지 않도록 명시적 false 만 실패 처리한다.
if ($isDownloadSuccess === false) {
Churn::detectExcelDownloadFail('goods');
} else {
Churn::detectExcelDownloadTotal('goods');
}
}
exit;
break;
 
Controller/Admin/Share/LayerExcelPsController.php+25-3
변경 전LayerExcelPsController.php
$postValue = $request->post()->toArray();
$excelRequest = \App::load('Component\\Excel\\ExcelRequest');
$logger->info(__METHOD__, $postValue);
 
try {
switch ($postValue['mode']) {
case 'excel':
$data = $excelRequest->saveInfoExcelRequest($postValue);
 
 
 
 
 
 
if ($data === true) {
if ($postValue['whereFl'] == 'total' && ($postValue['menu'] == 'member' || $postValue['menu'] == 'goods')) {
Churn::detectExcelDownloadTotal($postValue['menu']);
}
echo "<script> parent.set_excel_list('" . __('다운로드할 엑셀파일 생성이 완료되었습니다. 파일을 선택하여 다운로드하시기 바랍니다.') . "'); </script>";
} else {
echo "<script> parent.hide_process(); </script>";
}
}
} catch (\Exception $e) {
 
 
 
 
 
$logger->info($e->getMessage(), $e->getTrace());
throw new LayerException($e->getMessage());
}
exit();
}
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
변경 후LayerExcelPsController.php
$postValue = $request->post()->toArray();
$excelRequest = \App::load('Component\\Excel\\ExcelRequest');
$logger->info(__METHOD__, $postValue);
$isExtractLogPublished = false;
try {
switch ($postValue['mode']) {
case 'excel':
$data = $excelRequest->saveInfoExcelRequest($postValue);
// 조회 결과 0건도 추출 처리 자체는 성공이므로 상품 즉시 다운로드 경로와 같은 기준으로 성공 발행한다
if ($this->isTotalExtractTarget($postValue)) {
Churn::detectExcelDownloadTotal($postValue['menu']);
$isExtractLogPublished = true;
}
 
if ($data === true) {
 
 
 
echo "<script> parent.set_excel_list('" . __('다운로드할 엑셀파일 생성이 완료되었습니다. 파일을 선택하여 다운로드하시기 바랍니다.') . "'); </script>";
} else {
echo "<script> parent.hide_process(); </script>";
}
}
} catch (\Exception $e) {
// 권한 없음·DB 오류로 추출이 중단된 경우도 실패로 남긴다. 성공을 이미 발행했으면 중복으로 보내지 않는다
if (!$isExtractLogPublished && ($postValue['mode'] ?? '') === 'excel' && $this->isTotalExtractTarget($postValue)) {
Churn::detectExcelDownloadFail($postValue['menu']);
}
 
$logger->info($e->getMessage(), $e->getTrace());
throw new LayerException($e->getMessage());
}
exit();
}
 
/**
* 전체 범위 추출 로그 발행 대상인지 여부. 성공·실패 양쪽 호출부가 같은 조건을 쓰도록 묶는다.
*
* @param array $postValue whereFl, menu
*
* @return bool
*/
protected function isTotalExtractTarget(array $postValue): bool
{
return ($postValue['whereFl'] ?? '') == 'total'
&& in_array($postValue['menu'] ?? '', ['member', 'goods'], true);
}
}