PHPとjavascriptで営業日カレンダー

phpとjavascriptで営業カレンダーを作る

完成した表示
<img width="299" alt="スクリーンショット 2020-02-27 9.32.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52355/09fa6331-db2b-3c47-1217-285f4c451dca.png">
仕様
・休みは赤色にする
・定休日：祝日と日曜、木曜
・アイコンクリックで表示月変更

設計
・PHPでカレンダーを構築する配列をJSONで出力
・ajaxで受け取り出力する。

## 1.祝日配列のつくる
内閣府のページに祝日のcsvがあるので、そこからダウンロードする。
https://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html
※csvはUTF-8に変換して保存。

```php:calendar.php
function get_public_holidays(){
    $path = "./syukujitsu.csv";
    $csv = new SplFileObject($path);
    $csv->setFlags(SplFileObject::READ_CSV);
    $holidays = [];
    foreach ($csv as $key => $line){
        $holidays[$line[0]] = $line[1];
    }
    return $holidays;
}
```

## 2.カレンダーを構築する配列をつくる

```php:calendar.php
function make_date_list($year,$month){
    
    $regular_holiday = [0,4]; //定休日:曜日
    $public_holidays = get_public_holidays(); //祝日
    
    $target = new \DateTime("{$year}-{$month}-01");
    $date = [];
    for($i = 0; $i < intval($target->format('t')); $i++){

        if($i > 0) $target->modify('+1day');
        //祝日
        if(isset($public_holidays[$target->format('Y/n/d')])){
            $holiday = true;
        //定休日
        }else if(in_array($target->format('w'),$regular_holiday)){
            $holiday = true;
        }else{
            $holiday = false;
        }

        $dates[$i] = [
            'day' => $target->format('d'),
            'week' => $target->format('w'),
            'holiday' => $holiday,
        ];

    }
    
    /*カレンダーの空欄箇所*/
    $first_date = current($dates);
    $end_date = end($dates);

    $damy_num = intval($first_date['week']);
    if($damy_num > 0){
        $damy = [];        
        for($i = $damy_num - 1;0 <= $i;$i--){
            array_unshift($dates,['week'=>$i,'day'=>'&nbsp;']);
        }    
    }

    $damy_num = intval($end_date['week']);
    if($damy_num < 6){
        $damy = [];        
        for($i = $damy_num; $i < 6;$i++){
            array_push($dates,['week'=>$i,'day'=>'&nbsp;']);
        }
    }

    return $dates;
}
```

## 3.リクエストがよる出力
```php:calendar.php
if(isset($_GET['y']) and $_GET['y']){
    $year = $_GET['y'];
}else{
    $year = date('Y');
}

if(isset($_GET['m']) and $_GET['m']){
    $month = $_GET['m'];
}else{
    $month = date('m');
}

$dates = make_date_list($year,$month);

echo json_encode($dates);
```

## 4.javascriptでのカレンダー構築
２ヶ月先までの表示にしています。

```javascript:calendar.js

var nowDate;
var year;
var month;

$(function(){
    nowDate = new Date();
    year = nowDate.getFullYear(); // 年
    month = nowDate.getMonth() + 1; // 月

    MakeCalendar();
});

function prev(){
    if(month === 1){
        month = 12;
        year--;
    }else{
        month--;
    }
    MakeCalendar();

}

function next(){
    if(month === 12){
        month = 1;
        year++;
    }else{
        month++;
    }
    MakeCalendar();
}

function MakeCalendar(){
    $.ajax({
        url: 'calender.php?y='+year+'&m='+month,
        dataType: 'json',
        timeout: 10000,  
        success: function(json) {

            var c = '<div class="cal"><div class="cal_header">';
            if(nowDate.getFullYear() <= year && (nowDate.getMonth() + 1) < month ){
                c += '<a href="" onClick="prev();return false;" class="cal_prev"><img src="./images/cal_prev.png" alt="前の月" width="19"></a>';
            }else{}

            if(nowDate.getFullYear() >= year && (nowDate.getMonth() + 3) > month ){
                c += '<a href="" onClick="next();return false;" class="cal_next"><img src="./images/cal_next.png" alt="次の月" width="19"></a>'
            }else{}

            c += '<strong>'+year+'年'+month+'月</strong>';
            c += '</div>';
            c += '<div class="cal_body">';
            c += '<table class="table_cal">';
            c += '<thead><tr><th>日</th><th>月</th><th>火</th><th>水</th><th>木</th><th>金</th><th>土</th></tr></thead>';

            jQuery.each(json, function(i, date) {
                
                if(date.week === '0'){
                    c += '<tr>';
                }else{}
                if(date.holiday === true){
                    c += '<td><span class="closed">'+date.day+'</span></td>';
                }else{
                    c += '<td>'+date.day+'</td>';
                }
                
                if(date.week === '6'){
                    c += '</tr>';
                }else{}

            });

            c += '</tbody></table></div></div>';

            $('#calendar').html(c);

        },
         error: function(xhr, textStatus, error) {
            alert('ERR');
        }
    });

}
```
## 4.表示
表示する箇所にタグとCSSを構築して完成。


```html:sample.html

<div id="calendar"></div>

```

```css:sample.css

.cal{background:#fff;box-shadow:2px 2px 4px rgba(0,0,0,0.2);}
.cal_header{padding:15px 13px;border-bottom:1px solid #ddd;}
.cal_header a,.cal_header span{display:block;}
.cal_header strong{display:block;text-align:center;font-size:1.3rem;color:#005ca2;line-height:19px;}
.cal_prev{float:left;cursor:pointer;}
.cal_next{float:right;cursor:pointer;}
.cal_body{padding:10px 15px;text-align:center;}

.table_cal{width:100%;border-collapse:collapse;}
.table_cal th,.table_cal td{font-size:1.1rem;text-align:center;height:30px;min-width:31px;}

.today{font-weight:bold;text-decoration:underline;}
.closed{display:inline-block;width:22px;height:22px;background:#eb6e8f;color:#fff;border-radius:50%;line-height:23px;}

.cal_bottom{font-size:1.1rem;margin:10px 0 15px;}
.cal_bottom span{vertical-align:middle;margin-right:4px;}

```