なぜ HTML を生成しないのですか?
WML とか SOAP、PDF、GIF、コマンドライン、…… これらの立場は?
PEAR::Calendar を使用すれば、
どんな出力でも生成することができます (SOAP および WML の例を参照ください)。
特定の出力に縛られてしまうと、使用の幅が制限されてしまいます
(今まで私が見てきたパブリックドメインの PHP カレンダーライブラリは、
ことごとくこの問題にハマっています)。そのような目的のためには、
PEAR::Calendar を利用する
PEAR::HTML_Calendar を開発するとよいでしょう。
何でこんなにたくさんのオブジェクトやクラスやファイルがあるんでしょう。あり得ない!
Sourceforge のサーバ (ここはいつも負荷が高い状態です)
にあるサンプルを実行してみてください。
example 3.php をレンダリングするのにかかる時間は 0.1 秒以下
(通常はその半分くらい) です。このライブラリのコードは高度に最適化されており、
いわゆる「裏ワザ」のたぐいを駆使しています。これにより、
本当に必要なロジックだけを PHP が読み込めるようにしているのです。
もしそれが信じられないっていうのなら、ためしに
Cache_Lite で出力 HTML をキャッシュしてみるといいでしょう。
カレンダーの計算に Unix タイムスタンプを使用しているということは、
出力できる日付の範囲に制限があるということですよね。
これを変更することはできますか?
内部での計算は、すべて Calendar_Engine
インターフェイスを実装したクラスで処理されています。デフォルトの実装は
PHP の date() および mktime()
関数にもとづくものです (そのため、このエンジンでは Unix
タイムスタンプが必要になります)。これとは別に、
PEAR::Date を使用するエンジンも存在します。
これは少し処理速度が劣りますが、Unix タイムスタンプの範囲の制限を受けません。
エンジンの変更は、定数 CALENDAR_ENGINE
を用いて次のように行います。
<?php
// デフォルトの Unix タイムスタンプエンジン (この定義は不要です)
// define('CALENDAR_ENGINE', 'UnixTs');
// PEAR::Date エンジンに変更します
define('CALENDAR_ENGINE', 'PearDate');
?>
|
PearDate エンジンを使用するには
PEAR::
Date のバージョン 1.4
以降が必要であることに注意しましょう。
この例では曜日や月の名前が英語になっていますが、これを変更することはできますか?
PEAR::Calendar の内部では、単に十進数の計算を行っているだけです。
月の名前や曜日名は、カレンダーのレンダリング時に (あなたが) 生成するものです。
あなたがすべきことは、単に setlocale() で
PHP のロケールを設定して strftime() 関数を使用するだけです。例えば次のようになります。
<?php
$Day = & new Calendar_Day(2003, 10, 23);
setlocale (LC_TIME, 'de_DE'); // ドイツ語
echo strftime('%A %d %B %Y', $Day->getTimeStamp());
?>
|
Calendar_Decorator_Textual が生成する月名や曜日名は、
使用しているカレンダーエンジンが何であるかとは無関係です。これは、
setlocale() によって変更することができます。
空の日付とは?
PEAR::Calendar を使用すると、
以下のような表形式のカレンダー (人間がよく使う形式)
を簡単に出力することができます。
October 2003
M T W T F S S
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
ここで、カレンダーの左上と右下に注目してみましょう。
この部分が「空の日付」です。空の日付が作られるのは、
Calendar_Month_Weekdays および
Calendar_Week
のふたつのクラスのみです。例えば
Calendar_Month_Weekdays
を使用した場合の例は次のようになります。
<?php
require_once 'Calendar/Month/Weekdays.php';
$Month = & new Calendar_Month_Weekdays(2003, 10);
$Month->build();
while ($Day = & $Month->fetch()) {
if ($Day->isFirst()) // 週の最初の日付かどうかを調べます
echo "\n";
if ($Day->isEmpty()) // 空の日付かどうかを調べます
echo "\t";
else
echo $Day->thisDay()."\t";
if ($Day->isLast()) // 週の最後の日付かどうかを調べます
echo "\n";
}
?>
|
空の日付であっても、値を返します。返される値は、本来その位置にあるはずの
(前月あるいは翌月の) 日付となります。空の日付を取得する可能性があるのは
Calendar_Month_Weekdays および
Calendar_Week です。
Calendar_Week を使用した場合は 7 日ぶんしか構築できない
(
Calendar_Week オブジェクトを構築するためには
Calendar_Month_Weeks を使用します) ので、
isFirst() メソッドおよび
isLast()
メソッドは使用できません。
複数の日付を選択する方法は?
すべてのカレンダーオブジェクト (Calendar_Second は
「子オブジェクト」を持たないので例外です) には build()
メソッドがあり、そのオブジェクトの「子オブジェクト」を作成します。
例えば Calendar_Year::build()
は Calendar_Month オブジェクトを作成し、
Calendar_Hour::build() は
Calendar_Minute オブジェクトを作成します。
カレンダーオブジェクトの配列をオプションとしてこのメソッドに渡すと、
作成された子オブジェクトの中から該当するものを「選択」することができます。
使用例は次のようになります。
<?php
$Month = & new Calendar_Month(2003, 10); // Oct 2003
$SelectedDay1 = & new Calendar_Day(2003, 10, 5); // 2003 年 10 月 5 日
$SelectedDay2 = & new Calendar_Day(2003, 10, 21); // 2003 年 10 月 21 日
// 配列に格納します...
$selection = array($SelectedDay1, $SelectedDay2);
$Month->build($selection);
while ($Day = & $Month->fetch()) {
if ($Day->isSelected())
echo $Day->thisYear().' '.$Day->thisMonth().' '.$Day->thisDay().' が選択されています'."\n";
}
?>
|
注意:
build() メソッドに渡した日付オブジェクトは、
実際にこのメソッドが作成したオブジェクトを上書きします。
つまり、独自に作成した
Calendar_Decorator
のサブクラスをこのメソッドに渡すと、カレンダーのレンダリングループ内で
その追加機能を使用できるようになります。例えば、何らかの「イベントデータベース」
から取得した予定をカレンダーに反映させる場合などにこの手法が使用できるでしょう。
なぜ build() を明示的にコールしないといけないのですか?
子オブジェクトが自動的に作成されればいいのに。
最大の理由は、高速に動作させるためです。
子オブジェクトの作成は負荷がかかる処理であり、
それらの子オブジェクトが常に必要となるわけではありません。
そのため、このような処理は明示的にコールするようにすべきです。
さもないと、単に月を作成するために $Year->build() をコールしたつもりが、
その内部では
月が日を作り、日が時間を作り、時間が分を作り、……
といったはめになってしまいます。
また、build() を明示的にコールするようにすることで、
一部の子オブジェクトを「選択」することができるようになるという利点もあります。
日付の妥当性を検証するには?
日付や時刻の妥当性の検証については、あなたが使用している
Calendar_Engine で定義されています
(例えば $Month = & new Month(2003, 2, 29); は無効です。だって
2003 年はうるう年ではないのだから)。手っ取り早く検証を行いたい場合は、
任意の日付オブジェクトに対して isValid()
メソッドをコールします。もしそのオブジェクトに何らかの問題があった場合は
FALSE が返されます。もっと詳細な検証を行い、結果を詳しく知りたい場合は、
任意の日付オブジェクトに対して getValidator()
メソッドをコールしましょう。これは、次の例のように
Calendar_Validator クラスのインスタンスを返します。
<?php
$Month = & new Month(2003, 2, 29); // 2003 年 2 月 29 日 (???)
if (!$Month->isValid()) {
$Validator = & $Month->getValidator();
while ($Error = $Validator->fetch()) {
echo $Error->toString();
}
}
?>
|
検証を行うには、まず
getValidator() をコールした後で、
isValidYear()、
isValidMonth()、
isValidDay()、
isValidHour()、
isValidMinute() および
isValidSecond()
(あるいは単に
isValid() を実行すると、
isValidxxx 系のすべてのメソッドがコールされます) のいずれかをコールするという方法もあります。
無効な日付を調整することはできますか?
URL を指定してカレンダーを移動できるように設定している場合に
calendar.php?year=2003&month=13
のような URL が指定されたとしましょう。このような場合にエラーを表示する代わりに、
対応するカレンダーオブジェクトの
Calendar::adjust()
メソッドをコールすることができます。先ほどの例の場合、このメソッドを使用すると
2004 年 1 月に移動できます。これは、Unix タイムスタンプエンジンでは
mktime() の機能によって実現されており、
PearDate エンジンにも同等の機能が組み込まれています。
build() をコールした後で
特定のひとつのオブジェクトだけを取得したいのですが、
そのためにいちいちループさせないといけないのでしょうか?
任意の日付オブジェクトに対して fetchAll() メソッドを使用すると、
作成されたすべての子オブジェクトが配列として取得できます。
この配列を直接操作するとよいでしょう。ただし、配列の添字には注意が必要です。
添字が [0] から始まるものもあれば、中には添字が [1] から始まるものもあります。
作成された日付オブジェクトの型によって、[0] と [1] のどちらから始まるかが決まります。
<?php
$Month = & new Calendar_Month(2003, 10);
$Month->build();
$days = & $Month->fetchAll(); // ここでは、すべてが配列に入っています
echo $days[1]->thisDay(); // 最初の日付の添字は 1 です
$Hour = & new Calendar_Hour(2003, 10, 25, 15); // 2003 年 10 月 25 日 午後 3 時
$Hour->build();
$hours = & $Hour->fetchAll(); // ここでは、すべてが配列に入っています
echo $hours[0]->thisHour(); // 最初の時間の添字は 0 です
?>
|
次のクラスについては、常に最初の添字が 1 となります。
Calendar_Month、
Calendar_Month_Weekdays、
Calendar_Month_Weeks、
Calendar_Week および
Calendar_Day。
一方、
Calendar_Hour、
Calendar_Minute および
Calendar_Second
については、常に最初の添字が 0 となります。
build() がコールされた後には、任意の日付オブジェクトに対して
size() メソッドが使用できることも覚えておきましょう。
これを使用すると、子オブジェクトの数が取得できます。
PEAR::Calendar における「週」とはそもそも何なのでしょう?
週は「擬似的な」日付で、エンドユーザ向けのインターフェイスを作成するのに便利なものです。
週オブジェクトのインスタンスを作成する際には、年と月、そして日を指定します。
週オブジェクトから取得できる内容は、そのタイムスタンプ
(これは、週の最初の日付のタイムスタンプと同じになります)、
表形式の月における位置づけ
(上にある、空の日付について参照ください)、その年の中での位置づけ
(これは ISO-8601 で定義されている年間の週番号です。週は月曜日から始まります)、
あるいは数値形式の年、月および週の開始日 (その月の第何日めか)
を含む配列となります。例えば次のように使用します。
<?php
$Week = & new Calendar_Week(2003, 10, 15);
$Week = new Calendar_Week(2003, 10, 15);
echo $Week->thisWeek(); // 2 を表示します (2003 年 10 月の第 2 週)
echo $Week->thisWeek('n_in_month'); // 2 を表示します - 上と同じです
echo $Week->thisWeek('n_in_year'); // 41 を表示します (2003 年の第 41 週)
echo $Week->thisWeek('timestamp'); // 使用しているエンジンによって、Unix タイムスタンプ
// あるいは ISO-8601 形式の日付 (YYYY-MM-DD HH:MM:SS)
// のいずれかを表示します
print_r $Week->thisWeek('array'); // [year] => 2003 [month] => 10 [day] => 12
?>
|
Calendar_Year から、デフォルトの Calendar_Month オブジェクトではなく
Calendar_Month_Weekdays や Calendar_Month_Weeks を作成する方法は?
Calendar_Year を使用する際には、定数
CALENDAR_MONTH_STATE を設定することで
作成されるオブジェクトを変更することができます。
CALENDAR_MONTH_STATE に
CALENDAR_USE_MONTH_WEEKDAYS あるいは
CALENDAR_USE_MONTH_WEEKS を設定すると、それぞれ
Calendar_Month_Weekdays クラスあるいは
Calendar_Month_Week クラスが作成されます。
週の始まりが月曜日になっているようですが、これを変更できますか?
もちろん。「週」の概念がかかわってくるクラスでは、
週の最初の曜日を指定する値を渡すことができます。
タイムスタンプを使用したデフォルトのカレンダーエンジンでは、
これは 0 から 6 までの数で表されます。0 が日曜日、6 が土曜日です。
この値を、次のように指定します。
<?php
$Year = new Calendar_Year(2003);
$selection = array();
$Year->build($selection, 0); // 第 2 引数は、週の最初の曜日です (ここでは日曜日)
$MonthWeekdays = new Calendar_Month_Weekdays(2003, 10, 6); // 第 3 引数 - 土曜日
$MonthWeeks = new Calendar_Month_Weekdays(2003, 10, 2); // 第 3 引数 - 火曜日
$Week = new Calendar_Week(2003, 10, 15, 5) // 第 4 引数 - 金曜日
?>
|