Skip to content

Commit

Permalink
Merge pull request EC-CUBE#431 from seasoftjapan/20201208
Browse files Browse the repository at this point in the history
カテゴリに紐付いた商品が0となった場合に dtb_category_total_count が更新されない EC-CUBE#125
  • Loading branch information
nanasess authored Mar 24, 2024
2 parents bce476d + b8c1141 commit aea89c3
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 85 deletions.
143 changes: 62 additions & 81 deletions data/class/helper/SC_Helper_DB.php
Original file line number Diff line number Diff line change
Expand Up @@ -772,35 +772,37 @@ public function sfCountCategory($objQuery = NULL, $is_force_all_count = false, $
}

//共通のfrom/where文の構築
$sql_where = SC_Product_Ex::getProductDispConditions('alldtl');
$where_alldtl = SC_Product_Ex::getProductDispConditions('alldtl');
// 在庫無し商品の非表示
if ($is_nostock_hidden) {
$where_products_class = '(stock >= 1 OR stock_unlimited = 1)';
$from = $objProduct->alldtlSQL($where_products_class);
$from_alldtl = $objProduct->alldtlSQL('(stock >= 1 OR stock_unlimited = 1)');
} else {
$from = 'dtb_products as alldtl';
$from_alldtl = 'dtb_products as alldtl';
}

//dtb_category_countの構成
// 各カテゴリに所属する商品の数を集計。集計対象には子カテゴリを含まない。

