昨夜から、vagrantの動作を本書で提供されている環境を元に追いかけていました。とても分りやすく、無駄なコメントとかを取り除いてくれているので、読みやすいです。

しかし、分からない部分もあります。そこらへんも追いかけてみたいのですが、とりあえずカレンダーを完成させてしまいしょう。

ちなみに本書での環境では毎回vagrant upする必要があります。いちいちコマンドプロンプトを立ち上げてコマンドを打つのも面倒なので、batファイルを二つ作りました。いや、大げさでなくたった2行のテキストファイルです。

【vagrantup.bat】

cd c:\donichi\fuelphp-1.7.3\vagrant
vagrant up

【vagranthalt.bat】

cd c:\donichi\fuelphp-1.7.3\vagrant
vagrant halt

batファイルの置き場所は、どこでも、叩きやすい場所に置けばいいかと思います。このあたり、どこか本書にもっといい方法が書いてあったかも知れません。

さて、コントローラにボタンをクリックしたときにキックする新しいアクションを書いたところまでやりました。ボタンを押下したときにまずやりたいのが、年の入力ボックスが、空白でないか、ちゃんと西暦を表しているか、をチェックすることです。

このチェックの方法はjavascriptを使うなどして、サーバに負担をかけずにやることもできますし、FuelPHPが持っているValidationクラスを使ってやることもできます。他にもあるみたいです。

ちょっと前まではonsubmitでjavascriptを呼び出し、無駄な通信をさせない、というのを自分のスタイルにしておりました。

フレームワークが充実してきて、ネットの通信スピードも阿保かっつうくらいに早くなり(まだまだ早くなるらしいっすね。。)、あまり通信にかかる負荷を気にすることもなくなった今、例えば本書で扱っているFuelPHPのValidationクラスなどは、実はとても書きやすいものです。

私もFuelPHPではValidationクラスを使います。

実はValidationクラスを使うと、いちいちPOSTデータを取得するという必要がなくなります。Validationクラスがその機能を内包しているからです。あ、言い切るほど中身を知らないのですが、そうとしか思えない動きをします。

まず、Validationクラスのインスタンスを作成します。

    public function action_putbutton(){
        $val = Validation::forge();
    }

このインスタンスにPOSTで送られてくるどの値をどのようなチェックをするのか、という情報を持たせます。

ここでは、チェック方法は

required           必須チェック

match_pattern   西暦の形が入力されているかチェック

の二種類を作成することにします。チェックする対象は年だけです。

FuelPHPのValidationクラスへの情報のセットの仕方は何種類かありますが、個人的にはaddとadd_ruleを連ねて書くのがお勧めです。

public function action_putbutton(){
    $val = Validation::forge();
    $val->add(“year”,”年”)->add_rule(“required”)->add_rule(“match_pattern”,”/^[1-9][0-9][0-9][0-9]”,”西暦”);
}

あ、これまだ動作チェックしてないんで、不確かですけどね、書いた順にお見せしましょう。エラーになったらどのように修正していくかまで、お見せします。NetBeans上でエラーが出ていないので、構文的には大丈夫そうではありますが。。

ここまで書いたら、それぞれのチェックに引っかかったときに表示するメッセージをセットします。

public function action_putbutton(){
    $val = Validation::forge();
    $val->add(“year”,”年”)->add_rule(“required”)->add_rule(“match_pattern”,”/^[1-9][0-9][0-9][0-9]”,”西暦”);
    $val->set_message(“required”,”:labelは必須項目です。”);
    $val->set_message(“match_pattern”,”:labelは数字4桁で入力してください。”);
}

で、この後、チェックを実行します。

    public function action_putbutton(){
        $val = Validation::forge();
        $val->add(“year”,”年”)->add_rule(“required”)->add_rule(“match_pattern”,”/^[1-9][0-9][0-9][0-9]”,”西暦”);
        $val->set_message(“required”,”:labelは必須項目です。”);
        $val->set_message(“match_pattern”,”:labelは数字4桁で入力してください。”);
        
        if($val->run()){
            
        } else {
            
        }
    }

run()でチェックを実行しますが、その結果がtrueであればチェックにかからなかったのでカレンダーを表示、elseに入ってきてしまう場合は年が西暦の形をなしていないので、カレンダーを表示せず、エラーのメッセージを表示します。

引っかかった時の処理は少し違った視点が必要なので、先に正常系から作ってしまいましょう。

public function action_putbutton(){
    $val = Validation::forge();
    $val->add(“year”,”年”)->add_rule(“required”)->add_rule(“match_pattern”,”/^[1-9][0-9][0-9][0-9]”,”西暦”);
    $val->set_message(“required”,”:labelは必須項目です。”);
    $val->set_message(“match_pattern”,”:labelは数字4桁で入力してください。”);
        
    if($val->run()){
        $this->template->content->set_safe(‘cal_body’,$this->cal_body($val->input[‘year’], $val->input(‘month’)));
        $this->template->content->set_safe(‘options’,$this->makeOptions($val->input(‘month’)));
    } else {
            
    }
}

ここまで書いて実行したらエラーしてしまいました。

$val->run()がエラーしてます。どうやらmatch_patternがエラーしているようです。

