「オンラインストア」完成へ向けて各ファイルを再構築今から始める MySQL入門(9)(2/4 ページ)

» 2007年07月31日 00時00分 公開
[鶴長鎮一@IT]

「簡易在庫管理システム」の修正

 「簡易在庫管理システム」では、すでにDAOパターンを適用しているため、修正される個所は限られます。

  1  <?php
  2  class ItemDao extends BaseDao{
  3
  4    //コンストラクタ
  5    function __construct(){
  6      parent::__construct();
  7    }
  8
  9    //デストラクタ
 10    function __destruct(){
 11      parent::__destruct();
 12    }
 13
 14    //全アイテムの取得
 15    public function getAllItem(){
 16      is_null($this->mysqli) and $this->connect();
 17      $result = $this->mysqli->query("SELECT * FROM item");
 18      $item_array = array();
 19
 20      while($row = $result->fetch_array(MYSQLI_ASSOC)){  
                                      //<--MYSQLI_NUMではなく
 21        $item = new Item();
 22        $item->setId($row["id"]);
 23        $item->setName($row["name"]);
 24        $item->setDetail($row["detail"]);
 25        $item->setPrice($row["price"]);
 26        $item->setQty($row["qty"]);
 27        $item_array[] = $item;      
 28      }
 29      $result->close();
 30      return $item_array;
 31    }
 32
 33    //指定されたアイテムの取得
 34    private function getItem($sql){
 35      is_null($this->mysqli) and $this->connect();
 36      $result = $this->mysqli->query($sql);
 37
 38      $item = null;
 39
 40      if($result->num_rows != 0){
 41        $row = $result->fetch_array(MYSQLI_ASSOC);
 42        $item = new Item();
 43        $item->setId($row["id"]);
 44        $item->setName($row["name"]);
 45        $item->setDetail($row["detail"]);
 46        $item->setPrice($row["price"]);
 47        $item->setQty($row["qty"]);
 48      }
 49      $result->close();
 50
 51      return $item;
 52    }
 53
 54    //idでアイテムを取得
 55    public function getItemById($id){
 56      $id = $this->mysqli->real_escape_string($id);
 57      $sql = "SELECT * FROM item WHERE id = '$id'";
 58      return $this->getItem($sql);
 59    }
 60
 61    //nameでアイテムを取得
 62    public function getItemByName($name){
 63      $name = $this->mysqli->real_escape_string($name);
 64      $sql = "SELECT * FROM item WHERE name = '$name'";
 65      return $this->getItem($sql);
 66    }
 67
 68    //アイテムの更新
 69    public function updateItem($item){
 70      $item = $this->escapeStringItem($item);
 71      is_null($this->mysqli) and $this->connect();
 72      $sql = "UPDATE item SET
 73                     name = '" . $item->getName() . "',
 74                     detail = '" . $item->getDetail() . "',
 75                     price = '" . $item->getPrice() . "',
 76                     qty ='" . $item->getQty() . "'
 77              WHERE id = '" . $item->getId() . "'";
 78      if( !$this->mysqli->query($sql)){
 79        return "更新に失敗しました(1001) " .
 $this->mysqli->error . "\n";
 80      }
 81      return "更新しました";
 82    }
 83
 84    //新規アイテムの登録
 85    public function insertItem($item){
 86      $item = $this->escapeStringItem($item);
 87      is_null($this->mysqli) and $this->connect();
 88      //idカラムに空を挿入することで,auto_incrementによる
 89      //カウントアップ値
を代入できる
 90      $sql = "INSERT INTO item values ('',
 91                           '" . $item->getName() . "',
 92                           '" . $item->getDetail() . "',
 93                           '" . $item->getPrice() . "',
 94                           '" . $item->getQty() . "')";
 95      if( !$this->mysqli->query($sql)){
 96        return "登録に失敗しました(1002) " . $this->mysqli
->error . "\n";
 97      }
 98      return "一件追加しました";
 99    }
