PHPでポートフォリオ作成：カレンダー

# 記事の概要
作った背景、工夫したところ、機能をまとめました。

下にコードを記載しました。


# 背景

一般的なカレンダー（家の壁にかかっているものを想像してほしいです）を作成したときに、自分のスケジュールを書き込めると、カレンダーとしての価値がアップするのでないかなと思い作成にいたりました。

エクセルのようなレイアウトで日付とスケジュールを同時に表示するようなカレンダーを作成します。

工夫としては、当たり前ですが見た目を分かりやすく、使用者が使いやすいようにシンプルにしました。

# 目的
・PHPを用いて簡単なアプリケーションを作る
・見やすくて使いやすいアプリを作る
・カレンダー機能+スケジュール機能で単純なカレンダーに価値をつける

# スペック
言語
PHP 7.4.2
データーベース
MariaDB 10.4.11
開発環境
Apache　2.4.41

ビジュアルスタジオコード使用

# 主な機能

・今月の日付の表示機能
・来月、前月のカレンダーへのリンク
リンクをクリックすると、来月もしくわ前月のカレンダーに飛びます

・スケジュールの表示機能
カレンダーの日付の横にスケジュールの時間と内容を表示する

・スケジュールの保存機能
日付、時間、スケジュールという情報をデータベースに保存する

・スケジュールの更新機能
スケジュールを更新する

・スケジュールの削除機能
スケジュールを削除する

※データベースのカラムの情報があると説明しやすいので、詳しくは下部で説明します。

# 開発手順
1、要件定義
2、環境選定
3、データベース設計
4、設計
5、コーディング

# 1、要件定義
今回のアプリでの主要な機能は
・今月の日付の表示
・スケジュールの表示
・スケジュールの保存、更新、削除

今月の日付が表示できるということは、月（month）の部分を変更することで来月、前月のカレンダーが表示可能になります。
ということは、すべての日付のカレンダーが作成可能になります。

スケジュールの保存には、データベースが必要です。

# 環境選定

PHP,MySQL,apacheを使用。

Windowsローカル上に環境を構築しました。

# データベース設計
記入例

| id               |       day         |    time            |　 message         　|
|:-----------------|------------------:|:------------------:|:------------------:|
| 5             |           2018-12-15 |        18:00        |    予定を書く                |


スケジュールの情報をデータベースに保存。
スケジュールの情報としては
id,day,time,messageとして
idにはオートインクリメントを設定して、idの値がかぶることはないようにしました。
dayには2020-03-27の形式で年月日を保存
timeにはtextタイプなので時間の表現の仕方は自由です
messageにはスケジュールの内容を保存します

# 設計
のちほど追加予定


#　5.コーディング
設計を書いたのですが、後々変更することは多かったです。
理由は、コーディングしていて「このように表示する方が使用者にとっては、使いやすいのではないか」という考えの結果、レイアウトの変更をしました。


#5.1データベース作成
ローカル環境のMysqlサーバーに
データーベースを作成。テーブルを作成。

## 5.2データベース接続確認
PDOを用いて、データーベースの接続。
try~catchを用いて、成功しているか判断


## 5.3今月の日付の表示機能

![GIF 2020-03-28 8-39-33.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600143/d50f9077-0439-f9ab-1607-9077f6cff6d1.gif)


urlに?t=2020-04のような表記があれば、その年月（この場合2020-03）で取得し、表記がなければ今月の年月を取得する
これで、年月日の年月の情報を取得したので、年月の情報からDatePeriodを使って、年月日における日の部分の情報を取得します。
これで年月日の情報がそろったのでエクセルや表のような形式で表現します

## 5.4・来月、前月のカレンダーへのリンク
リンクをクリックすると、来月もしくわ前月のカレンダーに飛びます

![GIF 2020-03-28 8-42-58.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600143/62be9da1-3ed7-a2ab-6a0e-f179284bdfbb.gif)


