EC-CUBE 2系

リファクタリングガイドライン

by TheVOS posted Sep 28, 2019
?

ショートカット

Prev前へ 書き込み

Next次へ 書き込み

大きく 小さく 上へ 下へ コメントへ 印刷
?

ショートカット

Prev前へ 書き込み

Next次へ 書き込み

大きく 小さく 上へ 下へ コメントへ 印刷
Extra Form
原文出所 http://svn.ec-cube.net/open_trac/wiki/EC...4%E3%83%B3

init 関数

init 関数は, クラスの初期化を目的する. ビジネスロジックの記述はしないこと

<?php
function init() {

    /**
     * NG ビジネスロジックの記述はしない
     */
    if (count($this->arrPayment) > 0) {
        $i = 0;
        foreach ($this->arrPayment as $val) {
            $this->payment[$i] = $val;
            $i++;
        }
    }

    /**
     * OK クラスの初期化のみ行う
     */
    $this->tpl_mainpage = 'index.tpl';
    $this->arrDISP = $masterData->getMasterData('mtb_disp');
}

action 関数

action 関数は MVC のコントローラにあたり以下の処理を記述する.

  • 条件分岐
  • VIEW からの入力
  • VIEW に渡すメンバ変数($this->variable_name)への代入
  • 宣言
  • ビジネスロジックの呼び出し

action 関数に, ビジネスロジックを直接記述したり, SQL を実行する処理を記述しないこと.

<?php
/**
 * action 関数のサンプル
 */
function action() {

    /** OK VIEW からの入力を処理する */
    $this->arrForm = $this->lfConvertParam($_POST);

    /** OK 入力に応じて条件分岐する */
    switch ($this->getMode()) {
    case 'edit':

        /** OK エラーの内容に応じて条件分岐する */
        $this->arrErr = $this->lfProductClassError($this->arrForm);
        if (empty($this->arrErr)){
            $this->tpl_mainpage = 'products/product_class_confirm.tpl';
            $this->lfProductConfirmPage($this->arrForm);
        } else {
            $this->doPreEdit($this->arrForm, false ,true);
        }
        break;

    case 'delete':
        $this->doDelete($this->arrForm);
        break;

    case 'disp':
        /** NG ビジネスロジックの記述をしてはならない */
        foreach ($this->arrForm as $key => $val) {
            $foo[$key] = $val;
        }

        /** NG SQLを実行する処理を記述してはならない */
        $objQuery = SC_Query::getSingletonInstance();
        $arrResults = $objQuery->select('*', 'table_name');

        $this->doDisp($this->arrForm);
        break;

    case 'complete':
        $this->registerProductClass($this->arrForm, $this->arrForm['product_id']);
        SC_Response_Ex::sendRedirect('complete.php');
        break;

    default:
    }
}

MODE パラメータ

$_POST['mode'] や $_GET['mode'] に対する条件分岐は, LC_Page::getMode() を使用し, switch 文で記述する.

<?php
/** OK switch 文で mode の分岐を行う */
switch ($this->getMode()) {
case 'disp':
    $this->doDisp($this->arrForm);
    break;

case 'complete':
    SC_Response_Ex::sendRedirect('complete.php');
    break;
default:
}

/** NG mode の条件分岐に if 文を使用してはならない */
if ($_POST['mode'] == 'disp') {
    $this->doDisp($this->arrForm);
} elseif ($_POST['mode'] == 'complete') {
    SC_Response_Ex::sendRedirect('complete.php');
}

ビジネスロジック

  • ページ間で重複する処理が存在する場合は, Helper などの共通クラスへ記述する
  • ページ固有の処理は, ローカル関数で記述する
  • 可能であれば, PHPUnit を使用してテストケースを残すこと
  • 宣言を除き, 引数や返り値が無く, すべて内部のメンバ変数で処理するような関数は極力作成しない
    • ステートレスな処理を心掛けること
<?php

/**
 * NG 引数ではなく, クラスのメンバ変数を使用して振舞いを変更する
 */
function lfSendMail() {
     $objPurchase = new SC_Purchase_Ex();
     $objPurchase->sendOrderMail($this->order_id)
}

