プログラムのブラッシュアップ(関数を使ったカート画面の実装)
それでは、関数を使用してcart.php
を書き換えてみます。サンプルソースのoriginal
フォルダにあるcart.php
をメモ帳などで開き、87行目~96行目を削除し、次のように置き換えてください。
// d_purchase テーブルへの挿入 create_purchase( $mdb2, $customer_code, $total_price );
また、その直後のforeach
ループを以下に置き換えます。
foreach( $_SESSION["cart"] as $cart ) { create_purchase_detail( $mdb2, $order_id, $cart["item_code"], $cart["price"], $cart["num"] ); }
最後に、4行目以降に次のコードを挿入します。
/** * d_purchase テーブルに挿入する関数 */ function create_purchase( $mdb2, $customer_code, $total_price ) { // d_purchase テーブルへの挿入 $sql = " insert into d_purchase( customer_code, purchase_date, total_price) "; $sql.= " values( ?, now(), ? ) "; $stmt = $mdb2->prepare( $sql ); $res = $stmt->execute( array( $customer_code, $total_price ) ); } /** * d_purchase_detail テーブルに挿入する関数 */ function create_purchase_detail( $mdb2, $order_id, $item_code, $price, $num ) { $sql = " insert into d_purchase_detail( order_id, item_code, price, num ) "; $sql.= " values( ?, ?, ?, ? ) " ; $stmt = $mdb2->prepare( $sql ); $res = $stmt->execute( array( $order_id, $item_code, $price, $num ) ); }
編集が終了したら、C:\xampp\ec\cart.php
に上書き保存し、これまで同様に注文完了ができることを確認します。もし、うまく動作しない場合は、サンプルソースのSTEP1_Func
フォルダに完成版のファイルがあるので、そちらを利用してください。
それでは、プログラムの解説です。今回作成した関数は、create_purchase
関数とcreate_purchase_detail
関数です。create_purchase
関数は、d_purchase
テーブルにレコードを追加する関数です。create_purchase_detail
関数は、d_purchase_detail
テーブルにレコードを追加する関数です。create_purchase_detail
関数に関しては、次のようにforeach
ループごと関数内で処理することもできなくはありません。
function create_purchase_detail( $mdb2, $order_id ) { foreach( $_SESSION["cart"] as $cart ) { $sql = " insert into d_purchase_detail( order_id, item_code, price, num ) "; $sql.= " values( ?, ?, ?, ? ) " ; $stmt = $mdb2->prepare( $sql ); $res = $stmt->execute( array( $order_id, $cart["item_code"], $cart["price"], $cart["num"] ) ); } }
しかし、上記の記述ではショッピングカートのセッション変数が存在しなければループできません。今回のECサイトでは、カート画面からしか呼び出されない関数のためこれでもいいのですが、将来的な機能追加を想定し、他の画面でも使いやすい関数にするためにループ処理は含めませんでした。関数のメリットの1つである「同じ処理を2度も3度も書く必要がなくなる」点を生かすために、将来も想定した「汎用性」の高い関数を記述するように心がけましょう。
プログラムのブラッシュアップ(トランザクションの理解)
次に、データベース処理をより安全に行うための「トランザクション管理」という概念に関して説明をします。今回の注文確定処理のデータベース処理を考えてみましょう。次のような手順になるはずです。
- まず、
d_purchase
に注文情報のサマリー(誰が、いつ、いくら買ったか)をINSERT
- 次に、買い物履歴詳細テーブルに、商品の個数分、購入した商品の決済時の金額を
INSERT
上記の手順では、SQLを何回実行することになるでしょうか? 仮に商品個数が4個あったとしたら、(1)のSQLを1回、(2)のSQLを4回、合計5回のSQLを発行することになります。順調に5回とも成功すれば問題はないのですが、もし、何らかの原因で、(2)のSQLの3回目で失敗したらどうなるでしょうか? 中途半端な決済情報がデータベースに残ってしまいます。
このような場合は『すべて成功、またはすべて失敗』となるようにすることで中途半端な状態のデータを許可しないようにします。この考え方を「トランザクション管理」と呼びます。トランザクション管理が必要なのは、主に新規登録、更新、削除など「更新系SQL」と呼ばれる処理で、SELECT
文のみの場合は特に必要ありません。トランザクションは次のSQLで管理します。
begin
:トランザクション開始commit
:begin
から成功したすべてのSQLをデータベースに反映するrollback
:begin
から実行したすべてのSQLを破棄し、データベースに反映しない
MDB2
ではそれぞれ$mdb2->beginTransaction()
、$mdb2->commit()
、$mdb2->rollback()
という命令があらかじめ用意されているので、今回はこれらの命令を用いてトランザクション管理を行います。
トランザクション開始から、commit
またはrollback
の期間を「トランザクション内」と呼び、MDB2
では$mdb2->inTransaction()
という命令とif
文を組み合わせることでトランザクション内か否かを判断できます。