ToDoアイテムの状態(完了したかどうか)を更新する処理は、updateitem.phpファイルにまとめた。実際のコードは以下の通りだ。
<?php
require "util.php";
if (isset($_GET["id"]) && isset($_GET["val"])) {
$id = (int) $_GET["id"];
$val = (bool) $_GET["val"];
try {
$pdo = openDB();
$tsql = "UPDATE todoitems SET done = :val WHERE id = :id";
$stmt = $pdo->prepare($tsql);
$stmt->execute([":id" => $id, ":val" => $val]);
} catch (Exception $e) {
header("Content-Type: text/plain; charset=UTF-8", true, 500);
exit();
} finally {
$stmt = null;
$pdo = null;
}
}
$host = $_SERVER["HTTP_HOST"];
$uri = rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
$extra = "index.php";
header("Location: http://$host$uri/$extra");
exit();
前回に見た新規アイテムを追加するコードと基本構造は同等で、冒頭でデータベース接続を取得し、必要な処理を行った後に、header関数でindex.phpファイルに遷移するようになっている。また、前ページで見たように、コード冒頭ではrequireによりutil.phpファイルを読み込んで、そこで定義されているopenDB関数を呼び出している。
行っていることもSQL文の内容が列の挿入から、列の更新に変わっただけだ。ただし、前回は「PDOオブジェクトのprepareメソッドによるプリペアドステートメント(PDOStatementオブジェクト)の作成」→「PDOStatementオブジェクトのbindValueメソッドによるパラメーターマークとパラメーター値のバインド」→「PDOStatementオブジェクトのexecuteメソッドによるプリペアドステートメントの実行」という流れで処理を行っていたが、今回はパラメーターマークとパラメーター値のバインド、プリペアドステートメントの実行をexecuteメソッドだけで行っている点が異なる。
<?php
// …… 省略 ……
if (isset($_GET["id"]) && isset($_GET["val"])) {
// …… 省略 ……
try {
$pdo = openDB();
$tsql = "UPDATE todoitems SET done = :val WHERE id = :id";
$stmt = $pdo->prepare($tsql);
$stmt->execute([":id" => $id, ":val" => $val]);
} catch (Exception $e) {
// …… 省略 ……
} finally {
// …… 省略 ……
}
}
// …… 省略 ……
SQLStatementオブジェクトのexecuteメソッドには連想配列の形で入力パラメーター値を渡すことができ、今回はそちらの方法を使ってみた。ただし、bindValueメソッドでは、「PDO::PARAM_STR」などの定数を使って、各パラメーター値の型を指定できるが、executeメソッドではパラメーター値は全てPDO::PARAM_STR型として扱われることには注意が必要だ。厳密に型指定を行いたいのであれば、bindValueメソッドやbindParamメソッドを使用するようにしよう。
もう1つ注意したいのは、コード先頭のif文の内容だ。
<?php
// …… 省略 ……
if (isset($_GET["id"]) && isset($_GET["val"])) {
$id = (int) $_GET["id"];
$val = (bool) $_GET["val"];
// …… 省略 ……
}
// …… 省略 ……
[DONE]リンクまたは[UNDONE]リンクをクリックすると「updateitem.php?id=……&val=……」というURLがリクエストされる。PHPでは、GETメソッドでリクエストされたPHPファイルのURLパラメーターは「$_GET」という名前の連想配列に保存される。リンクを素直にクリックしてくれれば、これらの値が$_GET連想配列に含まれているはずだが、このファイルをアドレスバーから直接呼び出すことも可能なため、ここではisset関数を使って、$_GET連想配列にこれら2つのキーが存在し、それらがNULLでないことを確認している。その後、実際の値を取り出して、UPDATE文でデータを更新するようにしている。isset関数を使わずにそのまま「if ($_GET["id"]) && $_GET["val"]) {」のように書くと、コードの実行上は問題ないように見えるが、実際には例外が発生することもあるので注意しよう。
なお、index.phpファイルで既に見たように、未完了のToDoアイテムに表示される[DONE]リンクではvalパラメーターの値が1に、完了したToDoアイテムに表示される[UNDONE]リンクではvalパラメーターの値が0に指定されている。updateitem.phpファイルではこれらの値をtrue/falseと見なして、列の更新を行っている。
列の削除は[DELETE]リンクのクリック時にdeleteitem.phpファイルで行われる。このリンクにはURLパラメーターとして、削除対象のToDoアイテムのidが含まれている。そのため、そのidを指定して、DELETE文を実行するだけだ。
<?php
require "util.php";
if (isset($_GET["id"])) {
$id = (int) $_GET["id"];
try {
$pdo = openDB();
$tsql = "DELETE todoitems WHERE id = :id";
$stmt = $pdo->prepare($tsql);
$stmt->execute([":id" => $id]);
} catch (Exception $e) {
header("Content-Type: text/plain; charset=UTF-8", true, 500);
exit();
} finally {
$stmt = null;
$pdo = null;
}
}
$host = $_SERVER["HTTP_HOST"];
$uri = rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
$extra = "index.php";
header("Location: http://$host$uri/$extra");
exit();
ファイルの基本構造はupdateitem.phpと同様であり、実行するSQL文が異なるだけなので、詳細な解説は不要だろう。
最後に残ったadditem.phpファイルは、util.phpファイルを使用すること以外は前回と同様だ。
<?php
require "util.php";
if (isset($_POST["submit"])) {
try {
$pdo = openDB();
$tsql = "INSERT INTO todoitems (item, done) VALUES (?, 0)";
$stmt = $pdo->prepare($tsql);
$item = $_POST["item"];
$stmt->bindValue(1, $item, PDO::PARAM_STR);
$stmt->execute();
} catch (Exception $e) {
header("Content-Type: text/plain; charset=UTF-8", true, 500);
exit();
} finally {
$stmt = null;
$pdo = null;
}
}
$host = $_SERVER["HTTP_HOST"];
$uri = rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
$extra = "index.php";
header("Location: http://$host$uri/$extra");
exit();
これについては説明は不要だろう。詳細は前回の記事を参照されたい。
最後に、アプリが実際に動作しているところを以下に示す。前回同様、これはVS CodeのPHP Server拡張機能を使ってVS Codeでローカルにホストしているところだ。
今回はToDoアイテムの状態を変更したり、アイテムを削除したりするコードについて見ながら、PHPコードを記述する際の注意点を幾つか紹介した。次回はこのアプリをIISへ展開し、落ち穂拾い的に幾つかのトピックを紹介する予定だ。
Copyright© Digital Advantage Corp. All Rights Reserved.