Written by Manabu Bannai

【CodeIgniter】カレンダーライブラリをつかった『簡単なWebアプリケーションの作り方』

CodeIgniter PROGRAMMING

CodeIgniterでカレンダーアプリケーションを作る方法です。今回は基本的なサンプルですが、応用次第ではさまざまなWebアプリケーション開発に有効活用することができます。
» デモはこちら
» ソースコードはこちら

目次

それではまとめてきます。

CodeIgniterの初期設定

.htaccessを設置を設置



    RewriteEngine On
    RewriteBase /calendar/

    #Removes access to the system folder by users.
    #Additionally this will allow you to create a System.php controller,
    #previously this would not have been possible.
    #'system' can be replaced if you have renamed your system folder.
    RewriteCond %{REQUEST_URI} ^system.*
    RewriteRule ^(.*)$ /index.php?/$1 [L]

    #When your application folder isn't in the system folder
    #This snippet prevents user access to the application folder
    #Submitted by: Fabdrol
    #Rename 'application' to your applications folder name.
    RewriteCond %{REQUEST_URI} ^application.*
    RewriteRule ^(.*)$ /index.php?/$1 [L]

    #Checks to see if the user is attempting to access a valid file,
    #such as an image or css document, if this isn't true it sends the
    #request to index.php
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php?/$1 [L]



    # If we don't have mod_rewrite installed, all 404's
    # can be sent to index.php, and everything works as normal.
    # Submitted by: ElliotHaughin

    ErrorDocument 404 /index.php

RewriteBase /calendar/ の部分はフォルダ名にあわせて変更してください。

オートロード設定

編集ファイル:config/autoload.php

$autoload['libraries'] = array("database");
$autoload['helper'] = array("url");

ベースURL設定

編集ファイル:config/config.php

$config['base_url']	= 'http://localhost/calendar/';
$config['index_page'] = '';

DB作成

DB名:ci_calendar

データベース設定
編集ファイル:config/database.php


$db['default']['hostname'] = 'localhost';
$db['default']['username'] = 'root';
$db['default']['password'] = 'root';
$db['default']['database'] = 'ci_calendar';
$db['default']['dbdriver'] = 'mysql';

CodeIgniterのカレンダーライブラリを利用する

カレンダー表示用のコントローラーをつくる

新規作成ファイル:application/mycal.php


load->library("calendar");
		echo $this->calendar->generate();
	}
}

現時点で画面をロードすると以下となります。
mycal

カレンダーライブラリのオプションを利用する

編集ファイル:application/mycal.php


public function display(){

	$conf = array(
		"start_day" => "monday", //曜日初めを月曜日にする
		"show_next_prev" =>true, //Next, Prevリンクを生成
		"next_prev_url" => base_url() . "mycal/display" //生成されたNext. PrevリンクにURLを渡す
	);

	$this->load->library("calendar", $conf);
	echo $this->calendar->generate();
}

この状態でNext, Prevリンクをクリックすると、URLに変化は起きますが、カレンダー自体は変化しません。
理由は、カレンダーライブラリに情報は渡されていないからです。

カレンダーライブラリに情報を渡す

編集ファイル:application/mycal.php


public function display($year, $month){

	$conf = array(
		"start_day" => "monday",
		"show_next_prev" =>true,
		"next_prev_url" => base_url() . "mycal/display"
	);

	$this->load->library("calendar", $conf);
	echo $this->calendar->generate($year, $month);
}

この状態へページを読み込みするとカレンダーは動作します。
しかし、当月を表示する際に、$year, $monthがパラメータを受け取っていないためエラーが発生します。
パラメータをオプショナルにすることで解決できます。
具体的には、以下のとおりです。


public function display($year = null, $month = null)
// 省略
echo $this->calendar->generate($year, $month)

ここまでで、ベーシックなカレンダーが完成しました。
しかし、次からのステップでカレンダーには様々な情報を表示させるためには、先ほどつくったコントローラーをモデルとして利用したほうが使い勝手がよいです。

カレンダーライブラリがDBと情報をやりとりしやすくする

新規作成ファイル:models/mycal_model.php