public function action_putbutton(){
    $val = Validation::forge();
    $val->add(“year”,”年”)->add_rule(“required”)->add_rule(“match_pattern”,”/^[1-9][0-9][0-9][0-9]$/”,”西暦”);
    $val->set_message(“required”,”:labelは必須項目です。”);
    $val->set_message(“match_pattern”,”:labelは数字4桁で入力してください。”);
        
    if($val->run()){
        $this->template->content->set_safe(‘cal_body’,$this->cal_body($val->input[‘year’], $val->input(‘month’)));
        $this->template->content->set_safe(‘options’,$this->makeOptions($val->input(‘month’)));
    } else {
            
    }
}

match_patternに与えるパターンを丁寧に書き直しました。

エラーの内容が変わりました。ちゃんとrun()は動いたようです。しかも、ちゃんと正常系に入って、そこでエラーしているように思えます。

で、エラーを見ると、マヌケなエラーしてますね。直しましょう。

public function action_putbutton(){ 
    $val = Validation::forge();
    $val->add(“year”,”年”)->add_rule(“required”)->add_rule(“match_pattern”,”/^[1-9][0-9][0-9][0-9]$/”,”西暦”);
    $val->set_message(“required”,”:labelは必須項目です。”);
    $val->set_message(“match_pattern”,”:labelは数字4桁で入力してください。”);
    $this->template->title = ‘祝!フロイデさん31期!’;
    if($val->run()){
        $data[“month”] = date(“F”,mktime(0,0,0,$val->input(“month”),1,$val->input(“year”)));
        $data[“today”] = date(“Y/m/d”);
        $data[“year”] = $val->input(“year”);
            
        $this->template->content = View::forge(‘calendar/index’,$data);
        $this->template->content->set_safe(‘cal_head’,$this->cal_header());
        $this->template->content->set_safe(‘cal_body’,$this->cal_body($val->input(‘year’), $val->input(‘month’)));
        $this->template->content->set_safe(‘options’,$this->makeOptions($val->input(‘month’)));
            
    } else {
            
    }
}

こんな感じになりました。形としてはaction_indexと変わりませんが、当年当月ではなく、入力された年月を元に年月を作っている、というところが違うだけです。

動作としては

初期表示

翌月(8月)を選択して表示ボタンを押してみましょう。月曜日から1日が始まるはずですよね。

出来てます。

動きとしては正しく出来てます。しかし、action_indexとaction_putbuttonでは渡す値が違うだけで同じことをやっています。決して効率が良いとは言えません。プログラムはなるべく重複した記述をなくす、というのがポイントです。次回、目指してみましょう。完成までなかなかいきませんね。

その前に、実はここまででバグあります。7月も8月も31日なので上記の動作確認では現れませんが、試しに9月を選択して表示してみます。

カレンダーとしては合っていそうですが、最後の空白が罫線がありませんね。

では2月は?

やはり、カレンダーとしては良さそうですが、最後の空白が罫線がありません。

それもそのはず、空白部分を作っているfunctionを見てみましょう。

private function spacecell($count){
    $tmp_cell = “”;
    for($i = 0 ; $i < $count ; $i++){
         $tmp_cell .= “<td></td>”;
    }
    return $tmp_cell;        
}

渡された数だけ空白のセルを作って返す単純な作りです。では、これを呼び出している部分、

private function cal_body($year,$month){
    $cal_body = “”;
    $date = mktime(0,0,0,$month,1,$year);
        
    for($i = 0 ; $i < date(“t”,$date); $i++){
        $week_number = date(“w”,mktime(0,0,0,$month,$i+1,$year));
        if($week_number == 0 && $i != 0){
            $cal_body .= “<tr>”;
        } else if($i == 0){
            $cal_body .= $this->spacecell($week_number);
        }
        $cal_body .= “<td>” . ($i + 1) . “</td>”;
        if($week_number == 6){
            $cal_body .= “</tr>”;
        }
        if(($i + 1) == date(“t”)){
            $cal_body .= $this->spacecell(6 – $week_number);
        }
    }
    return $cal_body;
}

最後のif文

 if(($i + 1) == date(“t”)){ このdate(“t”)が間違いでした。これは当年当月が何日あるかを返すので、これを指定した年月が何日あるのかを返すように修正する必要があります。

実は上のfor文ですでに修正しています。if文は単なる修正漏れです。

private function cal_body($year,$month){
    $cal_body = “”;
    $date = mktime(0,0,0,$month,1,$year);
        
    for($i = 0 ; $i < date(“t”,$date); $i++){
        $week_number = date(“w”,mktime(0,0,0,$month,$i+1,$year));
        if($week_number == 0 && $i != 0){
            $cal_body .= “<tr>”;
        } else if($i == 0){
            $cal_body .= $this->spacecell($week_number);
        }
        $cal_body .= “<td>” . ($i + 1) . “</td>”;
        if($week_number == 6){
            $cal_body .= “</tr>”;
        }
        if(($i + 1) == date(“t”,$date)){
            $cal_body .= $this->spacecell(6 – $week_number);
        }
    }
    return $cal_body;
}

2月は

うるう年ではない2月を表示してみましょう。

なんかきれいに収まってますね。ほんとかな。

Windowsのカレンダーで調べたら合ってました。

次回、異常系の作りこみに入りたいところではありますが、カレンダーの表示部分の共通化に取り組んでみましょう。急がば回れ。