/**
 * OK 引数で振舞いを変更できる
 */
function lfSendMail($order_id) {
     $objPurchase = new SC_Purchase_Ex();
     $objPurchase->sendOrderMail($order_id)
}

/**
 * NG 引数や返り値が無く, メンバ変数の値を直接変更している
 */
function lfConvertLoginPass(){
    if(strlen($this->arrForm['login_pass']) < 1 ) {
        return;
    }
    $this->arrForm['login_pass'] = trim($this->arrForm['login_pass']);
    $this->arrForm['login_pass1'] = $this->arrForm['login_pass'];
    $this->arrForm['login_pass2'] = $this->arrForm['login_pass'];
}

/**
 * OK ローカル関数内では, ローカル変数を使用することで, 拡張性, 保守性が向上し, ユニットテストも書きやすい
 */

$this->arrForm = $this->lfConvertLoginPass($this->arrForm);

function lfConvertLoginPass(&$arrForm){
    if(strlen($arrForm['login_pass']) < 1 ) {
        return;
    }
    $arrForm['login_pass'] = trim($arrForm['login_pass']);
    $arrForm['login_pass1'] = $arrForm['login_pass'];
    $arrForm['login_pass2'] = $arrForm['login_pass'];
    return $arrForm;
}

/**
 * ユニットテストの例.
 */
function testLfConvertLoginPass() {
    $login_pass = 'login_pass_value';
    $arrForm = array('login_pass' => $login_pass);

    $expected = array('login_pass' => $login_pass,
                      'login_pass1' => $login_pass,
                      'login_pass2' => $login_pass);

    $actual = lfConvertLoginPass($arrForm);

    $this->assertEquals($expected, $actual);
}
  • ループ処理などで, メンバ変数や, スーパーグローバル変数は直接使わない
<?php

/**
 * NG ループ処理で, メンバ変数やスーパーグローバル変数を直接扱っている
 */
foreach ($_POST['params'] as $key => $val) {
     $this->arrForm[$key] = $val;
}

/**
 * OK メンバ変数や, スーパーグローバル変数に作用するループ処理は, 別途関数を作成する
 */
$this->arrParams = $this->getParams($_POST['params']);

function getParams($arrParams) {
     $arrResults = array();
     foreach ($arrParams as $key => $val) {
         $arrResults[$key] = $val;
     }
     return $arrResults;
}

データベースアクセス

特に理由の無い場合は SC_Query::getSingletonInstance() を使用してインスタンスを取得すること

<?php

/**
 * NG PHP4 環境では, 新たなインスタンスが生成されてしまう
 */
$objQuery = new SC_Query();

/**
 * OK シングルトンが保証され, トランザクションの扱いが容易になる
 */
$objQuery = SC_Query::getSingletonInstance();

SQL 文を散乱させない. SELECT id, name, foo, bar FROM table_name と SELECT id, name, foo, bar, too FROM table_name が存在する場合は, 後者を共通関数にリファクタリングすること

<?php

/**
 * NG 類似した SQL を散乱させてはいけない
 */
$arrResults = $objQuery->select('id, name, foo, bar', 'table_name');
$arrResult2 = $objQuery->select('id, name, foo, bar, too', 'table_name', 'too = ?', $arrParams['too']);

/**
 * OK カラム名や, WHERE の違いなどは共通関数で吸収する
 */
function getResults($arrParams = array()) {
    $where = '';
    $arrValues = array();
    if (isset($arrParams['too'])) {
        $where .= 'too = ?';
        $arrValues[] = $arrParams['too'];

    }
    $objQuery = SC_Query::getSingletonInstance();
    $arrResults = $objQuery->select('*', 'table_name', $where, $arrValues);
    return $arrResults;
}
$arrResults = getResults();
$arrResults2 = getResults($arrParams);

INSERT/UPDATE/DELETE は, SC_Query::insert(), SC_Query::update(), SC_Query::delete() を使用し, SC_Query::query() は使用しないこと

<?php

/** NG SC_Query::query() は使用しない */
$objQuery = SC_Query::getSingletonInstance();
$objQuery->query('INSERT INTO table_name (col1, col2) VALUES (?, ?)', arrary($col1, $col2));

