こんにちは、かじです。
前回はJavaScriptでToDoリストを作成し、DOMをJavaScriptから操作することを学びました。
ただ、JavaScriptでToDoリストを作成すると、フロントエンドでの実装のみであるため、ToDoの作成やToDoの完了などはできましたが、データの保存ができませんでした。
今回はサーバーサイド言語を使用してToDoリストを作成し、データベースとの連携をすることでデータの保存をできるようにすることを目標とします。
1.対象者
基本的なHTML、CSS、PHPの文法の学習が完了している方
2.目的
ToDoリストの作成によってサーバーサイド言語の役割やデータベースの連携を理解する
3.仕様
・入力欄にToDo項目を入力後追加ボタンをクリックすると、ToDoリストに追加される
・追加されたToDo項目には作成日時と完了ボタンが付帯する
・ToDo項目追加後には、入力欄の値はリセットされる
・完了ボタンをクリックすると、完了済みにToDo項目が移動する
・完了済みに追加された項目には完了ボタンが非表示になり、完了日時が追記される
4.留意点
サーバーサイド言語でのアプリケーションの作成への理解することを目標にしていますので、ざっくりと作成します。
また、今回はMAMPやXAMPPといった環境での作成を前提にチュートリアルを進めていますのでご了承ください。
MAMPの環境構築は下記を参照ください。
5.準備
5-1.データベースの準備
まずはデータベースの準備をします。
MAMPやXAMPPを起動し、phpMyAdmin上で下記SQLを実行してください。
CREATE DATABASE IF NOT EXISTS PHPToDo DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE PHPToDo;
CREATE TABLE todoItem (
id int(11) NOT NULL,
content varchar(255) NOT NULL,
completeFlg tinyint(1) NOT NULL DEFAULT '0',
createdAt datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
completedAt datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE todoItem
ADD PRIMARY KEY (id);
ALTER TABLE todoItem
MODIFY id int(11) NOT NULL AUTO_INCREMENT;
5-2.プロジェクトファイルの作成
MAMPの場合はMAMP直下のhtdocsフォルダに新規フォルダを作成し、XAMPPを使用している場合は、XAMPP直下のhtdocsをに新規フォルダを作成してください。
フォルダ名は「PHPToDo」としておきます。
6.ホーム画面の作成
まずは、ホーム画面です。
先ほど作成した、プロジェクトフォルダにindex.phpを作成し、下記を記述します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css"> // ①
</head>
<body>
<header>
<h1>ToDo List</h1>
</header>
<main>
<div>
// ②
<form action="add.php" method="POST">
<input type="text" name="todoItem">
<input type="submit" value="追加">
</form>
</div>
<div>
<div>
<h2>ToDoリスト</h2>
<table border="1">
<thead>
<tr>
<td class="itemName">タスク名</td>
<td class="itemCreatedAt">作成日時</td>
<td class="itemComplete"></td>
</tr>
</thead>
<tbody>
// ③
</tbody>
</table>
</div>
<div>
<h2>完了済み</h2>
<table border="1">
<thead>
<tr>
<td class="itemName">タスク名</td>
<td class="itemCreatedAt">作成日時</td>
<td class="itemComplete">完了日時</td>
</tr>
</thead>
<tbody>
// ④
</tbody>
</table>
</div>
</div>
</main>
</body>
</html>
①は今回使用するCSSになります。
index.phpと同じフォルダにstyle.cssを作成して、下記のコードを記載します。
table{
border-collapse: collapse;
}
.itemName{
width: 300px;
}
.itemCreatedAt, .itemComplete{
width: 200px;
}
そうしましたら、一旦MAMPを起動して、「localhost:8888/PHPToDo/index.php」とアドレスバーに入力して、アクセスしてみましょう。
下記のような画面が表示されていれば成功です。
MAMPで準備されているApacheがリクエストを処理して、該当のプログラムファイル(この場合PHPToDoフォルダ内のindex.php)へアクセスし、そのファイルのプログラムを実行して、レスポンスを返してwebブラウザにHTMLを表示しています。
②はformタグといいます。formタグで囲まれたinputタグなどのデータをサーバーにリクエストした際に通信します。
通信はformタグ内にあるsubmitタイプのinputタグやbuttonタグをクリックすると実行されます。
リクエストする先のプログラムは、action=””内に記載し、method=””内にどのリクエストメソッドを使用するかを記載します。
リクエストメソッドは全部で9種類ほどありますが、頻度高く使用するのはGETメソッドとPOSTメソッドになります。
詳しい説明は省きますが、データの取得はGETメソッド、データを送信するのはPOSTメソッドと覚えておいてもらえるといいかなと思います。
ここでは、ToDoの項目を送信するのでPOSTメソッドを指定しておきます。
③、④にはToDo項目や完了した項目をこの後追加しますが、現段階では表示すべきデータがないので、何もしないでおきます。
ここまで理解できましたら、続いて、②でPOSTした際のプログラムを記載していきたいと思います。
7.ToDo登録処理の作成
index.phpと同じフォルダにadd.phpを作成してください。
<?php
// ①
$todoItem = $_POST['todoItem'];
if($todoItem === ""){
header('Location: http://localhost:8888/PHPToDo/index.php');
exit;
}
// ②-1
$dsn = 'mysql:host=localhost;dbname=PHPToDo;charset=utf8';
$username = 'root';
$pass = 'root';
// ③-1
try{
// ②-2
$dbh = new \PDO($dsn, $username, $pass,[
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
]);
// ④-1
$dbh->beginTransaction();
// ⑤
$sql = "INSERT INTO todoItem(content) VALUES(:content)";
$stmt = $dbh->prepare($sql);
$stmt->bindValue(':content', $todoItem, PDO::PARAM_STR);
$stmt->execute();
// ④-2
$res = $dbh->commit();
}
// ③-2
catch(PDOException $e){
echo 'FALSE!'.$e->getMessage();
echo '<a href="http://localhost:8888/PHPToDo/index.php">前画面へ戻る</a>';
// ④-3
$dbh->rollback();
exit();
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php if($res): ?>
<p>登録しました。</p>
<a href="http://localhost:8888/PHPToDo/index.php">前画面へ戻る</a>
<?php endif; ?>
</body>
</html>
まず、POSTされた際にプログラムに渡されたデータを取り出しましょう。
①では、$_POST[‘todoItem’]の中にPOSTされたデータが含まれています。$_POSTの中に配列として、POSTされた情報が格納されており、配列のキーはPOSTされたinputタグのnameとなっております。この場合は、<input type=”text” name=”todoItem”>でPOSTされているため、$_POST[‘todoItem’]に情報が格納されています。
次のif文では、もし何も入力されていない場合はindex.phpに遷移するようにしております。
②では、データベースへの接続をしています。
$dsnには、データベースがホストされている場所(この場合はローカル環境)、データベース名、文字コードを指定しています。
$usernameにはデータベースに接続する際のユーザー名、$passにはユーザー名のパスワードになります。
②-2で$dsn、$username、$passを渡してPDOオブジェクトを生成していますが、これによって、データベースへ接続を行います。
③は例外処理と言います。try{}で囲まれた処理の中でエラー(例外)が起きた場合、そこで処理を止めて、catch()内の処理が実行されます。
この場合は、データベース名が異なる、ユーザー名やパスワードが誤っているなどデータベースでのエラーを想定していますので、エラーメッセージである、PDOException $eをcatchの引数として、エラーメッセージを例外処理で表示するようにしています。
④ではデータベースへのトランザクションを開始しています。トランザクションというのは、日本語にすると手続きという意味がありますが、データベースへの一連のやり取りを開始することを指しています。
上記のソースコードでは一つのSQLの発行しかしませんが、何個ものSQLを発行していて、途中でエラーが起きると整合性を保つことが難しくなってしまいます。
そのため、すべてのデータベースのやり取りが完了したら、④-2のcommit()で手続きの内容をデータベースへ反映させ、もし途中でエラーが起きている場合は、④-3のrollback()でトランザクションが始まる前までデータベースの内容を戻します。
⑤ではSQL文の発行と実行を行います。
ここまで実装ができましたら、index.phpからToDoを追加してみましょう。
下記の画面になることと、phpMyAdminでデータが追加されていることが確認できたらこのプログラムは成功です。
8.登録したToDoをホーム画面へ反映する
続いて登録したToDoをホーム画面に表示しましょう。
<?php
// ①追加
$dsn = 'mysql:host=localhost;dbname=PHPToDo;charset=utf8';
$username = 'root';
$pass = 'root';
try{
$dbh = new \PDO($dsn, $username, $pass,[
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
]);
$sql = "select * from todoItem" ;
$stmt = $dbh->query($sql);
$results = $stmt->fetchAll();
$dbh = null;
$results;
}
catch(PDOException $e){
echo 'FALSE!'.$e->getMessage();
exit();
}
// ①追加ここまで
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>ToDo List</h1>
</header>
<main>
<div>
<form action="add.php" method="POST">
<input type="text" name="todoItem">
<input type="submit" value="追加">
</form>
</div>
<div>
<div>
<h2>ToDoリスト</h2>
<table border="1">
<thead>
<tr>
<td class="itemName">タスク名</td>
<td class="itemCreatedAt">作成日時</td>
<td class="itemComplete"></td>
</tr>
</thead>
<tbody>
<!-- ②追加ここから -->
<?php foreach($results as $result): ?>
<?php if($result['completeFlg'] == 0): ?>
<form action="complete.php" method="POST">
<tr>
<td><?php echo $result['content']; ?></td>
<td><?php echo $result['createdAt']; ?></td>
<td><input type="submit" value="完了"></td>
<input type="hidden" name="completeItem" value="<?php echo $result['id']; ?>">
</tr>
</form>
<?php endif; ?>
<?php endforeach; ?>
<!-- ②追加ここまで -->
</tbody>
</table>
</div>
<div>
<h2>完了済み</h2>
<table border="1">
<thead>
<tr>
<td class="itemName">タスク名</td>
<td class="itemCreatedAt">作成日時</td>
<td class="itemComplete">完了日時</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</main>
</body>
</html>
①の追加分についてですが、データベースの接続や例外処理については8の登録処理で行ったものと同様になります。
実行するSQLについてはデータベースからToDo全件取得する命令にして、変数$resultに格納します。
②では、$resultに格納されたToDoをforeach文で表示するようにします。ただ、完了しているものをToDoに表示はさせたくないので、完了しているかどうかを表す$result[‘completeFlg’]が0の時にテーブルの行を表示させるようにif分岐にさせておきます。
completeFlgはToDoを登録する際に挿入していないよと思う方もいるかもしれませんが、データベースを作成する際に、デフォルト状態で0を挿入するように5-1.データベースの準備で実行したSQLで設定してあります。
また、完了させる時にPOSTさせたいので、テーブルの1行をformで囲みます。完了ボタンを押した際にcomplete.phpにPOSTするようにします。
ただ、この場合ですとどのToDoを完了にするかが明確になっていないため、画面上には非表示になるinputタグである、<input type=”hidden” name=”completeItem” value=”<?php echo $result[‘id’]; ?>”>を用意しておきます。
こちらのidはToDoが追加された際に採番されるIDになります。このIDでどのToDoを完了にするかをデータベース上で指定することができます。
ホーム画面に登録されたToDoを表示する処理はここまでになります。
下記のように表示されていたらここまでは完了です。
9.完了状態にする
続いて完了ボタンをクリックした際に、該当のToDoを完了状態にします。
この時、完了日時をToDoのデータに追加することと完了状態を示すcompleteFlgを1に更新することでデータベース上で表現します。
complete.phpをindex.phpと同じフォルダに作成し、下記のプログラムを記載します。
<?php
$completeItem = $_POST['completeItem'];
$dsn = 'mysql:host=localhost;dbname=PHPToDo;charset=utf8';
$username = 'root';
$pass = 'root';
try{
$dbh = new \PDO($dsn, $username, $pass,[
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
]);
$dbh->beginTransaction();
$sql = "UPDATE todoItem SET completeFlg=1 WHERE id=(:id)";
$stmt = $dbh->prepare($sql);
date_default_timezone_set('Asia/Tokyo');
$stmt->bindValue(':completedAt', date("Y/m/d H:i:s"), PDO::PARAM_STR);
$stmt->bindValue(':id', $completeItem, PDO::PARAM_INT);
$stmt->execute();
$res = $dbh->commit();
}
catch(PDOException $e){
echo 'FALSE!'.$e->getMessage();
echo '<a href="http://localhost:8888/PHPToDo/index.php">前画面へ戻る</a>';
$dbh->rollback();
exit();
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php if($res): ?>
<p>完了しました。</p>
<a href="http://localhost:8888/PHPToDo/index.php">前画面へ戻る</a>
<?php endif; ?>
</body>
</html>
ここはSQLをupdateにすること以外はadd.phpと同様になります。
完了ボタンを押した際にデータベースの
10.完了リストを表示する。
最後に完了リストを表示する部分の実装になります。
<?php
$dsn = 'mysql:host=localhost;dbname=PHPToDo;charset=utf8';
$username = 'root';
$pass = 'root';
try{
$dbh = new \PDO($dsn, $username, $pass,[
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
]);
$sql = "select * from todoItem" ;
$stmt = $dbh->query($sql);
$results = $stmt->fetchAll();
$dbh = null;
$results;
}
catch(PDOException $e){
echo 'FALSE!'.$e->getMessage();
exit();
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>ToDo List</h1>
</header>
<main>
<div>
<form action="add.php" method="POST">
<input type="text" name="todoItem">
<input type="submit" value="追加">
</form>
</div>
<div>
<div>
<h2>ToDoリスト</h2>
<table border="1">
<thead>
<tr>
<td class="itemName">タスク名</td>
<td class="itemCreatedAt">作成日時</td>
<td class="itemComplete"></td>
</tr>
</thead>
<tbody>
<?php foreach($results as $result): ?>
<?php if($result['completeFlg'] == 0): ?>
<form action="complete.php" method="POST">
<tr>
<td><?php echo $result['content']; ?></td>
<td><?php echo $result['createdAt']; ?></td>
<td><input type="submit" value="完了"></td>
<input type="hidden" name="completeItem" value="<?php echo $result['id']; ?>">
</tr>
</form>
<?php endif; ?>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div>
<h2>完了済み</h2>
<table border="1">
<thead>
<tr>
<td class="itemName">タスク名</td>
<td class="itemCreatedAt">作成日時</td>
<td class="itemComplete">完了日時</td>
</tr>
</thead>
<tbody>
<!-- 追加ここから -->
<?php foreach($results as $result): ?>
<?php if($result['completeFlg'] == 1): ?>
<tr>
<td><?php echo $result['content']; ?></td>
<td><?php echo $result['createdAt']; ?></td>
<td><?php echo $result['completedAt']; ?></td>
</tr>
<?php endif; ?>
<?php endforeach; ?>
<!-- 追加ここまで -->
</tbody>
</table>
</div>
</div>
</main>
</body>
</html>
index.phpを再度編集します。
8とは反対で、完了しているToDoを表示するようにします。
これで完成になります。
このようにサーバーサイド言語で実装することによってデータベースを使用してデータの保管を行うことができます。
他にもログイン認証や、メール送信、ファイルへの書き込みなどもサーバーサイドを実装することで組み込むことができます。
また、SQLをカスタマイズすることでより高度な機能を実装することも可能になりますので学習を進めてオリジナルアプリを作成してみましょう。
今回はここまでになります。最後まで閲覧くださりありがとうございました。