【Todoアプリ】かんたん検索機能をつけてみよう

【Todoアプリ】メインページの作成 で作成したメインページに追加で「検索機能」をつけてみましょう。

使用するコードは【Todoアプリ】編集ページの作成 の最後にも載せてありますが、こちらを使っていきます!

現場や何かの案件で、

本文にある文字列をキーワードとして入れたら、

それを含むデータを抽出できる検索機能を追加でつけてほしい

と、依頼されたと想定してやってみるのも良い練習になるかと思います。

完成イメージ

メインページに「検索欄」があって、
検索ボタンを押すと使用したキーワードを含むデータの一覧が表示されるようなものです。

「テスト」と入力すると、
本文に「テスト」という文字列を含むものを抽出して表示する機能

使用するSQL

検索ロジックに使うSQLはもちろん「SELECT」です。

先ほどの例を見てみると、「テスト」と入力しただけで
「テスト2の本文」「テスト3の本文」と言う二つの結果が取得できました。

これはLIKE文を使ったいわゆるあいまい検索と言う技です。

例えば、WHERE句の条件が
「テストという文字列を含んでいること」と言うのはこのように表現します。

SELECT * FROM posts WHERE content LIKE '%テスト%';

「テスト」の前後に何の文字がくるかわからない時は%を使っておきます。

こうすることで、

  • 漢字テスト
  • テスト結果
  • テスト

これらも対象になります。

しかし今回は、

が検索ワードになるかわからない」と言う点に注意が必要です。

それには、キーワードにされた文字列を変数に入れて対処します↓

SELECT * FROM posts WHERE content LIKE '%$search_word%';

このような形で使用することになります。

それでは、作り方の流れを確認しつつ、実際にコードを書いていきましょう。

実装の流れ

  1. main.phpformを準備する
  2. form送信された時のデータを変数で受け取る
  3. 「検索ボタンが押されたら」と言うのと「キーワードに何か入力されていたら」と言う条件で検索時ロジック開始

この3段階で作っていきます。

①HTMLのformを用意する

まずはHTMLですね。

入力欄と検索ボタンがあったら良いだけなので、
新規登録ボタンの下にこんな感じで記述します。

<body>
<h1>メインページ</h1>
<a href="create.php" ><button type="button" class="btn btn-primary">新規登録</button></a>
<br>
<!-- (今回追加分)検索機能↓ -->
<form action="" method="POST">
    検索キーワード:<input type="text" name="search_word"> <br>
    <input type="submit" name="search" value="検索">
</form>

name属性に指定するものは後で使用するので、しっかりつけておきましょう。

②POST通信でデータを受け取る

POST通信で受け取るのは、form送信した値なので今回だと

入力欄「search_word」と検索ボタンの「search」を受け取ります。

<?php
    require('db_connect.php');

    // (今回追加分)↓
    $search = $_POST['search'];
    $search_word = $_POST['search_word'];

    $pdo = db_connect();
    try {
        $sql = "SELECT * FROM posts ORDER BY time";
        $stmt = $pdo->prepare($sql);
        $stmt->execute();
    } catch(PDOException $e) {
        echo $e->getMessage();
        die(); 
    }

?>

③検索ロジックの作成

メイン画面あるボタンですが、
何も入力していないのにボタンだけ押されて処理が動いたりするのは良くないですね。

「送信ボタンが押されたこと」&「何か検索欄に入力されている」

この2つの状況を同時に満たすときに、処理が動くようにします。

すると、こうなります。

(HTMLのコードも載せておくのでこれが今回の完成系のコードになります。)

<?php
    require('db_connect.php');

    // (今回追加分)form送信された分を受け取る
    $search = $_POST['search'];
    $search_word = $_POST['search_word'];

    $pdo = db_connect();
    try {
        $sql = "SELECT * FROM posts ORDER BY time";
        $stmt = $pdo->prepare($sql);
        $stmt->execute();
    } catch(PDOException $e) {
        echo $e->getMessage();
        die(); 
    }

    // (今回追加分)キーワード検索ロジック
    if (!empty($search) && !empty($search_word)) {
       $search_pdo = db_connect();
      try {
        $search_sql = "SELECT * FROM posts WHERE content LIKE '%$search_word%'";
        $stmt = $search_pdo->prepare($search_sql);
        $stmt->execute();
      } catch(PDOException $e) {
        echo $e->getMessage();
        die();
      }
    } 
?>


<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">

    <title>メインページ</title>
  </head>
  <body>
    <h1>メインページ</h1>
    <a href="create.php" ><button type="button" class="btn btn-primary">新規登録</button></a>
    <br>
    <!-- 今回追加分 ↓ -->
    <form action="" method="POST">
      検索キーワード:<input type="text" name="search_word"> <br>
      <input type="submit" name="search" value="検索">
    </form>
    
    <!-- Option 1: Bootstrap Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>

    <table class="table table-striped">
        <thead>
          <tr>
            <th scope="col">記事ID</th>
            <th scope="col">タイトル</th>
            <th scope="col">本文</th>
            <th scope="col">作成日</th>
            <th scope="col">編集</th>
            <th scope="col">削除</th>
          </tr>
        </thead>
        <tbody>
          <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) : ?>
            <tr>
              <td><?php echo $row["id"]; ?></td>
              <td><?php echo $row["title"]; ?></td>
              <td><?php echo $row["content"]; ?></td>
              <td><?php echo $row["time"]; ?></td>
              <td><a href="edit.php?id=<?php echo $row['id'];?>">編集</a></td>
              <td><a href="delete.php?id=<?php echo $row['id'];?>">削除</a></td>
            </tr>
          <?php endwhile; ?>

        </tbody>
      </table>
  </body>
</html>


送信ボタンが押されたこと」&「何か検索欄に入力されている

という条件の中に全ての処理を書くことで、
特に検索が行われていない場合はこの処理は全く何も動かないということになります。

逆にいうと、検索ボタンが押された時だけ起動するという動きを実現できます。

処理の流れを軽く解説

  1. 最初にメイン画面が読み込まれた時は、form送信されたわけではないので、
    if (!empty($search) && !empty($search_word))
    この条件に合致しない。
    つまり、検索機能は無視されるので自動的に全件出力される。
  2. 検索ボタンを押されるとform送信される。「action=””」の中身が空欄なので、自分のページに返ってくる。
    ➡︎ main.phpが再読み込みされる。
    再読み込みされるときには、
    if (!empty($search) && !empty($search_word))
    この条件に合致するので、検索機能が動き出して結果が変数stmtの中に入る。
  3. 全件出力時」も「検索結果を入れる時」も全て変数stmtに代入される。
    一見、同じstmtという変数を2重で使っているように見えるが、
    検索機能が動き出すと、変数stmtに再代入されて上書かれるので問題ない。

まとめ

  • 検索機能はSQLのLIKE文「あいまい検索」を使う
  • if文を使って、検索ボタンが押された時だけ起動するようにする

作り方はいろいろなパターンがあるので、今回のは一つの例として参考にしていただければと思います。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA