商売力開発ブログ

非エンジニアがWebサービスの開発、運営によって商売力をつける記録、その他の雑記

【スポンサーリンク】

Laravelのクエリビルダを構築するメソッドの検討 - Select文を作成する①

今回はPHPフレームワークの一つのLaravelの中から、データベースのクエリビルダを自動構築する設定を検討してみたいと思います。具体的には取得条件のテーブルなどの定義情報を渡して、クエリビルダを構築するメソッドを検討します。今回利用するDBはMySQLです。SQLの基本が理解できていることが前提となります。
またこのメソッドに関連する他の記事については以下を参照して下さい。

Laravelのクエリビルダを構築するメソッドの検討 - Select文を作成する②複数の結合条件の対応など - 商売力開発ブログ

クエリビルダを活用する

Laravelではクエリビルダが用意されており、このメソッド使用することでクエリを作成してデータベースを操作することができることは、以前紹介しました。
www.prj-alpha.biz
クエリビルダを利用することで簡単にデータベースからデータを取得できますが、使用頻度が多い場合は毎回記述するとなると結構面倒です。そこでクエリビルダを構築するメソッドを検討したいと思います。今回は簡単なデータの取得の部分、要はSelect文を構築するクエリビルダについて考えていきたいと思います。

クエリビルダとSelect文の構成要素

Select文の構成は簡単なものだと以下のようになります。

SELECT select_list
FROM table_list
[ WHERE search_conditions ]
[ GROUP BY group_by_list ]
[ HAVING search_conditions ]
[ ORDER BY order_list [ ASC | DESC ] ]

今回はこの中で、SELECT、FROMについてクエリビルダを構築するメソッドを検討します。以下のようなSelect文を構成するためのクエリ定義情報を受け取ると、その定義に合わせたクエリビルダを構築するイメージです。

$queryDef=[
   'table' => [],
   'join' => [],
   'select' => [],
];

テーブルの設定と結合条件

まず始めにテーブルの設定に関して考えてみます。クエリビルダで記述する場合、DBファサードに基となるテーブルを設定し、結合を行う場合はjoinやleftJoinメソッドを利用し結合対象のテーブルを指定し、結合条件を記載します。

$query = DB::table('table1');
//内部結合
$query->join('joinTable2', 'table1.col1', '=', 'joinTable2.col1');
//左外部結合
$query->leftJoin('leftTable3', 'table1.col1', '=', 'leftTable3.col1');

ここで考えたいのがテーブル名についてです。結合条件にもテーブル名を持っていますが、これを別名で置き換えるようにします。別名を付けることで、同じテーブルとの結合が複数必要な場合にも対応することができます。例えば、クエリ定義情報のtable設定が以下のようになってるとします。

$queryDef['table']=['table1','joinTable2','leftTable3'];

結合条件にはテーブルのNoを指定して書き換えるようにします。わかりやすくするため、テーブルのプレフィックスも設定します。

//テーブル名のプレフィックス
$prefix = 'tbl';
$query = DB::table($queryDef['table'][0].' as '.$prefix.'0');
//内部結合
$query->join($queryDef['table'][1].' as '.$prefix.'1', $prefix.'0'.'.col1', '=', $prefix.'1'.'.col1');
//左外部結合
$query->leftJoin($queryDef['table'][2].' as '.$prefix.'2', $prefix.'0'.'.col1', '=', $prefix.'2'.'.col1');

この状態でどのようなSQLが発行されるか、確認してみます。以下のtoSqlメソッドで確認することができます。

logger($query->toSql());

この結果は以下のようになりました。

select
  * 
from
  `table1` as `tbl0` 
  inner join `joinTable2` as `tbl1` 
    on `tbl0`.`col1` = `tbl1`.`col1` 
  left join `leftTable3` as `tbl2` 
    on `tbl0`.`col1` = `tbl2`.`col1`

テーブルをクエリ定義情報から設定できるイメージができたので、続いては結合条件の部分です。結合条件には対象のテーブルと、結合するカラムの情報が必要になります。クエリ定義情報のjoin設定を以下のようにします。

$queryDef['join']=[
    [
        'tblNo' => 1,
        'type' => 'join',
        'cond'=>[
            ['leftTblNo' => 0,'leftCol'=>'col1','ope'=>'=','rightTblNo' => 1,'rightCol'=>'col1']
        ]
    ],
    [
        'tblNo' => 2,
        'type' => 'leftJoin',
        'cond'=>[
            ['leftTblNo' => 0,'leftCol'=>'col1','ope'=>'=','rightTblNo' => 2,'rightCol'=>'col1']
        ]
    ],
];

この定義情報から結合するようにしてみます。

//テーブル名のプレフィックス
$prefix = 'tbl';
$query = DB::table($queryDef['table'][0].' as '.$prefix.'0');

for ($i=0; $i < count($queryDef['join']); $i++) {
    //結合するテーブルと別名の設定
    $joinTable = $queryDef['table'][$queryDef['join'][$i]['tblNo']].' as '.$prefix.$queryDef['join'][$i]['tblNo'];
    //左結合カラム
    $leftCol = $prefix.$queryDef['join'][$i]['cond'][0]['leftTblNo'].'.'.$queryDef['join'][$i]['cond'][0]['leftCol'];
    //等号などの演算子
    $operator = $queryDef['join'][$i]['cond'][0]['ope'];
    //右結合カラム
    $rightCol = $prefix.$queryDef['join'][$i]['cond'][0]['rightTblNo'].'.'.$queryDef['join'][$i]['cond'][0]['rightCol'];
    //結合するタイプごとに設定するメソッドを変更する
    if($queryDef['join'][$i]['type']=='join'){
        //join
        $query->join($joinTable,$leftCol,$operator,$rightCol);
    }elseif($queryDef['join'][$i]['type']=='leftJoin'){
        //leftJoin
        $query->leftJoin($joinTable,$leftCol,$operator,$rightCol);
    }
}

この状態でtoSqlメソッドで確認すると同じ結果が得られました。

取得するカラムの設定

取得対象のテーブルの準備ができましたので、続いては取得するカラムの設定です。取得対象となるカラムの情報にはテーブルとカラムの情報が必要です。テーブルはNoを指定するようにします。クエリ定義情報のselect設定を以下のようにします。

$queryDef['select']=[
    [
        'tblNo' => 0,
        'column' => 'col1',
        'alias' => NULL,
    ],
    [
        'tblNo' => 1,
        'column' => 'col2',
        'alias' => 'ColName',
    ],
];

この定義情報からカラムを追加するようにしてみます。

//テーブル名のプレフィックス
$prefix = 'tbl';
$query = DB::table($queryDef['table'][0].' as '.$prefix.'0');

for ($i=0; $i < count($queryDef['join']); $i++) {
    //結合するテーブルと別名の設定
    $joinTable = $queryDef['table'][$queryDef['join'][$i]['tblNo']].' as '.$prefix.$queryDef['join'][$i]['tblNo'];
    //左結合カラム
    $leftCol = $prefix.$queryDef['join'][$i]['cond'][0]['leftTblNo'].'.'.$queryDef['join'][$i]['cond'][0]['leftCol'];
    //等号などの演算子
    $operator = $queryDef['join'][$i]['cond'][0]['ope'];
    //右結合カラム
    $rightCol = $prefix.$queryDef['join'][$i]['cond'][0]['rightTblNo'].'.'.$queryDef['join'][$i]['cond'][0]['rightCol'];
    //結合するタイプごとに設定するメソッドを変更する
    if($queryDef['join'][$i]['type']=='join'){
        //join
        $query->join($joinTable,$leftCol,$operator,$rightCol);
    }elseif($queryDef['join'][$i]['type']=='leftJoin'){
        //leftJoin
        $query->leftJoin($joinTable,$leftCol,$operator,$rightCol);
    }
}

for ($i=0; $i < count($queryDef['select']); $i++) { 
    //テーブルとカラムの設定
    $addCol=$prefix.$queryDef['select'][$i]['tblNo'].'.'.$queryDef['select'][$i]['column'];
    //別名の設定
    if(!empty($queryDef['select'][$i]['alias'])){
        //別名を設定する
        $addCol=$addCol.' as '.$queryDef['select'][$i]['alias'];
    }
    //カラムの設定
    $query->addSelect($addCol);
}

この状態でtoSqlメソッドで確認すると以下の結果が得られました。

select
  `tbl0`.`col1`
  , `tbl1`.`col2` as `ColName` 
from
  `table1` as `tbl0` 
  inner join `joinTable2` as `tbl1` 
    on `tbl0`.`col1` = `tbl1`.`col1` 
  left join `leftTable3` as `tbl2` 
    on `tbl0`.`col1` = `tbl2`.`col1`

問題なく別名も設定されました。

まとめ

今回はLaravelのデータベースのクエリビルダについて、定義情報から構築する方法を検討しました。
ここまではSelectを行うのに最低限の設定となります。この他の設定については、また別の機会で紹介します。

以上

【関連するリンク】 www.prj-alpha.biz www.prj-alpha.biz

Laravelのクエリビルダの基本機能を確認する

今回はPHPフレームワークの一つのLaravelの中から、データベースのクエリビルダの基本機能について確認します。今回利用するDBはMySQLです。

クエリビルダの基本

Laravelではクエリビルダが用意されており、このメソッド使用することでクエリを作成してデータベースを操作することができます。
クエリビルダを使用するにはDBファサードをuseしておく必要があります。

use DB;

まずDBファサードのtableメソッドを使用して取得したテーブル名を指定します。以下ではusersテーブルを指定してます。

$users = DB::table('users');

指定したテーブルのレコードを取得するには、getメソッドを使用します。getメソッドによりSelectされることになります。上記のクエリビルダインスタンスを使用する場合、以下のようにして取得できます。

$records = $users->get();

この場合、usersテーブルが全件取得されます。取得されたレコードは、StdClassオブジェクトのインスタンスを結果として含むCollectionオブジェクトとして返ってきます。以下では取得した結果の最初のデータのname(usersテーブルのnameカラム)を表示します。

echo $records[0]->name;

その他の基本構文

ここまでSelectを行うのに必要最低限のコードを確認しました。ここからSelectを行う際に良く使うメソッドを確認していきます。共通で以下のテーブルを使用するものとします。

$query = DB::table('table1');

取得するカラムを指定する

Selectする際に必要なカラムを指定する場合、selectメソッドやaddSelectメソッドで対応することができます。取得したいカラム名を渡すことが指定されます。両方のメソッドとも複数のカラム名を指定できます。

$query->select('col1','col2');
//ここでgetを行うと、2列取得されます

$query->addSelect('col3');
//ここでgetを行うと、3列取得されます

$query->select('col1','col2')->select('col1');
//ここでgetを行うと、1列取得されます

$query->select('col1');
$query->addSelect('col2','col3');
//ここでgetを行うと、3列取得されます

ちなみにカラム名に別名をつけたい場合は以下のようになります。

$query->select('col1','col2 as name2');
$query->addSelect('col3 as name3');

SQL文をそのまま使用する

selectメソッドでカラム名を指定して取得しましたが、関数や算出を行いたいなどSQLを直接使用したい場面もあります。そのようなときにはDB::rawメソッドを使用することで対応することができます。

$query->select(DB::raw('col1, CONCAT(col2,col3) as col23'));
//以下は上と同じとなります
$query->select('col1',DB::raw('CONCAT(col2,col3) as col23'));

DB::rawメソッドを使用して書きましたが、クエリのそれぞれに対応したrawメソッドが用意されています。
selectの部分についてはselectRawメソッドが用意されています。selectRawはaddSelect(DB::raw(...))と同じです。

$query->select(DB::raw('col1, CONCAT(col2,col3) as col23'));
//以下は上と同じとなります
$query->select('col1'));
$query->selectRaw('CONCAT(col2,col3) as col23'));
//以下も上と同じとなります
$query->select('col1'));
$query->addSelect(DB::raw('CONCAT(col2,col3) as col23'));

rawメソッドはそのままクエリとして実行されるので、SQLインジェクションが発生しないように気を付けましょう。

JOINを設定する

テーブルを結合する場合、内部結合がjoinメソッド、左外部結合がleftJoinメソッドが用意されています。テーブル名と結合条件を指定することができます。

//内部結合
$query->join('table2', 'table1.col1', '=', 'table2.col1')
    ->join('table3', 'table1.col2', '=', 'table3.col2');
//左外部結合
$query->leftJoin('table4', 'table1.col1', '=', 'table4.col1')
    ->leftJoin('table5', 'table1.col2', '=', 'table5.col3');

テーブルの結合条件が複数ある場合は、第2引数にクロージャを指定して設定することができます。

$query->join('table2', function($join){
    $join->on('table1.col1','=','table1.col1');
    $join->on('table1.col2','=','table1.col2');
});

ちなみにLaravel5.6ではサブクエリのJOINにも対応できるようになったようです。

WHEREを設定する

WHERE句についてはいくつものメソッドが用意されています。一番基本はwhereメソッドです。

$query->where('col1','=',0);
$query->where('col2','>',0);
$query->where('col3','<>',0);
$query->where('col4','like','%1');

この書き方やチェーンでつなげるとANDでのWHERE句になります。ORで対応したい場合はorWhereメソッドを使います。
この他にwhereBetween、whereIn、whereNotIn、whereNull、whereNotNull、whereRaw、orWhereRawなどがあります。

クエリビルダをどのように活用するか

クエリビルダを利用して簡単なSelectを行う方法は確認できました。SQLがわかっている人であれば、特に難しいことなく取得するコードを記述できると思います。
ただデータベースからSelectを行なおうとする度にこれらの構文を記述するのは結構面倒です。なので我々は、取得したいテーブル、結合条件、取得対象カラム、抽出条件などの定義情報を引数として渡すと、Select結果が返ってくるような関数やメソッドを定義して取得するようにしています。このあたりの設定例については、機会があれば別途紹介したいと思います。
※以下の記事で紹介しています。

Laravelのクエリビルダを構築するメソッドの検討 - Select文を作成する① - 商売力開発ブログ
Laravelのクエリビルダを構築するメソッドの検討 - Select文を作成する②複数の結合条件の対応など - 商売力開発ブログ

まとめ

今回はLaravelのデータベースのクエリビルダの基本機能のうち主にSelectの方法について確認しました。

以上
【関連するリンク】
www.prj-alpha.biz
www.prj-alpha.biz

はてなブログをHTTPS化した後の、Search Console の状態を確認する

今回は、はてなブログをHTTPS化した後のグーグルの Search Console の状態を紹介します。

HTTPS化した後の状態

はてなブログをHTTPS化しても、その直後はグーグル検索の結果はHTTPのURLが表示されますが、それが徐々にHTTPSに置き換わっていきます。その状況がグーグルの Search Console のインデックスの状態として確認できます。
以前に書いた以下のブログではHTTPS化した場合、 Search Console のアドレス変更で対応できるような記載をしていましたが、HTTPS化のみの場合はできませんでした。

www.prj-alpha.biz

Search Console のアドレス変更はできませんので、基本的にはインデックスが移行されるのをただ待つということになります。
ちなみにグーグル検索の結果がHTTPのURLの状態でも、はてなブログが自動で301リダイレクトしてHTTPSのURLへアクセスすることになります。301リダイレクトが分からない人は以下を参考にして下さい。

www.prj-alpha.biz

Search Console での確認

6月中旬にHTTPS化してからの状態を示します。ベータ版ですが新しい Search Console での表示結果を加工したもので示します。上がHTTPで下がHTTPSの表示結果となります。棒グラフがインデックスに登録されたページ数で、折れ線グラフは表示回数です。HTTP化を変更してから少しずつインデックスが移行されているのが分かります。

こちらも上がHTTPで下がHTTPSの表示結果となります。クリック回数の状況で、青がクリック回数で、ターコイズブルーが表示回数です。インデックスが移行されるにつれて、上のHTTPの表示回数とクリック回数が減っていき、HTTPSの方が増えていってます。注目したいのがクリック数と表示回数の目盛りの値です。HTTPSの方がどちらも3倍以上になっています。変更日以降に記事の数は多少増えてはいえますが、それ以上の伸び率です。HTTPSになってから、グーグル検索からのアクセスが大幅に伸びました。

ちなみにインデックスカバレッジでその「有効」と「除外」の内容のページがわかります。以下はHTTPSの方ですが、重複している部分が0となっていれば、移行がほぼ完了したものと思われます。

こちらはHTTPの方です。リダイレクトや重複しているページが増加してます。こちらをクリックすると移行されたページの情報が分かります。

HTTPS化してから約2か月かかってますね。早いのか遅いのか・・・URL変更の時はアドレス変更依頼をすることで一週間程度で移行できてたので、それと比べると大分時間がかかってますね。

Fetch as Google でリクエストすることもできる

Fetch as Google を利用して、インデックス登録をリクエストすることもできます。
移行に時間がかかっていたので試しにリクエストしてました。これにより大きな効果があるという感触はあまり得られませんでした。リクエストしたページは数日経つと移行されるものもあれば、なかなか移行されないものもありました。以下はHTTPSでのリクエストの画面です。

こちらはHTTPでの画面です。ステータスは「リダイレクトされました」となっており、インデックス登録を依頼するとリダイレクトページとして認識されるようです。

まとめ

今回ははてなブログをHTTPS化した後のグーグルの Search Console の状態の紹介でした。

以上

【関連するリンク】

www.prj-alpha.biz

www.prj-alpha.biz

www.prj-alpha.biz

はてなブログの Search Console がエラーとなってたので対処する

今回ははてなブログの Google Search Console の状態がエラーとなっていたので、それの対処方法を説明します。

Google Search Console が突然エラーとなる

Google Search Console をホーム画面を確認すると、HTTPS化したはてなブログに「未確認」というマークが付いていて、Google Search Console が機能していない状態となっていました。

