引き続きCRUD処理の開発を進めていきましょう。次はカテゴリー更新処理を実装します。
ここでは以下の手順にしたがってプログラムを作成します。
- カテゴリー詳細画面の修正 -
show.php
- カテゴリー更新画面の作成 -
edit.php
- カテゴリー更新処理の実装 -
update.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>
<hr>
<a href="index.php">BACK</a>
</body>
</html>
ここでは a
タグによって EDIT
リンクを追加しています。リンク先URLにはクエリパラメータ( id
)を指定しています。クエリパラメータ ?id=
の値部分にカテゴリーIDを指定しています。
2. カテゴリー更新画面の作成 - edit.php
続いてカテゴリー更新画面を表示する edit.php
ファイルを作成します。
<?php
$id = (string)filter_input(INPUT_GET, "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 = "select id, title from categories where id = :id";
$ps = $pdo->prepare($sql);
$ps->bindValue(":id", $id, PDO::PARAM_INT);
$ps->execute();
$category = $ps->fetch();
if ($category === false) {
error_log("Invalid id. $id");
header("Location: error.php");
exit();
}
} catch (PDOException $e) {
error_log("PDOException: " . $e->getMessage());
header("Location: error.php");
exit();
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>PHP DB</title>
</head>
<body>
<h3>Categories - Edit</h3>
<hr>
<form action="update.php" method="post">
<input type="hidden" name="id" value="<?= htmlspecialchars($category['id']) ?>">
ID: <?= htmlspecialchars($category['id']) ?><br>
TITLE: <input type="text" name="title" value="<?= htmlspecialchars($category['title']) ?>"><br>
<button type="submit">UPDATE</button>
</form>
<hr>
<a href="index.php">BACK</a>
</body>
</html>
少し長いコードになりますが、落ち着いて見ると以前に作成したカテゴリー詳細画面である show.php
とよく似ていることに気づくでしょう。プログラムの先頭部分からデータベースに接続して select
文を実行するまでの一連の処理は同じです。
カテゴリー詳細画面と異なるのは、HTMLコードの出力部分です。カテゴリー更新画面である edit.php
ファイルは form
タグを使って入力フォームを定義しています。
<form action="update.php" method="post">
<input type="hidden" name="id" value="<?= htmlspecialchars($category['id']) ?>">
ID: <?= htmlspecialchars($category['id']) ?><br>
TITLE: <input type="text" name="title" value="<?= htmlspecialchars($category['title']) ?>"><br>
<button type="submit">UPDATE</button>
</form>
この入力フォームは、カテゴリー作成画面と同様に ID
と TITLE
の2つの項目を表示します。ただしIDはテキストボックスではありません。またタイトルはテキストボックスで表示しますが value
属性を指定することでテキストボックスに初期値を表示しています。
入力フォームの中にはもうひとつ input
タグがあります。
<input type="hidden" name="id" value="<?= htmlspecialchars($category['id']) ?>">
上記の input
タグは type
属性の値が hidden
となっています。input
タグは type
属性に hidden
を指定すると隠し項目として機能します。つまり、画面上には表示されない項目になりますが、リクエストパラメータとしては値を送信する、という具合です。
このプログラムではID項目はテキストボックスではない、という点に注意してください。ID項目はユーザの入力を許可しないので、TITLE項目のようにリクエストパラメータとしてサーバに送信されません。それでは後のPHPプログラムで困るので、隠し項目(<input type="hidden>
)を定義してリクエストパラメータに ID項目を含むように実装しています。
3. カテゴリー更新処理の実装 - update.php
さいごにカテゴリー更新画面から送信されるリクエストを処理する update.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();
}
$title = (string)filter_input(INPUT_POST, "title");
if ($title === "") {
error_log("Validate: title is required.");
header("Location: error.php");
exit();
}
if (mb_strlen($title) > 255) {
error_log("Validate: title length > 255");
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 = "update categories set title = :title where id = :id";
$ps = $pdo->prepare($sql);
$ps->bindValue(":title", $title, PDO::PARAM_STR);
$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");
}
プログラムが少し長くなりましたが、これまでに作成してきたプログラムとよく似ているのがわかります。
このプログラムでは先頭部分で以下の仕様に従って入力チェックを実装しています。
項目名 | パラメータ名 | 入力チェック |
---|---|---|
カテゴリーID | id | 必須、整数型 |
タイトル | title | 必須、最大255文字まで |
<?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();
}
$title = (string)filter_input(INPUT_POST, "title");
if ($title === "") {
error_log("Validate: title is required.");
header("Location: error.php");
exit();
}
if (mb_strlen($title) > 255) {
error_log("Validate: title length > 255");
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 = "update categories set title = :title where id = :id";
$ps = $pdo->prepare($sql);
$ps->bindValue(":title", $title, PDO::PARAM_STR);
$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データベースに接続しています。それからプリペアドステートメント を定義して、リクエストパラメータをプレースホルダにバインドし、update
文を実行しています。今回は既存レコードの更新処理を行うので update
文を実行します。
update
文の実行が終わったら、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
リンクをクリックします。
上記のようにカテゴリー詳細画面に選択したレコードが表示されていることを確認できるでしょう。また新たに追加した EDIT
リンクも表示されているのがわかります。EDIT
リンクをクリックするとカテゴリー更新画面が表示されます。
表示された画面でそれからTITLEを更新してみましょう。
それから UPDATE
ボタンをクリックします。
上記のようにカテゴリー一覧画面にリダイレクトされると、更新したカテゴリーレコードを確認できるでしょう。
ターミナルからMySQLに接続して
categories
テーブルのレコードを確認すると、以前のレコードが更新されていることを確認できます。