プロジェクト型演習 #3 (DB作成, web画面)

# 本番環境の構築
実際にシステムで使用するDBを作成する。
前提として [プロジェクト型演習 #1 (raspberrypi DB操作)](https://qiita.com/kawanishi291/items/acae192ed2a22c2977a4) 実装済み、更に Apache2 をインストール済みののRaspberry Pi を利用しているものとして話を進める。
今回は、本番用DBを作成し、Web画面で確認するところまでやってみる。

## DB構築
### ログイン
面倒なので、以前作成したユーザ, DBを使い回す。
##### ユーザでログイン

```
pi@raspberry:~ $ sudo mysql -upi -praspberry
```
##### DBへ入る

```
MariaDB[(none)]> use sample_db
Database changed
```
### 各種テーブルの作成
※下記SQL文をそのままコピペでおけ。詳しくは [#1](https://qiita.com/kawanishi291/items/acae192ed2a22c2977a4) を参照。
##### スコアテーブルの作成

```sql
CREATE TABLE `score` (
  `num` int(32) NOT NULL AUTO_INCREMENT,
  `id` int(4) NOT NULL,
  `score` int(8) NOT NULL,
  `great` int(4) NOT NULL,
  `good` int(4) NOT NULL,
  `bad` int(4) NOT NULL,
  `datetime` DATETIME NOT NULL,
  PRIMARY KEY (`num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```
##### 楽曲テーブルの作成

```sql
CREATE TABLE `music` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `name` varchar(512) NOT NULL,
  `max` int(8) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```
##### 楽曲テーブルにデータを挿入

```sql
INSERT INTO `music` (`name`, `max`) VALUES
("ピタゴラスイッチ", 1000),
("きらきら星", 1000);
```
##### スコアテーブルにデータを挿入

```sql
INSERT INTO `score` (`id`, `score`, `great`, `good`, `bad`, `datetime`) VALUES
(1, 305, 25, 51, 24, '2021-06-01 21:45:31'),
(1, 700, 50, 40, 10, '2021-06-02 21:45:31'),
(2, 625, 40, 45, 15, '2021-06-03 21:45:31'),
(1, 125, 5, 15, 80, '2021-06-03 21:45:31');
```
## WEB画面 (PHP)

### TOPページ
今後修正予定だが、雑に作っておく。
以下の全ファイルを`/var/www/html/`内に配置。index.phpは前回作成したものを修正する。

```
pi@raspberry:~ $ cd /var/www/html
pi@raspberry:/var/www/html $ nano index.php
```
<details><summary>TOP</summary><div>

```php:index.php
<?php
    $title = "認知症予防システム";
    require('./header.php');
    $page = "home";
?>
    <h1 class="mx-auto" style="width: 200px; font-family: ヒラギノ丸ゴ ProN W4;">スコア表</h1>
    <table class="table">
        <thead class="table-light" style="background-color: #008b8b;">
            <th>日付</th>
            <th>曲名</th>
            <th>スコア</th>
            <th>GREAT</th>
            <th>GOOD</th>
            <th>BAD</th>
            <th>%</th>
        </thead>
<?php
    ini_set('display_errors', "On");
    //phpinfo();
    include "./pdo_connect.php";
    $sql = "SELECT * FROM score JOIN music WHERE score.id = music.id ORDER BY score.datetime DESC";
    $stmt = $pdo -> query($sql);
    foreach($stmt as $row){
?>
        <tbody id = "<?=$row['num']?>">
            <td><?=date('Y年m月d日 H:i',strtotime($row['datetime']))?></td>
            <td><?=$row['name']?></td>
            <td><?=$row['score']?></td>
            <td><?=$row['great']?></td>
            <td><?=$row['good']?></td>
            <td><?=$row['bad']?></td>
            <td><?=($row['score'] / $row['max']) * 100?></td>
        </tbody>
<?php
    }
?>
    </table>
<?php
    require('./footer.php');
?>
```
</div></details>

### ヘッダーファイル

```
pi@raspberry:/var/www/html $ nano header.php
```
<details><summary>ヘッダーファイル</summary><div>

```php:header.php
<!DOCTYPE html>
<html lang='ja'>
<head>
    <meta charset='utf-8' />
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
    <title><?=$title?></title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fullcalendar@5.5.0/main.min.css">
    <script src="https://cdn.jsdelivr.net/npm/fullcalendar@5.5.0/main.min.js"></script>
</head>
<body>
<nav class="navbar navbar-dark mb-5" style="background-color: #008080;">
  <a class="navbar-brand" href="./index.php">認知症予防システム</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarNavAltMarkup">
    <div class="navbar-nav">
      <a id="home" class="nav-item nav-link" href="./index.php">Home <span class="sr-only">(current)</span></a>
      <a id="calendar" class="nav-item nav-link" href="./calendar.php">Calendar</a>
      <a id="graph" class="nav-item nav-link" href="./graph.php">Graph</a>
    </div>
  </div>
</nav>
<div class="container w-80">
```
</div></details>

### フッターファイル
```
pi@raspberry:/var/www/html $ nano footer.php
```
<details><summary>フッターファイル</summary><div>

```php:footer.php
</div>
</body>
</html>
<script>
const div = document.getElementById("<?=$page?>");
div.classList.add('active');
</script>
```
</div></details>

### カレンダー
```
pi@raspberry:/var/www/html $ nano calendar.php
```
<details><summary>カレンダー</summary><div>

```php:calendar.php
<?php
    $title = "カレンダー";
    require('./header.php');
    $page = "calendar";
?>
<div id='calendar-box'></div>
<?php
    require('./footer.php');
?>
<script>
document.addEventListener('DOMContentLoaded', function() {
    var calendarEl = document.getElementById('calendar-box');
    var calendar = new FullCalendar.Calendar(calendarEl, {
        initialView: 'dayGridMonth',
        events: [
<?php
include "./pdo_connect.php";
$sql = "SELECT * FROM score JOIN music WHERE score.id = music.id";
$stmt = $pdo -> query($sql);
foreach($stmt as $row){
?>
                {
                    id: '<?=$row['num']?>',
                    title: '<?=$row['name']." ".$row['score']?>',
                    start: '<?=date('Y-m-d',strtotime($row['datetime']))?>',
                    url: './index.php#<?=$row['num']?>'
                },
<?php
}
?>

        ],
        // 日本語化
        locale: 'ja',
        buttonText: {
            prev:     '<',
            next:     '>',
            prevYear: '<<',
            nextYear: '>>',
            today:    '今日',
            month:    '月',
            week:     '週',
            day:      '日',
            list:     '一覧'
        },
    });
    calendar.render();
});
</script>
```
</div></details>

### グラフ
```
pi@raspberry:/var/www/html $ nano graph.php
```
<details><summary>グラフ</summary><div>

```php:graph.php
<?php
    $title = "グラフ";
    require('./header.php');
    $page = "graph";
    $labels = [];
    $datetime_list = [];
    for ($i = 6; $i >= 0; $i--) {
        $m = (int)date("m", strtotime("-"."$i"." day"));
        $d = (int)date("d", strtotime("-"."$i"." day"));
        $labels[] = $m."月".$d."日";
        $datetime_list[] = date("Y-m-d", strtotime("-"."$i"." day"));
    }
    $start = date("Y-m-d", strtotime("-6 day"));
    $start .= " 00:00:00";
    $end = date("Y-m-d", strtotime("-0 day"));
    $end .= " 99:99:99";

    include "./pdo_connect.php";
    $sql = "SELECT * FROM score JOIN music WHERE score.id = music.id AND score.datetime BETWEEN '$start' AND '$end' ORDER BY score.datetime ASC";
    $stmt = $pdo -> query($sql);
    $cnt = 0;
    $max_list = [0, 0, 0, 0, 0, 0, 0];
    $min_list = [200, 200, 200, 200, 200, 200, 200];
    foreach($stmt as $row){
        for ($i = $cnt; $i < 7; $i++) {
            if ($datetime_list[$i]." 00:00:00" <= $row['datetime'] && $row['datetime'] <= $datetime_list[$i]." 99:99:99") {
                if ($max_list[$cnt] < ($row['score'] / $row['max']) * 100) {
                    $max_list[$cnt] = ($row['score'] / $row['max']) * 100;
                }
                if ($min_list[$cnt] > ($row['score'] / $row['max']) * 100) {
                    $min_list[$cnt] = ($row['score'] / $row['max']) * 100;
                }
                break;
            } else {
                $cnt ++;
            }
        }
    }
    for ($i = 0; $i < 7; $i++) {
        if ($min_list[$i] == 200) {
            $min_list[$i] = 0;
        }
    }
?>
<h1>折れ線グラフ</h1>
  <canvas id="myLineChart"></canvas>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"></script>

  <script>
  var ctx = document.getElementById("myLineChart");
  var myLineChart = new Chart(ctx, {
    type: 'line',
    data: {
        labels: ['<?=$labels[0]?>', '<?=$labels[1]?>', '<?=$labels[2]?>', '<?=$labels[3]?>', '<?=$labels[4]?>', '<?=$labels[5]?>', '<?=$labels[6]?>'],
      datasets: [
        {
          label: '最高得点率(%）',
          data: [<?=$max_list[0]?>, <?=$max_list[1]?>, <?=$max_list[2]?>, <?=$max_list[3]?>, <?=$max_list[4]?>, <?=$max_list[5]?>, <?=$max_list[6]?>],
          borderColor: "rgba(255,0,0,1)",
          backgroundColor: "rgba(0,0,0,0)"
        },
        {
          label: '最低得点率(%）',
          data: [<?=$min_list[0]?>, <?=$min_list[1]?>, <?=$min_list[2]?>, <?=$min_list[3]?>, <?=$min_list[4]?>, <?=$min_list[5]?>, <?=$min_list[6]?>],
          borderColor: "rgba(0,0,255,1)",
          backgroundColor: "rgba(0,0,0,0)"
        }
      ],
    },
    options: {
      title: {
        display: true,
        text: '得点率（<?=$labels[0]?> ~ <?=$labels[6]?>）'
      },
      scales: {
        yAxes: [{
          ticks: {
            suggestedMax: 100,
            suggestedMin: 0,
            stepSize: 10,
            callback: function(value, index, values){
              return  value +  '%'
            }
          }
        }]
      },
    }
  });
  </script>
<?php
    require('./footer.php');
?>
```
</div></details>

### DB接続ファイル

```
pi@raspberry:/var/www/html $ nano pdo_connect.php
```
<details><summary>DB接続ファイル</summary><div>

```php:pdo_connect.php
<?php
//データベースの接続と選択
$hostdbname = 'mysql:host=localhost;dbname=sample_db;charset=UTF8';
$username = "pi";
$password = "raspberry";
$pdo = new PDO($hostdbname, $username, $password);
$pdo -> setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
?>
```
</div></details>

# 実行

> + [TOPページの確認](http://raspberrypi/index.php)
![スクリーンショット 2021-06-06 1.16.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1115711/f5c12ff1-51d6-3e49-19d8-d0d9c9e84cc0.png)
> + [カレンダーページの確認](http://raspberrypi/calendar.php)
![スクリーンショット 2021-06-06 1.16.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1115711/3a64ebda-a331-940e-fd81-41b14042f0b2.png)
> + [グラフページの確認](http://raspberrypi/graph.php)
![スクリーンショット 2021-06-06 1.16.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1115711/441bc967-ea73-15ea-9f4c-2a766d0bf5e0.png)


おそらくこんな感じでできるはず、、、
※この画像はPC上にDockerで環境構築したものを使用している為、実際とは異なる。
# 今後
+ TOPページの装飾
+ 検索機能やランキング、ソートなんかの実装（余力あれば）