この一覧を見ると分かる通り、HTTPS化した方だけが「未確認」となっており、HTTPの方はエラーとはなっていません。はてなブログ側も Google Search Console も特に設定を変更していないのに、この状態になっていました。
とりあえずクリックして状態を確認してみると、内部エラーが発生しているとのことでした。ちなみに確認方法ははてなブログでは一般的なメタタグによるものです。

履歴を見ると、5日前から内部エラーが発生しています。ちなみにこの内部エラーが出ていた期間も Google Search Console は問題なく利用できていました。約5日間など一定期間で解決しないと、最終的に使用できない状態になるようです。
また Analytics の Search Console の部分を見ると、2日前からクリック数が取れなくなっていました。このあたりで関連付けの設定が切れたのかもしれません。

メタタグを使用しての確認を再度行ってみます。ちなみにこの確認に際して、はてなブログと Google Search Console については何の設定変更もしていません。

問題なく確認がされました。

一覧画面でも「未確認」が消えてます。

※追記 更に Google Analytics と Google Search Console の関連付けが消えている場合があります。

Google Analytics を利用していて関連付けを行っていた場合、今回の事象により関連付けが消えていることがあります。この場合は Google Search Console で再度関連付けを行って下さい。

突然エラーとなった理由は不明

今回設定を何も変更してないのにエラーとなった理由はわかりませんでした。対処方法自体は簡単ですが、気がかりなのはエラーとなってもGoogleからは何の通知もなかったことです。 Google Search Console の画面を起動して、「未確認」となっている状態を見て、初めて気が付きました。そこまで頻繁に確認しないので、気付くのがかなり遅くなるかもしれません。

まとめ

今回は Google Search Console の状態がエラーとなっていたので、それの対処方法を説明しました。

以上

開始と終了日付から稼働日数(営業日数)を算出してみる

今回は、開始日付と終了日付から、その期間の稼働日数(営業日数)を算出してみます。ロジックを考えることがメインですが、コードはJavaScriptで記載します。

算出するための条件

稼働日数を算出するのに、土日など週の中での定休日と祝日について考慮する必要があります。今回は以下の条件で考えてみます。

  • 週の定休日となる曜日を自由に指定できる。
  • 祝日となる日付を自由に指定できる。

今回は開始日付が終了日付以下の関係が担保された状態のものとし、このチェックロジックは含めません。

ロジックの検討

開始日付と終了日付からの単純な期間を求める場合、JavaScriptではDateオブジェクトのタイムスタンプの差分で算出します。開始日付と終了日付が同じ場合、1日と考えると以下のようになります。

    var beginDate = new Date('2018/08/01');
    var endDate = new Date('2018/08/02');
    //開始と終了日付のタイムスタンプ
    var beginTime = beginDate.getTime();
    var endTime = endDate.getTime();
    //時間差を算出
    var diff = endTime - beginTime;
    //時間差をミリ秒単位を日単位に変換し(切り捨て)、1日分を加算
    var term = Math.floor(diff / (24 * 60 * 60 * 1000)) + 1;

開始日付から終了日付の間の各日付について、定休日となる曜日か、または祝日かを判定していくことで稼働日数を算出することも可能ですが、無駄な部分も多いので定休日の判定と祝日の判定を別けて対応します。これらを大きく別けると以下のようになります。

  1. 開始日付と終了日付の期間となる日数を算出する(上記で算出済み)。
  2. 対象期間の中で定休日となる日数を算出する。
  3. 対象期間の中で祝日となる日数を算出する。
  4. 対象期間から定休日となる日数と祝日となる日数を差し引いて、稼働日数を算出する。

定休日となる日数を算出する

ここでの定休日は曜日を指定してのものです。例えば土日などです。この指定した曜日の数が、一週間での定休日の日数となります。ある期間に含まれる週の数と一週間の定休日数を掛ければ簡単に求められことになります。ただし、割り切れない余りについては、個別に判定する必要があります。これらを順に行っていきます。

  1. 一週間の定休日の日数を算出する。
  2. 対象期間に含まれる週数を算出して、週数分の定休日の日数を算出する。
  3. 対象期間の中で上記の週数に含まれない余りを算出して、その余りの日数に含まれる定休日の日数を算出する。

JavaScriptではDateオブジェクトの曜日は、0が日曜日で順に連番され、6が土曜日という数値になります。定休日となる設定はこれらの数値を配列で保持しているものとします。

    //定休日となる曜日の設定
    var regularDayOff = [0,6];
    //一週間の定休日の数
    var lenDayOff = regularDayOff.length;

上で算出している開始日付から終了日付の対象期間を7で割った商がその期間に収まる週の数となります。そして余りの日数については、日毎に判定する必要があります。今回は余りが出た場合は開始日付から、その余りの日数分だけ曜日の判定を行うようにしてみます。(終了日付から、その余りの日数分だけ戻って判定しても良い)

    //期間に入る週の数、7で割って切り捨てて算出する
    var weeks = Math.floor(term / 7);
    //週の数から、その期間の定休日の休日数を算出する
    var dayOffs = weeks * lenDayOff;

後は余り日数の部分を開始日付から曜日の判定を行います。余りと曜日の判定は剰余演算子を使用します。JavaScriptでは「%」です。

    //週の数に入らない余りの日数
    var remainderDays = term % 7;
    //余りの日の処理
    if(remainderDays>0){
    	//余りの日がある場合、開始日付から余りの日数だけ曜日が定休日かの判定を行う
    	//開始日付の曜日数値の取得
    	var beginDay = beginDate.getDay();//0~6の曜日数値
    	for(var i = 0; i < remainderDays; i++){
    	    //曜日数値に余りの日数を加算していき、7で割った余りの曜日数値が定休日の配列に含まれるか
            if(regularDayOff.indexOf((beginDay + i) % 7) != -1){
                //定休日の配列に含まれる場合、休日数に加算する
                dayOffs++;
            }
    	}
    };

これで、対象期間に含まれる定休日の日数が算出できました。

祝日となる日数を算出する

続いて対象期間に含まれる祝日の日数を算出します。祝日は自由に指定できる想定ですが、それらを配列で設定したものとします。まず祝日の一覧と開始日付、終了日付を比較できるようにするためタイムスタンプに変換します。そのタイムスタンプと開始日付と終了日付を比較して日数を算出します。

  1. 祝日の一覧をタイムスタンプに変換する。
  2. 祝日の一覧から開始日付のタイムスタンプより大きく、終了日付のタイムスタンプより小さい祝日を探し、カウントする。

祝日は「YYYY/MM/DD」の形式で配列で保持しているものとします。

    //祝日の設定
    var holidayDates = ['2018/01/01','2018/01/02','2018/01/09'];

この祝日の一覧をタイムスタンプに変換するのですが、いくつか処理を検討します。まずこの祝日の一覧ですが、ソートされていない状態のもであればソートします。ソートしておくことで日付の比較を行う際に終了日付より大きくなったところで、それ以後は比較する必要がなくなります。
続いて祝日と定休日の問題です。祝日の中に定休日となる曜日の日付が含まれている場合、定休日の処理と合わせてカウントされてしまいます。よって定休日の曜日に含まれる日付について除いたものだけをタイムスタンプにした配列を作成して比較に使用します。

    //祝日をソートする
    holidayDates.sort();

    //祝日のタイムスタンプの配列
    var holidayTime=[];
    
    for(var i = 0; i < holidayDates.length; i++){
        //日付オブジェクトを設定する
        var dateObj = new Date(holidayDates[i]);
        if(regularDayOff.indexOf(dateObj.getDay())==-1){
            //定休日の曜日に存在しない場合、祝日のタイムスタンプの配列に追加する
            holidayTime.push(dateObj.getTime());
        }
    }

祝日のタイムスタンプ一覧ができたら、日付の比較を行いカウントします。祝日のタイムスタンプ一覧から、開始日付のタイムスタンプより大きい祝日があったら以後は終了日付のタイムスタンプより小さい祝日をカウントすることで祝日の日数を求めることができます。

    //祝日のカウント用
    var holidays=0;

    //開始日付より大きいかのフラグ
    var flgBegin=false;
    
    for(var i = 0; i < holidayTime.length; i++){
        //開始日付のフラグにより処理を変える
        if(flgBegin == false){
            //開始日付より大きくない状態
            if(beginTime <= holidayTime[i]){
                //祝日が開始日付より大きい場合、フラグを設定する
                flgBegin=true;
                if(holidayTime[i] <= endTime){
                    //終了日付より小さい場合、対象期間の範囲内なので加算する
                    holidays++;
                }else{
                    //終了日付より大きい場合、対象期間の範囲外なのでループを抜け出す
                    break;
                }
            }
        }else{
            //開始日付より大きい状態
            if(holidayTime[i] <= endTime){
                //終了日付より小さい場合、対象期間の範囲内なので加算する
                holidays++;
            }else{
                //終了日付より大きい場合、対象期間の範囲外なのでループを抜け出す
                break;
            }
        }
    }