<?php
class Mycal_model extends CI_Model{
	function generate ($year, $month){
		$conf = array(
			"start_day" => "monday",
			"show_next_prev" =>true,
			"next_prev_url" => base_url() . "mycal/display"
		);

		$this->load->library("calendar", $conf);
		return $this->calendar->generate($year, $month);
	}
}

プログラムの最後がechoではなく、returnになっています。

Mycal_modelをコントローラーで読み込む

編集ファイル:controller/mycal.php


public function display($year = null, $month = null){

	$this->load->model("Mycal_model");
	// generate機能で取得したデータを$dataに挿入
	$data["calendar"] = $this->Mycal_model->generate($year, $month);

	$this->load->view("mycal", $data);

	// $conf = array(
	// 	"start_day" => "monday",
	// 	"show_next_prev" =>true,
	// 	"next_prev_url" => base_url() . "mycal/display"
	// );

	// $this->load->library("calendar", $conf);
	// echo $this->calendar->generate($year, $month);
}

基礎知識ですが、以下のプログラムに関して。

$data["calendar"] = $this->Mycal_model->generate($year, $month);

上記プログラムは、以下のように書き換えることも可能です。


$data = array(
	"calendar" => $this->Mycal_model->generate($year, $month)
);

カレンダー表示用のビューを作成する

新規作成ファイル:views/mycal.php

<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="utf-8">
	<title>CodeIgniterカレンダー</title>
	<meta name="keywords" content="">
	<meta name="description" content="">
</head>
<body>
	<?php echo $calendar; ?>
</body>
</html>

ここまでで、DBとの情報のやり取りに関して、より利便性のたかいカレンダーが完成しました。
次にカレンダー内に情報を入れ込む機能を作成していきます。

カレンダー内に情報を埋込む

編集ファイル:models/mycal_model.php


$this->load->library("calendar", $conf);

$cal_data = array(
	17 => "Normalday",
	25 => "HappyPayment"
);

return $this->calendar->generate($year, $month, $cal_data);

すると、17日と25日にURLパラメータが渡されるようになります。

$confをgenerate機能内から出す

編集ファイル:models/mycal_model.php


class Mycal_model extends CI_Model{

	var $conf;

	function Mycal_model(){
		parent::__construct();
		$this -> conf = array(
			"start_day" => "monday",
			"show_next_prev" =>true,
			"next_prev_url" => base_url() . "mycal/display"
		);
	}

	function generate ($year, $month){

		$this->load->library("calendar", $this->conf);

		$cal_data = array(
			17 => "Normalday",
			25 => "HappyPayment"
		);

		return $this->calendar->generate($year, $month, $cal_data);
	}
}

CodeIgniterのカレンダーライブラリとDBを繋ぐ

テーブルの作成

次回以降のステップでDBを使うので、ここで一度テーブルを作成します。
テーブル名:calendar
カラム数:2

cal_db

次に以下のようにテスト用データを挿入しておきます。

testing_data

DBからカレンダー情報を取得できるようにする

編集ファイル:models/mycal_model.php
以下のプログラムを変更します。


// $cal_data = array(
// 	17 => "Normalday",
// 	25 => "HappyPayment"
// );

// get_calendar_dataを実行して、取得情報を$cal_dataに挿入する
$cal_data = $this->get_calendar_data($year, $month);

get_calendar_dataを作成していきます。

DBからカレンダー情報を取得する機能(get_calendar_data)の作成

編集ファイル:models/mycal_model.php



function get_calendar_data($year, $month){
	// 生成されるSQL : date LIKE "2014-08%"
	$query = $this->db->select("date, data") -> from("calendar") -> like("date", "$year-$month", "after") -> get();

	$cal_data = array();

	foreach ( $query -> result() as $row ){
		// $queryで日付を取得しているので、substrを利用している
		// 例:2014-08-15の場合⇒15が取得される
		// substr(8, 2)⇒8番目の文字から2文字を取得するという意味
		// 最後の+0の意味:Mysqlは数字を(01, 02, 03,,,)のように返しますが、カレンダークラスは(1,2,3,4,,,)のうように返します。その問題を+0で解決しています。
		$cal_data[substr($row->date, 8,2)] = $row -> data;
	}

	return $cal_data;

}

