EC-CUBE 2系

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

by TheVOS posted Jan 02, 2020
?

Shortcut

Prev前へ 書き込み

Next次へ 書き込み

Larger Font Smaller Font 上へ 下へ Go comment 印刷
?

Shortcut

Prev前へ 書き込み

Next次へ 書き込み

Larger Font Smaller Font 上へ 下へ Go comment 印刷
Extra Form
原文出所 http://www.neobit.jp/archives/565

受注データの備考などにお客様が入力した文章にShift_JISで表現できない文字や記号がまざっていると、受注CSVをダウンロードしたときにその受注データがそっくり欠落してしまいます。

これはCSVデータをShift_JISに変換するときのiconvのパラメータがデフォルトの「不正な文字があったらデータを捨てる」指定になっているからです。
受注データが抜け落ちてしまっては、発見が遅れて実務上のトラブルになりかねないので、変換できない文字があっても近似文字に置き換えて出力するTRANSLIT指定をつけた方が良いと思います。

SC_Helper_CSV.php の
function fopen_for_output_csv のiconv指定を変更

-        stream_filter_append($fp, 'convert.iconv.utf-8/cp932');
+        stream_filter_append($fp, 'convert.iconv.utf-8/cp932//TRANSLIT');

Facebook [ja]コメント 


  • Q: [EC-CUBE 4系] 管理機能一覧 2020.11.12
    A:

    ○:標準搭載機能。要件によって個別のカスタマイズが必要な可能性があります。
    PLG:プラグインにて対応可能です。


    分類機能説明3系4系
    A:認証機能1パスワード認証管理者登録したユーザでのID/パスワードによるログイン。
    2管理者登録複数の管理者の登録が行えます。
    B:TOPページ1受注状況現在の商品の受注の状態をTOPページに表示します。
    2売上状況現在の売上げ、会員数をTOPページに表示します。
    3売上状況グラフ売上状況を週間・月間・年間のグラフで確認できます。×
    4ショップ状況現在の在庫状況や会員数をTOPページに表示します。
    5EC-CUBEのお知らせEC-CUBEのバージョンUPやイベント情報等お知らせを表示します。
    6おすすめプラグインオーナーズストアからおすすめするプラグインを表示します。×
    C:商品管理1商品検索/一覧商品の検索、一覧表示が行えます。
    2商品登録/編集機能商品名、価格、コメント、SHOP専用備考欄などの商品基本データの登録が行えます。
    3商品画像登録商品画像のアップロード、登録が行えます。
    4在庫情報登録在庫数の登録が行えます。
    5商品情報CSV出力商品データのCSV出力が行えます。
    6商品一括変更機能商品一覧画面で、公開・非公開・廃止・完全に削除 の4つの変更を一括で行えます。×
    7規格登録商品の規格の登録が行えます。
    8カテゴリ登録/編集機能商品の表示スタイル選択、階層の登録/編集が行えます。
    9カテゴリコンテンツ登録カテゴリページに説明文や画像などのコンテンツを追加することができます。PLG×
    10タグ登録/編集商品情報に付与できるタグを登録/編集することができます。×
    11カテゴリ情報CSV出力カテゴリ情報のCSV出力が行えます。
    12商品情報CSV登録商品データをCSVで一括登録できます。
    13カテゴリ情報CSV登録カテゴリ情報のCSV登録が行えます。
    14販売制限一度の注文で同時に購入可能な商品数の制限が行えます。
    15関連商品手動登録/編集商品を購入した人に推奨する関連商品の手動登録が行えます。PLGPLG
    16商品レビュー管理商品のレビュー管理が行えます。PLGPLG
    17複数カテゴリ商品を複数カテゴリに登録して管理する事ができます。
    18商品キーワード検索項目登録商品のキーワードの項目を登録できます。
    19メーカー管理機能商品ごとにメーカーとメーカーURLを登録することができます。お客向けには商品詳細画面でメーカーとメーカーURLが表示されます。PLGPLG
    20リスティング広告 入稿用CSV作成機能リスティング広告の入稿用CSVファイルを(商品ごとの広告テキスト/キーワードの生成)出力します。PLG×
    D:受注管理1受注情報検索/一覧受注情報の検索、一覧表示が行えます。
    2受注情報CSV出力受注内容のCSV出力が行えます。
    3配送情報CSV出力配送情報のCSV出力が行えます。
    4新規受注情報入力電話やFAXで発生した受注情報の登録が行えます。
    5出荷CVS登録出荷日時や問い合わせ番号(出荷伝票番号)をCSVで登録することができます。×
    6受注情報編集受注情報の編集が行えます。
    7対応状況一括変更受注の対応状況を一括で変更できます。×
    8出荷メール一括送信機能出荷メールを一括で送信することができます。×
    9問い合わせ番号(出荷伝票番号)入力機能問い合わせ番号(出荷伝票番号)を受注一覧画面、及び、詳細画面から入力することができます。×
    10対応状況設定未処理、商品手配中、配送中などのステータスの設定が受注詳細画面から行えます。
    11各種メール送信注文されたお客様に任意のタイミングで「商品発送済みメール」などのメールを受注詳細画面から送信できます。
    12納品書PDF出力納品書のPDF出力が行えます。一括出力することも可能です。PLG
    13ショップ用メモ登録機能ショップ運営者が確認する用のメモを登録することができます。
    14配達用メモ登録機能出荷作業者や、配送業者に対するメモを登録することができます。×
    E:会員情報1顧客情報検索/一覧顧客情報の検索、一覧表示が行えます。
    2顧客情報CSV出力顧客情報のCSV出力が行えます。
    3顧客情報登録/編集顧客情報の登録/編集が行えます。
    4会員登録仮登録完了メール再送会員登録仮登録完了メールを再送できます。
    F:コンテンツ管理1新着情報管理フロントTOPページなどに表示する新着情報の登録/編集が行えます。
    2オススメ管理フロントTOPページなどに表示するオススメ商品の登録が行えます。
    (最大8個まで)
    PLGPLG
    3ファイル管理ファイルのアップロード、ダウンロードが行えます。
    4SEO管理ページ毎にメタタグにキーワードを埋め込む事ができます。
    5レイアウト編集TOPページ、商品一覧ページ、商品詳細ページのレイアウトを変更する事ができます。
    6モバイル専用レイアウト設定レスポンシブウェブデザインの他、モバイル専用のレイアウトを追加することができます。×
    7ブロック編集TOPページのレイアウト編集にて、表示させるブロックを登録する事ができます。
    8ヘッダー・フッター編集全ページで共通で使用するヘッダー・フッターの編集をする事ができます。
    9HTMLコードエディタコードエディタ上で、HTMLやTwigファイルの修正が行えます。また、Twigの構文エラーがある場合は検知し、通知してくれます。×
    10キャッシュ管理Twigキャッシュを削除できます。(FTPなどでTwigファイルをアップロードして入れ替えた場合に利用する機能です)
    11CSS管理CSSを追加・編集することができます。×
    12JavaScript管理JavaScriptを追加・編集することができます。×
    13favicon設定ファイル管理から、faviconの変更を行うことができます。×
    G:店舗設定(旧基本情報設定)1基本設定(旧ショップマスター)サイト運営に必要な会社情報の設定、編集が行えます。
    2特定商取引に関する法律特定商取引に関する法律に定める要件等の記入、編集が行えます。
    3会員規約設定会員登録時に確認する規約の記入、編集が行えます。
    4支払い方法/手数料設定支払い方法、及び支払い方法ごとの手数料の設定が行えます。
    5支払い方法利用条件設定購入金額の上限下限の設定が行え、支払い方法の利用制限が行えます。
    6配送料無料条件設定購入金額合計等から配送料が無料になる条件の設定が行えます。
    7配送業者/配送料/配送時間設定配送業者、及び配送業者ごとの配送料、配送時間の設定が行えます。
    8税率設定消費税の端数を何桁で切り捨てるか、四捨五入/切捨てのどちらで計算するかを設定が行えます。
    9商品別税率設定商品別に税率を設定できます(軽減税率に対応)。
    10メール設定機能EC-CUBEからお客様に送信するメール文章を編集できます。PLG
    11マルチパートメール設定テキストメールとHTMLメールを設定することができます。×
    12CSV出力項目設定CSVで出力する際に記載される内容を設定できます。
    13ポイント設定◎ポイント付与率の設定
    商品全体に対するポイントの付与率の設定が行えます。
    ◎商品ごとポイント付与率設定
    一括付与率ではなく、個別に変更したい場合、商品ごとに付与率の変更が行えます。
    PLG
    14サイト管理設定機能を利用するかどうか設定できます。
    H:システム情報設定(設定)1システム情報サーバ、OS、DB、PHP等システム設定の情報を確認できます。
    2メンバー管理管理画面にログインできるメンバーの管理をします。
    3権限管理メンバーグループごとでアクセスできるページを設定できます。
    4セキュリティー管理管理画面にアクセスできるIPの制限や管理画面のURLの変更サイトのSSL制限の設定ができます。
    5ログ表示EC-CUBEから出力されたログを表示します。
    6マスターデータ管理各種マスターデータを編集できます。
    7カスタムCSV出力機能SQLを作成し、CSVファイルをダウンロードすることができます。PLG×
    I:オーナーズストア(設定)1プラグイン一覧購入・インストールしたプラグインの一覧を表示します。
    2プラグイン検索・インストールオーナーズストアで販売しているプラグインを管理画面から検索し、
    無料プラグインはそのままインストールすることができます。
    (有料プラグインはオーナーズストアで購入する必要があります。)
    ×
    3ダウンロードプラグインインストールオーナーズストアからダウンロードしたプラグインをアップロードしてインストールすることができます。
    4プラグインハンドラ設定インストールしたプラグインの設定を行うことができます。×
    5テンプレート設定あらかじめ用意された専用テンプレートをワンボタンで適用できます。
    J:その他1アップデート対応EC-CUBEのマイナーバージョンアップ時にコア機能のアップデートとDBのマイグレーションが可能。
    K:ポイント1ポイント購入に応じて会員へポイントを付与し、次回購入時に利用できる機能。PLG
    L:売上げ集計1期間別集計任意の期間の売上集計結果をグラフと一覧で表示できます。PLGPLG
    2商品別集計商品別の売上集計結果をグラフと一覧で表示できます。
    3年代別集計購入者の年代別の売上集計結果をグラフと一覧で表示できます。
    4職業別集計購入者の職業別の売上集計結果をグラフと一覧で表示できます。
    5会員別集計購入者の会員別の売上集計結果をグラフと一覧で表示できます。
    M:メルマガ配信1メルマガ配信検索/配信予約メルマガ配信先のしぼり込み検索、配信予約設定が行えます。PLGPLG
    N:クーポン1クーポン管理機能商品・カテゴリーに対して、一定額・一定率での割引を適用するクーポンを発行できます。PLGPLG

    Facebook [ja]コメント 

  • Q: [EC-CUBE 4系] フロント機能一覧 2020.11.12
    A:

    ○:標準搭載機能。要件によって個別のカスタマイズが必要な可能性があります。
    PLG:プラグインにて対応可能です。

    分類機能説明3系4系
    A:商品紹介1商品一覧ページ登録商品をカテゴリごとに一覧表示します。
    2商品サムネイル表示一覧ページで商品がサムネイル表示されます。
    3一覧並び替え機能商品を価格順、新着順で並び替えをする事ができます。
    4商品詳細ページ説明文表示、商品画像表示、カゴへボタン表示。
    5商品タグおすすめ、残り僅かなどのステータスを表示(手動)させることができます。
    6在庫終了ステータス在庫が切れた場合には、自動的に在庫切れを表示します。
    7ユーザレビュー商品詳細ページ商品レビューを登録、表示できるようにします。PLGPLG
    8商品お気に入り登録会員登録しログインしている状態で、商品をお気に入りに登録することができます。
    B:商品注文1ショッピングカート機能複数商品選択などを行う、基本的なショッピングカート機能です。
    2非会員購入機能非会員のユーザでも購入できる機能です。
    3別のお届け先入力機能会員登録しているユーザーの場合、1ユーザが複数のお届け先を保持することができます。
    4配送時間指定管理者画面で登録した配送時間の指定を行えます。
    5お支払い方法選択管理者画面で登録した支払い方法の選択を行えます。
    6購入前見積表示送料、手数料を自動計算した後、注文内容の確認ページを表示します。
    7注文処理注文登録と同時にThanksメールを自動送信し、管理者にも注文受付メールを送信します。
    8ポイント購入機能商品購入で蓄積したポイントを利用して商品を購入することができます。PLG
    9商品一覧からカートに追加商品一覧画面から直接カートに商品を追加し購入することができます。×
    10カートの永続化機能ログイン期限切れやログアウト後でもカート情報を保持し、次回ログイン時にカート情報を復活させる機能。また、カート情報は異なるデバイスでログインしても復活します。×
    C:お客様ページ(MYページ)1会員登録機能会員登録を行うことができます。
    2ログイン機能ユーザログイン画面を提供します。
    3会員情報編集機能会員情報の登録、変更が出来ます。
    4注文履歴一覧表示過去の注文を一覧表示します。
    5注文詳細確認機能現在の注文内容を表示します。
    6別のお届け先編集機能複数の配送先の登録・編集・削除が出来るようにします。
    7お気に入り商品一覧お気に入りに登録した商品を一覧表示します。
    8退会退会手続きを行えるようにします。
    D:その他1パスワードリセット機能ユーザがパスワードを忘れた際に会員登録時に入力したメールアドレスへメールを送信し、メールが認証されると、再発行したパスワードがメールアドレスへ送信される。
    2パスワード再設定ユーザがパスワードを忘れた際にパスワードを再設定することができる機能。パスワードリセット機能に代わり、よりセキュリティの高い機能を採用。×
    3オススメ商品表示トップページのオススメ枠に設定したオススメ商品を表示します。PLGPLG
    4新着情報表示新着情報の表示を行えます。
    5商品カテゴリ検索商品カテゴリをもとに検索できます。
    6商品キーワード検索キーワード検索(ブランド名、商品名の一部など)で検索できます。
    7お問い合わせフォーム問い合わせフォームから管理者宛てに問い合わせをメールすることができます。

    Facebook [ja]コメント 

  • Q: [EC-CUBE 2系] EC-CUBE 2系でポート番号付で管理画面を動かす 2020.01.02
    A:

    Apacheの処理分散させるために、ロードバランサーを介してラウンドロビンを掛けた複数台で同じEC-CUBEを動かす必要が出てきました。
    Apacheを動作させるフロントエンドをコピーした複数台でPHP処理を分担、MySQLはローカル接続されているバックエンドの専用サーバーで運用という形です。

    EC-CUBEはそもそもPHPセッションをDB保存しているので、DBをバックエンドのサーバーで共通化しておけば複数台でのPHPセッションの共有化を配慮する必要はなく、複数台運用への切り替えは簡単です。

    ただし、管理画面からアップロードした画像等はApacheを動かしているサーバーに物理的に保存されるため、ラウンドロビンが掛かった状態ではどのサーバーにファイル保存されるか分からなくバラバラになってしまうため、どれか1台固定のサーバーを正としてそこへ保存し、rsync等で各サーバーへコピーしなくてはなりません。

    サブドメインではっきり分けれれば良いのですが、ドメイン追加をできない場合は1443などの独自のポート番号でポートフォワードで振り分けて管理画面を動かすサーバーを固定したいところ。

    ただし、普通にポート番号付きでアクセスしてしまうと、管理画面でログインした直後にリダイレクトエラーが出ます。
    これは/data/config/config.php で設定している HTTP_URL や HTTPS_URL と異なるURLへジャンプすることを防ぐセキュリティ対策の影響です。
    では、そもそもHTTP_URL に:1443付きで定義したらどうかとなりますが、そうすると今後はポート番号無しでアクセスしているカート画面などでリダイレクトエラーが出ます。訪問者画面も管理画面も同じEC-CUBEだと設定も共通なので。

    そこで、ポート番号付きでアクセスしたときだけこのURLを書き換えてしまうと良いです。
    具体的には /data/config/config.php をこんな風に書きます。常時SSLのご時勢ですからHTTP_URLは振り分けなくても良いかな?

    define('HTTP_URL', 'http://www.exsample.co.jp/');
    if ($_SERVER['SERVER_PORT'] == '1443') {
      define('HTTPS_URL', 'https://www.exsample.co.jp:1443/');
    } else {
      define('HTTPS_URL', 'https://www.exsample.co.jp/');
    }

    Facebook [ja]コメント 

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

    注文された規格を削除して、dtb_products_classテーブルから該当する規格データが無くなると、受注内容のたとえば発送先住所などを編集しようとしても数量の上限チェックに引っかかりエラーが出て受注内容の変更ができなくなってしまいます。

    ※ この現象は、規格のチェックBOXを外して更新 → チェックBOXを再度立てて更新 でも発生します。見た目は同じ規格が存在しているように見えますが、内部のproduct_class_idが変わってしまうのが原因です

    product_class_idも引用してこれていないので画面処理もうまくいきません。
    対応策として、もし規格データが削除されていた場合は在庫数チェックを行わないようにする事で受注内容の編集をできるようにしてみます。

    まずdtb_products_classから規格データが無くなっていてもproduct_class_idやproduct_idを引用できるように商品詳細dtb_order_detailの方から参照するようにします
    SC_Helper_Purchase.php の
    function getOrderDetail のSQL文を書き換えます

    -            T3.product_id,
    -            T3.product_class_id as product_class_id,
    +            T2.product_id,
    +            T2.product_class_id as product_class_id,

    LC_Page_Admin_Order_Edit.php の
    function lfCheckError に処理をスルーさせるIF文を追加

                // 在庫数のチェック
                $arrProduct = $objProduct->getDetailAndProductsClass($arrValues['product_class_id'][$i]);
    
    +            // 規格が削除されていたら在庫数チェックしない
    +            if ($arrProduct['product_class_id'] == '') {
    +                continue;
    +            }

    商品種類 product_type_id も引用してこれていなくて、画面にはエラー表示されませんが必須チェックに引っかかり先に進めなくなるのでこれもスルーさせます。
    LC_Page_Admin_Order_Edit.php の
    function lfInitParam を修正

            // 受注詳細情報
    -        $objFormParam->addParam('商品種別ID', 'product_type_id', INT_LEN, 'n', array('EXIST_CHECK', 'MAX_LENGTH_CHECK', 'NUM_CHECK'), '0');
    +        $objFormParam->addParam('商品種別ID', 'product_type_id', INT_LEN, 'n', array('MAX_LENGTH_CHECK', 'NUM_CHECK'), '0');

    視覚的にも、規格が削除されていて在庫数が連動しない商品だと分かったほうが良いので、数量欄のあるTDの背景色を赤色で表示してみます。
    /data/Smarty/templates/admin/order/edit.tpl を修正

    -                    <td class="center">
    -                        <!--{assign var=key value="quantity"}-->
    +                    <td class="center"<!--{if $arrForm.product_type_id.value[$product_index] == ''}--> style="background-color:#fdd"<!--{/if}-->>
    +                        <!--{assign var=key value="quantity"}-->

    そもそも関連データが存在している規格データを容易にdeleteしてしまう実装ってどうなの?っていう話なんですが。

    Facebook [ja]コメント 

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

    受注データの備考などにお客様が入力した文章にShift_JISで表現できない文字や記号がまざっていると、受注CSVをダウンロードしたときにその受注データがそっくり欠落してしまいます。

    これはCSVデータをShift_JISに変換するときのiconvのパラメータがデフォルトの「不正な文字があったらデータを捨てる」指定になっているからです。
    受注データが抜け落ちてしまっては、発見が遅れて実務上のトラブルになりかねないので、変換できない文字があっても近似文字に置き換えて出力するTRANSLIT指定をつけた方が良いと思います。

    SC_Helper_CSV.php の
    function fopen_for_output_csv のiconv指定を変更

    -        stream_filter_append($fp, 'convert.iconv.utf-8/cp932');
    +        stream_filter_append($fp, 'convert.iconv.utf-8/cp932//TRANSLIT');

    Facebook [ja]コメント 

  • Q: [EC-CUBE 2系] EC-CUBE 2系で商品情報をCSVで更新するとき関連商品情報が削除される 2020.01.02
    A:

    CSVアップロードして商品データを更新する事ができるのですが、そのCSVに「関連商品」の列が無いと、CSVをアップロードしたときにその商品に今まで登録されていた関連商品の内容が全て削除されてしまいます。

    これは、CSVアップロード処理が「関連商品」に関する列がCSVに存在している事を前提に処理しているからで、関連商品がCSV列名に存在しているかどうかチェックして、列が無かったら関連商品の処理を行わないようにすることで回避できます。

    LC_Page_Admin_Products_UploadCSV.php の
    function lfRegistReccomendProducts の冒頭に以下のコードを挿入

            $cnt = 0;
            for ($i = 1; $i <= RECOMMEND_PRODUCT_MAX; $i++) {
                $keyname = 'recommend_product_id' . $i;
                $comment_key = 'recommend_comment' . $i;
                if (array_key_exists($keyname, $arrList) == true) $cnt++;
                if (array_key_exists($comment_key, $arrList) == true) $cnt++;
            }
            if ($cnt == 0) return;

    ※ 自分でコミュニティへ参加してパッチを作成するマンパワーが無いのでその予定はありません

    Facebook [ja]コメント 

  • Q: [EC-CUBE 2系] EC-CUBE 2系で商品を沢山購入すると住所情報が欠落する 2020.01.02
    A:

    以外と有名な問題なのですが、カートに沢山の商品を入れて注文すると、受注メールは送信されてエラーも出ないのに「送料がゼロ円になる」とか「管理画面に受注データが表示されない」という障害が起きます。

    これは、セッション情報を保存するDBテーブルが text型で取られているため、65,535バイト(MySQLの場合)以上のセッション情報を保存しようとすると後ろの方のデータが欠落するためです。

    CREATE TABLE dtb_session (
        sess_id text NOT NULL,
        sess_data text,
        create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
        update_date timestamp NOT NULL,
        PRIMARY KEY (sess_id(255))
    );

    このセッションデータには、カートに入れた商品の情報+購入者情報+配送先情報が入るため、欠落するときは真っ先に配送先の情報が欠落してしまい、結果として都道府県が分からなくなるので送料が計算できずにゼロ円になってしまいます。また、受注データとJOINする配送先データが生成されないので一覧に受注データが表示されないという症状に繋がります。

    対策としては、text → logtext に型を変更するだけで65Kバイト→4Gバイトまで保持できるようになるので情報欠落は無くなります。sessionデータはdtb_order_tempテーブルにも持っているのでそちらも修正が必要です。

    alter table dtb_session modify sess_data longtext;
    alter table dtb_order_temp modify session longtext;

    ※ かなり以前から報告されている障害ですがバージョン2.13.5でも対策されていないので公式に対応する予定は無いようです
    ※ 自分でコミュニティへ参加してパッチを作成するマンパワーが無いのでその予定はありません

    Facebook [ja]コメント 

  • Q: [EC-CUBE 2系] EC-CUBE 2系の「もっと見る」を簡潔に 2020.01.02
    A:

    今更ながら、EC-CUBE 2系のスマホ版のデザイン変更で苦労しました。

    EC-CUBEに組み込まれている「もっと見る」ボタンですが、Ajaxで次ページのjsonデータを取得してきて画像、商品名、価格等のspanやimgタグの中身を1個ずつコピーしている。。。(3系でも同じなのかな??)

    これでは、つぶしが気かないったらありゃしないので、デザイン変更しても動作するJavaScriptに書き換えてみました。jsonではなく2ページ目のHTMLをそのままGETしてきて商品一覧部分のタグをそのまま現在の一覧の下に差し込むだけ。

    ・総HIT数が<span id=”productscount”>XXX</span>に書かれていること。
    ・もっと見るボタンにid=”btn_more_product”が付いていること。
    ・商品リストの個別商品が class=”list_area” に入っていて、各商品ブロックが<form>で囲まれていること。
    (<form>で囲まれていないなら、2ヶ所の .closest(‘form’) は不要)

    の3点だけ守られていれば、デザイン変更しても大丈夫です。

    <script>
        var pageNo = 2;
        var url = "<!--{$smarty.const.P_DETAIL_URLPATH}-->";
        var imagePath = "<!--{$smarty.const.IMAGE_SAVE_URLPATH|sfTrimURL}-->/";
        var statusImagePath = "<!--{$TPL_URLPATH}-->";
    	
        function getProducts(limit) {
            $.mobile.showPageLoadingMsg();
            var i = limit;
            //送信データを準備
            var postData = {};
            $('#form1').find(':input').each(function(){
                postData[$(this).attr('name')] = $(this).val();
            });
            postData["mode"] = "html";
            postData["pageno"] = pageNo;
    
            // デザイン変更に左右されない「もっと見る」処理に書き換えました。
            $.ajax({
                type: "POST",
                data: postData,
                url: "<!--{$smarty.const.ROOT_URLPATH}-->products/list.php",
                cache: false,
                dataType: "html",
                error: function(XMLHttpRequest, textStatus, errorThrown){
                    alert(textStatus);
                    $.mobile.hidePageLoadingMsg();
                },
                success: function(result){
                    $('.list_area:last').closest('form').after($(result).find('.list_area').closest('form').clone(true));
                    pageNo++;
    
                    //すべての商品を表示したか判定
                    if (parseInt($("#productscount").text()) <= $(".list_area").length) {
                        $("#btn_more_product").hide();
                    }
                    $.mobile.hidePageLoadingMsg();
                }
            });
        }
    </script>
    

    Facebook [ja]コメント 

  • Q: [EC-CUBE 2系] EC-CUBEをインストールする 2019.12.10
    A:

    EC-CUBEを利用することになりそうなので、ひとまずEC-CUBEをレンタルサーバーにインストールしてみました。その手順備忘録です。

    EC-CUBEをダウンロードする

    EC-CUBE公式サイトからファイルをダウンロードします。
    2019年12月時点で最新バージョンは、2.13.5です。なのでダウンロードしたファイルは eccube-2.13.5.zipでした。
    screencapture-ec-cube-net.jpg
    ダウンロードするには、EC-CUBEメンバーである必要があります。登録は無料なので迷わず登録しました。

    補足ですが、バージョンによっては不具合修正ファイルがあることもあるようなので、その場合はその不具合修正ファイルもダウンロードしておきます。(今回はありませんでした。)

    EC-CUBEのファイルを配置する

    ダウンロードしたファイルは圧縮ファイルなのでとりあえず解凍します。
    そして、サーバーに配置する前に少し準備します。

    解凍すると以下のフォルダが存在すると思います。
    /data
    /docs
    /html
    /test
    /tests
    必要になのは「data」「html」の2つだけです。
    (不具合修正ファイルがある場合は上書きしてください。)

    これから構築するサイトのURLを「http://ドメイン/html」ではなく「http://ドメイン/」としたいので、「data」フォルダを丸ごと「html」フォルダ直下に移動します。
    その移動に伴い、html/define.phpを修正します。

    (修正前)

    1
    define("HTML2DATA_DIR", "/../data/");

    (修正後)

    1
    define("HTML2DATA_DIR", "/data/");

    次に「html」フォルダ直下にある.htaccessを削除します。

    ↓↓↓↓↓ 重要 ↓↓↓↓↓
    このままでは、dataフォルダにWEbからアクセスできてしまうため、とっても危険です。
    例えばlogファイルが丸見えになってしまうので、管理画面のログインIDやサーバーのパスや何のプラグイン使ってるかーなど、いろいろとデータが取れてしまうのです。(他にもいろいろ問題アリ。)
    そこで、dataフォルダ直下に以下を記述した.htaccessを配置します。

    1
    2
    order allow, deny
    deny from all

    ほんとは、dataフォルダはhtmlフォルダ内じゃなくて、ルートディレクトリ外に配置できる方が理想です。
    今回はどうしてもそれが出来ない環境の場合を例にしています。
    ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

    ここまで出来たら、サーバーに配置します。
    配置する場所はサーバーによって異なりますが、たいていはApacheのドキュメントルート直下に「html」フォルダ内のフォルダ、ファイル全てを配置します。

    データベースを作る

    EC-CUBEはデータベースを必要とするのでデータベースを事前に準備します。
    PostgreSQLかMySQLを使用することができます。私はphpMyAdminを使ってMySQLを作成しました。
    後で必要になるので、データベース名、MySQLユーザー名、MySQLパスワード、ホスト名をメモしておきます。

    EC-CUBEをインストールする

    「http://ドメイン/」にアクセスします。以下の画面が表示されたら「次へ進む」ボタンを押します。
    eccube-ins-02

    チェック結果が表示されます。成功していれば「次に進む」ボタンを押します。
    eccube-ins-03

    必要なファイルのコピーが開始されます。これも成功していれば「次に進む」ボタンを押します。
    eccube-ins-04

    ECサイトの設定をします。
    純国産のCMSというだけあって説明が丁寧です。さすがです。必要事項を入力して次へ進みましょう。
    eccube-ins-05

    データベースの設定です。
    事前に準備したデータベースの情報を入力します。DBの種類を間違えないようにしましょう。
    入力できたら「次へ進む」ボタンを押します。
    eccube-ins-07

    データベースの初期化です。
    eccube-ins-08
    eccube-ins-09

    デバッグのために情報提供を依頼されます。無難に「はい(推奨)」にしました。「いいえ」にしたらどうなるかは、試してないのでわかりません。
    eccube-ins-10

    インストール完了です。管理画面ログインにすすみます。
    eccube-ins-11

    ここで画面上部に警告が出ます。install/index.phpを削除しろと言っています。おとなしく従いましょう。
    eccube-ins-12

    ファイルを削除するとログイン画面から警告が消えるので、改めて管理画面にログインします。
    eccube-ins-13

    これにて終了です。

    Facebook [ja]コメント 

  • Q: [EC-CUBE 2系] EC-CUBE2.13カスタマイズ:新しいページを追加する 2019.11.11
    A:

    EC-CUBEで新しいページを追加する方法として、管理画面で追加して、そのページのURLを任意に変更する手順をメモ。

    管理画面からページを追加する

    管理画面でデザイン管理>PC>ページ詳細設定を開き、必要事項を入力して登録するボタンを押下。
    ※スマホ、モバイルもそれぞれ同様です。
    EC-CUBE-add-page-01

    これにより以下の追加が行われます。
    1)/html/user_data/sample.phpが生成される。
    ※sample.phpは登録した任意のファイル名
    ※処理はこのファイルに記述していきます
    2)/data/Smarty/templates/(テンプレート名)/user_data/sample.tplが生成される。
    ※管理画面から入力した内容が入ります。
    3)dtb_pagelayoutテーブルにこのページ情報が1レコード追加される。

    作成されたページのこの時点では以下のパスで確認できます。
    http://www.example.com/html/user_data/sample.php
    このままではイケテないので以下になるように変更していきたいと思います。
    http://www.example.com/html/sample/

    追加したページのURLを変更する

    phpファイルを移動する

    まず生成されたphpファイルを以下に移動します。フォルダを新規作成してファイル名も変更します。
    /html/sample/index.php

    DBを書き換える

    dtb_pagelayoutテーブルのurlフィールドをsample/index.phpに変更する。
    これで、URLの変更ができました。

    ちなみに、dtb_pagelayoutテーブルの中身ですが、おそらくこんな感じ。
    device_type_id・・・「10」はPC用のページという意味
    page_id・・・同じdevice_type_idで重複しないID
    page_name・・・ページ名(管理画面で表示している名前)
    url・・・ページのURL
    filename・・・tplファイルの保管場所
    edit_flg・・・削除可能フラグ

    注:インストールされた環境によってパスは異なります。一般的なパスで紹介しています。

    2014.09.08 追記
    追加したページのURLを変更した場合は、ページを更新するときに管理画面のデザイン管理>PC>ページ詳細設定から編集できなくなります。
    編集してしまうとdtb_pagelayoutテーブルのurlフィールドがデフォルトに戻ってしまうからです。
    更新はテンプレートを直接しなくてはなりません。
    んー、イマイチ?URLを変更しても管理画面から更新できる方法ないかなー?

    Facebook [ja]コメント 

  • Q: [EC-CUBE 3系] 관리 화면의 사이드 메뉴에 항목 추가하는 방법 2019.11.11
    A:

    EC-CUBE3에서는 관리 화면의 사이드 메뉴에 쉽게 메뉴를 추가 할 수 있습니다.

    관리 화면에 메뉴 추가

    외형 수정이므로 템플릿 (twig)를 편집 ...라고 생각했는데, 수정할 필요가있는 것은 ServiceProvider입니다.
    실제로 ServiceProvider에서하지 않아도 좋다고 생각 합니다만,로드 된 적당한 ServiceProvider 다음의 설명합니다.

            $ app [ 'config'] = $ app-> share ($ app-> extend ( 'config', function ($ config) {
                $ nav = array (
                    'id'=> 'admin_new_menu'
                    'name'=> '새 메뉴'
                    'url'=> 'admin_new_menu'
                    'has_child'=> 'false'
                    'icon'=> 'cb-chart'
                    'child'=> array (
                        array (
                            'id'=> 'xx_submenu1'
                            'url'=> 'xx_submenu1'
                            'name'=> '하위 메뉴 1'
                        ),
                    ),
                );
    
                $ config [ 'nav'] [] = $ nav;
    
                return $ config;
            }));

    이렇게 app.config.nav 메뉴 배열을 추가하여 메뉴를 늘릴 수 있습니다.
    반대로 필요없는 항목이 배열로부터 삭제 해 주면 제거 할 수 있습니다.

    EC-CUBE3를 이용하시는 분은 꼭보세요.

    Facebook [ja]コメント 

  • Q: [EC-CUBE 2系] イベントセット販売プラグインマニュアル 2019.11.07
    A:
    • プラグイン登録
      1. ファイルの選択ボタンをクリックします。
      2. 登録するファイル(EventSetSale.tar.gz)を選択し、開くをクリックします。
      3. インストールのボタンをクリックして、待って、インストールを待ちます。
      4. 下の1-2画面の①の赤長方形のボックスのように表示されたら、通常のインストールがされました。
        1-2.インストール完了画面:通常のインストールが完了した画面
      5. プラグインの基本的な設定をするために②プラグインの設定をクリックして設定画面を開いて、各値を入力して設定します。
      6. インストールされてプラグインを動作させるために1-2画面の③有効チェックボックスをクリックしてチェック 表示をします。

    Facebook [ja]コメント 

  • Q: [EC-CUBE 4系] EC-CUBE4系で管理画面に新規メニュー項目を追加する方法 2019.10.28
    A:

    今回は商品管理の一番下に新規メニュー項目を追加することを考えます。
    まずメニューから開けるページが必要ですのでコントローラーを作成し、新しいページを作った後でそのページをメニューに追加してみましょう。今回はeccube_nav.yamlを編集するもっとも簡単な方法をご紹介します。

    管理画面に新規ページを作る方法は下記URLで紹介しています。
    管理画面に2ステップで新規ページを作る方法

    それでは、このページを商品管理のメニューに追加してみます。

    初期状態での管理画面のメニュー一覧はapp/config/eccube/packages/eccube_nav.yamlに配列として記載されています。
    商品のメニュー部分は下記のようになっています。

    parameters:
        eccube_nav:
            product:
                name: admin.product.product_management
                icon: fa-cube
                children:
                    product_master:
                        name: admin.product.product_list
                        url: admin_product
                    product_edit:
                        name: admin.product.product_registration
                        url: admin_product_product_new
                    class_name:
                        name: admin.product.class_management
                        url: admin_product_class_name
                    class_category:
                        name: admin.product.category_management
                        url: admin_product_category
                    product_tag:
                        name: admin.product.tag_management
                        url: admin_product_tag
                    product_csv_import:
                        name: admin.product.product_csv_upload
                        url: admin_product_csv_import
                    category_csv_import:
                        name: admin.product.category_csv_upload
                        url: admin_product_category_csv_import
                    #商品管理に新規メニュー追加

    category_csv_importの下に次のように追記することでメニューを追加することができます。

    product_new_menu:
        name: 新メニュー
        url: admin_new_menu

    new_menuはメニューにつけるID名で、このメニューをアクティブにしたい時にtwigから指定します。
    nameは表示する名称
    urlはコントローラーのRouteで指定したURLの名前です。

    動作検証

    これで管理画面にアクセスするとカテゴリCSV登録の下に新規メニューが追加されました。twigでメニューの位置を指定しているのでアクティブ表示になっています。

    メニュー追加

    eccube_nav.yamlを編集するとバージョンアップの際に上書きされてしまう可能性があります。
    大きなカスタマイズをするとバージョンアップできない可能性も高いですが、バージョンアップをご検討の方はEccubeNav(NavCompilerPass)の仕組みを利用するか、app/config/eccube/packages/prodなどに複製して用いると良いかもしれません。

    Facebook [ja]コメント 

  • Q: [EC-CUBE 2系] 2.13系 ソフトウェア要件 2019.10.11
    A:
    分類 ソフトウェア 動作確認済み
    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

    推奨PHPライブラリ

    • JSON(PHP5.2以降でオーナーズストアを使用する場合は必須)
    • xml(プラグイン機能を使用する場合は必須)
    • OpenSSL
    • cURL
    • hash
    • mhash (PHP 5.3.0 未満の場合)
    • mcrypt
    • zip

    Facebook [ja]コメント 

  • Q: [EC-CUBE 2系] ECCUBE 2.13のインストール方法をスクリーンショット付きでわかりやすく徹底解説! 2019.10.10
    A:

    EC-CUBE v2.13 インストール에 대한 이미지 검색결과


    EC-CUBE」とは、ECサイトに必要なカート機能や決済機能がパッケージ化されている、無料のツールです。ECサイトを運営したことがある人なら、きっと知っている人も多いはず。あとはWebサーバーさえあれば、わりと簡単にECサイトを立ち上げることができます。これからECサイトをはじめる方向けに、EC-CUBE バージョン2.13のインストール方法を、各画面のスクリーンショット付きでわかりやすく解説します。


    まずはダウンロード

    EC-CUBEサイトから、ZIPファイルをダウンロードしましょう。(この記事では、バージョンは2.13.2です。)

    なお、ダウンロードには会員登録が必要です。

    ECCUBEダウンロード

    つづいてメンバー登録

    ECCUBE 新規メンバー登録

    「eccube-2.13.2.zip」がダウンロードできたら、解凍してみましょう。
    すると、下記のようにいろいろなファイルが入っているはずです。
    このうち「data」と「html」の2つだけを、Webサーバーにアップロードしましょう。

    ECCUBE解凍フォルダ

    アップロード

    アップロードする前に、FTPソフトの設定でアップロード時のパーミッションを指定しておくことをおすすめします。
    ファイルは「644」、ディレクトリは「755」で設定しておきましょう。

    なお、data はセキュリティの面で、一般のユーザーから見えない階層にアップしたほうが良いです。

    私の場合はこんな感じ↓

    /root/data(=一般のユーザーは見れない領域)
    /root/www/html(=www配下は一般のユーザでも見れる領域)

    define.phpを編集

    私の場合は data と html が同階層でなくなったので、html 内の define.php を変更する必要があります。
    (data と html が同階層であれば、変更する必要はありませんので、このステップは飛ばして構いません)

    html ディレクトリから見た、dataディレクトリの相対パスを指定しましょう。

    [php]
    /** HTMLディレクトリからのDATAディレクトリの相対パス */
    define(‘HTML2DATA_DIR’, ‘../../data/’);
    [/php]


    データーベースを作成

    ECCUBEのインストール時にはデータベースの情報を求められますので、あらかじめ用意しておきましょう。

    ここでは私が利用しているさくらサーバーでのやり方をご紹介します。

    コントロールパネルにログイン。

    左ナビから「データベースの設定」を選択。

    データーベースの設定を選択

    「データベースの新規作成」を選択。

    データベースの新規作成を選択

     

    データーベースの情報を設定します。
    MySQLのバージョンは「5.5」、
    データベース名は、自由に命名してください。
    文字コードは「UTF-8」にします。

     

    データーベースの情報を入力

    これでデータベースが作成されました!


    ECCUBEのインストール画面

    先ほどアップした「html」ディレクトリにアクセスしてみましょう。

    パーミッションとdefine.phpのパスが正しく設定されていれば、次の画面が現れるはずです。

    ECCUBE インストール

    ECCUBE - インストール02

    ひとまず必須項目を入力していきます。
    これらの項目はインストール後でも管理画面から変更できます。

    ECCUBE - インストール04

    先ほど作成したデータベースの情報を入力していきます。
    さくらのコントロールパネルのデータベース一覧画面を参照してコピペしましょう。

    ECCUBE - インストール05

    つづいて、データベースの初期化を行います。(ちょっとドキドキ)

    ECCUBE - インストール06

    データベースの初期化に成功しました。

    ECCUBE - インストール07

    情報提供を送信するかをたずねられますが、これはどちらでも構いません。

    ECCUBE - インストール08

    以上でインストールが完了しました!

    ECCUBE - インストール09

    htmlディレクトリにアクセスすると、デフォルトのストアページが表示されるはずです。

    ECCUBE - 初期サイト

    次回は、管理画面から商品情報を変更してみます。

    Facebook [ja]コメント 

  • Q: [EC-CUBE運用マニュアル] EC-CUBE2.12 運用マニュアル 2019.09.29
    A:

    EC-CUBE 

    Ver2120 

    Ver2121 

    Ver2122 

    運用マニュアル

    2012年11月28日




    目次

    開店準備4
    基本情報設定4
    SHOPマスターの設定4
    特定商取引に基づく表記の登録5
    配送方法の設定6
    支払い方法の設定8
    ポイントの設定9
    受注受付メールの設定9
    会員規約の設定11
    郵便番号DB登録11
    SEO管理13
    定休日管理13
    商品登録14
    カテゴリーの登録14
    メーカーの登録15
    商品の登録15
    規格の登録19
    商品並び替え21
    運用22
    受注管理22
    受注管理22
    対応状況管理25
    会員管理26
    会員マスター26
    売上集計28
    売上集計の参照28
    メルマガ管理30
    テンプレート設定30
    配信内容設定32
    コンテンツ管理34
    新着情報管理34
    おすすめ商品管理36
    ファイル管理38



    目次

    ファイル管理38
    CSV出力設定39
    レビュー管理41
    レビュー管理41
    デザイン管理42
    レイアウト管理42
    ページ詳細設定45
    ブロック設定46
    ヘッダー / フッダーの編集47
    CSS設定48
    テンプレート追加49
    テンプレート設定50
    システム設定51
    ユーザ管理51
    バックアップ管理52
    プラグイン管理53




    Facebook [ja]コメント 

  • Q: [EC-CUBE 2系] 単体テストガイドライン 2019.09.28
    A:

    本ガイドラインはEC-CUBEの単体テストをPHPUnitを使って行う上でのガイドラインを
    株式会社SHIFT様(http://www.shiftinc.jp/)のご協力によりまとめたものとなります。

    各クラス共通のガイドライン

    1. テストを含めたフォルダ構成

    テストコードを含んだフォルダ構成は以下のようになります。
    tests以下には、テストコード本体の他にテスト用のユーティリティや設定ファイル等が含まれます。

    build.xmlテストやインスペクションを行うための設定ファイルです。
    tests
    ├phpunit.xmlPHPUnitで使う各種設定を記載したファイルです。
    SVN上にはphpunit.xml.baseというファイルがありますが、ローカルではこれをコピーしてphpunit.xmlを作成してください。
    ├ruleset.xmlPHP_CodeSniffer(インスペクションツール)用の設定ファイルです。
    ├require.phpテストに必要なファイルをインクルードするためのクラスです。
    SVN上にはrequire.php.baseというファイルがありますが、ローカルではこれをコピーしてrequire.phpを作成してください。
    └classテスト用のクラスを格納するディレクトリです。
     ├Common_TestCase.php他のテストクラスの基底となるクラスです。
     ├replaceテスト用に実装を入れ替えているクラスを格納するディレクトリです。
     └test/utilテスト用のユーティリティを格納するディレクトリです。

    テストコードはそれぞれ対応するソースコードと同じ階層に保存します。

    2. テストの実行方法

    2.1.  実行の準備(初回のみ)

    単体テストを実行するためには、ローカルの環境にPHPUnitをインストールしておく必要があります。
    また、インクルードパス等をローカルの環境に合わせて書き換えるため、SVNに含まれているファイルをコピーしてローカル用の設定ファイルを作成する必要があります。
    手順は下記の通りです。

    • tests/phpunit.xml.baseをコピーしてtests/phpunit.xmlを作成します。
    • <filter><blacklist>タグ以下の「/usr/local/lib」の部分を、ローカルで使われる各種ライブラリが含まれているパスと置換します。
      • この設定はどのファイルをテストのカバレッジ測定の対象にするかを設定するためのものなので、設定をし直さなくても単体テスト自体は問題なく動作します。
    • tests/require.php.baseをコピーしてtests/require.phpを作成します。
    • PHPUnitのモジュールが使用できるように、インクルードパスを設定します。

    tests/phpunit.xml、tests/require.phpはsvn:ignoreに設定されているため、自由に書き換えてもコミットはされません。

    2.2.  実行

    全体のテストを行う場合には、phingのtestターゲットを実行します。
    テストの内容はbuild.xmlの中に定義されているため、実際にはphpunitコマンドが発行されます。

    % phing test
    

    テストが完了すると、結果がreportsディレクトリ以下に出力されます。

    • reports/tap.log TAP形式のテスト結果
    • reports/unitreport.xml xUnit形式のテスト結果
    • reports/coverage/coverage.xml カバレッジ測定結果のXML(主にJenkinsで処理するためのものなので気にしなくて良いです)
    • reports/coverage/.html カバレッジ測定結果のHTML

    個々のテストを行う場合には、テスト対象のディレクトリを指定してphpunitコマンドを実行します。
    標準出力ですぐにテスト結果を確認したい場合にはこちらのやり方のほうが良いでしょう。

    % phpunit –c tests/phpunit.xml tests/class/pages/LC_Page/LC_Page_InitTest.php
    % phpunit –c tests/phpunit.xml tests/class/pages
    

    下の例のようにディレクトリを指定した場合には、ディレクトリ以下にあるテストケースが実行されます。

    また、--colorsオプションを付けると、結果が色付きで表示され見やすくなります。

    % phpunit --colors –c tests/phpunit.xml tests/class/pages/LC_Page/LC_Page_InitTest.php
    

    カバレッジを測定したい場合には、専用のオプションを指定します。

    % phpunit -c tests/phpunit.xml --coverage-html reports/coverage tests/class/pages/LC_Page/LC_Page_InitTest.php
    

    3. テストクラスの構成

    テストクラスは、基本的にtests/class/Common_TestCase.phpを継承して作成します。
    Common_TestCaseの中には、次節で述べるAssertionを一度に行うverify()関数や
    テストの開始時と終了時にDBの準備・後片付けを行うsetUp()/tearDown()関数が含まれています。
    個々のテストクラスでは、Common_TestCaseのsetUp()/tearDown()の処理に必要な処理を追加して使います。
    また、テストに使用するユーティリティクラスもCommon_TestCaseでまとめてrequireします。

    <?php
    SampleTest extends Common_TestCase {
    
      protected function setUp() {
        parent::setUp();
         // 個々のテストケースで必要な処理
      }
    
      protected function tearDown() {
        // 個々のテストケースで必要な処理
        parent::tearDown();
      }
      public function testFunctionName_❍❍の場合_△△になる() {
        $this->expected = array('hoge', 'fuga');
        $this->actual = array();
        $this->actual[0] = functionName('a');
        $this->actual[1] = functionName('b');
    
        $this->verify();
      }
    }
    

    4. Assertion(期待値の確認)の方法

    PHPUnitにはassertEquals()、assertTrue()など様々な期待値の確認用funcitonが存在します。
    これらを細かく使用してテストの期待値を確認することもできますが、複数のasseritionを並べると
    最初の方で失敗した場合に後のassertionが実行されず、全体の修正までに時間がかかってしまう場合があります。
    これを防ぐため、基本的に期待値と実際の結果はarrayに格納して一度でassertできるようにします。
    もちろん、それぞれの値が1つずつの場合はarrayに入れなくても構いません。

    <?php
    protected function verify($msg = null) {
      $this->assertEquals($this->expected, $this->actual, $msg);
    }
    
    public function testHoge() {
      $this->expected = array(1, "山田", "太郎");
      // テスト対象を実行して$actualに結果を格納
      $this->verify();
    } 
    

    5. テストfunctionの分け方

    原則として、1つのテストfunctionで1つの条件をテストします。

    • 良い例
      <?php
      function testAbs_正の値の場合() {
        $expected = 1;
        // テスト対象functionの呼び出し
        $actual = abs(1);
        $this->verify();
      }
      
      function testAbs_負の値の場合() {
        $expected = 2;
        // テスト対象funcitonの呼び出し
        $actual = abs(-2);
        $this->verify();
      }
      
      
    • 悪い例
    <?php
    function testAbs() {
      $expected[0] = 1;
      $actual[0] = abs(1);
    
      $expected[1] = 2;
      $actual[1] = -2;
    
      $this->verify();
    }
    

    「悪い例」の書き方の場合、ケースの中身を確認しないと
    ・何種類のテストを行っているのかが把握できない
    ・どんな観点でテストを行っているのかが把握できない
    といった問題点があります。
    1funciton1条件の前提を守った上で、なるべく条件分岐を網羅するようにテストを作成していきます。

    6. テストfunctionの命名規則

    テストfunctionの名称は、テストの内容を分かりやすくするため

    test【function名】_【条件】_【期待する結果】()
    

    という形式で統一します。命名規則を統一することで可読性が上がり、
    テストコードを書いた本人でなくてもJenkinsのテストレポートを見るとどのようなテストが行われているかが一目でわかります。
    また、条件・期待する結果は日本語で記載することでさらに分かりやすくすることができます。

    testAction_必須項目が入力されていない場合_エラー画面に遷移する()
    

    7. テストクラスの分け方

    テストクラスはテスト対象のfunction毎に1つずつ分けて作成します。
    ただし、後述する「定数による条件分岐」をテストする場合には条件毎にクラスを分ける必要があるためさらに細分化されます。

    8.テストクラスの命名規則

    上で述べたとおり基本的にテストクラスはテスト対象のfunctionに対応するため、

    【対象クラス】_【対象function】Test.php
    

    という名称にします。さらに条件毎にファイルを分ける場合には、

    【対象クラス】_【対象function】_【条件】Test.php
    

    とします。

    • LC_Page_Products_Detail_ActionTest.php
      LC_Page_Products_Detail_Action_HasErrorTest.php
      

    条件によってファイル名を分ける場合には、ファイル名は日本語を避けて定義するようにしてください。

    9. より網羅的にテストを書く方法

    1. 定数による条件分岐

    defineを使って定義されている定数は、テスト中に自由に上書きすることができません。
    そこで、定数の値によって条件が分岐する場合は定数の値ごとにテストコードのファイルを分割します。

    • ソースコード
      <?php
      function sfGetHashString($str, $salt) {
        $res = '';
        if ($salt == '') {
          $salt = AUTH_MAGIC;
        }
        if (AUTH_TYPE == 'PLAIN') {
          $res = $str;
        } else {
          $res = hash_hmac(PASSWORD_HASH_ALGOS, $str . ':' . AUTH_MAGIC, $salt);
        }
        return $res;
      }
      
    • テストコード
      <?php
      $HOME = realpath(dirname(__FILE__)) . "/../../../..";
      // このテスト専用の定数の設定。必ずCommon_TestCase.phpより先に定義する
      define('AUTH_TYPE', 'PLAIN');
      require_once($HOME, "/tests/class/Common_TestCase.php");
      
      // クラス名に条件(authTypePlain)も含める
      class SC_Utils_sfGetHasString_authTypePlainTest extends Common_TestCase {
      
        // AUTH_TYPE=PLAINであることを想定した実際のテストコード
      }
      

    このようにCommon_TestCaseより先に指定したい定数を定義することで、このテストクラスに限定した値を定義することができます。

    2. exitする箇所のテスト

    PHPUnitでテストを行う際には実際にphpのプログラムを走らせることになりますが、
    プログラム中にexitする箇所があるとそこでPHPUnit自体も終了してしまうため、有効なテスト結果を得ることができません。
    EC-CUBEの場合は、pages以下のクラスでSC_Response_Ex::sendRedirect()やSC_Response_Ex::actionExit()を呼んでいる箇所がそれにあたります。
    このような部分をきちんとテストするために、テスト実施時はSC_Response_Exの実装を切り替えてexitしないようにします。
    実装を切り替えた後のクラスはtests/class/replace以下に存在します。
    このクラスをCommon_TestCaseから呼び出すことにより、テスト時の実装を切り替えます。

    <?php
     /**
       * actionExit()呼び出しを書き換えてexit()させない例です。
       */
      public function testExit() {
        $resp = new SC_Response_Ex();
        $resp->actionExit();
    
        $this->expected = TRUE;
        $this->actual = $resp->isExited();   // exit()したかどうかをチェックします。
        $this->verify('exitしたかどうか');
      }
    

    10. テストを書きやすくする対策

    1. functionを「単体」でテストする

    functionの中でさらにfunctionが呼ばれている場合、いちばん外側のfunctionをそのまま実行すると中の分岐が多すぎてテストしきれない場合があります。
    そのような場合は、内側のfunctionの実装をモックに切り替えて欲しい値を自由に返すようにし、外側のfunctionだけをテストするようにします。

    • ソースコード
      <?php
      class Sample {
      function hoge() {
        if (fuga()) {
          return 1;
        } else {
          return 2;
        }
      }
      
      function fuga() {
         return rand() % 2 == 0;
      }
      }
      
    • テストコード
      <?php
      class SampleTest extends PHPUnit_Framcework_TestCase {
        function testHoge_fugaがtrueの場合() {
          $sample = new Sample_Mock();
          $sample->fuga_val = TRUE;
          $this->assertEquals(1, $sample->hoge());
        }
      }
      
      class Sample_Mock extends Sample {
        $fuga_val;
      
        function fuga() {
          return $fuga_val;
        }
      }
      

    この例はそれほど分岐が複雑ではありませんが、内側の関数fuga()の返り値がランダムなのでテストで要求する値を返却させるためにオーバーライドしています。

    2. ユーティリティクラスを使ってデータ準備を効率化する

    テストで常に同じ結果を得られるようにするには、テスト実行のたびにDBの内容を期待値に合わせてリセットする必要があります。
    そのため、EC-CUBEのユーティリティであるSC_Queryクラスを使ってsetUp()の中でデータの準備を行い、tearDown()でロールバックを行います。

    <?php
    class SampleTest extends PHPUnit_Framework_TestCase {
      // データ準備
      protected function setUp() {
        $this->objQuery = SC_Query_Ex::getSingletonInstance();
        $this->objQuery->begin();
        $this->setUpCustomer();  // 実際にデータを投入する箇所
      }
    
      // ロールバック
      protected function tearDown() {
        $this->objQuery->rollback();
      }
    
      // データの定義
      protected function setUpCustomer() {
            $arrValue['customer_id'] = $this->customer_id;
            $arrValue['name01'] = $this->name01;
            $arrValue['name02'] = $this->name02;
            $arrValue['kana01'] = $this->name01;
            $arrValue['email'] = 'test@example.com';
            $arrValue['secret_key'] = 'aaaaaa';
            $arrValue['status'] = 2; // 会員
            $arrValue['create_date'] = 'CURRENT_TIMESTAMP';
            $arrValue['update_date'] = 'CURRENT_TIMESTAMP';
            $this->objQuery->insert('dtb_customer', $arrValue);
      }
    }
    

    よく使うデータ定義はtests/class/util以下のユーティリティクラスから取得できるようにしておき、データの再利用性を高めます。

    3. ユーティリティクラスを使って端末の種類を設定する

    端末の種類がPC・モバイル・スマートフォンのいずれになっているかによって条件が分岐する場合は、
    テスト専用のユーティリティを使用して擬似的に端末の種別を設定します。ユーティリティはtests/class/test/util/User_Utils.phpに定義されています。

    <?php
    /**
       * 端末種別をテストケースから自由に設定する例です。
       */
      public function testDeviceType() {
        $this->expected = array(DEVICE_TYPE_MOBILE, DEVICE_TYPE_SMARTPHONE);
        $this->actual = array();
    
        // 端末種別を設定
        User_Utils::setDeviceType(DEVICE_TYPE_MOBILE);
        $this->actual[0] = SC_Display_Ex::detectDevice();
        User_Utils::setDeviceType(DEVICE_TYPE_SMARTPHONE);
        $this->actual[1] = SC_Display_Ex::detectDevice();
    
        $this->verify('端末種別');
      }
    

    4. ユーティリティクラスを使ってログイン状態を設定する

    ユーザがログインしているかどうかによって処理が分岐する場合は、セッションの情報とDBの値を書き換えることによりテストで要求する分岐を実現します。
    情報を書き換えるfunctionは、端末種別設定と同じくtests/class/test/util/User_Utils.php内で定義されています。

    <?php
      /**
       * ログイン状態をテストケースから自由に切り替える例です。
       */
      public function testLoginState() {
        $this->expected = array(FALSE, TRUE);
        $this->actual = array();
    
        $objCustomer = new SC_Customer_Ex();
        // ログインしていない状態に設定
        User_Utils::setLoginState(FALSE);
        $this->actual[0] = $objCustomer->isLoginSuccess();
        // ログインしている状態に設定
        User_Utils::setLoginState(TRUE, null, $this->objQuery);
        $this->actual[1] = $objCustomer->isLoginSuccess();
    
        $this->verify('ログイン状態');
      }


    Facebook [ja]コメント 

  • Q: [EC-CUBE 2系] リファクタリングガイドライン 2019.09.28
    A:

    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]コメント 

  • Q: [EC-CUBE 2系] EC-CUBE標準規約 2019.09.28
    A:

    基本的に Zend Framework PHP 標準コーディング規約 に順ずる.
    以下, 要点及び相違点を規定する.

    また, コーディングに際して, 以下のガイドラインに沿うことが望ましい

    EC-CUBE標準規約 > リファクタリングガイドライン

    PHPUnitを利用した単体テストを行う際は以下のガイドラインに沿う事が望ましい

    EC-CUBE標準規約 > 単体テストガイドライン

    命名規約

    ファイル名

    • 拡張子は, 各ファイル形式に準ずる.
      • PHPファイルは, 必ず .php を使用する.
    • PHPクラスは, 特別な場合を除き, 1クラス1ファイルとし, クラス名.php とする.

    PHPクラス名

    • 区切り文字としてはアンダースコア(_)を使用する.
    • クラス名称の先頭には, 大文字でその種類を表す Prefix を付加する.
      Prefix 種類
      SC, GC 1つのサイト内で共有するクラス (他のクラスから呼ばれる) SC_Customer.php
      LC 1つのソースファイル内で使用するクラス (通常他のクラスから呼ばれない) LC_Page_Abouts.php
    • クラスがパッケージに属する場合は, Prefix の後にパッケージ名を付加する.
      • Page パッケージでインデックスページとしてアクセスされるクラス名は Index とせず, 属する階層名をクラス名とする.
    • ユーザーが拡張するために extends するクラスは, クラス名の最後に Ex を付加する.

    関数名

    • 関数名の先頭には, 小文字でその種類を表す Prefix を付加する.
      • クラス名: LC_*
        • private または protected を意図する場合、Prefix「lf」を省略できる。(Prefix の付加がない場合、「lf」相当とみなす。)
        • public を意図する場合、Prefix「sf」を省略できない。
      • クラス名: SC_*, GC_*
        • public を意図するメソッドの場合、Prefix「sf」を省略できる。(Prefix の付加がない場合、「sf」相当とみなす。)
        • private または protected を意図する場合、Prefix「lf」を省略できない。
    • 名称が複数の単語からなる場合, それぞれの単語の先頭を大文字にする.
    • 関数名は, Prefix + 動詞 + 対象 を原則とする.
      Prefix 種類
      sf 一つのサイト内で共有する関数 sfGetProductName()
      lf 一つのソースファイル内で使用する関数 lfGetProductName()
      fn JavaScript で宣言された関数 fnGetProductName()

    変数名(Smarty 変数も含む)

    • 変数名の先頭には, 小文字でその種類を表す Prefix を付加する.
      • ループ等で一時的に使用する, 数値型の変数には慣習的な $i, $j, $k を使用しても良い.
    • リテラルを格納する (つまり配列・オブジェクト以外の) 変数名は, すべて小文字を使用し, アンダーバーで区切る.
    • 配列・オブジェクトの変数名はキャメルケースを使用する.
      Prefix 種類
      obj クラス変数(オブジェクト) $objQuery
      arr 配列 $arrCustmers
      tpl テンプレート変数(リテラル) $this->tpl_csv_id

    定数名

    • すべて大文字で宣言する.
    • 区切り文字としてアンダースコア(_)を使用する.
    • パスに関わるもの(パラメータを含む)は、下記を適用する。(#834 から展開)
      • *_URL: URL
        • 先頭は「スキーム名:」
      • *_URLPATH: URL における url-path 相当 (絶対パス)
        • 先頭は「/」
      • *_HTMLPATH: URL 上の EC-CUBE の /html/ からの相対パス
        • 先頭に「/」を含まない。(/html/ と同一の場合、空文字)
        • 命名に改善余地あり。 (参考: concrete5=DIR_REL) 現在は利用箇所が無いが、今後利用する必要も考えられるので再考していきたい。
      • *_REALFILE: (サーバの)ファイルシステム上のファイルの絶対パス
        • 先頭は「/」
      • *_REALDIR: (サーバの)ファイルシステム上のディレクトリの絶対パス
        • 先頭は「/」。末尾は「/」。
      • *_DIR: 上記に該当しない断片的なディレクトリ情報。
        • 先頭に「/」を含まない。
      • *_FILE: 上記に該当しない断片的なファイル情報。
      • *_PATH: 上記に該当しないもの。上記の複数に該当するもの。

    DBテーブル名

    • テーブル名の先頭には, 小文字でその種類を表す Prefix を付加する.
    • 区切り文字としてアンダースコア(_)を使用する.
    • Prefix 種類
      mtb マスタデータ mtb_pref
      dtb データテーブル dtb_order_detail

    DBカラム名

    • 特に指定の無い限り, すべて小文字を使用する.
    • 区切り文字としてアンダースコア(_)を使用する.

    CSS クラス名

    • 特に定義なし

    コーディング規約

    HTML

    • ラジオボタン, チェックボックスは <label></label> で囲み, 文字をクリックしてもチェックされるようにする.

    PHPコード

    • 改行コードは, 基本的に LF を使用する.
      • 使用する Subversion クライアントによっては, svn add を実行した際に, OS 元来の改行コードがリポジトリに反映されてしまう場合があるため, svn propset で svn:eol-style=LF を設定しておくのが望ましい.
    • PHPコードの開始タグと, 終了タグは以下のように記述する.
    • 終了タグの後に必ず LF (UNIX の改行コード)を1つ入れる.
    • 余分な空行, 行末の空白は極力削除する.
    • クラス定義, 関数定義の後, 括弧の後で改行する.
    • 80 文字を目安に改行する.
      <?php
      class LC_Page_Abouts
      {
      
          function process()
          {
              // some logic.
          }
      }
      

    制御文

    • if, for, while, switch 等の制御構造は, 次のルールで開き括弧で記述する.
    • インデントは, 半角スペース4文字を使用し, タブは使用しない.
    • if 文
      <?php
      if ($flag == '1') { // '1' == $flag と書くのは NG
          $ret = 1;
      } elseif ($flag == '2') {
          $ret = 2;
      } else {
          $ret = 3;
      }
      
      • 判定文の対象となる処理結果は先に記述する.
    • for 文
      <?php
      for ($i = 0; $i < $max; $i++) {
          echo $i . "\n";
      }
      
    • foreach 文
      <?php
      foreach ($var as $key => $val) {
          echo $key . ':' . $val . "\n";
      }
      
    • while 文
      <?php
      while ($flag) {
          var_dump($flag);
      }
      
    • do while 文
      <?php
      do {
          var_dump($flag);
      } while ($flag);
      
    • switch 文
      <?php
      switch ($var) {
          case VAR_ONE:
              echo 'one';
              break;
      
          case VAR_TWO:
              echo 'two';
              break;
      
          default:
              echo 'default';
              break;
      }
      
      • case の記述は, 定数を用いるのが望ましい.

    文字列

    • 長くなる文字列は分割し, "." で結合する.
      <?php
      $sql = 'SELECT name, age, birthday, zipcode, address, comment '
           . '  FROM user_information '
           . ' WHERE user_id = ? '
           . '   AND is_delete = 0 ';
      
    • ヒアドキュメントを使用しても良い
      <?php
      $sql = <<< __EOS__
          SELECT name,
                 age,
                 birthday,
                 zipcode,
                 address,
                 comment
            FROM user_information
           WHERE user_id = ?
             AND is_delete = 0
      __EOS__;
      

    SQL文

    • フォームから入力された値を利用して SQL文を生成する場合, SQLインジェクションを防ぐため, 必ず PEAR::MDB2 のブレースホルダを利用する.

    コメント

    • コメントのコーディングは基本的に phpDocumentor に準ずる.

    ヘッダ

    • 各ファイルのヘッダに著作権表記を記述する.
      <?php
      /*
       * This file is part of EC-CUBE
       *
       * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
       *
       * http://www.lockon.co.jp/
       *
       * This program is free software; you can redistribute it and/or
       * modify it under the terms of the GNU General Public License
       * as published by the Free Software Foundation; either version 2
       * of the License, or (at your option) any later version.
       *
       * This program is distributed in the hope that it will be useful,
       * but WITHOUT ANY WARRANTY; without even the implied warranty of
       * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       * GNU General Public License for more details.
       *
       * You should have received a copy of the GNU General Public License
       * along with this program; if not, write to the Free Software
       * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
       */
      

    クラス定義

    • phpDoc コメントは必要に応じて記述する.
    • @version は $Id$ を使用する.
    • メンバ変数は / */ を使用することによって phpDoc コメントとして認識される.
      <?php
      /**
       * クラスの簡単な説明
       *
       * クラスの詳細な説明....
       * ...
       *
       * @package Page
       * @author LOCKON CO.,LTD.
       * @version $Id$
       */
      class LC_Page
      {
      
          /** メンバ変数 */
          var foo;
      
      }
      

    Pageクラス

    • class/pages以下において exit; を個別の処理でしない。exit処理はすべてSC_Response_Ex::actionExit(); に共通化すること.

    関数定義

    • phpDoc コメントは必要に応じて記述する.
      • @param と @return は必須
    • コード文中にも必要に応じて的確なコメントを記述する.
      <?php
      /**
       * 関数の簡単な説明.
       *
       * 関数の詳細な説明....
       * ....
       *
       * @access private
       * @param string $foo 引数の説明
       * @param string|integer $bar 引数の説明
       * @return string 返り値の説明
       */
      function process($foo, $bar = '')
      {
          // some process...
          return 'string value';    
      }
      

    その他

    • 必要に応じて, 下記のタスクタグを使用しても良い
      • TODO - TODO として残したいコメント
      • FIXME - 必ず修正することを促すコメント
      • XXX - 動くけど怪しい...
        <?php
        // TODO リファクタリングすること.
        
        // FIXME 要修正. バグの説明(#135)
        
        /**
         * :XXX: 以下, 怪しいロジック(#999)
         * 複数行のコメントはこのように.
         *
         * 必要に応じて チケットの ID も記述する.
         */
        
    • コメントによってソースコードが見難くならないように注意する.

    Facebook [ja]コメント 

Board Pagination Prev 1 Next
/ 1