以上で対象期間とその期間に含まれる定休日の日数と祝日の日数の算出ができました。後は差引した結果が稼働日数となります。

    //稼働日数の算出
    var workingDay = term - dayOffs - holidays;

稼働日数の算出ができたので利用しやすい形式に関数などを設定して下さい。

まとめ

今回は稼働日数(営業日数)の算出ロジックを考えてみました。

以上

【マニュアル】新規アカウントの作成について

※Project-Alphaは2019年12月をもって、サービスの提供を終了します。

今回は我々が開発しているプロジェクト管理ツールProject-Alpha(プロジェクトアルファ)の操作マニュアルとなります。

新規アカウントの作成について

新規のアカウント作成を行うと、設定用のメールが送信されます。

送信されたメールの手順に従って、アカウントの登録が完了すると、初期画面ではプロジェクトの作成画面に移動します。もちろんここで作成しないで後から作成することができます。

プロジェクトを作成すると、作成したプロジェクトの設定画面に移動します。

特に設定の変更が必要無い場合、プロジェクトホームのメニューを選択します。

ホーム画面からはいくつかのリンクからガントチャートに移動することができます。

利用プランの変更について

初期の状態ではプロジェクトは、上限により1つしか作成することができません。プロジェクトが完了するまで追加できませんが、利用プランを変更することで上限が変更され、プロジェクトを追加することができるようになります。これにより複数のプロジェクト管理とガントチャートに対応することができるようになります。また登録可能なメンバーの人数についても上限がありますが、同様に利用プランを変更することで上限が変更されます。
現在、利用プランの変更は無料で行うことができます。

登録可能状況の確認

メニューからそれぞれの状況の確認をすることができます。メンバーについては管理者メニューを選択するとメンバー管理が表示され、そこから上限や登録可能な人数を確認することができます。内部と外部で登録可能な上限が区分けされます。

プロジェクトについては、プロジェクト作成を選択すると追加画面が表示され、追加できない状態の場合、その旨を示すメッセージが表示されます。そこから利用状況を選択するとプロジェクトの利用状況が表示され上限や登録可能なプロジェクト数を確認することができます。

利用プランの変更

管理者メニューの中にある、利用プランを選択します。

利用プラン設定で現在のプランタイプが表示されます。初期はフリーのプランとなっていますので、こちらを変更して新しい利用プランに変更して下さい。メンバーやプロジェクトを追加することが可能となります。

以下はスタンダードに変更した場合です。スタンダードに限らずどのプランにも無料で変更できるようになっています。

以下は利用プランを変更後のメンバーの利用状況になります。上限が増加しているのがわかります。

利用プランを変更後のプロジェクト作成と利用状況の例です。上限が増加しているのがわかります。

まとめ

今回は新規アカウント登録時の操作マニュアルの説明でした。

以上

【関連するリンク】 

www.prj-alpha.biz

home.prj-alpha.biz

Google API を利用して、PHPで日本とアメリカの祝日を取得する

今回はGoogleのカレンダーAPIを利用して、PHPで日本とアメリカの祝日を取得する方法を紹介します。

GoogleAPIを利用する

GoogleのカレンダーAPIを利用するには、Googleのアカウントを作成して、Google Developers Console でAPIを利用できるように設定する必要があります。この辺りの手順は以下を参考にして下さい。

Google Calendar API を使って祝日を取る PHP編 - Qiita

ここにあるPHPのAPIのコードも参考にしましょう。

    $api_key = '取得したAPIキー';
    $holidays_id = 'japanese__ja@holiday.calendar.google.com';
    $holidays_url = sprintf(
        'https://www.googleapis.com/calendar/v3/calendars/%s/events?'.
        'key=%s&timeMin=%s&timeMax=%s&maxResults=%d&orderBy=startTime&singleEvents=true',
        $holidays_id,
        $api_key,
        $start_date,
        $end_date,
        30  
    );

    if( $results = file_get_contents($holidays_url, true))
    {
        $results = json_decode($results);
        $holidays = array();
        foreach($results->items as $item)
        {
            $date = strtotime((string) $item->start->date);
            $title = (string) $item->summary;
            $holidays[date('Y-m-d', $date)] = $title;   
        }
        ksort($holidays);   
    }

カレンダーを指定して日本とアメリカの祝日を取得する