/** OK SC_Query::insert(), SC_Query::update(),  SC_Query::delete() を使用する */
$objQuery = SC_Query::getSingletonInstance();
$objQuery->insert('table_name', array('col1' => $col1,
                                      'col2' => $col2));

LIMIT, OFFSET は SC_Query::setLimit(), SC_Query::setLimitOffset() を使用すること.

<?php

/** NG LIMIT, OFFSET を直接使用しない */
$objQuery = SC_Query::getSingletonInstance();
$arrResults = $objQuery->getAll('SELECT * FROM table_name WHERE del_flg = 0 LIMIT 10 OFFSET 5');

/** OK SC_Query::setLimit(), SC_Query::setLimitOffset() を使用する */
$objQuery = SC_Query::getSingletonInstance();
$objQuery->setLimitOffset(10, 5);
$arrResults = $objQuery->select('*', 'table_name', 'del_flg = ?', array('0'));

RDBMS の可搬性向上のため USING 句は使用しないこと

<?php

/** NG USING 句は使用しない */
$objQuery = SC_Query::getSingletonInstance();
$arrResults = $objQuery->select('T1.*', 'table_name T1 JOIN table2_name T2 USING(col)');

/** OK ON 句 を使用する */
$objQuery = SC_Query::getSingletonInstance();
$arrResults = $objQuery->select('T1.*', 'table_name T1 JOIN table2_name T2 ON T1.col = T2.col');

入力チェック

入力チェック用のクラスには, SC_FromParam と SC_CheckError が存在するが, 極力 SC_FormParam を使用すること

端末種別の判別

Net_UserAgent_Mobile::isMobile() や MOBILE_SITE 定数など存在するが, SC_Display_Ex::detectDevice() に統一する

スーパーグローバル変数

$_POST や $_GET の値は, 必ず入力チェック後に使用する. SC_FormParam を使用していれば, SC_FormParam::getHashArray() で取得できる

<?php

/** NG $_POST の値を入力チェックせずに使用する */
$this->register($_POST);

/** OK 必ず入力チェックを行う */
$objFormParam = new SC_FormParam();
$objFormParam->addParam('商品規格ID', 'product_class_id', INT_LEN, 'n', array('EXIST_CHECK', 'MAX_LENGTH_CHECK', 'NUM_CHECK'));
$objFormParam->setParam($_POST);
$objFormParam->convParam();
$arrErr = $objFormParam->checkError()
if (SC_Utils_Ex::isBlank($arrErr)) {
     // 入力チェック後の値が取得可能
     $arrForm = $objFormParam->getHashArray();
}
$this->register($arrForm);

$_SESSION は, SC_CartSession クラス等, セッションを扱うビジネスロジックを通じて使用するのが望ましい.

どうしても, グローバル変数を使用したい場合は, global キーワードは使用せず, $GLOBALS を使用すること.

<?php
/**
 * NG global キーワードの使用すると, 変数名衝突の原因となる
 */
function globalSample() {
    global $conn;

    // 外部からは $conn という変数を使用しているのがわからない
    if (is_null($conn)) {
        $conn = new ClassName();
    }
}

/**
 * OK $GLOBALS を使用すると, ローカル変数との衝突の心配は無い
 */
function globalSample() {
    if (is_null($GLOBALS['_conn'])) {
        $GLOBALS['_conn'] = new ClassName();
    }
}

変数名

変数名で, どんなデータか識別できるよう考慮すること

<?php

/**
 * NG 一見して, どんなデータが格納されているかわからない
 */
$arrRet = getProducts();

/**
 * OK 商品データの配列だと, 変数名で判別可能
 */
$arrProducts = getProducts();

リテラルを格納する (つまり配列・オブジェクト以外の) 変数名は, すべて小文字を使用し, アンダーバーで区切ること

<?php

/**
 * リテラルを格納する変数名は, 連想配列の添字で使用されることも考慮し
 * アンダーバー区切りの方が扱いやすい
 */

/**
 * NG
 */
$productId = getProductId();

/**
 * OK
 */
$product_id = getProductId();

