カレンダーデコレータ

カレンダーデコレータ --  Calendar_Decorator とは

カレンダーデコレータ

Calendar_Decorator を使用すると、 既存のカレンダーオブジェクトに機能を追加する際に、 カレンダーオブジェクトのサブクラスを作成する必要がなくなります。 これは、さまざまな場面で役立ちます。例えば、 データベースへのクエリの結果を用いてカレンダーをレンダリングしたり、 カレンダークラスのメソッドからの返り値を変更したり (よくあるのは、数字で返された月を文字列形式に変換するなど) などがあげられます。

PEAR::Calendar では、 デコレータの具象クラスがいくつか提供されています。これは、 このライブラリを使用するにあたって問題となるであろう問題に対応するためのものです。 万人向けのものではなく、個々の問題領域に特化したものになっています。 コードの中で明示的にインクルードしない限り、これらのコードは 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_Decorator は、 Calendar のすべてのサブクラスの API を組み合わせたものを「ミラー」しています。このクラスは、 コンストラクタでカレンダーオブジェクトを受け取り、その API を 「継承」します。これで、カレンダーオブジェクトのメソッドを直接コールするのではなく 継承した API 経由で使用できるようになります。 Calendar_Decorator は、 デコレート対象のカレンダーオブジェクトに対するコールを横取りし、 適切な処理を施してその結果を返します。

デコレータおよび日付選択

デコレータの主要な使用法のひとつは、カレンダーをレンダリングするループ内にデータを 「注入」することです。これは、データベースに登録されている何らかの「イベント」 情報を取得してカレンダーに反映させるのに便利です。選択範囲の配列を何らかの build() メソッドに渡すと、 デフォルトのオブジェクトが選択された日付オブジェクトで置き換えられます。 また、fetch() ループ内で isSelected() メソッドを使用すると、その内容を取得することができます。 PEAR::Calendar をダウンロードすると、その中に使用例が含まれています。 必要なイベントデータは、常に 1 回のクエリで取得できるようにしておくべきです...

バンドルされているデコレータ

PEAR::Calendar には、いくつかのデコレータがバンドルされています。

Calendar_Decorator_Textual の例

このデコレータでは、月名や曜日名を処理するのに便利なメソッドを定義しています。

Calendar_Decorator_Uri の例

このデコレータで定義されているメソッドは次のとおりです。

簡単な使用例を示します。
$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 と表示されます。

Calendar_Decorator_Weekday の例

このデコレータで定義されているメソッドは次のとおりです。

使用例は次のようになります。
$Day = new Calendar_Day(2003, 10, 23);
$Weekday = & new Calendar_Decorator_Weekday($Day);
$Weekday->setFirstDay(0); // 一週間を日曜日から始めるようにします (デフォルトは月曜日からです)
echo $Weekday->thisWeekDay(); // 5 (日曜日から数えて 5 日め) を表示します

Calendar_Decorator_Wrapper の例

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 />';
}