引き続きCRUD処理の開発を進めていきましょう。次はカテゴリー削除処理を実装します。

ここでは以下の手順にしたがってプログラムを作成します。

  1. カテゴリー詳細画面の修正 - show.php
  2. カテゴリー削除処理の実装 - destroy.php

1. カテゴリー詳細画面の修正 - show.php

show.php ファイルのHTMLコードに削除処理用の入力フォームを追加します。

...省略
<body>
  <h3>Categories - Show</h3>
  <hr>
  ID: <?= htmlspecialchars($category["id"]) ?><br>
  TITLE: <?= htmlspecialchars($category["title"]) ?><br>
  <a href="edit.php?id=<?= htmlspecialchars($category['id']) ?>">EDIT</a> 
  <form action="destroy.php" method="post">
    <input type="hidden" name="id" value="<?= htmlspecialchars($category['id']) ?>">
    <button type="submit">DESTROY</button>
  </form>
  <hr>
  <a href="index.php">BACK</a>
</body>
</html>

ここでは form タグによって DESTROY ボタンを追加しています。また input タグの type 属性に hidden を指定して、カテゴリーIDを隠し項目として定義しています。DESTROY とは削除する(破棄する)という意味です。DESTROY ボタンをクリックすると次に作成する destroy.php プログラムに対してカテゴリーIDを送信します。

2. カテゴリー削除処理の実装 - destroy.php

続いてカテゴリー削除処理である destroy.php ファイルを作成します。

<?php
$id = (string)filter_input(INPUT_POST, "id");
if ($id === "") {
    error_log("Validate: id is required.");
    header("Location: error.php");
    exit();
}
if (filter_var($id, FILTER_VALIDATE_INT) === false) {
    error_log("Validate: id is not int.");
    header("Location: error.php");
    exit();
}

try {
    $dsn = "mysql:host=localhost;dbname=eldb;charset=utf8mb4";
    $username = "root";
    $password = "admin";
    $options = [
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_EMULATE_PREPARES => false
    ];
    $pdo = new PDO($dsn, $username, $password);

    $sql = "delete from categories where id = :id";
    $ps = $pdo->prepare($sql);
    $ps->bindValue(":id", $id, PDO::PARAM_INT);
    $ps->execute();

    header("Location: index.php");
} catch (PDOException $e) {
    error_log("PDOException: " . $e->getMessage());
    header("Location: error.php");
}

このプログラムも先頭部分で入力チェック、後半の try - catch 文でデータベースとのやりとりを実装しています。

先頭部分で以下の仕様に従って入力チェックを実装しています。

項目名 パラメータ名 入力チェック
カテゴリーID id 必須、整数型
<?php
$id = (string)filter_input(INPUT_POST, "id");
if ($id === "") {
    error_log("Validate: id is required.");
    header("Location: error.php");
    exit();
}
if (filter_var($id, FILTER_VALIDATE_INT) === false) {
    error_log("Validate: id is not int.");
    header("Location: error.php");
    exit();
}

隠し項目として送信されたカテゴリーIDについて入力チェックを実装しています。

次にデータベースへの接続部分を見ていきましょう。

try {
    $dsn = "mysql:host=localhost;dbname=eldb;charset=utf8mb4";
    $username = "root";
    $password = "admin";
    $options = [
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_EMULATE_PREPARES => false
    ];
    $pdo = new PDO($dsn, $username, $password);

    $sql = "delete from categories where id = :id";
    $ps = $pdo->prepare($sql);
    $ps->bindValue(":id", $id, PDO::PARAM_INT);
    $ps->execute();

    header("Location: index.php");
} catch (PDOException $e) {
    error_log("PDOException: " . $e->getMessage());
    header("Location: error.php");
}

こちらもこれまでに作成してきたコードとよく似ています。先頭部分ではPDOインスタンスを生成してMySQLデータベースに接続しています。それからプリペアドステートメント を定義して、リクエストパラメータをプレースホルダにバインドし、delete 文を実行しています。今回は既存レコードの削除処理を行うので delete 文を実行します。

delete 文の実行が終わったら、header 関数を使って index.php にリダイレクトするように実装しています。

データベースとのやりとりで例外が発生した場合は catch ブロックの処理が実行されます。ここでは error_log 関数を使ってエラーログを出力して、エラー画面にリダイレクトするように実装しています。

動作確認

それではビルトインWebサーバを起動して、ブラウザから実行結果を確認してみましょう。

コマンドラインからビルトインWebサーバを起動します。

$ php -S localhost:8080

ブラウザから以下のURLにアクセスします。

https://〜.vfs.cloud9.ap-northeast-1.amazonaws.com/categories/index.php

上記のようにカテゴリー一覧画面が表示されることを確認します。表示されたテーブルの中から任意のレコードの SHOW リンクをクリックします。

上記のようにカテゴリー詳細画面に選択したレコードが表示されていることを確認できるでしょう。また新たに追加した DESTROY ボタンも表示されているのがわかります。

表示されている DESTROY ボタンをクリックしてみましょう。

上記のようにカテゴリー一覧画面が表示されます。カテゴリーレコードが削除されていることを確認できるでしょう。

ターミナルからMySQLに接続して categories テーブルのレコードを確認すると、レコードが削除されていることを確認できます。