1行の文字数/行数

  • 1行の文字数は80文字までにすることを目指すこと. すなわち, コードの長さを現実的な範囲で80文字までにおさめるよう努力すべきです. しかしながら, 場合によっては少々長くなってしまってもかまいません.
  • 1関数の行数は多くても200行程度に留めるのが望ましい. これ以上行数が増えてしまう場合は, 関数を分割する等, コーディングの見直しを行ってください

PHPDoc コメント

関数の PHPDoc コメントは必ず記述する.

  • 関数の説明
  • 引数
    • 引数の無い関数は省略可能
  • 返り値
    • 返り値が無くても void を明記すること

非推奨機能

error_reporting(E_ALL) で, エラー及び警告が出力されないようコーディングすること.

PHP5.3 で非推奨となっている関数は使用しないこと.

  • call_user_method() (かわりに call_user_func() を使用します)
  • call_user_method_array() (かわりに call_user_func_array() を使用します)
  • define_syslog_variables()
  • dl()
  • ereg() (かわりに preg_match() を使用します)
  • ereg_replace() (かわりに preg_replace() を使用します)
  • eregi() (かわりに preg_match() で 'i' 修正子を使用します)
  • eregi_replace() (かわりに preg_replace() で 'i' 修正子を使用します)
  • set_magic_quotes_runtime() およびそのエイリアスである magic_quotes_runtime()
  • session_register() (かわりにスーパーグローバル $_SESSION を使用します)
  • session_unregister() (かわりにスーパーグローバル $_SESSION を使用します)
  • session_is_registered() (かわりにスーパーグローバル $_SESSION を使用します)
  • set_socket_blocking() (かわりに stream_set_blocking() を使用します)
  • split() (かわりに preg_split() を使用します)
  • spliti() (かわりに preg_split() で 'i' 修正子を使用します)
  • sql_regcase()
  • is_dst を mktime() に渡すこと。 かわりにタイムゾーン処理用の新しい関数を使用します。

以下の機能も, PHP5.3.x で非推奨となっているが, PHP4互換のために使用しても良い EC-CUBE 2.12.0 から PHP4 は非対応となりました.

  • new の返り値を参照で代入すること
  • 呼び出し時の参照渡し

参考 http://www.php.net/manual/ja/migration53.deprecated.php