5.3にて年月日の情報を取得しています。なのでリンクをその月（month）に+1すれば翌月、-1すれば前月へ飛ぶように設定しました。

## 5.5スケジュールの表示機能
カレンダーの日付の横にスケジュールの時間と内容を表示する

if文で取得している年月日とデータベースにあるdayの部分で一致するレコード（行部分）が存在したら、そのレコードのスケジュール時間と内容を日付の横に表示する

## 5.6スケジュールの保存機能
日付、時間、スケジュールという情報をデータベースに保存する
この時、日付の形式が2020-03-27のような形式でない場合はerrorとし
errorが存在する場合はエラーメッセージを表示する

![GIF 2020-03-28 8-48-45.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600143/f1b3b54e-9a12-e0ec-260a-db5920706b87.gif)


## 5.7スケジュールの更新機能
スケジュールを更新する

![GIF 2020-03-28 8-53-15.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600143/ee8198e2-913a-c4fa-bee6-5ba7cb2d8f99.gif)



構造上、日付1つに対して1つのメッセージになるため、
更新機能を使う場合、既存のスケジュールの情報を削除してから、また新しくスケジュールをデータベースに保存する方法を使用

※1つの日付に対して、複数のメッセージがある場合はidが新しいメッセージが表示される。
※また、ある日付に対してメッセージが存在するにも関わらず、メッセージを作成した場合は、メッセージは既存のメッセージが表示されるので、新しく作ったmemberテーブルは表示されない

## 5.8スケジュールの削除機能
スケジュールを削除する

削除ボタンを作って、削除を実行する
この時、日付に該当する箇所を変更した場合、その日付のメッセージが削除される。

## 5.9レイアウト
新しくスケジュールを作る機能はアイコンにして、右上に固定しました。
これは、下にスクロールしたとしても、スケジュール作成できるためです
配色の統一、シンプルにわかりやすいをこころがけました

# 課題点
・「1つの日付に対して、1つのスケジュール」でなく複数のスケジュールを表示すべきだが、技術的にできなかった。
・わかりやすく,シンプルに作ったつもりであるが、その分、説明不足で慣れれ宇までに時間がかかる可能性がある
・スケジュールの保存に関して、使用者の制約があり親切でない、
1999-03-20のような形式でなくタイプをradio形式（複数の選択肢から1つを選択する形式）で年、月、日に分けて表現すれば良かったかもしれない。
・スケジュールの削除に関して、入力されている年月日のデータの削除があることを説明していない
・オブジェクト思考がなってない。機能を別ファイルでプログラミングして、呼び出すことができてない

# code
index.php
画像

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

//セキュリティ対策
function h($s){
  return htmlspecialchars($s,ENT_QUOTES,'UTF-8');
}
//

//今月を取得する
try{
if(!isset($_GET['t']) || !preg_match('/\A\d{4}-\d{2}\Z/',$_GET['t'])){
  throw new Exception();
}
  $thisMonth=new DateTime($_GET['t']);
}catch(Exception $e){
  $thisMonth = new DateTime('first day of this month');
}


//今月から来月と翌月を取得する
  $dt= clone $thisMonth;
  $prev = $dt->modify('-1 month')->format('Y-m');
  $dt= clone $thisMonth;
  $next=$dt->modify('+1 month')->format('Y-m');
//


$yearMonth=$thisMonth->format('F Y');

//日付、メッセージの表示機能
  $period=new DatePeriod(
    new DateTime('first day of'.$yearMonth),
    new DateInterval('P1D'),
    new DateTime('first day of'.$yearMonth.'+1 month')
  );

  //複数のメッセージをつけたいがつけれなかった
  $body='';
  $today=new DateTime('today');
  foreach($period as $day){
    
    $messages=$db->prepare('SELECT * FROM posts WHERE day=?');
    $messages->execute(array($day->format('Y-m-d')));
    $message=$messages->fetch();

    $todayClass=($day->format('Y-m-d') === $today->format('Y-m-d'))?'today':'';
    $body .= sprintf('<tr><td class="youbi_%d %s">%d</td><td>%s</td><td class="message"><a   href="message.php?t=%d-%02d-%2d">%s</a></td></tr>',$day->format('w'),$todayClass,$day->format('j'),$message['time'],$day->format('Y'),$day->format('n'),$day->format('d'),$message['message']);
  }
