スポンサードリンク

EC CUBE
EC CUBE

この前、廃番になった商品を非公開設定したのですが、

あまりにも多かったので

こちらでSQL文作って作業をしました。

このままだと、SQL使う人しか大量の品を変更する作業を

できなくなってしまいます。

簡単に誰でもできるようにするため

一括で公開・非公開と削除できるようにカスタマイズしました。

スポンサードリンク

管理画面のイメージ

商品マスター
商品マスター

商品を一括で公開・非公開や削除する場合は

関連する商品も表示させれるといいので

商品検索機能がついている

商品管理→商品マスター画面で作業できるようにしました。

実装する内容はこちらです。

・商品検索結果一覧にチェックボタンを付ける

・チェックボタンがついているものだけ公開・非公開を切り替える

・チェックボタンがついているものだけ削除させる

LC_Page_Admin_Products.phpを編集

/data/class/pages/admin/products/LC_Page_Admin_Products.phpを編集します。

103行目辺りにある

 switch ($this->getMode()) {

のswitch文の前後に以下を追加します。

※一部記述漏れがありましたので訂正しました。(2013.5.21)
※s.suzukiさんありがとうございます。

//表示件数を取得を追加
$n = $_POST["search_page_max"];
//表示件数をパラメータに渡す
$this->lfInitParam($objFormParam, $n);

switch ($this->getMode()) {
  //一括ボタン追加ここから
   case 'check_status':
     	for ($i=0; $i<$n; $i++){
       		if(isset($this->arrForm["product_id$i"]["value"])){
        		if($this->arrForm["check$i"]["value"] == 1){
        			if($this->arrForm["status$i"]["value"] == 1){
        				$cols['status']  = 2;
        			}elseif($this->arrForm["status$i"]["value"] == 2){
        				$cols['status']  = 1;
        			}
        			$col['update_date'] = 'CURRENT_TIMESTAMP';
        			$wheres = "product_id = ?";
        			$objQuery->begin();
        			$objQuery->update('dtb_products', $cols, $wheres, array($this->arrForm["product_id$i"]["value"]));
        			$objQuery->commit();
        		}
       		}
       	}
       	$objFormParam->convParam();
       	$objFormParam->trimParam();
       	$this->arrErr = $this->lfCheckError($objFormParam);
       	$arrParam = $objFormParam->getHashArray();
        	if (count($this->arrErr) == 0) {
       		$where = "del_flg = 0";
       		foreach ($arrParam as $key => $val) {
       			if($val == "") {
       				continue;
       			}
       			$this->buildQuery($key, $where, $arrval, $objFormParam, $objDb);
       		}
        		$order = "update_date DESC";
        		// 行数の取得
       		$this->tpl_linemax = $this->getNumberOfLines($where, $arrval);
       		// ページ送りの処理
       		$page_max = SC_Utils_Ex::sfGetSearchPageMax($objFormParam->getValue('search_page_max'));
       		// ページ送りの取得
       		$objNavi = new SC_PageNavi_Ex($this->arrHidden['search_pageno'],
       				$this->tpl_linemax, $page_max,
       				'fnNaviSearchPage', NAVI_PMAX);
       		$this->arrPagenavi = $objNavi->arrPagenavi;

       		// 検索結果の取得
       		$this->arrProducts = $this->findProducts($where, $arrval,
       				$page_max, $objNavi->start_row, $order, $objProduct);
        		// 各商品ごとのカテゴリIDを取得
       		if (count($this->arrProducts) > 0) {
       			foreach ($this->arrProducts as $key => $val) {
       				$this->arrProducts[$key]['categories'] = $objDb->sfGetCategoryId($val["product_id"], 0, true);
       				$objDb->g_category_on = false;
       			}
       		}
       	}
        	break;
        case 'check_delete':
       	for ($i=0; $i<$n; $i++){
       		if(isset($this->arrForm["product_id$i"]["value"])){
        		if($this->arrForm["check$i"]["value"] == 1){
        			// 商品、子テーブル(商品規格)、顧客お気に入り商品の削除
			        $cols['del_flg']     = 1;
			        $cols['update_date'] = 'CURRENT_TIMESTAMP';
			        $wheres = "product_id = ?";
			        $objQuery->begin();
			        $objQuery->update('dtb_products_class', $cols, "product_id IN (SELECT product_id FROM dtb_products WHERE $wheres)", array($this->arrForm["product_id$i"]["value"]));
			        $objQuery->delete('dtb_customer_favorite_products', "product_id IN (SELECT product_id FROM dtb_products WHERE $wheres)", array($this->arrForm["product_id$i"]["value"]));
			        $objQuery->update('dtb_products', $cols, $wheres, array($this->arrForm["product_id$i"]["value"]));
			        $objQuery->commit();
        			// 件数カウントバッチ実行
        			$objDb->sfCountCategory($objQuery);
        			$objDb->sfCountMaker($objQuery);
        		}
       		}
       	}
       	$objFormParam->convParam();
       	$objFormParam->trimParam();
       	$this->arrErr = $this->lfCheckError($objFormParam);
       	$arrParam = $objFormParam->getHashArray();

       	if (count($this->arrErr) == 0) {
       		$where = "del_flg = 0";
       		foreach ($arrParam as $key => $val) {
       			if($val == "") {
       				continue;
       			}
       			$this->buildQuery($key, $where, $arrval, $objFormParam, $objDb);
       		}
        		$order = "update_date DESC";
        		// 行数の取得
       		$this->tpl_linemax = $this->getNumberOfLines($where, $arrval);
       		// ページ送りの処理
       		$page_max = SC_Utils_Ex::sfGetSearchPageMax($objFormParam->getValue('search_page_max'));
       		// ページ送りの取得
       		$objNavi = new SC_PageNavi_Ex($this->arrHidden['search_pageno'],
       				$this->tpl_linemax, $page_max,
       				'fnNaviSearchPage', NAVI_PMAX);
       		$this->arrPagenavi = $objNavi->arrPagenavi;
        		// 検索結果の取得
       		$this->arrProducts = $this->findProducts($where, $arrval,
       				$page_max, $objNavi->start_row, $order, $objProduct);

       		// 各商品ごとのカテゴリIDを取得
       		if (count($this->arrProducts) > 0) {
       			foreach ($this->arrProducts as $key => $val) {
       				$this->arrProducts[$key]['categories'] = $objDb->sfGetCategoryId($val["product_id"], 0, true);
       				$objDb->g_category_on = false;
       			}
       		}
       	}
       	break;
        //一括ボタン追加ここまで

        case 'delete':
            // 商品、子テーブル(商品規格)、顧客お気に入り商品の削除
     ・・・
     //以下デフォルトのまま

次にパラメーターを設定します。

lfInitParam関数に引数とfor文を追加します。

function lfInitParam(&$objFormParam, $page) {
    // POSTされる値
    $objFormParam->addParam('商品ID', 'product_id', INT_LEN, 'n', array('NUM_CHECK', 'MAX_LENGTH_CHECK'));
    $objFormParam->addParam('カテゴリID', 'category_id', STEXT_LEN, 'n', array('SPTAB_CHECK', 'MAX_LENGTH_CHECK'));
    $objFormParam->addParam('ページ送り番号','search_pageno', INT_LEN, 'n', array('MAX_LENGTH_CHECK', 'NUM_CHECK'));
    $objFormParam->addParam('表示件数', 'search_page_max', INT_LEN, 'n', array('MAX_LENGTH_CHECK', 'NUM_CHECK'));
    
    //追加ここから
    // 追加POSTされる値 表示件数によって数を変える
    for($i=0; $i < $page; $i++){
       	$objFormParam->addParam('チェックボタン', 'check'.$i, INT_LEN, 'n', array('MAX_LENGTH_CHECK', 'NUM_CHECK'));
       	$objFormParam->addParam('チェックボタン用id', 'product_id'.$i, INT_LEN, 'n', array('MAX_LENGTH_CHECK', 'NUM_CHECK'));
       	$objFormParam->addParam('ステータス', 'status'.$i, INT_LEN, 'n', array('MAX_LENGTH_CHECK', 'NUM_CHECK'));
    }
  //ここまで

    // 検索条件
    $objFormParam->addParam('商品ID', 'search_product_id', INT_LEN, 'n', array('NUM_CHECK', 'MAX_LENGTH_CHECK'));
    // ・・・
  //以下同じ

【解説】※読み飛ばしても構いません。

//表示件数を取得を追加
$n = $_POST["search_page_max"];

まず、ポストされる表示件数を取得します。

取得した表示件数でパラメーターの個数を決めてパラメーターを作ります。

action内でこのように記述しておきます。

$this->lfInitParam($objFormParam, $n);

lfInitParam関数で引数に件数を入れられるようにします。

function lfInitParam(&$objFormParam, $page) {

次に件数を繰り返し回数としてパラメーターを作ります。

    for($i=0; $i < $page; $i++){
       	$objFormParam->addParam('チェックボタン', 'check'.$i, INT_LEN, 'n', array('MAX_LENGTH_CHECK', 'NUM_CHECK'));
       	$objFormParam->addParam('チェックボタン用id', 'product_id'.$i, INT_LEN, 'n', array('MAX_LENGTH_CHECK', 'NUM_CHECK'));
       	$objFormParam->addParam('ステータス', 'status'.$i, INT_LEN, 'n', array('MAX_LENGTH_CHECK', 'NUM_CHECK'));
    }

以上で、フォームから送られるデータの準備ができました。

次に、switch文です。

一括で公開・非公開するボタン名は 【check_status】

一括で削除するボタン名は 【check_delete】

としたのでswitch文にボタンごとの挙動を書きます。

     	for ($i=0; $i<$n; $i++){
       		if(isset($this->arrForm["product_id$i"]["value"])){
        		if($this->arrForm["check$i"]["value"] == 1){
        			if($this->arrForm["status$i"]["value"] == 1){
        				$cols['status']  = 2;
        			}elseif($this->arrForm["status$i"]["value"] == 2){
        				$cols['status']  = 1;
        			}
        			$col['update_date'] = 'CURRENT_TIMESTAMP';
        			$wheres = "product_id = ?";
        			$objQuery->begin();
        			$objQuery->update('dtb_products', $cols, $wheres, array($this->arrForm["product_id$i"]["value"]));
        			$objQuery->commit();
        		}
       		}
       	}

まず、表示件数10件で5件しかデータがない場合もあるので

変数の中身を確認します。

次に、値が入っていたら商品に関連した商品IDで「公開・非公開」を確認して

変数に入れ変えた値を代入して、

SQLで書き換えます。

$objFormParam->convParam();
~
break;

までは、処理後に検索結果を表示させたいので

もともとswitch文のdelete以下にある部分で

必要なところだけ追加しました。

次に【check_delete】です。

for ($i=0; $i<$n; $i++){
       		if(isset($this->arrForm["product_id$i"]["value"])){
        		if($this->arrForm["check$i"]["value"] == 1){
        			// 商品、子テーブル(商品規格)、顧客お気に入り商品の削除
			        $cols['del_flg']     = 1;
			        $cols['update_date'] = 'CURRENT_TIMESTAMP';
			        $wheres = "product_id = ?";
			        $objQuery->begin();
			        $objQuery->update('dtb_products_class', $cols, "product_id IN (SELECT product_id FROM dtb_products WHERE $wheres)", array($this->arrForm["product_id$i"]["value"]));
			        $objQuery->delete('dtb_customer_favorite_products', "product_id IN (SELECT product_id FROM dtb_products WHERE $wheres)", array($this->arrForm["product_id$i"]["value"]));
			        $objQuery->update('dtb_products', $cols, $wheres, array($this->arrForm["product_id$i"]["value"]));
			        $objQuery->commit();
        			// 件数カウントバッチ実行
        			$objDb->sfCountCategory($objQuery);
        			$objDb->sfCountMaker($objQuery);
        		}
       		}
       	}

これも【check_status】とほぼ同じで

変数の値の確認後、

消す内容が同じなのでswitch文のdelete項目のdoDeleteメソッドを利用しています。

$objFormParam->convParam();
~
break;

上記の部分は【check_status】と同じです。

スポンサードリンク

【check_status】と【check_delete】のボタン名を登録

【check_status】と【check_delete】のボタン名を登録します。

/js/site.jsのファイルを編集します。

// モードとキーを指定してSUBMITを行う。
function fnModeSubmit(mode, keyname, keyid) {
    switch(mode) {
    case 'delete_category':
        if(!window.confirm('選択したカテゴリとカテゴリ内のすべてのカテゴリを削除します')){
            return;
        }
        break;
    case 'delete':
        if(!window.confirm('一度削除したデータは、元に戻せません。\n削除しても宜しいですか?')){
            return;
        }
        break;
    case 'delete_order':
        if(!window.confirm('一度削除したデータは、元に戻せません。\n削除しても宜しいですか?\n\n※ 在庫数は手動で戻してください。')){
            return;
        }
        mode = 'delete';
        break;
    case 'confirm':
        if(!window.confirm('登録しても宜しいですか')){
            return;
        }
        break;
    case 'delete_all':
        if(!window.confirm('検索結果をすべて削除しても宜しいですか')){
            return;
        }
        break;
    //項目追加
    case 'check_status':
        if(!window.confirm('チェックしたものをすべて表示/非表示しても宜しいですか')){
            return;
        }
        break;
    case 'check_delete':
        if(!window.confirm('チェックしたものをすべて削除しても宜しいですか')){
            return;
        }
        break;
    default:
        break;
    }
    document.form1['mode'].value = mode;
    if(keyname != "" && keyid != "") {
        document.form1[keyname].value = keyid;
    }
    document.form1.submit();
}

fnModeSubmitメソッドに追加します。

商品マスターにチェックボタンを追加

/data/Smarty/templates/admin/products/index.tplを編集します。

※一部記述漏れがありましたので訂正しました。(2013.5.21)
※s.suzukiさんありがとうございます。

・・・
    <h2>検索結果一覧</h2>
    <div class="btn">
        <span class="attention"><!--検索結果数--><!--{$tpl_linemax}-->件</span>&nbsp;が該当しました。
        <!--検索結果-->
        <!--{if $smarty.const.ADMIN_MODE == '1'}-->
            <a class="btn-normal" href="javascript:;" onclick="fnModeSubmit('delete_all','',''); return false;">検索結果をすべて削除</a>
        <!--{/if}-->
        <a class="btn-tool" href="javascript:;" onclick="fnModeSubmit('csv','',''); return false;">CSV ダウンロード</a>
        <a class="btn-tool" href="../contents/csv.php?tpl_subno_csv=product">CSV 出力項目設定</a>
	<!-- ●ボタン追加始まり● -->
        <a  class="btn-tool" href="javascript:;" onclick="fnModeSubmit('check_status','',''); return false;">チェックしたものを「公開⇔非公開」切替</a>
        <a  class="btn-tool" href="javascript:;" onclick="fnModeSubmit('check_delete','',''); return false;">チェックしたものを削除</a>
	<!-- ●ボタン追加終わり● -->
    </div>
・・・

<!--{if count($arrErr) == 0 and ($smarty.post.mode == 'search' or $smarty.post.mode == 'delete' or $smarty.post.mode == 'check_status' or $smarty.post.mode == 'check_delete')}-->
・・・

<!--★★検索結果一覧★★-->
<form name="form1" id="form1" method="post" action="?">
・・・

        <!--検索結果表示テーブル-->
        <table class="list" id="products-search-result">
            <colgroup width="5%">
            <colgroup width="5%">
            <colgroup width="8%">
            <colgroup width="8%">
            <colgroup width="8%">
            <colgroup width="26%">
            <colgroup width="5%">
            <colgroup width="5%">
            <colgroup width="5%">
            <colgroup width="5%">
            <colgroup width="5%">
            <colgroup width="5%">
            <colgroup width="5%">
            <tr>
                <th rowspan="2">全て<br /><input type="checkbox" name="all_check" value="1" id="all_check" /></th>
                <th rowspan="2">商品ID</th>
                <th rowspan="2">商品画像</th>
                <th rowspan="2">商品コード</th>
                <th rowspan="2">価格(円)</th>
                <th>商品名</th>
                <th rowspan="2">在庫</th>
                <th rowspan="2">種別</th>
                <th rowspan="2">編集</th>
                <th rowspan="2">確認</th>
                <!--{if $smarty.const.OPTION_CLASS_REGIST == 1}-->
                <th rowspan="2">規格</th>
                <!--{/if}-->
                <th rowspan="2">削除</th>
                <th rowspan="2">複製</th>
            </tr>
            <tr>
                <th nowrap><a href="#" onClick="lfnDispChange(); return false;">カテゴリ ⇔ URL</a></th>
            </tr>

            <!--{section name=cnt loop=$arrProducts}-->
                <!--▼商品<!--{$smarty.section.cnt.iteration}-->-->
                <!--{assign var=status value="`$arrProducts[cnt].status`"}-->
                <tr style="background:<!--{$arrPRODUCTSTATUS_COLOR[$status]}-->;">
		    <!-- ●追加始まり● -->
                    <td class="check" rowspan="2">
			<input type="checkbox" name="check<!--{$smarty.section.cnt.index}-->" class="check_box" value="1" />
			<input type="hidden" name="product_id<!--{$smarty.section.cnt.index}-->" value="<!--{$arrProducts[cnt].product_id}-->" />
                    </td>
                    <!-- ●追加終わり● -->
                    <td class="id" rowspan="2"><!--{$arrProducts[cnt].product_id}--></td>
                    <td class="thumbnail" rowspan="2">
 
          ・・・
                    <!-- ●追加始まり● -->
                    <!--{* 表示 *}-->
                    <!--{assign var=key value=$arrProducts[cnt].status}-->
                    <td class="menu" rowspan="2">
                    	<!--{$arrDISP[$key]}-->
                    	<input type="hidden" name="status<!--{$smarty.section.cnt.index}-->" value="<!--{$arrProducts[cnt].status}-->" />
                    </td>
                    <!-- ●追加終わり● -->
          ・・・

            <!--{/section}-->
        </table>
        <input type="hidden" name="item_cnt" value="<!--{$arrProducts|@count}-->" />
        <!--検索結果表示テーブル-->
    <!--{/if}-->

【解説】※読み飛ばしても構いません。

検索結果一覧の項目の場所にボタンを設置します。

次は、if文に

<!--{if count($arrErr) == 0 and ($smarty.post.mode == 'search' or $smarty.post.mode == 'delete' or $smarty.post.mode == 'check_status' or $smarty.post.mode == 'check_delete')}-->

条件式を追加します。

これを最初書いていなかったので、削除などしても

一覧が出なかったんですよ。

<!-- ●追加始まり● -->
<td class="check" rowspan="2">
   <input type="checkbox" name="check<!--{$smarty.section.cnt.index}-->" class="check_box" value="1" />
   <input type="hidden" name="product_id<!--{$smarty.section.cnt.index}-->" value="<!--{$arrProducts[cnt].product_id}-->" />
</td>
<!-- ●追加終わり● -->

ここの部分で結果項目に合わせた

商品IDとチェックボックスの値を取れるようにしておきます。

<!-- ●追加始まり● -->
<!--{* 表示 *}-->
<!--{assign var=key value=$arrProducts[cnt].status}-->
<td class="menu" rowspan="2">
<!--{$arrDISP[$key]}-->
 <input type="hidden" name="status<!--{$smarty.section.cnt.index}-->" value="<!--{$arrProducts[cnt].status}-->" />
</td>
<!-- ●追加終わり● -->

次に、上記の部分で現在の表示か非表示かの状態をhiddenで持つようにして

POSTしたときの判断材料にします。

スポンサードリンク

すべてチェックできるようにjQueryで制御します

1個1個チェックしていくのは面倒くさいので

全てチェックするというチェックボックスを作っています。

<th rowspan="2">全て<br /><input type="checkbox" name="all_check" value="1" id="all_check" /></th>

ここの部分です。

これをjQueryを使って全てチェックするをできるようにします。

/*商品検索のチェックボタン*/
$(function(){
	$('#all_check:checkbox').click(function(){
		if($('#all_check').attr('checked')) {
			$('.check_box').attr('checked','checked');
		}else{
			$('.check_box').removeAttr('checked');
		}
	})
})

面倒くさいので同じindex.tplに記述しています。

EC CUBEの2.11.4はjQUery1.4.2なので

上記のjQueryでチェックのON/OFFができますが、

最新の1.9.1だとできません。

attrの記述が変わったようです。

これについては後日検証してみます。

【検証してみました】
jQuery チェックボックスの全チェック、外しを実装(修正版)

動作を確認します

後は動作を確認してみます。

ちなみに、削除したものを戻す場合は

dtb_productテーブルとdtb_product_classテーブルのdel_flgカラムを

【0】に戻せばも元に戻ります。

dtb_customer_favorite_productsテーブルは

del_flgのフラグがなく、データが削除されるので

dtb_customer_favorite_products使っている人は

削除の挙動の確認の時には

dtb_customer_favorite_productsに登録されていない商品で

挙動を確認してください。

スポンサードリンク