【PHP】PHPでメモアプリを作成【2】

# 前回記事の概要
PHPでCRUD機能を搭載した簡単なメモアプリの作成を行ったため、その備忘録を記事として残しておきます。
前回の記事(https://qiita.com/iwatsukayura/items/43c42d5378616b932f24)
では、DB設計をし、メモを一覧として表示させるところまで、行いました。
本記事ではメモの削除や、詳細画面、編集画面などを追加していきます。


# ページ数を求める
今回のメモアプリでは、メモを5件ずつでページを変更するように記述しました。
以下のコード、計算方法で実現しています。(前回記事のindex.htmlの一部です)

```php
<?php
//最大ページ数を求める
$counts = $db->query('select count(*) as cnt from memos');
$count = $counts->fetch_assoc();
$max_page = floor(($count['cnt']-1)/5 + 1);

$stmt = $db->prepare('select * from memos order by id desc limit ?, 5');
if (!$stmt){
  die($db->error);
}

$page = filter_input(INPUT_GET, 'page', FILTER_SANITIZE_NUMBER_INT);
$page = ($page ?: 1);
$start = ($page-1)*5;
$stmt->bind_param('i', $start);
$result = $stmt->execute();
?>
<!DOCTYPE html>
<html lang="ja">
<body>
  <p>
    <?php if($page > 1): ?>
      <a href="?page=<?php echo $page-1; ?>"><?php echo $page-1?>ページ目</a> | 
    <?php endif; ?>
    <?php if($page < $max_page): ?>
      <a href="?page=<?php echo $page+1; ?>"><?php echo $page+1?>ページ目</a>
    <?php endif; ?>
  </p>

</body>
</html>
```

すこし計算や演算子が複雑なのでひとつずつ見ていきましょう。
```php
<?php
//最大ページ数を求める
$counts = $db->query('select count(*) as cnt from memos');
$count = $counts->fetch_assoc();
$max_page = floor(($count['cnt']-1)/5 + 1);
?>
```

countsにはDBに格納されているデータ件数をcntという変数に代入した値を格納しています。SQLで引っ張ってきた値をfetch_assoc()を利用してcountに連想配列として格納しています。
ここでメモ5件ずつで区切るとき、最大のページ数は、{(メモ数-1)/5+1}の整数部分となりますので、floor関数を利用して切り捨てを行います。これで最大ページ数が求まりました。

また、5件ずつでページを変更させるということは、ステートメントの指定しているSQL文の?に入る値は0,5,10...のように5の倍数にすることで、実現されます。

```php
<?php
$page = filter_input(INPUT_GET, 'page', FILTER_SANITIZE_NUMBER_INT);
$page = ($page ?: 1);
$start = ($page-1)*5;
$stmt->bind_param('i', $start);
$result = $stmt->execute();
?>
```

この部分ですね。
URLパラメータからページ数を指定した値を変数pageに格納しています。このとき、メモ件数によってそのページ数が存在するかしないかの判定を行う必要があります。if文を使用しても構いませんが簡略化のために今回は三項演算子(エルビス演算子)を利用します。

エルビス演算子については以下を参照してください。
>【PHP入門】三項演算子とは？使いこなしてコードをスッキリする
>https://www.sejuku.net/blog/23070

エルビス演算子によって指定されたページ数が存在するならば(条件式がTrue)その値を返し、存在しないならば(条件式がFalse)1を返すようになっています。
ここでページ数が指定されたら、そのページの一番先頭のメモがDBの何行目かを計算する必要があります。
例えば3ページ目の先頭のメモは11個目のメモ、5ページ目の先頭のメモは21個目のメモであるから、計算式は
{(ページ数-1)*5}となる、つまり{($page-1)*5}となり、この値を変数startに格納。
この変数startをbind_pramでステートメントのSQLに代入することで、5件ずつでページを切り替えることができます。

あとは、メモ一覧画面から、次のページや前のページに遷移できるようにしていきましょう。

```php
  <p>
    <?php if($page > 1): ?>
      <a href="?page=<?php echo $page-1; ?>"><?php echo $page-1?>ページ目</a> | 
    <?php endif; ?>
    <?php if($page < $max_page): ?>
      <a href="?page=<?php echo $page+1; ?>"><?php echo $page+1?>ページ目</a>
    <?php endif; ?>
  </p>
```

条件式を抜きにしてみると非常に簡単です。今いるページに-1した値をURLパラメータに渡すようにリンクを作成して、前のページに遷移できるようにしています。次のページに行くのも同様です。
ここの条件式は1ページ目にいるときに、前ページには遷移できないことや、最後のページにいるときに次ページに遷移できないことを実装するためのものである。

# メモの詳細
メモの一覧画面が完成した。メモ一覧ではメモの文字数は最大50文字までとなっているため、それぞれのメモの詳細画面を作成していく。index.phpでメモのリンクはmemo.phpを指定しているため、memo.phpを見ていこう。

```php:memo.php
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>メモの詳細</title>
</head>
<body>
  <?php
  require('dbconnect.php');
  $stmt = $db->prepare('select * from memos where id=?');
  if (!$stmt){
    die($db->error);
  }
  $id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);
  if (!$id){
    echo '表示するメモを指定してください';
    exit();
  }
  $stmt->bind_param('i', $id);
  $stmt->execute();

  $stmt->bind_result($id, $memo, $created);
  $result = $stmt->fetch();
  if(!$result){
    echo '指定されたメモは見つかりませんでした';
    exit();
  }
  ?>

  <div><pre><?php echo htmlspecialchars($memo); ?></pre></div>

  <p>
    <a href="update.php?id=<?php echo $id ?>">編集する</a> |
    <a href="delete.php?id=<?php echo $id ?>">削除する</a> |
    <a href="/memo">一覧へ</a>
  </p>
</body>
</html>
```

ここまでくると同じようなコードがたくさん出てきます。
require()でDBと接続して、URLパラメータでメモのidを受け取るようにしていますが、メモ一覧からメモのリンクをクリックしてきたらもうすでにURLパラメータにはidが入るようになっています。

詳細画面の中にメモの編集画面へのリンクと削除画面のリンクを用意しています。

# メモの削除・編集

メモの削除画面はdelete.phpで行います。
```php:delete.php
<?php
require('dbconnect.php');

$stmt = $db->prepare('delete from memos where id=?');
if(!$stmt){
  die($db->error);
}
$id = filter_input(INPUT_GET,'id', FILTER_SANITIZE_NUMBER_INT);
if(!$id){
  echo 'メモが正しく指定されていません';
  exit();
}

$stmt->bind_param('i', $id);
$success = $stmt->execute();
if(!$success){
  die($db->error);
}

header('Location: index.php');

?>
```

メモの詳細画面と同じようにURLパラメータにidを受け取り、SQLでDELETE文を実行しています。
DELETEが実行されたらheaderでindex.phpに遷移するように記述されています。

メモの編集画面については、update.phpで行います。
```php:update.php
<?php
require('dbconnect.php');
$stmt = $db->prepare('select * from memos where id=?');
if(!$stmt){
  die($db->error);
}
$id=filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);
$stmt->bind_param('i', $id);
$stmt->execute();

$stmt->bind_result($id, $memo, $created);
$result = $stmt->fetch();
if(!$result){
  die('メモの指定が正しくありません');
}
?>

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>メモの編集</title>
</head>
<body>
  <form action="update_do.php" method="post">
    <input type="hidden" name="id" value="<?php echo $id; ?>" >
    <textarea name="memo" cols="30" rows="10" placeholder="メモを入力してください"><?php echo htmlspecialchars($memo) ?></textarea><br>
    <button type="submit">編集する</button>
  </form>
</body>
</html>
```

情報を更新する際も今までと同じようにURLパラメータにidを渡してメモの更新を行います。
その時、更新したメモが新しいidにならないようにinputのtypeをhiddenとして、そのままのidの値と更新したメモの内容をupdate_do.phpへと送ります。

```php:update_do.php
<?php
require('dbconnect.php');

$stmt = $db->prepare('update memos set memo=? where id=?');
if(!$stmt){
  die($db->error);
}
$id=filter_input(INPUT_POST,'id', FILTER_SANITIZE_NUMBER_INT);
$memo=filter_input(INPUT_POST,'memo', FILTER_SANITIZE_STRING);
$stmt->bind_param('si', $memo, $id);
$success = $stmt->execute();
if(!$success){
  die($db->error);
}

header('Location: memo.php?id='. $id);

?>
```
update.phpのフォームから渡ってきた値を受け取り、DBに格納しなおしています。
idはそのままの値を、memoは変更した内容をDBに記録し、headerでメモの詳細画面に遷移するようにしています。

# 最後に
これでメモアプリ作成の記事は終わりとなります。今コードを見返すとなんでこうなっているのだろうか...?と考えてしまいます笑
CRUDの機能を搭載したメモアプリの作成を行ったことでphpの基礎が身につきました。
現在別のアプリケーションの作成も行っていますのでそちらも完成したら記事にしようと思います。