URL のファイルパス部の取得は $_SERVER['PHP_SELF'] を使わず、代わりに $_SERVER['SCRIPT_NAME'] を使用する。(参考: #1717)

Facebook [ja]コメント 


  1. 管理機能一覧

    管理機能一覧

    ○:標準搭載機能。要件によって個別のカスタマイズが必要な可能性があります。 PLG:プラグインにて対応可能です。 分類♯機能説明3系4系A:認証機能1パスワード認証管理者登録したユーザでのID/パスワードによるログイン。○○2管理者登録複数の管理者の登録が行...
    Date2020.11.12 CategoryEC-CUBE 4系 Views227
    Read More
  2. フロント機能一覧

    フロント機能一覧

    ○:標準搭載機能。要件によって個別のカスタマイズが必要な可能性があります。 PLG:プラグインにて対応可能です。 分類♯機能説明3系4系A:商品紹介1商品一覧ページ登録商品をカテゴリごとに一覧表示します。○○2商品サムネイル表示一覧ページで商品がサムネイ...
    Date2020.11.12 CategoryEC-CUBE 4系 Views233
    Read More
  3. EC-CUBE 2系でポート番号付で管理画面を動かす

    EC-CUBE 2系でポート番号付で管理画面を動かす

    Apacheの処理分散させるために、ロードバランサーを介してラウンドロビンを掛けた複数台で同じEC-CUBEを動かす必要が出てきました。 Apacheを動作させるフロントエンドをコピーした複数台でPHP処理を分担、MySQLはローカル接続されているバックエンドの専用サ...
    Date2020.01.02 CategoryEC-CUBE 2系 Views1861
    Read More
  4. EC-CUBE 2系で注文を受けた商品の規格を後で削除すると、管理画面で受注内容を編集できなくなる

    EC-CUBE 2系で注文を受けた商品の規格を後で削除すると、管理画面で受注内容を編集できなくなる

    注文された規格を削除して、dtb_products_classテーブルから該当する規格データが無くなると、受注内容のたとえば発送先住所などを編集しようとしても数量の上限チェックに引っかかりエラーが出て受注内容の変更ができなくなってしまいます。 ※ この現象は、規...
    Date2020.01.02 CategoryEC-CUBE 2系 Views547
    Read More
  5. EC-CUBE 2系でShift_JISに存在しない文字が含まれた受注データがあると、その受注内容が受注CSVからまるごと欠落する

    EC-CUBE 2系でShift_JISに存在しない文字が含まれた受注データがあると、その受注内容が受注CSVからまるごと欠落する

    受注データの備考などにお客様が入力した文章にShift_JISで表現できない文字や記号がまざっていると、受注CSVをダウンロードしたときにその受注データがそっくり欠落してしまいます。 これはCSVデータをShift_JISに変換するときのiconvのパラメータがデフォル...
    Date2020.01.02 CategoryEC-CUBE 2系 Views314
    Read More
  6. EC-CUBE 2系で商品情報をCSVで更新するとき関連商品情報が削除される

    EC-CUBE 2系で商品情報をCSVで更新するとき関連商品情報が削除される

    CSVアップロードして商品データを更新する事ができるのですが、そのCSVに「関連商品」の列が無いと、CSVをアップロードしたときにその商品に今まで登録されていた関連商品の内容が全て削除されてしまいます。 これは、CSVアップロード処理が「関連商品」に関す...
    Date2020.01.02 CategoryEC-CUBE 2系 Views399
    Read More
  7. EC-CUBE 2系で商品を沢山購入すると住所情報が欠落する

    EC-CUBE 2系で商品を沢山購入すると住所情報が欠落する

    以外と有名な問題なのですが、カートに沢山の商品を入れて注文すると、受注メールは送信されてエラーも出ないのに「送料がゼロ円になる」とか「管理画面に受注データが表示されない」という障害が起きます。 これは、セッション情報を保存するDBテーブルが tex...
    Date2020.01.02 CategoryEC-CUBE 2系 Views291
    Read More
  8. EC-CUBE 2系の「もっと見る」を簡潔に

    EC-CUBE 2系の「もっと見る」を簡潔に

    今更ながら、EC-CUBE 2系のスマホ版のデザイン変更で苦労しました。 EC-CUBEに組み込まれている「もっと見る」ボタンですが、Ajaxで次ページのjsonデータを取得してきて画像、商品名、価格等のspanやimgタグの中身を1個ずつコピーしている。。。(3系でも同じ...
    Date2020.01.02 CategoryEC-CUBE 2系 Views896
    Read More
  9. EC-CUBEをインストールする

    EC-CUBEを利用することになりそうなので、ひとまずEC-CUBEをレンタルサーバーにインストールしてみました。その手順備忘録です。 EC-CUBEインストール手順 EC-CUBEをダウンロードする EC-CUBEのファイルを配置する データベースを作る EC-CUBEをインストールす...
    Date2019.12.10 CategoryEC-CUBE 2系 Views323
    Read More
  10. EC-CUBE2.13カスタマイズ:新しいページを追加する

    EC-CUBEで新しいページを追加する方法として、管理画面で追加して、そのページのURLを任意に変更する手順をメモ。 管理画面からページを追加する管理画面でデザイン管理>PC>ページ詳細設定を開き、必要事項を入力して登録するボタンを押下。 ※スマホ、モバイ...
    Date2019.11.11 CategoryEC-CUBE 2系 Views897
    Read More
  11. 관리 화면의 사이드 메뉴에 항목 추가하는 방법

    EC-CUBE3에서는 관리 화면의 사이드 메뉴에 쉽게 메뉴를 추가 할 수 있습니다. 외형 수정이므로 템플릿 (twig)를 편집 ...라고 생각했는데, 수정할 필요가있는 것은 ServiceProvider입니다. 실제로 ServiceProvider에서하지 않아도 좋다고 생각 합니다만,로드 ...
    Date2019.11.11 CategoryEC-CUBE 3系 Views361
    Read More
  12. イベントセット販売プラグインマニュアル

    イベントセット販売プラグインマニュアル | THEVOS作成日:2019年 10月 29日 火曜日 24時間/365日技術サポート: あなたが直面している問題を教えてください。 イベントセット販売プラグインをお買い上げいただきありがとうございます。このユーザーマニュアル...
    Date2019.11.07 CategoryEC-CUBE 2系 Views344
    Read More
  13. EC-CUBE4系で管理画面に新規メニュー項目を追加する方法

    今回は商品管理の一番下に新規メニュー項目を追加することを考えます。 まずメニューから開けるページが必要ですのでコントローラーを作成し、新しいページを作った後でそのページをメニューに追加してみましょう。今回はeccube_nav.yamlを編集するもっとも簡...
    Date2019.10.28 CategoryEC-CUBE 4系 Views808
    Read More
  14. 2.13系 ソフトウェア要件

    2.13系 ソフトウェア要件

    分類 ソフトウェア 動作確認済み WEBサーバ IIS 7.0~ Apache 2.0.x~ 2.2.x~ 言語 PHP 5.2~ データベース PostgreSQL 8.1.4~ 9.x~ MySQL 5.0.x~ 必須PHPライブラリ pgsql / mysql gd freetype2 mbstring zlib ctype spl (PHP 5.3.0 未満の場合) session ...
    Date2019.10.11 CategoryEC-CUBE 2系 Views276
    Read More
  15. ECCUBE 2.13のインストール方法をスクリーンショット付きでわかりやすく徹底解説!

    「EC-CUBE」とは、ECサイトに必要なカート機能や決済機能がパッケージ化されている、無料のツールです。ECサイトを運営したことがある人なら、きっと知っている人も多いはず。あとはWebサーバーさえあれば、わりと簡単にECサイトを立ち上げることができます。...
    Date2019.10.10 CategoryEC-CUBE 2系 Views543
    Read More
  16. EC-CUBE2.12 運用マニュアル

    EC-CUBE ver2120 2121 2122 運用マニュアル1 Page EC-CUBE Ver2120 Ver2121 Ver2122 運用マニュアル 2012年11月28日 Thi s document is licensed under a Creative Commons 表示 - 継承 2 1 日本 License THEVOS ECO LAB Inc EC-CUBE ver2120 2121 212...
    Date2019.09.29 CategoryEC-CUBE運用マニュアル Views195
    Read More
  17. 単体テストガイドライン

    単体テストガイドライン

    本ガイドラインはEC-CUBEの単体テストをPHPUnitを使って行う上でのガイドラインを 株式会社SHIFT様(http://www.shiftinc.jp/)のご協力によりまとめたものとなります。 各クラス共通のガイドライン1. テストを含めたフォルダ構成テストコードを含んだフォルダ構...
    Date2019.09.28 CategoryEC-CUBE 2系 Views380
    Read More
  18. リファクタリングガイドライン

    リファクタリングガイドライン

    init 関数init 関数は, クラスの初期化を目的する. ビジネスロジックの記述はしないこと &lt;?php function init() { /** * NG ビジネスロジックの記述はしない */ if (count($this-&gt;arrPayment) &gt; 0) { $i = 0; foreach ($this-&gt;arrPayment as $val) { $this-&gt;pa...
    Date2019.09.28 CategoryEC-CUBE 2系 Views467
    Read More
  19. EC-CUBE標準規約

    EC-CUBE標準規約

    基本的に Zend Framework PHP 標準コーディング規約 に順ずる. 以下, 要点及び相違点を規定する. また, コーディングに際して, 以下のガイドラインに沿うことが望ましい EC-CUBE標準規約 &gt; リファクタリングガイドライン PHPUnitを利用した単体テストを行う際...
    Date2019.09.28 CategoryEC-CUBE 2系 Views664
    Read More
  20. 메일 사용자 설명서

    메일 사용자 설명서

    원 포인트 가이드메일 소프트에 다음 정보를 설정하십시오. 메일 서버 (POP)sv11.star.ne.jp메일 서버 (SMTP)sv11.star.ne.jp계정 (사용자 이름)만든 계정 이름 (@이후도 포함)비밀번호설정 한 패스워드
    Date2019.03.29 Categoryメールサービス Views287
    Read More
Board Pagination Prev 1 2 Next
/ 2