「$holidays_url」となっている部分で取得対象を指定することになります。

    $holidays_url = sprintf(
        'https://www.googleapis.com/calendar/v3/calendars/%s/events?'.
        'key=%s&timeMin=%s&timeMax=%s&maxResults=%d&orderBy=startTime&singleEvents=true',
        $holidays_id, //取得元のカレンダーID
        $api_key, //取得したAPIキー
        $start_date, //取得開始日付
        $end_date, //取得終了日付
        30  //最大取得日数
    );

取得する開始日付と終了日付については、いったんは今年1年間となるように設定してみます。

    $year = date(Y);
    $start_date = date($year."-01-01\T00:00:00\Z"); //取得開始日付
    $end_date  = date($year."-12-31\T00:00:00\Z"); //取得終了日付

「$holidays_id」に設定するカレンダーによって取得される祝日が変わってきます。「japanese__ja@holiday.calendar.google.com」を指定すると以下のような日付データが取得できました。これは日本の祝日になっています。

No 日付 名称
1 2018/01/01 元日
2 2018/01/08 成人の日
3 2018/02/11 建国記念の日
4 2018/02/12 建国記念の日 振替休日
5 2018/03/21 春分の日
6 2018/04/29 昭和の日
7 2018/04/30 昭和の日 振替休日
8 2018/05/03 憲法記念日
9 2018/05/04 みどりの日
10 2018/05/05 こどもの日
11 2018/07/16 海の日
12 2018/08/11 山の日
13 2018/09/17 敬老の日
14 2018/09/23 秋分の日
15 2018/09/24 秋分の日 振替休日
16 2018/10/08 体育の日
17 2018/11/03 文化の日
18 2018/11/23 勤労感謝の日
19 2018/12/23 天皇誕生日
20 2018/12/24 天皇誕生日 振替休日

続いて「japanese__en@holiday.calendar.google.com」を指定すると以下のような日付データが取得できました。これは英語での日本の祝日になっています。

No 日付 名称
1 2018/01/01 New Year's Day
2 2018/01/08 Coming of Age Day
3 2018/02/11 National Foundation Day
4 2018/02/12 National Foundation Day observed
5 2018/03/21 Spring Equinox
6 2018/04/29 Shōwa Day
7 2018/04/30 Shōwa Day observed
8 2018/05/03 Constitution Memorial Day
9 2018/05/04 Greenery Day
10 2018/05/05 Children's Day
11 2018/07/16 Sea Day
12 2018/08/11 Mountain Day
13 2018/09/17 Respect for the Aged Day
14 2018/09/23 Autumn Equinox
15 2018/09/24 Autumn Equinox observed
16 2018/10/08 Sports Day
17 2018/11/03 Culture Day
18 2018/11/23 Labor Thanksgiving Day
19 2018/12/23 Emperor's Birthday
20 2018/12/24 Emperor's Birthday observed

「usa__ja@holiday.calendar.google.com」を指定すると以下のような日付データが取得できました。これはアメリカの祝日になっていますが、一部祝日でない日付も含まれています。また日本語ではなく英語でした。

No 日付 名称
1 2018/01/01 New Year's Day
2 2018/01/15 Martin Luther King Jr. Day
3 2018/02/14 Valentine's Day
4 2018/02/19 Presidents' Day (regional holiday)
5 2018/03/11 Daylight Saving Time starts
6 2018/03/17 St. Patrick's Day
7 2018/04/01 Easter Sunday
8 2018/04/17 Tax Day
9 2018/05/05 Cinco de Mayo
10 2018/05/13 Mother's Day
11 2018/05/28 Memorial Day
12 2018/06/17 Father's Day
13 2018/07/04 Independence Day
14 2018/09/03 Labor Day
15 2018/10/08 Columbus Day (regional holiday)
16 2018/10/31 Halloween
17 2018/11/04 Daylight Saving Time ends
18 2018/11/11 Veterans Day
19 2018/11/12 Veterans Day observed
20 2018/11/22 Thanksgiving Day
21 2018/11/23 Black Friday
22 2018/12/24 Christmas Eve
23 2018/12/25 Christmas Day

Googleカレンダーでアメリカの祝日を選択すると上記と同じものが取得されるので、APIでもこのような英語での日付データとなります。これは「usa__en@holiday.calendar.google.com」を指定した場合も同様のデータとなります。アメリカの祝日に関してはAPIで取得したままだと、余計な日付が含まれてしまうので少し工夫をする必要がありそうです。またアメリカ以外の外国を選択した場合も、同様の状態がありえそうです。

まとめ

今回はGoogleのカレンダーAPIを利用して、PHPで日本とアメリカの祝日を取得する方法を紹介しました。

以上
【関連するリンク】
www.prj-alpha.biz

【スポンサーリンク】