Calendar_Decorator を使用すると、 既存のカレンダーオブジェクトに機能を追加する際に、 カレンダーオブジェクトのサブクラスを作成する必要がなくなります。 これは、さまざまな場面で役立ちます。例えば、 データベースへのクエリの結果を用いてカレンダーをレンダリングしたり、 カレンダークラスのメソッドからの返り値を変更したり (よくあるのは、数字で返された月を文字列形式に変換するなど) などがあげられます。
PEAR::Calendar では、 デコレータの具象クラスがいくつか提供されています。これは、 このライブラリを使用するにあたって問題となるであろう問題に対応するためのものです。 万人向けのものではなく、個々の問題領域に特化したものになっています。 コードの中で明示的にインクルードしない限り、これらのコードは PHP エンジンによってパースされることはありません。 デコレータがいかに便利なものであるのかを、以下の例で示します。
<?php
require_once 'Calendar/Day.php';
require_once 'Calendar/Decorator.php';
class WorkingDay extends Calendar_Decorator {
function WorkingDay(& $Calendar) {
parent::Calendar_Decorator($Calendar);
}
// カレンダーオブジェクトのデフォルトの fetch メソッドを上書きします
function fetch() {
if ($Hour = parent::fetch()) {
// 再帰的なフェッチにより、午前 8 時から午後 6 時までのみを返します
if ($Hour->thisHour() < 8 || $Hour->thisHour() > 18) {
return $this->fetch();
} else {
return $Hour;
}
} else {
// 本来の fetch メソッドが何も返さなかった場合、あるいは
// 無限ループに陥った場合に、確実に FALSE を返すようにします
return FALSE;
}
}
}
// 通常の日付オブジェクトを作成し、時間オブジェクトを構築します
$Day = new Calendar_Day(date('Y'), date('n'), date('d'));
$Day->build();
// デコレータを作成し、通常の日付オブジェクトを渡します
$WorkingDay = new WorkingDay($Day);
// 勤務時間中の時間のみが表示されます...
while ($Hour = $WorkingDay->fetch()) {
echo $Hour->thisHour().'<br />';
}
?>
基底クラスである Calendar_Decorator は、 Calendar のすべてのサブクラスの API を組み合わせたものを「ミラー」しています。このクラスは、 コンストラクタでカレンダーオブジェクトを受け取り、その API を 「継承」します。これで、カレンダーオブジェクトのメソッドを直接コールするのではなく 継承した API 経由で使用できるようになります。 Calendar_Decorator は、 デコレート対象のカレンダーオブジェクトに対するコールを横取りし、 適切な処理を施してその結果を返します。
デコレータの主要な使用法のひとつは、カレンダーをレンダリングするループ内にデータを 「注入」することです。これは、データベースに登録されている何らかの「イベント」 情報を取得してカレンダーに反映させるのに便利です。選択範囲の配列を何らかの build() メソッドに渡すと、 デフォルトのオブジェクトが選択された日付オブジェクトで置き換えられます。 また、fetch() ループ内で isSelected() メソッドを使用すると、その内容を取得することができます。 PEAR::Calendar をダウンロードすると、その中に使用例が含まれています。 必要なイベントデータは、常に 1 回のクエリで取得できるようにしておくべきです...
PEAR::Calendar には、いくつかのデコレータがバンドルされています。
Calendar_Decorator_Textual
月名や曜日のテキスト表記の取得を補助するデコレータ。
Calendar_Decorator_Uri
カレンダーを移動するための HTML リンクの作成を補助するデコレータ。
Calendar_Decorator_Weekday
曜日を取得するデコレータ。
Calendar_Decorator_Wrapper
別のデコレータの子オブジェクトの構築をラップするデコレータ。
このデコレータでは、月名や曜日名を処理するのに便利なメソッドを定義しています。
monthNames($format
='long')
月名の配列を返します。返される月の書式は
format
パラメータ
(one、two、short あるいは long) に依存します。
weekdayNames($format
='long')
曜日名の配列を返します。返される曜日の書式は
format
パラメータ
(one、two、short あるいは long) に依存します。
prevMonthName($format
='long')
デコレート対象のカレンダーオブジェクトの、前月のテキスト表現を返します。
thisMonthName($format
='long')
デコレート対象のカレンダーオブジェクトの、当月のテキスト表現を返します。
nextMonthName($format
='long')
デコレート対象のカレンダーオブジェクトの、翌月のテキスト表現を返します。
prevDayName($format
='long')
デコレート対象のカレンダーオブジェクトの、前日のテキスト表現を返します。
thisDayName($format
='long')
デコレート対象のカレンダーオブジェクトの、当日のテキスト表現を返します。
nextDayName($format
='long')
デコレート対象のカレンダーオブジェクトの、翌日のテキスト表現を返します。
orderedWeekdays($format
='long')
デコレート対象のカレンダーオブジェクトで定義されている順番で、 曜日を返します。Calendar_Month_Weekdays、 Calendar_Month_Weeks および Calendar_Week でのみ有用です。それ以外の場合は、常に日曜日から始まる配列が返されます。
このデコレータで定義されているメソッドは次のとおりです。
setFragments($y, $m=null, $d=null, $h=null, $i=null, $s=null)
各日付要素に対して URI 変数の名前を設定します。
setSeparator($separator
)
区切り文字を、例えば '/' のように指定します (デフォルトは &)。
setScalar(boolean $state
=TRUE)
Uri デコレータを「スカラーモード」に移行します。 URI 変数の名前は返されません。
prev($method
)
ひとつ前 (年、月、週、日など) のカレンダーの URI 文字列を取得します。
this($method
)
現在 (年、月、週、日など) のカレンダーの URI 文字列を取得します。
next($method
)
ひとつ先 (年、月、週、日など) のカレンダーの URI 文字列を取得します。
簡単な使用例を示します。
<?php
$Day = new Calendar_Day(2003, 10, 23);
$Uri = & new Calendar_Decorator_Uri($Day);
$Uri->setFragments('year', 'month', 'day');
echo $Uri->prev('day');
// year=2003&month=10&day=22 と表示されます。
?>
このデコレータで定義されているメソッドは次のとおりです。
setFirstDay($firstDay)
週の最初の曜日を設定します (0 = 日曜日, 1 = 月曜日 [デフォルト] など)
prevWeekDay($format='int')
週の前日を返します。$format
パラメータの内容
(int, array, object, timestamp) によって書式が変わります。
thisWeekDay($format='int')
週の当日を返します。$format
パラメータの内容
(int, array, object, timestamp) によって書式が変わります。
nextWeekDay($format='int')
週の翌日を返します。$format
パラメータの内容
(int, array, object, timestamp) によって書式が変わります。
使用例は次のようになります。
<?php
$Day = new Calendar_Day(2003, 10, 23);
$Weekday = & new Calendar_Decorator_Weekday($Day);
$Weekday->setFirstDay(0); // 一週間を日曜日から始めるようにします (デフォルトは月曜日からです)
echo $Weekday->thisWeekDay(); // 5 (日曜日から数えて 5 日め) を表示します
?>
<?php
require_once 'Calendar/Month.php';
require_once 'Calendar/Decorator.php'; // 必須ではありませんが、わかりやすくするために追加しています
require_once 'Calendar/Decorator/Wrapper.php';
class MyBoldDecorator extends Calendar_Decorator
{
function MyBoldDecorator(&$Calendar)
{
parent::Calendar_Decorator($Calendar);
}
function thisDay()
{
return '<b>'.parent::thisDay().'</b>';
}
}
$Month = new Calendar_Month(date('Y'), date('n'));
$Wrapper = & new Calendar_Decorator_Wrapper($Month);
$Wrapper->build();
echo '<h2>ラッパーデコレータ</h2>';
echo '<i>日付が太字でレンダリングされます</i><br /> <br />';
while ($DecoratedDay = $Wrapper->fetch('MyBoldDecorator')) {
echo $DecoratedDay->thisDay().'<br />';
}
?>