100
101    //指定されたアイテムの削除
102    public function deleteItem($item){
103      return $this->deleteItemById($item->getId());
104    }
105
106    //idで指定されたアイテムの削除
107    public function deleteItemById($id){
108      $id = $this->mysqli->real_escape_string($id);
109      is_null($this->mysqli) and $this->connect();
110
111      $sql = "DELETE FROM item WHERE id = '" . $id . "'";
112      if( !$this->mysqli->query($sql)){
113         $error_no = $this->mysqli->errno;
114         if( $error_no == 1451){
115           return "注文を1度でも受けた商品は在庫一覧から
削除できません<br>(外部キー制約エラー)";
116         }else{
117           return "削除に失敗しました(1003) " . $this->mysqli
->error . "\n";
118         }
119      }
120      return "削除しました";
121    }
122
123    //Itemクラスの各プロパティから特殊文字をエスケープ
124    private function escapeStringItem($item){ 
125      $item->setId($this->mysqli->real_escape_string($item
->getId()));
126      $item->setName($this->mysqli->real_escape_string($it
em->getName()));
127      $item->setDetail($this->mysqli->real_escape_string($
item->getDetail()));
128      $item->setPrice($this->mysqli->real_escape_string($i
tem->getPrice()));
129      $item->setQty($this->mysqli->real_escape_string($ite
m->getQty()));
130      return $item;
131    }
132  }
133  ?>
      リスト3 ItemDao.php

 まずItemDao.phpを、基底クラスBaseDao.phpを継承するようにします(2行目)。BaseDao.phpを継承することでMySQL接続(connect())/切断手順(disconnect())はBaseDao.phpのものが使用できるようになります。コンストラクタ(__construct)/デストラクタ(__destruct)は、先ほどの説明のようにサブクラスに継承されないため、意図的に親クラスのものを呼び出すよう修正します(4〜12行目)。

 次に、前回採用したデータベースの外部キー制約設定に伴う修正を行います。外部キー制約エラーが発生した場合とそれ以外の場合とを区別し、画面にメッセージを表示するようにします。

 updateItem()/insertItem()/deleteItem()/deleteItemById()の各メソッドでは、終了結果やエラー内容をreturn文を使って戻すようにします。deleteItemById()ではエラーの際にMySQLサーバから出力されるエラーコードを受け取り(114行目)、1451番(注)であれば外部キー制約エラーの旨を返すようにします(115行目)。

 なおsample5では、RDBMSに依存する操作をDAOに集約するため、SQLクエリ中の特殊文字のエスケープは、「mysqli->real_escape_string()」を使ってDAO内で行うよう修正しています(56、63、108、125〜129行目)。

注:第8回の「外部キー制約の利用」中の「DELETE FROM item WHERE id = '3';」実行の際のエラーを参照。


 1  <HTML lang="ja">
 2  <HEAD>
 3  <meta http-equiv="content-type" content="text/html; char
set=UTF-8">
 4  <title>在庫管理:在庫一覧</title>
 5  </HEAD>
 6
 7  <?php  8  require_once("Item.php");
 9  require_once("BaseDao.php");
