Calendar Decorators

Calendar Decorators --  What Calendar_Decorator is for

Calendar Decorators

The Calendar_Decorator is provided to allow you to attach functionality to existing Calendar objects without needing to subclass them. This helps in a number of situations, such as allowing results from, say, a database query to be rendered in the calendar or to modify the values returned from Calendar methods (perhaps converting a numeric month into its textual name).

Some concrete decorators are provided with PEAR::Calendar, to address what may be common problems you encounter in using the library. These are not designed to suit everyone but instead focus on solving a more narrow problem domain. They will only be parsed by the PHP engine should you explicitly include them in your code. An example of why decorators can be useful:
require_once 'Calendar/Day.php';
require_once 'Calendar/Decorator.php';

class WorkingDay extends Calendar_Decorator {
    function WorkingDay(& $Calendar) {
        parent::Calendar_Decorator($Calendar);
    }

    // Overides the default fetch method of the calendar object
    function fetch() {
        if ($Hour = parent::fetch()) {

            // Recursive fetch, return only hours between 8am and 6pm
            if ($Hour->thisHour() < 8 || $Hour->thisHour() > 18) {
                return $this->fetch();
            } else {
                return $Hour;
            }
        } else {
            // Make sure to return FALSE when the real fetch returned nothing
            // or you will get an infinite loop
            return FALSE;
        }
    }
}

// Create a normal day and build the hours
$Day = new Calendar_Day(date('Y'), date('n'), date('d'));
$Day->build();

// Create the decorator, passing it the normal day
$WorkingDay = new WorkingDay($Day);

// Only hours in a working day are displayed...
while ($Hour = $WorkingDay->fetch()) {
    echo $Hour->thisHour().'<br />';
}

The base Calendar_Decorator

The base class Calendar_Decorator "mirrors" the combined API of all the subclasses of Calendar. It accepts a Calendar object to its constructor then "takes over" the API allowing you to make calls through it rather than directly to the original calendar object. The Calendar_Decorator simply routes calls through to the calendar object it is decorating and returns values where appropriate.

Decorators and Date Selection

One important use of decorators is to help "inject" data into the loop which renders the calendar. This helps with fetching data from some sort of "event" table in a database. When passing a selection array to any build() method, the selected date objects will replace the default built objects, allowing you to get them back as inside the fetch() loop, using the isSelected() method. You'll find an example of this in the PEAR::Calendar download. It should always be possible to fetch the event data you need with a single database query...

The bundled Decorators

PEAR::Calendar already provides a few decorators:

Calendar_Decorator_Textual example

This decorator defines a few methods that can be useful to handle month and day names:

Calendar_Decorator_Uri example

Methods defined by this decorator:

A simple usage example:
$Day = new Calendar_Day(2003, 10, 23);
$Uri = & new Calendar_Decorator_Uri($Day);
$Uri->setFragments('year', 'month', 'day');
echo $Uri->prev('day');
// Displays year=2003&month=10&day=22

Calendar_Decorator_Weekday example

Methods defined by this decorator:

Example:
$Day = new Calendar_Day(2003, 10, 23);
$Weekday = & new Calendar_Decorator_Weekday($Day);
$Weekday->setFirstDay(0); // Set first day of week to Sunday (default Mon)
echo $Weekday->thisWeekDay(); // Displays 5 - fifth day of week relative to Sun

Calendar_Decorator_Wrapper example

require_once 'Calendar/Month.php';
require_once 'Calendar/Decorator.php'; // Not really needed but added to help this make sense
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>The Wrapper decorator</h2>';
echo '<i>Day numbers are rendered in bold</i><br /> <br />';
while ($DecoratedDay = $Wrapper->fetch('MyBoldDecorator')) {
    echo $DecoratedDay->thisDay().'<br />';
}