본문으로 건너뛰기

상품 리스트 복사 시 이미지 보호 기능 개선.

PHP 8 · GODO26
변경 파일 수: 2개
변경 파일 목록
2
변경 파일 코드
추가삭제
Component/Goods/GoodsAdmin.php+76-51
변경 전GoodsAdmin.php
 
// 상품이미지 > obs 카프카 컨슈머 처리 start (상품복사)
if($arrData['applyGoodsCopy'] && gd_in_array($arrData['imageStorage'], self::DEFAULT_STORAGE)) {
 
 
 
$copiedGoodsData = ['goodsNo' => $arrData['applyNo'], 'newGoodsNo' => $arrData['goodsNo'], 'convertedType' => 'copy'];
$kafka = new ProducerUtils();
$result = $kafka->send($kafka::TOPIC_CONVERTED_GOODS_IMAGE, $kafka->makeData($copiedGoodsData, 'cgi'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', [$result, $copiedGoodsData]);
if ($result['result'] == 'success') {
// originGoodsNo, newGoodsNo obsConvertFl = N 업데이트 필요
$goodsObsConvertStatus->updateObsConvertFl($arrData['applyNo']);
$goodsObsConvertStatus->updateObsConvertFl($arrData['goodsNo']);
}
}
// 상품이미지 > obs 카프카 컨슈머 처리 end
 
if (!empty($goodsImageMigrationLog)) {
$goodsImageMigrationLog['convertedType'] = 'manage'; // 상품이미지 등록,수정,삭제
 
$kafka = new ProducerUtils();
$result = $kafka->send($kafka::TOPIC_CONVERTED_GOODS_IMAGE, $kafka->makeData($goodsImageMigrationLog, 'cgi'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', [$result, $goodsImageMigrationLog]);
if ($result['result'] == 'success') {
// goodsNo obsConvertFl = N 업데이트 필요
$goodsObsConvertStatus->updateObsConvertFl($arrData['goodsNo'], $goodsImageMigrationLog);
}
}
}
// 상품아이콘 > obs 카프카 컨슈머 처리 end
 
// URL 이미지는 OBS 변환 대상 아님 → 'y' 고정 (legacy 'n' 잠금 해제 포함)
if (gd_in_array($arrData['imageStorage'], self::DEFAULT_STORAGE)) {
if ($arrData['applyGoodsCopy']) {
$goodsObsConvertStatus->setObsConvertFlagForUrlImages($arrData['applyNo']);
if ($extraArrData['callBy'] == OPEN_API) {
$goodsImageMigrationLog['convertedType'] = 'manage'; // 상품이미지 등록,수정,삭제
 
$kafka = new ProducerUtils();
$result = $kafka->send($kafka::TOPIC_CONVERTED_GOODS_IMAGE_BY_OPEN_API, $kafka->makeData($goodsImageMigrationLog, 'cgi'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', [$result, 'openAPI', $goodsImageMigrationLog]);
if ($result['result'] == 'success') {
// goodsNo obsConvertFl = N 업데이트 필요
$goodsObsConvertStatus->updateObsConvertFl($this->goodsNo, $goodsImageMigrationLog);
}
}
 
// URL 이미지는 OBS 변환 대상 아님 → 'y' 고정 (legacy 'n' 잠금 해제 포함)
$goodsObsConvertStatus->setObsConvertFlagForUrlImages($this->goodsNo);
}
// 상품이미지 > obs 카프카 컨슈머 처리 end
return $fbImageInfo;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 상품 복사
*
$addLogData = $goodsNo . ' -> ' . $newGoodsNo . ' 상품 복사' . chr(10);
LogHandler::wholeLog('goods', null, 'copy', $newGoodsNo, $data['goodsNm'], $addLogData);
 
// 상품이미지 > obs 카프카 컨슈머 처리 start
if(gd_in_array($data['imageStorage'], self::DEFAULT_STORAGE)) {
$copiedGoodsData = ['goodsNo' => $goodsNo, 'newGoodsNo' => $newGoodsNo, 'convertedType' => 'copy'];
$kafka = new ProducerUtils();
$result = $kafka->send($kafka::TOPIC_CONVERTED_GOODS_IMAGE, $kafka->makeData($copiedGoodsData, 'cgi'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', [$result, $copiedGoodsData]);
if ($result['result'] == 'success') {
// originGoodsNo, newGoodsNo obsConvertFl = N 업데이트 필요
$goodsObsConvertStatus = \App::load('\\Component\\Goods\\GoodsObsConvertStatus');
$goodsObsConvertStatus->updateObsConvertFl($goodsNo);
$goodsObsConvertStatus->updateObsConvertFl($newGoodsNo);
}
}
// 상품이미지 > obs 카프카 컨슈머 처리 end
 
// URL 이미지는 OBS 변환 대상 아님 → 'y' 고정 (legacy 'n' 잠금 해제 포함)
if (gd_in_array($data['imageStorage'], self::DEFAULT_STORAGE)) {
$goodsObsConvertStatusForUrl = \App::load('\\Component\\Goods\\GoodsObsConvertStatus');
$goodsObsConvertStatusForUrl->setObsConvertFlagForUrlImages($goodsNo);
$goodsObsConvertStatusForUrl->setObsConvertFlagForUrlImages($newGoodsNo);
}
 
// --- 이미지 복사 처리
if($data['imageStorage'] !='url') {
if ($data['imageStorage'] == 'obs') {
 
$this->db->commit();
 
// 에디터 이미지 복사 토픽 발행
$kafka = new ProducerUtils();
$contentsInfo = ['contentsKey' => $newGoodsNo, 'tableName' => DB_GOODS, 'orgContentsKey' => $goodsNo, 'orgTableName' => DB_GOODS];
$result = $kafka->send($kafka::TOPIC_COPIED_EDITOR_IMAGE, $kafka->makeData($contentsInfo, 'cpei'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', [$result, $contentsInfo]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
return $newGoodsNo;
} catch (\Exception $e) {
 
변경 후GoodsAdmin.php
 
// 상품이미지 > obs 카프카 컨슈머 처리 start (상품복사)
if($arrData['applyGoodsCopy'] && gd_in_array($arrData['imageStorage'], self::DEFAULT_STORAGE)) {
// 신규 상품을 변환 대기(obsConvertFl='n')로 표시
$goodsObsConvertStatus->updateObsConvertFl($arrData['goodsNo']);
 
$copiedGoodsData = ['goodsNo' => $arrData['applyNo'], 'newGoodsNo' => $arrData['goodsNo'], 'convertedType' => 'copy'];
$this->publishObsConvertTopic($goodsObsConvertStatus, ProducerUtils::TOPIC_CONVERTED_GOODS_IMAGE, $copiedGoodsData, $arrData['goodsNo'], '상품복사 OBS 토픽 발행 실패 - obsConvertFl 해제(fail-open)');
 
 
 
 
 
 
 
}
// 상품이미지 > obs 카프카 컨슈머 처리 end
 
if (!empty($goodsImageMigrationLog)) {
$goodsImageMigrationLog['convertedType'] = 'manage'; // 상품이미지 등록,수정,삭제
 
// 상품 이미지를 변환 대기(obsConvertFl='n')로 표시
$goodsObsConvertStatus->updateObsConvertFl($arrData['goodsNo'], $goodsImageMigrationLog);
 
$this->publishObsConvertTopic($goodsObsConvertStatus, ProducerUtils::TOPIC_CONVERTED_GOODS_IMAGE, $goodsImageMigrationLog, $arrData['goodsNo'], '상품이미지 OBS 토픽 발행 실패 - obsConvertFl 해제(fail-open)');
 
 
 
}
}
// 상품아이콘 > obs 카프카 컨슈머 처리 end
 
// URL 이미지는 변환 대상이 아니므로 'y'로 고정
if (gd_in_array($arrData['imageStorage'], self::DEFAULT_STORAGE)) {
if ($arrData['applyGoodsCopy']) {
$goodsObsConvertStatus->setObsConvertFlagForUrlImages($arrData['applyNo']);
if ($extraArrData['callBy'] == OPEN_API) {
$goodsImageMigrationLog['convertedType'] = 'manage'; // 상품이미지 등록,수정,삭제
 
// 상품 이미지를 변환 대기(obsConvertFl='n')로 표시
$goodsObsConvertStatus->updateObsConvertFl($this->goodsNo, $goodsImageMigrationLog);
 
$this->publishObsConvertTopic($goodsObsConvertStatus, ProducerUtils::TOPIC_CONVERTED_GOODS_IMAGE_BY_OPEN_API, $goodsImageMigrationLog, $this->goodsNo, '상품이미지 OBS 토픽 발행 실패(openAPI) - obsConvertFl 해제(fail-open)', ['openAPI']);
 
 
 
}
 
// URL 이미지는 변환 대상이 아니므로 'y'로 고정
$goodsObsConvertStatus->setObsConvertFlagForUrlImages($this->goodsNo);
}
// 상품이미지 > obs 카프카 컨슈머 처리 end
return $fbImageInfo;
}
 
/**
* OBS 이미지 변환 토픽 발행 + 발행 실패 시 fail-open 처리
*
* 발행에 실패(예외 발생 또는 비성공 응답)하면 obsConvertFl을 'y'로 되돌려
* 이미지가 '변환 대기(편집 잠금)' 상태로 고착되는 것을 방지한다.
* 잠금(updateObsConvertFl) 자체는 발행 대상/시점이 달라 호출부에서 수행한다.
*
* @param \Component\Goods\GoodsObsConvertStatus $goodsObsConvertStatus 상태 처리 컴포넌트
* @param string $topic 발행 토픽
* @param array $data 발행 데이터(makeData 입력)
* @param mixed $unlockGoodsNo 발행 실패 시 잠금 해제할 상품번호
* @param string $failMessage 발행 실패 시 남길 로그 메시지
* @param array $infoLogContext info 로그에 추가로 남길 항목(예: ['openAPI'])
* @return void
*/
private function publishObsConvertTopic($goodsObsConvertStatus, string $topic, array $data, $unlockGoodsNo, string $failMessage, array $infoLogContext = []): void
{
$obsPublishOk = false;
$obsPublishError = '';
try {
$kafka = new ProducerUtils();
$result = $kafka->send($topic, $kafka->makeData($data, 'cgi'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', array_merge([$result], $infoLogContext, [$data]));
$obsPublishOk = (isset($result['result']) && $result['result'] === 'success');
} catch (\Throwable $obsPublishException) {
$obsPublishError = $obsPublishException->getMessage();
}
 
if (!$obsPublishOk) {
// 발행 실패 → obsConvertFl 'y'로 재변환
// 미변환 시, 이미지 변경 불가능 상태로 고착화됨
$goodsObsConvertStatus->unlockObsConvertFl($unlockGoodsNo);
\Logger::channel('kafka')->warning($failMessage, [$unlockGoodsNo, $obsPublishError]);
}
}
 
/**
* 상품 복사
*
$addLogData = $goodsNo . ' -> ' . $newGoodsNo . ' 상품 복사' . chr(10);
LogHandler::wholeLog('goods', null, 'copy', $newGoodsNo, $data['goodsNm'], $addLogData);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// --- 이미지 복사 처리
if($data['imageStorage'] !='url') {
if ($data['imageStorage'] == 'obs') {
 
$this->db->commit();
 
try {
if(gd_in_array($data['imageStorage'], self::DEFAULT_STORAGE)) {
// 신규 상품을 변환 대기(obsConvertFl='n')로 표시
$goodsObsConvertStatus = \App::load('\\Component\\Goods\\GoodsObsConvertStatus');
$goodsObsConvertStatus->updateObsConvertFl($newGoodsNo);
 
$copiedGoodsData = ['goodsNo' => $goodsNo, 'newGoodsNo' => $newGoodsNo, 'convertedType' => 'copy'];
$this->publishObsConvertTopic($goodsObsConvertStatus, ProducerUtils::TOPIC_CONVERTED_GOODS_IMAGE, $copiedGoodsData, $newGoodsNo, '상품복사 OBS 토픽 발행 실패 - obsConvertFl 해제(fail-open)');
}
// 상품이미지 > obs 카프카 컨슈머 처리 end
 
// URL 이미지는 변환 대상이 아니므로 'y'로 고정
if (gd_in_array($data['imageStorage'], self::DEFAULT_STORAGE)) {
$goodsObsConvertStatusForUrl = \App::load('\\Component\\Goods\\GoodsObsConvertStatus');
$goodsObsConvertStatusForUrl->setObsConvertFlagForUrlImages($newGoodsNo);
}
 
// 에디터 이미지 복사 토픽 발행
$kafka = new ProducerUtils();
$contentsInfo = ['contentsKey' => $newGoodsNo, 'tableName' => DB_GOODS, 'orgContentsKey' => $goodsNo, 'orgTableName' => DB_GOODS];
$result = $kafka->send($kafka::TOPIC_COPIED_EDITOR_IMAGE, $kafka->makeData($contentsInfo, 'cpei'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', [$result, $contentsInfo]);
} catch (\Throwable $postCommitException) {
// 이미지 로컬 복사는 성공. 토픽 처리 실패만 기록하고 넘어간다.
\Logger::channel('kafka')->warning('상품복사 commit 이후 부가처리 실패', [$postCommitException->getMessage(), $newGoodsNo]);
}
 
return $newGoodsNo;
} catch (\Exception $e) {
 
Component/Goods/GoodsObsConvertStatus.php+20
변경 전GoodsObsConvertStatus.php
$this->db->bind_param_push($arrBind, 'i', $goodsNo);
$this->db->bind_query($strSQL, $arrBind);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
변경 후GoodsObsConvertStatus.php
$this->db->bind_param_push($arrBind, 'i', $goodsNo);
$this->db->bind_query($strSQL, $arrBind);
}
 
/**
* 상품번호를 기준으로 상품 이미지의 변환 대기 표시(obsConvertFl='n')를 풀어줌('y').
*/
public function unlockObsConvertFl(int $goodsNo): void
{
// 상품이미지
$arrBind = [];
$strSQL = 'UPDATE ' . DB_GOODS_IMAGE . ' SET obsConvertFl = ? WHERE goodsNo = ? AND imageName NOT LIKE "http%" ';
$this->db->bind_param_push($arrBind, 's', 'y');
$this->db->bind_param_push($arrBind, 'i', $goodsNo);
$this->db->bind_query($strSQL, $arrBind);
 
// 상품옵션이미지
$arrBind = [];
$strSQL = 'UPDATE ' . DB_GOODS_OPTION_ICON . ' SET obsConvertFl = ? WHERE goodsNo = ? AND goodsImage NOT LIKE "http%" ';
$this->db->bind_param_push($arrBind, 's', 'y');
$this->db->bind_param_push($arrBind, 'i', $goodsNo);
$this->db->bind_query($strSQL, $arrBind);
}
}