//まずテーブル内容の元を取得
if (!$is_force_all_count) {
$arrCategoryCountOld = $objQuery->select('category_id,product_count', 'dtb_category_count');
if ($is_force_all_count) {
$objQuery->delete('dtb_category_count');
$arrCategoryCountOld = [];
} else {
$arrCategoryCountOld = array();
// テーブル内容の元を取得
$arrCategoryCountOld = $objQuery->select('category_id, product_count', 'dtb_category_count');
}

//各カテゴリ内の商品数を数えて取得
$sql = <<< __EOS__
SELECT T1.category_id, count(T2.category_id) as product_count
SELECT T1.category_id, count(*) as product_count
FROM dtb_category AS T1
LEFT JOIN dtb_product_categories AS T2
INNER JOIN dtb_product_categories AS T2
ON T1.category_id = T2.category_id
LEFT JOIN $from
INNER JOIN $from_alldtl
ON T2.product_id = alldtl.product_id
WHERE $sql_where
GROUP BY T1.category_id, T2.category_id
AND $where_alldtl
WHERE T1.del_flg = 0
GROUP BY T1.category_id
HAVING count(*) <> 0
__EOS__;

$arrCategoryCountNew = $objQuery->getAll($sql);
Expand All @@ -809,118 +811,97 @@ public function sfCountCategory($objQuery = NULL, $is_force_all_count = false, $

//各カテゴリ毎のデータ値において以前との差を見る
//古いデータの構造入れ替え
$arrOld = array();
$arrOld = [];
foreach ($arrCategoryCountOld as $item) {
$arrOld[$item['category_id']] = $item['product_count'];
}
//新しいデータの構造入れ替え
$arrNew = array();
$arrNew = [];
foreach ($arrCategoryCountNew as $item) {
$arrNew[$item['category_id']] = $item['product_count'];
}

unset($arrCategoryCountOld);
unset($arrCategoryCountNew);

$arrDiffCategory_id = array();
//新しいカテゴリ一覧から見て商品数が異なるデータが無いか確認
foreach ($arrNew as $cid => $count) {
if ($arrOld[$cid] != $count) {
$arrDiffCategory_id[] = $cid;
}
}
$arrNotExistsProductCategoryId = [];
//削除カテゴリを想定して、古いカテゴリ一覧から見て商品数が異なるデータが無いか確認。
foreach ($arrOld as $cid => $count) {
if ($arrNew[$cid] != $count && $count > 0) {
$arrDiffCategory_id[] = $cid;
foreach ($arrOld as $category_id => $count) {
// 商品が存在しない
if (!isset($arrNew[$category_id])) {
$arrNotExistsProductCategoryId[] = $category_id;
}
// 変更なし
elseif ($arrNew[$category_id] == $count) {
unset($arrNew[$category_id]);
}
}

//対象IDが無ければ終了
if (count($arrDiffCategory_id) == 0) {
if ($is_out_trans) {
$objQuery->commit();
}
// 差分があったIDとその親カテゴリID
$arrTgtCategoryId = $arrNotExistsProductCategoryId;

return;
}
foreach ($arrNotExistsProductCategoryId as $category_id) {
$objQuery->delete('dtb_category_count', 'category_id = ?', array($category_id));

//差分対象カテゴリIDの重複を除去
$arrDiffCategory_id = array_unique($arrDiffCategory_id);
$arrParentID = self::sfGetParentsArray('dtb_category', 'parent_category_id', 'category_id', $category_id);
$arrTgtCategoryId = array_merge($arrTgtCategoryId, $arrParentID);
}

//dtb_category_countの更新 差分のあったカテゴリだけ更新する。
foreach ($arrDiffCategory_id as $cid) {
$sqlval = array();
// dtb_category_countの更新 差分のあったカテゴリだけ更新する。
foreach ($arrNew as $category_id => $count) {
$sqlval = [];
$sqlval['create_date'] = 'CURRENT_TIMESTAMP';
$sqlval['product_count'] = (string) $arrNew[$cid];
if ($sqlval['product_count'] =='') {
$sqlval['product_count'] = (string) '0';
}
if (isset($arrOld[$cid])) {
$objQuery->update('dtb_category_count', $sqlval, 'category_id = ?', array($cid));
$sqlval['product_count'] = $count;
if (isset($arrOld[$category_id])) {
$objQuery->update('dtb_category_count', $sqlval, 'category_id = ?', array($category_id));
} else {
if ($is_force_all_count) {
$ret = $objQuery->update('dtb_category_count', $sqlval, 'category_id = ?', array($cid));
if ($ret > 0) {
continue;
}
}
$sqlval['category_id'] = $cid;
$sqlval['category_id'] = $category_id;
$objQuery->insert('dtb_category_count', $sqlval);
}
$arrParentID = self::sfGetParentsArray('dtb_category', 'parent_category_id', 'category_id', $category_id);
$arrTgtCategoryId = array_merge($arrTgtCategoryId, $arrParentID);
}
$arrTgtCategoryId = array_unique($arrTgtCategoryId);

unset($arrOld);
unset($arrNew);

//差分があったIDとその親カテゴリIDのリストを取得する
$arrTgtCategory_id = array();
foreach ($arrDiffCategory_id as $parent_category_id) {
$arrTgtCategory_id[] = $parent_category_id;
$arrParentID = $this->sfGetParentsArray('dtb_category', 'parent_category_id', 'category_id', $parent_category_id);
$arrTgtCategory_id = array_unique(array_merge($arrTgtCategory_id, $arrParentID));
}

unset($arrDiffCategory_id);

//dtb_category_total_count 集計処理開始
//更新対象カテゴリIDだけ集計しなおす。
$arrUpdateData = array();
$where_products_class = '';
if ($is_nostock_hidden) {
$where_products_class .= '(stock >= 1 OR stock_unlimited = 1)';
}
$from = $objProduct->alldtlSQL($where_products_class);
foreach ($arrTgtCategory_id as $category_id) {
$arrWhereVal = array();
$arrUpdateData = [];
foreach ($arrTgtCategoryId as $category_id) {
$arrWhereVal = [];
list($tmp_where, $arrTmpVal) = static::sfGetCatWhere($category_id);
if ($tmp_where != '') {
$sql_where_product_ids = 'product_id IN (SELECT product_id FROM dtb_product_categories WHERE ' . $tmp_where . ')';
$where_product_ids = 'product_id IN (SELECT product_id FROM dtb_product_categories WHERE ' . $tmp_where . ')';
$arrWhereVal = $arrTmpVal;
} else {
$sql_where_product_ids = '0<>0'; // 一致させない
$where_product_ids = '0<>0'; // 一致させない
}
$where = "($sql_where) AND ($sql_where_product_ids)";
$where = "($where_alldtl) AND ($where_product_ids)";

$arrUpdateData[$category_id] = $objQuery->count($from, $where, $arrWhereVal);
$arrUpdateData[$category_id] = $objQuery->count($from_alldtl, $where, $arrWhereVal);
}

unset($arrTgtCategory_id);
unset($arrTgtCategoryId);

// 更新対象だけを更新。
foreach ($arrUpdateData as $cid => $count) {
$sqlval = array();
$sqlval['create_date'] = 'CURRENT_TIMESTAMP';
$sqlval['product_count'] = $count;
if ($sqlval['product_count'] =='') {
$sqlval['product_count'] = (string) '0';
foreach ($arrUpdateData as $category_id => $count) {
if ($count == 0) {
$objQuery->delete('dtb_category_total_count', 'category_id = ?', array($category_id));
continue 1;
}
$ret = $objQuery->update('dtb_category_total_count', $sqlval, 'category_id = ?', array($cid));
$sqlval = [
'product_count' => $count,
'create_date' => 'CURRENT_TIMESTAMP',
];
$ret = $objQuery->update('dtb_category_total_count', $sqlval, 'category_id = ?', array($category_id));
if (!$ret) {
$sqlval['category_id'] = $cid;
$sqlval['category_id'] = $category_id;
$objQuery->insert('dtb_category_total_count', $sqlval);
}
}

// トランザクション終了処理
if ($is_out_trans) {
$objQuery->commit();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,49 @@ protected function setUp()

public function testSfCountCategory()
{
// 全カテゴリに1商品を割り当てる
$this->objDb->updateProductCategories($this->category_ids, $this->product_id);
$this->objDb->sfCountCategory($this->objQuery);

// 検証
$category_counts = $this->objQuery->select('*', 'dtb_category_count');
$category_ids = [];
foreach ($category_counts as $arrCategoryCount) {
$this->assertTrue(in_array($arrCategoryCount['category_id'], $this->category_ids));
$category_ids[] = $arrCategoryCount['category_id'];
$this->assertEquals(1, $arrCategoryCount['product_count']);
}

// カテゴリに過不足がないことを検証する。
// TODO: phpUnit 7.5 以降になったら、assertEqualsCanonicalizing を使うべき。ただ、型の違いが無視されるか分からない。(array_diff は無視されるので都合が良い。)
$this->assertSame(
array_diff($category_ids, $this->category_ids), // 過剰を検出
array_diff($this->category_ids, $category_ids), // 不足を検出
'不足 (that 側に出力) または過剰 (to 側に出力) がある。'
);
}

public function testSfCountCategoryWithTotalCount()
{
$this->objDb->addProductBeforCategories($this->category_ids[0], $this->product_id);
// できるだけ深い階層のカテゴリをテスト対象とする。
$arrCategory = $this->objQuery->getRow('*', 'dtb_category', '0=0 ORDER BY level DESC LIMIT 1');

// 商品カテゴリ登録
$this->objDb->addProductBeforCategories($arrCategory['category_id'], $this->product_id);
$this->objDb->sfCountCategory($this->objQuery);
// 検証
$category_total_counts = $this->objQuery->select('*', 'dtb_category_total_count');
$this->assertCount(1, $category_total_counts);
$this->assertCount((int)$arrCategory['level'], $category_total_counts);
foreach ($category_total_counts as $arrCategoryTotalCount) {
$this->assertTrue(in_array($arrCategoryTotalCount['category_id'], $this->category_ids));
$this->assertEquals(1, $arrCategoryTotalCount['product_count']);
}

// 商品カテゴリ削除
$this->objDb->removeProductByCategories($arrCategory['category_id'], $this->product_id);
$this->objDb->sfCountCategory($this->objQuery);
// 検証
$category_ids = $this->objQuery->getCol('category_id', 'dtb_category_total_count');
$this->assertEmpty($category_ids, 'dtb_category_total_count にデータが残っている。: ' . var_export($category_ids, true));
}

public function testSfCountCategoryWithNoStockHidden()
Expand Down Expand Up @@ -79,7 +102,6 @@ public function setUpCategories()
$delete_tables = ['dtb_category', 'dtb_product_categories', 'dtb_category_total_count', 'dtb_category_count'];
foreach ($delete_tables as $table) {
$this->objQuery->delete($table);

}

$this->product_id = $this->objGenerator->createProduct();
Expand Down

0 comments on commit aea89c3

Please sign in to comment.