PHPで日本の祝日付きカレンダーを作る

#CarbonとYasumiを使います

CarbonはLaravelに入ってるので直観的に扱える人は多いかなと。

##インストール
composerで導入します。
###Carbon 
https://qiita.com/hiroita/items/ed642b6acac4cef45bda

###Yasumi 
https://qiita.com/sola-msr/items/7901835b3bfe145de033

#サンプル
以下のようなDirで配置

```
html/index.php
html/vender/...
```

<details><summary>サンプルコード（折り畳み）</summary><div>

```php:index.php
<?php
ini_set('display_errors', "On");
ini_set('error_reporting', E_ALL);
require 'vendor/autoload.php';

use Yasumi\Yasumi;
use Carbon\Carbon;
use HtmlPrinter as HP;
date_default_timezone_set('Asia/Tokyo');

?><!DOCTYPE html>
<html lang="ja" class="no-js">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width">

  <title>sample</title>

<!-- reset.css ress -->
<link rel="stylesheet" href="https://unpkg.com/ress/dist/ress.min.css">
</head>
<body>
<table>

</table>
<?php
HP::pp(Carbon::now());
HP::pp(Carbon::now()->startOfMonth()->toDateString() . "->" . Carbon::now()->endOfMonth()->toDateString());

$startMonth = Carbon::now()->subMonth(Carbon::now()->month);
for($i = 0;$i < 12; $i++){
        CalenderBuilder::makeCalendar($startMonth->addMonth());
}

?>
</body>
</html><?php
class CalenderBuilder{
        public static function makeCalendar(Carbon $carbon = null){
                //初期化
                $c = is_null($carbon) ? Carbon::now() : $carbon->copy();
                $ysm = Yasumi::create('Japan',$c->year,'ja_JP');
                HP::pp($c->format('Y年m月'));
                //月初はその週の日曜日まで前月の日にちを補完
                $som = $c->copy()->startOfMonth()->subDay($c->copy()->startOfMonth()->dayOfWeek);
                //月末は翌月の土曜日まで補完
                $eom = $c->copy()->endOfMonth()->addDay(6 - $c->copy()->endOfMonth()->dayOfWeek);
                
                for ($sd = $som->copy(); $sd < $eom ; $sd->addDay()) {
                        if($ysm->isHoliday($sd)){
                                HP::pnr($sd->format('d日'), $ysm->getHoliday(array_search($sd->format('Y-m-d'),$ysm->getHolidayDates()))->getName());
                        }else{
                                HP::pn($sd->format('d日'));
                        }
                        if($sd->isSaturday()){
                                echo '<br>';
                        }
                }
        }
}
class HtmlPrinter{
        private CONST ECHO_DEBUG = true;
        public static function pnr(string $p,string $title = ''):void{
                if(!static::ECHO_DEBUG)return;
                echo '<span title="'.htmlspecialchars($title).'" style="color:red ;">'. htmlspecialchars($p,ENT_QUOTES|ENT_SUBSTITUTE) . "</span>\n";
        }
        public static function pn(string $p):void{
                if(!static::ECHO_DEBUG)return;
                echo "<span>". htmlspecialchars($p,ENT_QUOTES|ENT_SUBSTITUTE) . "</span>\n";
        }
        public static function pp(string $p):void{
                if(!static::ECHO_DEBUG)return;
                echo "<p>". htmlspecialchars($p,ENT_QUOTES|ENT_SUBSTITUTE) . "</p>\n";
        }
        public static function pt(string $p):void{
                if(!static::ECHO_DEBUG)return;
                echo "<pre>". htmlspecialchars($p,ENT_QUOTES|ENT_SUBSTITUTE) . "</pre>\n";
        }
}

```
</div></details>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36304/c53be095-43e6-4d26-2621-dd46e56dc172.png)

1か月を前月と翌月で補完して12か月分表示し
休日に色を付けてマウスカーソルを合わせると休日の名前が出るようになった

##その休日の名前を取得する時癖のあるYasumi

基本的にYasumiはインスタンスを生成するときに年を指定してその年の休日一覧を取得する

```php
$ysm = Yasumi::create('Japan',$c->year,'ja_JP');
foreach($ysm as $holiday) {
        HP::pp($holiday . ':' . $holiday->getName());
}

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36304/abd9a259-bcaf-923d-be49-041f52e36428.png)

よってその日の休日名を取得するときはかなり遠回りをする

```php
$holidays = Yasumi::create('Japan',2021,'ja_JP');
foreach($holidays as $v){
        $ysmDays[$v->__toString()]=$v->getName();
}
echo $ysmDays['2021-01-01'];
//元日
```

結果的に年に依存しており、依存性を解消するため
サンプル内では以下のように取得している

```php
$c = is_null($carbon) ? Carbon::now() : $carbon->copy();
$ysm = Yasumi::create('Japan',$c->year,'ja_JP');
if($ysm->isHoliday($sd)){
   HP::pnr($sd->format('d日'), $ysm->getHoliday(array_search($sd->format('Y-m-d'),$ysm->getHolidayDates()))->getName());
}
```

軽くソースを読むと
https://github.com/azuyalabs/yasumi/tree/develop/src/Yasumi
感覚的にはYasumi->onでDateTimeを渡し
OnFilterで休日であればその祝日のHolidayを返せばいいと思うのだが
Testとか面倒なのでライブラリへのプルリクやめてごり押し実装した。