すると、2014-08-26の部分のリンクが、ここをテスト中になっているはずです。
次に、リンクではなく、カレンダー内に文字を出現させていきます。

カレンダーテンプレートの作成

編集ファイル:models/mycal_model.php
カレンダーテンプレートを作成することで、カレンダーのデザインを100%コントロールできます。
Smartyみたいなテンプレートですね。以下のとおりに修正してください。


function Mycal_model(){
	parent::__construct();
	$this -> conf = array(
		"start_day" => "monday",
		"show_next_prev" =>true,
		"next_prev_url" => base_url() . "mycal/display"
	);

	$this->conf["template"] = '
		{table_open}{/table_open}

		{heading_row_start}{/heading_row_start}

		{heading_previous_cell}{/heading_previous_cell}
		{heading_title_cell}{/heading_title_cell}
		{heading_next_cell}{/heading_next_cell}

		{heading_row_end}{/heading_row_end}

		{week_row_start}{/week_row_start}
		{week_day_cell}{/week_day_cell}
		{week_row_end}{/week_row_end}

		{cal_row_start}{/cal_row_start}
		{cal_cell_start}{/cal_cell_end}
		{cal_row_end}{/cal_row_end}

		{table_close}
<<{heading}>>
{week_day}
{/cal_cell_start} {cal_cell_content}
{day}
{content}
{/cal_cell_content} {cal_cell_content_today}
{day}
{content}
{/cal_cell_content_today} {cal_cell_no_content}
{day}
{/cal_cell_no_content} {cal_cell_no_content_today}
{day}
{/cal_cell_no_content_today} {cal_cell_blank}{/cal_cell_blank} {cal_cell_end}
{/table_close}'; }

次に、CSS。以下のとおりです。
編集ファイル:views/mycal.php


.calendar {
	font-family: Arial;
	font-size:   12px;
}

table.calendar {
	margin:          auto;
	border-collapse: collapse;
}

.calendar .days td {
	width:            80px;
	height:           80px;
	padding:          4px;
	border:           1px solid #999;
	vertical-align:   top;
	background-color: #DEF;
}

.calendar .days td:hover {
	background-color: #FFF;
}

.calendar .highlight {
	font-weight: bold;
	color:       #00F;
}

これで、カレンダー内にDB情報が表示されるようになりました。
カレンダーテンプレート作成方法の詳細は以下からどうぞ。
カレンダークラス : CodeIgniter ユーザガイド 日本語版

次にブラウザから情報をPOSTできるようにします。

ブラウザからカレンダー内に情報をPOSTする

カレンダー内に情報をPOSTするモデルを作成する

編集ファイル:models/mycal_model.php


function add_calendar_data($date, $data){

	// calendarのDB内にarrayした情報を挿入する
	$this->db->insert("calendar", array(

		// dateに取得済みを$dateを挿入する
		"date" => $date,

		// dataに取得済みを$dataを挿入する
		"data"  => $data
	));

}

動作テストを行なってみます。
http://localhost/calendar/mycal/display/にアクセスした際に、displayコントローラーが実行されます。
displayコントローラーでは、Mycal_modelが読み込まれ、Mycal_model内のgenerateメソッドが実行されます。
ということは、generateメソッド内で、DBへの情報追加機能がテストできることになります。
つまり、プログラムは以下です。


function generate ($year, $month){

	$this->load->library("calendar", $this->conf);

	$this->add_calendar_data("2014-08-11", "テスト投稿");

	// get_calendar_dataを実行して、取得情報を$cal_dataに挿入する
	$cal_data = $this->get_calendar_data($year, $month);

	return $this->calendar->generate($year, $month, $cal_data);
}

ページ読み込みをすると、情報がDBに挿入され、カレンダーに表示されたことがわかります。
しかし、ページを再度読み込むと以下のエラーが発生します。

A Database Error Occurred
Error Number: 1062
Duplicate entry '2014-08-15' for key 'PRIMARY'
INSERT INTO `calendar` (`date`, `data`) VALUES ('2014-08-15', 'テスト投稿')
Filename: /Applications/MAMP/htdocs/calendar/models/mycal_model.php
Line Number: 81

日本語が文字化けしちゃっていますが、要するに、情報の入っているDBに、再度情報を挿入(insert)しようとしたためにエラーが発生しています。
なので、カラムに情報は入っている場合は、insertではなく、updateするようにプログラムを書き換える必要があります。

カレンダー情報のアップデート

編集ファイル:models/mycal_model.php


function add_calendar_data($date, $data){

	// カレンダーDBのdateを選択し、データをカウントする
	if( $this->db->select("date")->from("calendar")->where("date", $date)->count_all_results()){
		// 情報をアップデートする
		$this->db->where("date", $date)->update("calendar", array(
			"date" => $date,
			"data"  => $data
		));
	}else{
		// calendarのDB内にarrayした情報を挿入する
		$this->db->insert("calendar", array(
			"date" => $date,
			"data"  => $data
		));
	}
}

これで無事にエラーから解消されました。
この時点で、テストコードを削除して、DBテーブルも空にしておいてください。

jQueryでデータ挿入できる機能をつくる

編集ファイル:views/mycal.php
各日付をクリックしたら、日付を取得できるようにします。

	 <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>
<body>
	<?php echo $calendar; ?>
	<script type="text/javascript" charset="utf-8">
	$(document).ready(function(){
		$(".calendar .day").click(function(){
			// class="day_num"の次には数字が入っているので、それを.html()で取得			day_num = $(this).find(".day_num").html();
			alert (day_num);
		})
	})
	</script>

AJAXでデータ挿入を行なっていく(フロントエンドのみ)

編集ファイル:views/mycal.php


$(document).ready(function(){
	$(".calendar .day").click(function(){

		// class="day_num"の次には数字が入っているので、それを.html()で取得
		day_num = $(this).find(".day_num").html();
		// alert (day_num);

		// prompt:ポップアップでテキストのインプットボックスが出現します。
		day_data = prompt("予定を入力");

		if( day_data != null ){
		// ユーザーがprompt後にキャンセルしなければ以下を実行
			$.ajax({
				url:window.location,
				type:"POST",
				data:{
					// dayがPostされる
					day:day_num,

					//prompt部分で入力された情報
					data:day_data
				},
				success:function(msg){
					location.reload();
				}
			});
		}
	})
})

以上でフロントエンド部分んは動くようになります。
次はAJAXデータをDBに挿入していきます。

AJAXデータをDBに挿入する

編集ファイル:controllers/mycal.php


public function display($year = null, $month = null){

	$this->load->model("Mycal_model");

	if( $day = $this->input->post("day") ){
	// dayがPOSTされたら以下を実行。同時に、day情報を$dayに格納

		$this->Mycal_model->add_calendar_data(
			// add_calendar_dataは2つのパラメータが必要
			// add_calendar_data($date, $data)
			"$year-$month-$day", //パラメータ1つめ
			$day //パラメータ2つ目
		);

	}

これで正しいように見えますが、$year = null, $month = nullがあるので、正常に動きません。
$year、$monthがない場合は以下のように初期化(イニシャライズ)しておきます。



if( !$year ){
	// $yearが空なら現在の年を挿入
	$year = date('Y');
}
if( !$month ){
	// $yearが空なら現在の年を挿入
	$month = date('m');
}

$this->load->model("Mycal_model");

これで、99%完成です。
最後に少しだけ追加して、ユーザビリティを上げます。

すでに値が挿入されている場合は、Prompt画面に情報が表示されるようにします。
つまり以下のとおり。

■現状

before

上記をクリックした場合に、以下のように表示されるようにします。
※現状のままだと、ボックスが空です。

■変更後

after

promptに第2引数をわたす

編集ファイル:views/mycal.php
HTML内部にあるvalueをフェッチできるようにします。


day_data = prompt("予定を入力", $(this).find(".content").html());

以上で完成です!お疲れさまでした。

photo credit: bubbo.etsy.com via photopin cc