본문으로 건너뛰기

회원 등급 평가 스케줄러 개선

PHP 7 · GODO25
변경 파일 수: 4개
변경 파일 목록
총 4개
변경 파일 코드
추가삭제
Component/Coupon/CouponAdmin.php+2-2
변경 전CouponAdmin.php
$smsAuto->setSmsAutoCodeType(Code::COUPON_MANUAL);
$smsAuto->setSmsType(SmsAutoCode::PROMOTION);
$smsAuto->setReceiver($member);
$smsAuto->setReplaceArguments(['name' => $member['memNm'], 'CouponName' => $couponInfo['couponNm'], 'rc_memid' => $member['memId']]);
$smsAuto->autoSend();
} else {
$logger->info(sprintf('Disallow sms receiving. memNo[%s], smsFl [%s]', $member['memNo'], $member['smsFl']));
$smsAuto->setSmsAutoCodeType(Code::COUPON_MANUAL);
$smsAuto->setSmsType(SmsAutoCode::PROMOTION);
$smsAuto->setReceiver($val);
$smsAuto->setReplaceArguments(['name' => $val['memNm'], 'CouponName' => $couponInfo['couponNm'], 'rc_memid' => $val['memId']]);
$smsAuto->autoSend();
} else {
$logger->info(sprintf('Disallow sms receiving. memNo[%s], smsFl [%s]', $val['memNo'], $val['smsFl']));
 
변경 후CouponAdmin.php
$smsAuto->setSmsAutoCodeType(Code::COUPON_MANUAL);
$smsAuto->setSmsType(SmsAutoCode::PROMOTION);
$smsAuto->setReceiver($member);
$smsAuto->setReplaceArguments(['name' => $member['memNm'], 'CouponName' => $couponInfo['couponNm'], 'rc_memid' => $member['memId'], 'rc_mallNm' => Globals::get('gMall.mallNm')]);
$smsAuto->autoSend();
} else {
$logger->info(sprintf('Disallow sms receiving. memNo[%s], smsFl [%s]', $member['memNo'], $member['smsFl']));
$smsAuto->setSmsAutoCodeType(Code::COUPON_MANUAL);
$smsAuto->setSmsType(SmsAutoCode::PROMOTION);
$smsAuto->setReceiver($val);
$smsAuto->setReplaceArguments(['name' => $val['memNm'], 'CouponName' => $couponInfo['couponNm'], 'rc_memid' => $val['memId'], 'rc_mallNm' => Globals::get('gMall.mallNm')]);
$smsAuto->autoSend();
} else {
$logger->info(sprintf('Disallow sms receiving. memNo[%s], smsFl [%s]', $val['memNo'], $val['smsFl']));
 
Component/Member/Group/Appraisal.php+262-28
변경 전Appraisal.php
/** @var array 현재 평가대상 회원 */
protected $currentMembers;
/** @var array 등급평가 제외 설정된 등급 sno 배열 */
protected $apprExclusionOfRating;
/** @var array 그룹 sno별 등급 */
protected $groupSort;
 
 
/** @var array 그룹 관리 설정 */
public $policy;
/** @var array 기본 설정 */
protected $couponAdmin;
/** @var array [couponNo => [memNo, ...]] — updateGroup에서 누적 후 flush 로 쿠폰별 일괄 발급 */
protected $couponSmsBuffer = [];
 
 
/**
* Appraisal constructor.
*
public function __construct(AppraisalSearch $search = null)
{
parent::__construct();
 
 
 
$this->setSearch($search);
$this->groupConfig();
$this->validateAppraisalGroupConfig();
$this->policy = ComponentUtils::getPolicy('member.group');
$this->basicInfo = gd_policy('basic.info');
$this->memberFields = DBTableField::getFieldTypes('tableMember');
$this->logger = App::getInstance('logger');
$this->couponAdmin = new CouponAdmin();
ini_set('memory_limit', '-1');
}
$validation->validateOverlapStandard();
$this->groupSort[$group['sno']] = $group['groupSort']; // 그룹 key: sno, value: sort 배열 생성
}
 
 
 
 
 
 
// 회원등급 평가시 제외인 등급 그룹 배열 생성
$exclusionGroups = $dao->selectGroupExclusion();
foreach ($exclusionGroups as $key){
$this->groupConfig = $groups;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* setGroupNames
* @return void
{
$session = \App::getInstance('session');
$db = \App::getInstance('DB');
 
 
try {
$groupSno = $this->group->get('sno');
$settleGb = $this->group->get('settleGb');
$this->checkGroupByFigure($item);
}
$beforeGroupSort = $this->groupSort[$item['groupSno']];
$afterGroupSort = $this->groupSort[$groupSno];
//하향펑가를 설정하지 않았거나, 하향평가를 사용하거나, 하향평가를 사용하지 않고 변경 등급이 기존 등급보다 높거나 같을 때 만 업데이트
if (empty($this->policy['downwardAdjustment']) || $this->policy['downwardAdjustment'] == 'y' || ($this->policy['downwardAdjustment'] == 'n' && $beforeGroupSort < $afterGroupSort)) {
if ($this->isCurrentGroupMember || $this->isDefaultGroupMember) {
$this->logger->info('Group change target. sno[' . $this->group->get('sno', 0) . '], name[' . $this->group->get('', '-') . ']', $item);
 
$this->updateGroup($memNo);
$this->writeHistory($memNo);
$this->addMailReceiver($storage, $this->group);
$this->addSmsReceiver($storage, $this->group);
unset($members[$index]);
}
}
$db->commit();
$this->currentMembers = $members;
}
 
 
 
 
 
} catch (Exception $e) {
$this->logger->error(__METHOD__ . ', ' . $e->getFile() . '[' . $e->getLine() . '], ' . $e->getMessage(), $e->getTrace());
$db->rollback();
$this->couponSmsBuffer = [];
 
 
 
 
}
}
foreach ($this->couponSmsBuffer as $couponNo => $memNos) {
\Request::post()->set('couponNo', $couponNo);
$this->couponAdmin->saveMemberCouponSms($memNos, null, $passwordCheckFlBool);
 
 
 
}
$this->couponSmsBuffer = [];
}
$memNos,
$couponSaveAdminId,
$passwordCheckFl,
$targetDate
 
);
}
/**
* 평가 대상 중 "현재 기본등급(1)인 회원"만 autoGroupAppraisalDt를 targetDate로 기록한다.
* - 전체 기본등급이 아니라, 이번 실행의 대상(memNo 배열)만 처리
* - 이미 targetDate로 기록된 회원은 제외
*
* @param array $memNos
* @param string $targetDate Y-m-d
return;
}
 
 
 
 
$db = \App::getInstance('DB');
$touchDateTime = $targetDate . ' 00:00:00';
$from = $targetDate . ' 00:00:00';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$arrBind = [];
$db->bind_param_push($arrBind, 's', $touchDateTime);
$placeholders = implode(',', array_fill(0, count($memNos), '?'));
foreach ($memNos as $memNo) {
$db->bind_param_push($arrBind, 'i', $memNo);
}
// 기본등급 + 활성회원만
$db->bind_param_push($arrBind, 'i', 1);
$db->bind_param_push($arrBind, 's', 'y');
$db->bind_param_push($arrBind, 's', 'n');
// 이미 targetDate 이후로 평가 완료된 회원은 제외
$db->bind_param_push($arrBind, 's', $from);
$strField = 'autoGroupAppraisalDt = ?';
$strWhere = 'memNo IN (' . $placeholders . ')'
. ' AND groupSno = ?'
. ' AND appFl = ?'
. ' AND sleepFl = ?'
. ' AND (autoGroupAppraisalDt IS NULL OR autoGroupAppraisalDt < ?)';
$db->set_update_db(DB_MEMBER, $strField, $strWhere, $arrBind);
$this->logger->info('Update autoGroupAppraisalDt for default group members', [
'table' => DB_MEMBER,
'memNoCount' => count($memNos),
'from' => $from,
]);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 수정이력 추가
$observer = new SmsAutoObserver();
$observer->setSmsType(SmsAutoCode::MEMBER);
$observer->setSmsAutoCodeType(Code::GROUP_CHANGE);
$observer->setReceiver($storage->get('cellPhone'));
 
 
 
 
 
$observer->setReplaceArguments(
[
'rc_groupNm' => $group->get('groupNm'),
'name' => $storage->get('memNm'),
'memNm' => $storage->get('memNm'),
 
'groupNm' => $group->get('groupNm'),
'rc_mallNm' => \Globals::get('gMall.mallNm'),
'shopUrl' => $this->basicInfo['mallDomain'],
* 전체 등급 설정을 스캔하여 실제 필요한 데이터 유형을 결정
* @return array ['order' => bool, 'review' => bool, 'login' => bool]
*/
private function resolveRequiredData(): array
{
$isPoint = $this->_isAppraisalSystemPoint();
 
변경 후Appraisal.php
/** @var array 현재 평가대상 회원 */
protected $currentMembers;
/** @var array 등급평가 제외 설정된 등급 sno 배열 */
protected $apprExclusionOfRating = [];
/** @var array 평가 대상 그룹 sno별 등급 */
protected $groupSort;
/** @var array 평가 대상 여부와 무관한 전체 그룹 sno별 등급 */
protected $allGroupSort = [];
/** @var array 그룹 관리 설정 */
public $policy;
/** @var array 기본 설정 */
protected $couponAdmin;
/** @var array [couponNo => [memNo, ...]] — updateGroup에서 누적 후 flush 로 쿠폰별 일괄 발급 */
protected $couponSmsBuffer = [];
/** @var array rollback 된 배치의 memNo — 유지회원 stamp 제외 대상 */
protected $rolledBackMemNos = [];
/**
* Appraisal constructor.
*
public function __construct(AppraisalSearch $search = null)
{
parent::__construct();
$this->memberFields = DBTableField::getFieldTypes('tableMember');
$this->logger = App::getInstance('logger');
$this->setSearch($search);
$this->groupConfig();
$this->validateAppraisalGroupConfig();
$this->policy = ComponentUtils::getPolicy('member.group');
$this->basicInfo = gd_policy('basic.info');
 
 
$this->couponAdmin = new CouponAdmin();
ini_set('memory_limit', '-1');
}
$validation->validateOverlapStandard();
$this->groupSort[$group['sno']] = $group['groupSort']; // 그룹 key: sno, value: sort 배열 생성
}
$this->allGroupSort = (array)$this->groupSort;
if ($isAppraisalFigure) {
foreach ($dao->selectAppraisalGroups() as $group) {
$this->allGroupSort[$group['sno']] = $group['groupSort'];
}
}
// 회원등급 평가시 제외인 등급 그룹 배열 생성
$exclusionGroups = $dao->selectGroupExclusion();
foreach ($exclusionGroups as $key){
$this->groupConfig = $groups;
}
/**
* 직전 평가일(autoAppraisalDateTime)은 배치 완료 후에 갱신되므로, 평가주기만큼 전진시켜 이번 회차를 찾는다.
*
* @param string $targetDate Y-m-d
*
* @return string Y-m-d
*/
protected function resolveAppraisalCycleStartDate($targetDate)
{
$calcCycleDay = (int)$this->getPolicyValue('calcCycleDay');
$base = date_create((string)$targetDate);
if ($calcCycleDay < 1 || $base === false) {
return $targetDate;
}
$base = date_create($base->format('Y-m-d'));
$cycleStart = $this->resolveCycleStartByPreviousAppraisal($base, $calcCycleDay);
if ($cycleStart === null) {
$cycleStart = $this->cycleDateInMonth($base, $calcCycleDay);
if ($cycleStart > $base) {
$cycleStart = $this->cycleDateInMonth($this->shiftMonth($base, -1), $calcCycleDay);
}
}
return $cycleStart->format('Y-m-d');
}
/**
* @param \DateTime $base
* @param int $calcCycleDay
*
* @return \DateTime|null
*/
protected function resolveCycleStartByPreviousAppraisal(\DateTime $base, $calcCycleDay)
{
$calcCycleMonth = (int)$this->getPolicyValue('calcCycleMonth');
$previous = (string)$this->getPolicyValue('autoAppraisalDateTime');
if ($calcCycleMonth < 1 || $previous === '') {
return null;
}
$cycleStart = date_create($previous);
if ($cycleStart === false) {
return null;
}
$cycleStart = date_create($cycleStart->format('Y-m-d'));
if ($cycleStart > $base) {
return null;
}
while (true) {
$next = $this->cycleDateInMonth($this->shiftMonth($cycleStart, $calcCycleMonth), $calcCycleDay);
if ($next > $base) {
return $cycleStart;
}
$cycleStart = $next;
}
}
/**
* @param \DateTime $base
* @param int $months
*
* @return \DateTime
*/
protected function shiftMonth(\DateTime $base, $months)
{
return date_create($base->format('Y-m-01'))->modify(sprintf('%+d month', $months));
}
/**
* @param \DateTime $base
* @param int $calcCycleDay
*
* @return \DateTime
*/
protected function cycleDateInMonth(\DateTime $base, $calcCycleDay)
{
$day = min($calcCycleDay, (int)$base->format('t'));
return date_create($base->format('Y-m-') . sprintf('%02d', $day));
}
/**
* @param string $key
*
* @return mixed
*/
protected function getPolicyValue($key)
{
return isset($this->policy[$key]) ? $this->policy[$key] : '';
}
/**
* @param int $groupSno
*
* @return int
*/
protected function resolveGroupSort($groupSno)
{
if (array_key_exists($groupSno, $this->allGroupSort)) {
return (int)$this->allGroupSort[$groupSno];
}
if (array_key_exists($groupSno, (array)$this->groupSort)) {
return (int)$this->groupSort[$groupSno];
}
$this->logger->warning('Not found groupSort. groupSno[' . $groupSno . ']');
return 0;
}
/**
* setGroupNames
* @return void
{
$session = \App::getInstance('session');
$db = \App::getInstance('DB');
$updateTargetMemNos = [];
$pendingReceivers = [];
try {
$groupSno = $this->group->get('sno');
$settleGb = $this->group->get('settleGb');
$this->checkGroupByFigure($item);
}
$beforeGroupSort = $this->resolveGroupSort($item['groupSno']);
$afterGroupSort = $this->resolveGroupSort($groupSno);
//하향펑가를 설정하지 않았거나, 하향평가를 사용하거나, 하향평가를 사용하지 않고 변경 등급이 기존 등급보다 높거나 같을 때 만 업데이트
if (empty($this->policy['downwardAdjustment']) || $this->policy['downwardAdjustment'] == 'y' || ($this->policy['downwardAdjustment'] == 'n' && $beforeGroupSort < $afterGroupSort)) {
if ($this->isCurrentGroupMember || $this->isDefaultGroupMember) {
$this->logger->info('Group change target. sno[' . $this->group->get('sno', 0) . '], name[' . $this->group->get('', '-') . ']', $item);
$updateTargetMemNos[] = $memNo;
$this->updateGroup($memNo);
$this->writeHistory($memNo);
$pendingReceivers[] = $storage;
 
unset($members[$index]);
}
}
$db->commit();
$this->currentMembers = $members;
}
foreach ($pendingReceivers as $receiver) {
$this->addMailReceiver($receiver, $this->group);
$this->addSmsReceiver($receiver, $this->group);
}
} catch (Exception $e) {
$this->logger->error(__METHOD__ . ', ' . $e->getMessage(), ['exception' => $e]);
$db->rollback();
$this->couponSmsBuffer = [];
$this->rolledBackMemNos = array_merge($this->rolledBackMemNos, $updateTargetMemNos);
if (method_exists($this->search, 'removeEvaluatedMemberSnapshots')) {
$this->search->removeEvaluatedMemberSnapshots($updateTargetMemNos);
}
}
}
foreach ($this->couponSmsBuffer as $couponNo => $memNos) {
\Request::post()->set('couponNo', $couponNo);
$result = $this->couponAdmin->saveMemberCouponSms($memNos, null, $passwordCheckFlBool);
if ($result === false) {
$this->logger->warning(sprintf('Coupon issue skipped (checkCouponType failed). couponNo[%d] memNo_cnt[%d]', $couponNo, count($memNos)));
}
}
$this->couponSmsBuffer = [];
}
$memNos,
$couponSaveAdminId,
$passwordCheckFl,
$targetDate,
$this->resolveAppraisalCycleStartDate($targetDate)
);
}
/**
* 변경자는 updateGroup 에서 이미 stamp 되므로, 유지자만 보완해 동일자 재평가 대상에서 제외되도록 한다.
 
 
*
* @param array $memNos
* @param string $targetDate Y-m-d
return;
}
if (!method_exists($this->search, 'getEvaluatedMemberSnapshots')) {
throw new Exception('AppraisalSearch 구버전 감지: getEvaluatedMemberSnapshots 누락. 평가 스냅샷 없이 유지회원 stamp 시 미평가 회원까지 평가완료 처리되어 다음 회차에서 누락될 수 있어 사전 차단합니다.');
}
$db = \App::getInstance('DB');
$touchDateTime = $this->appraisalDateTime ?: ($targetDate . ' 00:00:00');
$from = $targetDate . ' 00:00:00';
$snapshots = $this->search->getEvaluatedMemberSnapshots();
$exclusion = $this->apprExclusionOfRating ?? [];
$appraisalGroupSnos = $this->resolveAppraisalGroupSnos();
if (empty($appraisalGroupSnos)) {
$this->logger->warning('Skip retained member stamp. Not found appraisal target group.', [
'groupSort' => $this->groupSort,
'exclusion' => $exclusion,
]);
return;
}
if (empty($snapshots)) {
// 평가 검색이 실행되지 않은 실행(평가기준 그룹 없음 등) — 종전 라이브 조회 방식으로 stamp
$memNos = array_values(array_diff($memNos, $this->rolledBackMemNos));
if (empty($memNos)) {
return;
}
$arrBind = [];
$db->bind_param_push($arrBind, 's', $touchDateTime);
$placeholders = implode(',', array_fill(0, count($memNos), '?'));
foreach ($memNos as $memNo) {
$db->bind_param_push($arrBind, 'i', $memNo);
}
$db->bind_param_push($arrBind, 's', 'y');
$db->bind_param_push($arrBind, 's', 'n');
$groupPlaceholders = implode(',', array_fill(0, count($appraisalGroupSnos), '?'));
foreach ($appraisalGroupSnos as $sno) {
$db->bind_param_push($arrBind, 'i', $sno);
}
$db->bind_param_push($arrBind, 's', $from);
$strWhere = 'memNo IN (' . $placeholders . ')'
. ' AND appFl = ?'
. ' AND sleepFl = ?'
. ' AND groupSno IN (' . $groupPlaceholders . ')'
. ' AND (autoGroupAppraisalDt IS NULL OR autoGroupAppraisalDt < ?)';
$db->set_update_db(DB_MEMBER, 'autoGroupAppraisalDt = ?', $strWhere, $arrBind);
$this->logger->info('Update autoGroupAppraisalDt for retained members (no snapshot fallback)', [
'table' => DB_MEMBER,
'memNoCount' => count($memNos),
'from' => $from,
]);
return;
}
$retainedMemNos = $this->resolveRetainedStampTargets($snapshots, $exclusion, $appraisalGroupSnos);
if (empty($retainedMemNos)) {
return;
}
$arrBind = [];
$db->bind_param_push($arrBind, 's', $touchDateTime);
$placeholders = implode(',', array_fill(0, count($retainedMemNos), '?'));
foreach ($retainedMemNos as $memNo) {
$db->bind_param_push($arrBind, 'i', $memNo);
}
 
 
$db->bind_param_push($arrBind, 's', 'y');
$db->bind_param_push($arrBind, 's', 'n');
 
 
$db->bind_param_push($arrBind, 's', $from);
 
$strWhere = 'memNo IN (' . $placeholders . ')'
 
. ' AND appFl = ?'
. ' AND sleepFl = ?'
. ' AND (autoGroupAppraisalDt IS NULL OR autoGroupAppraisalDt < ?)';
$db->set_update_db(DB_MEMBER, 'autoGroupAppraisalDt = ?', $strWhere, $arrBind);
$this->logger->info('Update autoGroupAppraisalDt for retained members', [
'table' => DB_MEMBER,
'memNoCount' => count($retainedMemNos),
'from' => $from,
]);
}
/**
* @param array $snapshots memNo => search 결과 row
* @param array $exclusion 제외그룹 sno => sno
* @param array $appraisalGroupSnos 평가 대상 등급 sno 배열
*
* @return array
*/
public function resolveRetainedStampTargets(array $snapshots, array $exclusion, array $appraisalGroupSnos)
{
$retainedMemNos = [];
$appraisalGroupSnos = array_map('intval', $appraisalGroupSnos);
foreach ($snapshots as $memNo => $row) {
$groupSno = is_array($row) ? ($row['groupSno'] ?? null) : null;
if ($groupSno !== null && array_key_exists($groupSno, $exclusion)) {
continue;
}
if ($groupSno !== null && in_array((int)$groupSno, $appraisalGroupSnos, true) === false) {
continue;
}
$retainedMemNos[] = (int)$memNo;
}
return $retainedMemNos;
}
/**
* @return array
*/
public function resolveAppraisalGroupSnos()
{
$groupSnos = array_keys((array)$this->groupSort);
$exclusionSnos = array_values((array)$this->apprExclusionOfRating);
return array_values(array_diff($groupSnos, $exclusionSnos));
}
/**
* 수정이력 추가
$observer = new SmsAutoObserver();
$observer->setSmsType(SmsAutoCode::MEMBER);
$observer->setSmsAutoCodeType(Code::GROUP_CHANGE);
$observer->setReceiver([
'memNo' => $storage->get('memNo'),
'memNm' => $storage->get('memNm'),
'smsFl' => $storage->get('smsFl', 'y'),
'cellPhone' => $storage->get('cellPhone'),
]);
$observer->setReplaceArguments(
[
'rc_groupNm' => $group->get('groupNm'),
'name' => $storage->get('memNm'),
'memNm' => $storage->get('memNm'),
'memNo' => $storage->get('memNo'),
'groupNm' => $group->get('groupNm'),
'rc_mallNm' => \Globals::get('gMall.mallNm'),
'shopUrl' => $this->basicInfo['mallDomain'],
* 전체 등급 설정을 스캔하여 실제 필요한 데이터 유형을 결정
* @return array ['order' => bool, 'review' => bool, 'login' => bool]
*/
protected function resolveRequiredData(): array
{
$isPoint = $this->_isAppraisalSystemPoint();
 
Component/Member/Group/AppraisalSearch.php+27-4
변경 전AppraisalSearch.php
protected $targetDateTime;
/** @var array airflow 가 지정한 memNo 배열 */
protected $targetMembers = [];
 
 
/** @var array 필요한 서브쿼리 플래그 ['order' => bool, 'review' => bool, 'login' => bool] */
protected $requiredData = ['order' => true, 'review' => true, 'login' => true];
$this->buildQuery(empty($this->targetMembers) ? '' : $this->whereExcludeCompleteMember());
$logger->info(sprintf('Build query complete. %s', $this->query));
$results = $this->db->query_fetch($this->query);
$logger->debug('Appraisal search result keys', array_keys($results[0]));
$return = [];
foreach ($results as $index => $result) {
if (key_exists($result['memNo'], $return)) {
$return[$result['memNo']] = $result;
}
 
 
 
 
 
 
 
 
return $return;
}
*/
public function searchDefaultGroup($appraisalDateTime)
{
$this->db->strField = 'm.memNo, m.memNm, m.email, m.cellPhone, m.groupSno, m.adminMemo, m.groupModDt';
// 다른등급 대상 회원 조회(_pushWhere())와 조건 동일하게 설정
$this->db->strWhere = 'm.sleepFl=\'n\' AND m.appFl=\'y\'';
if (!empty($this->targetMembers)) {
$return[$result['memNo']] = $result;
}
}
 
return $return;
}
*/
private function _pushColumn()
{
$this->column[] = 'm.memNo, m.memNm, m.email, m.cellPhone, m.groupSno, m.adminMemo, m.groupModDt';
if ($this->requiredData['login']) {
$this->column[] = 'IFNULL(l.cnt, 0) AS loginCount';
$this->targetMembers = $target;
}
 
 
 
 
 
 
 
 
 
 
 
 
/*
* 타겟일자기준 회원등급평가 완료대상 제외 where 조건
*
*/
public function whereExcludeCompleteMember()
{
$from = "{$this->targetDateTime} 00:00:00";
return "(m.autoGroupAppraisalDt IS NULL OR m.autoGroupAppraisalDt < '{$from}')";
}
}
 
변경 후AppraisalSearch.php
protected $targetDateTime;
/** @var array airflow 가 지정한 memNo 배열 */
protected $targetMembers = [];
/** @var array 실제 평가된 회원 스냅샷 (memNo => search 결과 row). 유지회원 stamp 대상 판정 기준 */
protected $evaluatedMembers = [];
/** @var array 필요한 서브쿼리 플래그 ['order' => bool, 'review' => bool, 'login' => bool] */
protected $requiredData = ['order' => true, 'review' => true, 'login' => true];
$this->buildQuery(empty($this->targetMembers) ? '' : $this->whereExcludeCompleteMember());
$logger->info(sprintf('Build query complete. %s', $this->query));
$results = $this->db->query_fetch($this->query);
$logger->debug('Appraisal search result keys', empty($results) ? [] : array_keys($results[0]));
$return = [];
foreach ($results as $index => $result) {
if (key_exists($result['memNo'], $return)) {
$return[$result['memNo']] = $result;
}
$logger->info(sprintf('Appraisal search matched %d of %d requested members. groupSno[%s]', count($return), count($this->targetMembers), $group->get('sno', '-')));
if (!empty($this->targetMembers)) {
foreach ($return as $memNo => $row) {
$this->evaluatedMembers[$memNo] = $row;
}
}
return $return;
}
*/
public function searchDefaultGroup($appraisalDateTime)
{
$this->db->strField = 'm.memNo, m.memNm, m.email, m.cellPhone, m.smsFl, m.maillingFl, m.groupSno, m.adminMemo, m.groupModDt';
// 다른등급 대상 회원 조회(_pushWhere())와 조건 동일하게 설정
$this->db->strWhere = 'm.sleepFl=\'n\' AND m.appFl=\'y\'';
if (!empty($this->targetMembers)) {
$return[$result['memNo']] = $result;
}
}
return $return;
}
*/
private function _pushColumn()
{
$this->column[] = 'm.memNo, m.memNm, m.email, m.cellPhone, m.smsFl, m.maillingFl, m.groupSno, m.adminMemo, m.groupModDt';
if ($this->requiredData['login']) {
$this->column[] = 'IFNULL(l.cnt, 0) AS loginCount';
$this->targetMembers = $target;
}
public function getEvaluatedMemberSnapshots()
{
return $this->evaluatedMembers;
}
public function removeEvaluatedMemberSnapshots(array $memNos)
{
foreach ($memNos as $memNo) {
unset($this->evaluatedMembers[$memNo]);
}
}
/*
* 타겟일자기준 회원등급평가 완료대상 제외 where 조건
*
*/
public function whereExcludeCompleteMember()
{
$from = $this->db->escape("{$this->targetDateTime} 00:00:00");
return "(m.autoGroupAppraisalDt IS NULL OR m.autoGroupAppraisalDt < '{$from}')";
}
}
 
Component/Member/History.php+4-11
변경 전History.php
/**
* 수정 전/후 데이터 불러오기
*
* @param array $before 수정 전 데이터를 호출부에서 주입 (empty 면 세션에서 조회)
* @param array $after 수정 후 데이터를 호출부에서 주입 (empty 면 DB 에서 조회)
* @return $this
*/
public function initBeforeAndAfter(array $before = [], array $after = [])
{
if (empty($before)) {
$session = \App::getInstance('session');
$before = $session->get(Member::SESSION_MODIFY_MEMBER_INFO, null);
}
if (empty($after)) {
// 호출부가 수정 후 데이터를 주입하지 않은 경우에만 DB 조회 (자동 등급평가 등 대량 호출 시 주입으로 SELECT N→0 감소)
$after = $this->db->getData(DB_MEMBER, $this->memNo, 'memNo');
}
 
// 자동 등급평가 등 세션 미세팅 경로에서 null 이 들어올 수 있음.
// combineMemberData → ArrayUtils::unsetDiff(array $keys) 가 strict 타입이라 TypeError 발생 → 빈 배열로 보정.
 
변경 후History.php
/**
* 수정 전/후 데이터 불러오기
*
 
 
* @return $this
*/
public function initBeforeAndAfter()
{
$session = \App::getInstance('session');
$before = $session->get(Member::SESSION_MODIFY_MEMBER_INFO, null);
$after = $this->db->getData(DB_MEMBER, $this->memNo, 'memNo');
 
 
 
 
 
 
// 자동 등급평가 등 세션 미세팅 경로에서 null 이 들어올 수 있음.
// combineMemberData → ArrayUtils::unsetDiff(array $keys) 가 strict 타입이라 TypeError 발생 → 빈 배열로 보정.