10  require_once("ItemDao.php");
11
12  $item = new Item();
13  $item_dao = new ItemDao();
14  ?>
15
16  <BODY TEXT="black" BGCOLOR="white">
17  <!-- タイトル -->
18  <div align="center"><font size="5"><b>在庫管理 </b></fo
nt><font size="3">在庫一覧</b><br></font>
19  </div>
20  <hr width="600" align="center">
21
22  <?php
23  //アイテム一覧
24  foreach($item_dao->getAllItem() as $item){
25
26    $id = $item->getId();
27    $name = $item->getName();
28    $detail = $item->getDetail();
29    $price = $item->getPrice();
30    $qty = $item->getQty();
31    //各アイテムの表示ここから
32  ?>
33
34  <!-- 更新(UPDATE)、削除(DELETE) -->
35  <form action="updateStock.php" method="POST" enctype="ap
plication/x-www-form-urlencoded" name="form">
36  <table border="0" cellspacing="0" cellpadding="7" height
="160" align="center">
37  <tr>
38  <td valign="top" bgcolor="lightgreen">
39  <b>商品ID:<?php print htmlspecialchars($id,ENT_QUOTES);
 ?></b>
40  <input type=hidden name="id" value="<?php print htmlspeci
alchars($id,ENT_QUOTES); ?>"><br>
41  <b>商品名:</b><input type=text name="name" size="48" val
ue="<?php pri
nt htmlspecialchars($name,ENT_QUOTES); ?>"><br>
42  <b>説明 :</b><br>
43  <textarea name="detail" cols="45" rows="4"><?php print ht
mlspecialchars($detail,ENT_QUOTES); ?></textarea><br>
44  <b>価格:</b><input type=text name="price" value="<?php p
rint htmlsp
ecialchars($price,ENT_QUOTES); ?>" size="5"><b>円/個</b>  
45  <b>個数:</b><input type=text name="qty" value="<?php pri
nt htmlspecialchars($qt,ENT_QUOTESy); ?>" size="5"><b>個</b>
46  </td>
47  <td bgcolor="gray" align="center" width="70">
48  <input type="submit" value="UPDATE" name="button"><p>
49  <!-- 本当はこうしたいがIEのためできない <button type="sub
mit" value="UPD name="button">更新</button><p>-->
50  <input type="submit" value="DELETE" name="button"><p>
51  <input type="reset" value="RESET">
52  </td></tr>
53  </table>
54  </form>
55
56  <?
57    //各アイテムの表示ここまで
58  }
59  $item_dao = null;
60  ?>
... 以下省略 ...
      リスト4 displayStock.php

 displayStock.phpではBaseDao.phpを読み込むよう、記述を1行加えます(9行目)。HTML出力を行う際はhtmlspecialchars()を使用し、特殊文字のエスケープを行います。SQLクエリに対する特殊文字の処理は、各DAOクラスで行うようにします。

 続いて、updateStock.phpにも修正を加えます。

 1  <?php
 2
 3  require_once("Item.php");
 4  require_once("BaseDao.php");
 5  require_once("ItemDao.php");
 6
 7  $item = new Item();
 8  $item_dao = new ItemDao();
 9
10  //フォーム値の取得
11  $item->setId($_POST["id"]);
12  $item->setName($_POST["name"]);
13  $item->setDetail($_POST["detail"]);
14  $item->setPrice($_POST["price"]);
15  $item->setQty($_POST["qty"]);
16
17  switch($_POST["button"]){          //ボタンのラベルで条件分岐
18    case "UPDATE":                   //更新処理    
19      display($item_dao->updateItem($item));
20      break;
21   case "INSERT":                    //挿入処理
22      display($item_dao->insertItem($item));
23      break;
24   case "DELETE":                    //削除処理
25      display($item_dao->deleteItem($item));
26      break;
27   default:                          //それ以外
28      display("指定された処理が不正です");
29      break;
30  }
31
32  //引き渡されたメッセージをHTMLで表示
33  function display($message){
34    print <<<EOS
35  <HTML lang="ja">
36  <HEAD>
37  <meta http-equiv="content-type" content="text/html; char
set=UTF-8">
38  <title>在庫管理:データ更新</title>
39  </HEAD>
40
41  <BODY TEXT="black" BGCOLOR="white">
42  <!-- タイトル -->
43  <div align="center"><font size="5"><b>在庫管理 </b></font><font size="3">データ更新</b><br></font>
44  </div>
45  <hr width="600" align="center">
46
47  <!-- メッセージ -->
48  <p>
49  <div align="center"><font size=+2>$message</font><p>
50  <a href=displayStock.php><font size=+1>在庫一覧へ戻る</fo
nt></a>
51  </div><p>
52  
53  <!-- フッター -->
54  <hr width="600" align="center">
55  <table width="600" border="0" align="center">
56  <tr>
57  <td align="right"><font size="2">@IT LinuxSquare「今から
始める MySQL入門」<br>
58  2007/06/25作成</font></td>
59  </tr>
60  </table>
61
62  </BODY>
63  </HTML>
64  EOS;
65  }
66
67  ?>
      リスト5 updateStock.php

 まず4行目のようにBaseDao.phpを読み込みます。ボタンラベルで条件分岐をさせる17行目以降で、単にItemDaoクラスのメソッドを呼び出すだけではなく、メッセージを受け取り、そのメッセージを後半で定義しているdisplay()関数の引数として渡すようにします。

 その際、HTML出力を行うときにはhtmlspecialchars()を使用し、特殊文字のエスケープを行います。SQLクエリに対する特殊文字の処理は、ItemDaoクラスで行うようにします。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。