//

  


//cssでのレイアウト
//オブジェクト思考


//終了。前月次月のリンク.todayのリンク,データベースに保存する
//今日を太文字、土日は色変える,時間の指定もあり、消去、変更

?>



<!DOCTYPE html>
<html lang='ja'>
<head>
  <meta charset='utf-8'>
  <title>カレンダー</title> 
  <link rel='stylesheet' href='styles.css'>
</head>
  <body>
      <a class='write' href="message.php" name='write_message'><img  src="write.png"  alt="写真"></a>
    <table>
      <thead>
        <tr>
          <th><a href="/test/index.php?t=<?php echo h($prev); ?>">&laquo;</a></th>
          <th><?php echo $yearMonth; ?></th>
          <th><a href="/test/index.php?t=<?php echo h($next); ?>">&raquo;</a></th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>day</td>
          <td>time</td>
          <td>message</td>
        </tr>   
        <?php echo $body;?>
      </tbody>
    </table>
  </body>
</html>
```

message.php
画像





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


//入力機能は取得して、それをインサートするだけ

if(!empty($_POST)){
    //すでにメッセージが存在する場合、そのメッセージを消去する
    //先に消去をおした場合にはメッセージを消去してexitする
    if($_POST['delete'] ==='1'){
      $deletes=$db->prepare('DELETE FROM posts WHERE day=? ');
      $deletes->execute(array($_POST['day']));
      header('Location:index.php');
      exit();
    }


    if(!empty($_POST)){

      $posts=$db->prepare('SELECT * FROM posts WHERE day=?');
      $posts->execute(array($_POST['day']));
      $post=$posts->fetch();
      
      if(!empty($post['message'])){
      $deletes=$db->prepare('DELETE FROM posts WHERE day=? ');
      $deletes->execute(array($_POST['day']));
    }

    
  //日付の設定はシビアで形式が決まっているので、形式が違えばエラーをだす
  if( preg_match('/\A\d{4}-\d{2}-\d{2}\z/',$_POST['day'])){
    $message=$db->prepare('INSERT INTO posts SET day=? ,message=?,time=?');
    $message->execute(array(
      $_POST['day'],
      $_POST['message'],
      $_POST['time']
    ));
    
    header('Location:index.php');
    exit();
  }else{
    $error['day']='format';
  }

}


}
//messageの再取得、
  $messages=$db->prepare('SELECT * FROM posts WHERE day=?');
  $messages->execute(array($_REQUEST['t']));
  $message=$messages->fetch();

?>
<!DOCTYPE html>
<html lang='ja'>
<head>
  <meta charset='utf-8'>
  <title>カレンダー</title> 
  <link rel='stylesheet' href='styles.css'>
</
head>
  <body>
    <div class='title'>
      <a href="index.php"><<　ホーム</a>
    </div>
    <div class='content'>

      <form action="" method='post'>
        <p class='delete_p'>メッセージを消去＞＞<button type='subimt' class='delete'  name='delete' value='1'>消去</button></p>
        <p >日付　（※2020-01-01の形式で入力してください）</p>
        <input name='day' type="text" value="<?php echo $_REQUEST['t'];?>" >
        <?php if($error['day'] === 'format'): ?>
          <p class='error'>※2020-01-01の形式で入力してください。</p>
          <?php endif;?>
          <p>時間</p> 
          <input name='time' type="text" value='<?php echo $message['time'] ?>'>
          <p>メッセージ</p>
          
          <textarea name="message" id="" cols="30" rows="10" ><?php echo $message['message']; ?></textarea>
          <button type='submit'>メッセージを保存する</button>
          
          
          
          
    </div>
  </form> 

  </body>
</html>
```