Date_Holidays
[ class tree: Date_Holidays ] [ index: Date_Holidays ] [ all elements ]

Source for file Composite.php

Documentation is available at Composite.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. /**
  4.  * Composite driver.
  5.  *
  6.  * PHP Version 4
  7.  *
  8.  * Copyright (c) 1997-2008 The PHP Group
  9.  *
  10.  * This source file is subject to version 3.0 of the PHP license,
  11.  * that is bundled with this package in the file LICENSE, and is
  12.  * available at through the world-wide-web at
  13.  * http://www.php.net/license/3_01.txt.
  14.  * If you did not receive a copy of the PHP license and are unable to
  15.  * obtain it through the world-wide-web, please send a note to
  16.  * license@php.net so we can mail you a copy immediately.
  17.  *
  18.  * @category Date
  19.  * @package  Date_Holidays
  20.  * @author   Carsten Lucke <luckec@tool-garage.de>
  21.  * @license  http://www.php.net/license/3_01.txt PHP License 3.0.1
  22.  * @version  CVS: $Id: Composite.php,v 1.13 2008/01/26 00:08:34 kguest Exp $
  23.  * @link     http://pear.php.net/package/Date_Holidays
  24.  */
  25.  
  26. /**
  27.  * driver not found
  28.  *
  29.  * @access  public
  30.  */
  31. define('DATE_HOLIDAYS_DRIVER_NOT_FOUND'100);
  32.  
  33. /**
  34.  * Composite driver - you can use this one to combine two or more drivers
  35.  *
  36.  * @category   Date
  37.  * @package    Date_Holidays
  38.  * @subpackage Driver
  39.  * @author     Carsten Lucke <luckec@tool-garage.de>
  40.  * @license    http://www.php.net/license/3_01.txt PHP License 3.0.1
  41.  * @version    CVS: $Id: Composite.php,v 1.13 2008/01/26 00:08:34 kguest Exp $
  42.  * @link       http://pear.php.net/package/Date_Holidays
  43.  */
  44. {
  45.     /**
  46.      * compound of drivers
  47.      *
  48.      * @access   private
  49.      * @var      array 
  50.      */
  51.     var $_drivers = array();
  52.  
  53.     /**
  54.      * Driver-ids ordered by importance
  55.      *
  56.      * @access   private
  57.      * @var      array 
  58.      */
  59.     var $_driverIds = array();
  60.  
  61.     /**
  62.      * Constructor
  63.      *
  64.      * Use the Date_Holidays::factory() method to construct an object of a
  65.      * certain driver
  66.      *
  67.      * @access   protected
  68.      */
  69.     function Date_Holidays_Driver_Composite()
  70.     {
  71.     }
  72.  
  73.     /**
  74.      * Build the internal arrays that contain data about the calculated holidays
  75.      *
  76.      * @access   private
  77.      * @return   boolean true on success, otherwise a PEAR_ErrorStack object
  78.      * @throws   object PEAR_ErrorStack
  79.      */
  80.     function _buildHolidays()
  81.     {
  82.     }
  83.  
  84.     /**
  85.      * Add a driver component
  86.      *
  87.      * @param object $driver Date_Holidays_Driver driver-object
  88.      *
  89.      * @access   public
  90.      * @return   boolean true on success, false otherwise
  91.      */
  92.     function addDriver($driver)
  93.     {
  94.         if (is_a($driver'Date_Holidays_Driver')) {
  95.             return false;
  96.         }
  97.  
  98.         $id                  md5(serialize($driver));
  99.         $this->_drivers[$id$driver;
  100.         array_push($this->_driverIds$id);
  101.  
  102.         $this->_internalNames = array_merge($driver->getInternalHolidayNames(),
  103.                                             $this->_internalNames);
  104.         return true;
  105.     }
  106.  
  107.     /**
  108.      * Remove a driver component
  109.      *
  110.      * @param object $driver Date_Holidays_Driver driver-object
  111.      *
  112.      * @access   public
  113.      * @return   boolean true on success, otherwise a PEAR_Error object
  114.      * @throws   object PEAR_Error   DATE_HOLIDAYS_DRIVER_NOT_FOUND
  115.      */
  116.     function removeDriver($driver)
  117.     {
  118.         if (is_a($driver'Date_Holidays_Driver')) {
  119.             return false;
  120.         }
  121.  
  122.         $id md5(serialize($driver));
  123.         // unset driver object
  124.         if (isset($this->_drivers[$id])) {
  125.             return Date_Holidays::raiseError(DATE_HOLIDAYS_DRIVER_NOT_FOUND,
  126.                                              'Driver not found');
  127.         }
  128.         unset($this->_drivers[$id]);
  129.  
  130.         // unset driver's prio
  131.         $index array_search($id$this->_driverIds);
  132.         unset($this->_driverIds[$index]);
  133.  
  134.         // rebuild the internal-names array
  135.         $this->_internalNames = array();
  136.         foreach ($this->_driverIds as $id{
  137.             $this->_internalNames =
  138.                     array_merge($this->_drivers[$id]->_internalNames,
  139.                                 $this->_internalNames);
  140.         }
  141.  
  142.         return true;
  143.     }
  144.  
  145.     /**
  146.      * Returns the specified holiday
  147.      *
  148.      * Return format:
  149.      * <pre>
  150.      *   array(
  151.      *       'title' =>  'Easter Sunday'
  152.      *       'date'  =>  '2004-04-11'
  153.      *   )
  154.      * </pre>
  155.      *
  156.      * @param string $internalName internal name of the holiday
  157.      * @param string $locale       locale setting that shall be used by this
  158.      *                               method
  159.      *
  160.      * @access   public
  161.      * @return   object Date_Holidays_Holiday holiday's information on
  162.      *                                         success, otherwise a PEAR_Error
  163.      *                                         object
  164.      * @throws   object PEAR_Error       DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  165.      */
  166.     function getHoliday($internalName$locale = null)
  167.     {
  168.         foreach ($this->_driverIds as $id{
  169.             $holiday $this->_drivers[$id]->getHoliday($internalName$locale);
  170.             if (Date_Holidays::isError($holiday)) {
  171.                 /**
  172.                  * lets skip this error, perhaps another driver knows this
  173.                  * internal-name
  174.                  */
  175.                 continue;
  176.             }
  177.             return $holiday;
  178.         }
  179.  
  180.                                     'Invalid internal name: ' $internalName);
  181.     }
  182.  
  183.     /**
  184.      * Returns date of a holiday
  185.      *
  186.      * @param string $internalName internal name for holiday
  187.      *
  188.      * @access   public
  189.      * @return   object Date       date of the holiday as PEAR::Date
  190.      *                               object on success, otherwise a PEAR_Error
  191.      *                               object
  192.      * @throws   object PEAR_Error DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  193.      */
  194.     function getHolidayDate($internalName)
  195.     {
  196.         foreach ($this->_driverIds as $id{
  197.             $date $this->_drivers[$id]->getHolidayDate($internalName);
  198.             if (Date_Holidays::isError($date)) {
  199.                 /**
  200.                  * lets skip this error, perhaps another driver knows this
  201.                  * internal-name
  202.                  */
  203.                 continue;
  204.             }
  205.             return $date;
  206.         }
  207.  
  208.                                     'Invalid internal name: ' $internalName);
  209.     }
  210.  
  211.     /**
  212.      * Returns dates of all holidays or those accepted by the specified filter.
  213.      *
  214.      * @param Date_Holidays_Filter $filter filter-object
  215.      *                                        (or an array !DEPRECATED!)
  216.      *
  217.      * @access   public
  218.      * @return   array   array with holidays' dates on success, otherwise a
  219.      *                        PEAR_ErrorStack object
  220.      * @throws   object PEAR_ErrorStack   DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  221.      */
  222.     function getHolidayDates($filter = null)
  223.     {
  224.         if (is_null($filter)) {
  225.             $filter = new Date_Holidays_Filter_Blacklist(array());
  226.         elseif (is_array($filter)) {
  227.             $filter = new Date_Holidays_Filter_Whitelist($filter);
  228.         }
  229.  
  230.         $errorStack &Date_Holidays::getErrorStack();
  231.         $dates      = array();
  232.         $notFound   = array();
  233.  
  234.         foreach ($this->_internalNames as $internalName{
  235.             // check if the filter permits further processing
  236.             if ($filter->accept($internalName)) {
  237.                 continue;
  238.             }
  239.  
  240.             foreach ($this->_driverIds as $id{
  241.                 $date $this->_drivers[$id]->getHolidayDate($internalName);
  242.                 if (Date_Holidays::isError($date)) {
  243.                     if ($date->getCode(== DATE_HOLIDAYS_DATE_UNAVAILABLE{
  244.                         /**
  245.                          * this means a fatal error (would be the right place
  246.                          * for sth. like an assert, as this should normally
  247.                          * never happen)
  248.                          */
  249.  
  250.                         $message 'No date found for holiday with internal ' .
  251.                                    'name: ' $internalName;
  252.                         $errorStack->push(DATE_HOLIDAYS_DATE_UNAVAILABLE,
  253.                                           'error',
  254.                                           array(),
  255.                                           $message,
  256.                                           false,
  257.                                           debug_backtrace());
  258.                         continue;
  259.                     }
  260.  
  261.                     /**
  262.                      * current driver doesn't have this internalName, trying
  263.                      * next driver
  264.                      */
  265.                     array_push($notFound$internalName);
  266.                     continue;
  267.                 }
  268.                 /**
  269.                  * internal name found in highest priorized driver, stepping
  270.                  * to next internal name
  271.                  * checks if internal name is existent in $notFound array and
  272.                  * unsets this entry as it has been found now
  273.                  */
  274.                 $notFound array_unique($notFound);
  275.                 if (in_array($internalName$notFound)) {
  276.                     unset($notFound[array_search($internalName$notFound)]);
  277.                 }
  278.                 $dates[$internalName$date;
  279.                 continue 2;
  280.             }
  281.         }
  282.  
  283.         if (empty($notFound)) {
  284.             foreach ($notFound as $internalName{
  285.                 $errorStack->push(DATE_HOLIDAYS_INVALID_INTERNAL_NAME,
  286.                                   'error',
  287.                                   array(),
  288.                                   'Invalid internal name: ' $internalName,
  289.                                   false,
  290.                                   debug_backtrace());
  291.             }
  292.         }
  293.  
  294.         if ($errorStack->hasErrors(&& empty($notFound)) {
  295.             return $errorStack;
  296.         }
  297.         return $dates;
  298.     }
  299.  
  300.     /**
  301.      * Returns the title of the holiday, if any was found, matching the
  302.      * specified date.
  303.      *
  304.      * Normally the method will return the title/data for the first holiday
  305.      * matching the date.
  306.      * If you want the mthod to continue searching holidays for the specified
  307.      * date, set the 4th param to true
  308.      * If multiple holidays match your date, the return value will be an array
  309.      * of the titles/data.
  310.      * <pre>
  311.      * array(
  312.      *   array(
  313.      *       'title' => 'New Year',
  314.      *       'date'  => Object of type Date
  315.      *   ),
  316.      *   array(
  317.      *       'title' => 'Circumcision of Jesus',
  318.      *       'date'  => Object of type Date
  319.      *   )
  320.      * )
  321.      * </pre>
  322.      *
  323.      * @param mixed   $date     date (timestamp | string | PEAR::Date object)
  324.      * @param string  $locale   locale setting that shall be used by this method
  325.      * @param boolean $multiple true if multiple search is required.
  326.      *
  327.      * @access   public
  328.      * @return   object  object of type Date_Holidays_Holiday on success
  329.      *                       (numeric array of those on multiple search); if no
  330.      *                       holiday was found, matching this date, null is returned
  331.      * @uses     getHoliday()
  332.      * @uses     getHolidayTitle()
  333.      * @see      getHoliday()
  334.      */
  335.     function getHolidayForDate($date$locale = null$multiple = false)
  336.     {
  337.         $holidays = array();
  338.         foreach ($this->_driverIds as $id{
  339.             $holiday $this->_drivers[$id]->getHolidayForDate($date,
  340.                                                                $locale,
  341.                                                                $multiple);
  342.             if (is_null($holiday)) {
  343.                 /**
  344.                  * No holiday found for this date in the current driver, trying
  345.                  * next one
  346.                  */
  347.                 continue;
  348.             }
  349.  
  350.             if (is_array($holiday)) {
  351.                 for ($i = 0; $i count($holiday); ++$i{
  352.                     $holidays[$holiday[$i];
  353.                 }
  354.             else {
  355.                 $holidays[$holiday;
  356.             }
  357.  
  358.             if ($multiple{
  359.                 return $holiday;
  360.             }
  361.         }
  362.  
  363.         if (empty($holidays)) {
  364.             return null;
  365.         }
  366.         return $holidays;
  367.     }
  368.  
  369.     /**
  370.      * Returns all holidays that were found
  371.      *
  372.      * Return format:
  373.      * <pre>
  374.      *   array(
  375.      *       'easter' =>  array(
  376.      *           'title' =>  'Easter Sunday'
  377.      *           'date'  =>  '2004-04-11'
  378.      *       ),
  379.      *       'eastermonday'  =>  array(
  380.      *           'title' =>  'Easter Monday'
  381.      *           'date'  =>  '2004-04-12'
  382.      *       ),
  383.      *       ...
  384.      *   )
  385.      * </pre>
  386.      *
  387.      * @param Date_Holidays_Filter $filter filter-object
  388.      *                                        (or an array !DEPRECATED!)
  389.      *
  390.      * @access   public
  391.      * @return   array   numeric array containing objects of Date_Holidays_Holiday
  392.      *                        on success, otherwise a PEAR_ErrorStack object
  393.      * @throws   object PEAR_ErrorStack   DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  394.      */
  395.     function getHolidays($filter = null)
  396.     {
  397.         if (is_null($filter)) {
  398.             $filter = new Date_Holidays_Filter_Blacklist(array());
  399.         elseif (is_array($filter)) {
  400.             $filter = new Date_Holidays_Filter_Whitelist($filter);
  401.         }
  402.  
  403.         $errorStack &Date_Holidays::getErrorStack();
  404.         $holidays   = array();
  405.         $notFound   = array();
  406.  
  407.         foreach ($this->_internalNames as $internalName{
  408.             // check if the filter permits further processing
  409.             if ($filter->accept($internalName)) {
  410.                 continue;
  411.             }
  412.  
  413.             foreach ($this->_driverIds as $id{
  414.                 $holiday $this->_drivers[$id]->getHoliday($internalName);
  415.                 if (Date_Holidays::isError($holiday)) {
  416.                     /**
  417.                      * current driver doesn't have this internalName, trying
  418.                      * next driver
  419.                      */
  420.                     array_push($notFound$internalName);
  421.                     continue;
  422.                 }
  423.                 /**
  424.                  * internal name found in highest priorized driver, stepping to
  425.                  * next internal name checks if internal name is existent in
  426.                  * $notFound array and unsets this entry as it has been found now
  427.                  */
  428.                 $notFound array_unique($notFound);
  429.                 if (in_array($internalName$notFound)) {
  430.                     unset($notFound[array_search($internalName$notFound)]);
  431.                 }
  432.                 $holidays[$internalName$holiday;
  433.                 continue 2;
  434.             }
  435.         }
  436.  
  437.         if (empty($notFound)) {
  438.             foreach ($notFound as $internalName{
  439.                 $errorStack->push(DATE_HOLIDAYS_INVALID_INTERNAL_NAME,
  440.                                   'error',
  441.                                   array(),
  442.                                   'Invalid internal name: ' $internalName,
  443.                                   false,
  444.                                   debug_backtrace());
  445.             }
  446.         }
  447.  
  448.         if ($errorStack->hasErrors(&& empty($notFound)) {
  449.             return $errorStack;
  450.         }
  451.         return $holidays;
  452.     }
  453.  
  454.     /**
  455.      * Returns localized title for a holiday
  456.      *
  457.      * @param string $internalName internal name for holiday
  458.      * @param string $locale       locale setting that shall be used by this method
  459.      *
  460.      * @access   public
  461.      * @return   string  title on success, otherwise a PEAR_Error object
  462.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  463.      * @throws   object PEAR_Error   DATE_HOLIDAYS_TITLE_UNAVAILABLE
  464.      */
  465.     function getHolidayTitle($internalName$locale = null)
  466.     {
  467.         foreach ($this->_driverIds as $id{
  468.             $title $this->_drivers[$id]->getHolidayTitle($internalName$locale);
  469.             if (Date_Holidays::isError($title)) {
  470.                 /**
  471.                  * lets skip this error, perhaps another driver knows this
  472.                  * internal-name
  473.                  */
  474.                 continue;
  475.             }
  476.             return $title;
  477.         }
  478.  
  479.                                          'Invalid internal name: ' $internalName);
  480.     }
  481.  
  482.     /**
  483.      * Returns localized titles of all holidays or those specififed in
  484.      * $restrict array
  485.      *
  486.      * @param Date_Holidays_Filter $filter filter-object
  487.      *                                       (or an array !DEPRECATED!)
  488.      * @param string               $locale locale setting that shall be used by
  489.      *                                       this method
  490.      *
  491.      * @access   public
  492.      * @return   array   array with localized holiday titles on success,
  493.      *                       otherwise a PEAR_Error object
  494.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  495.      */
  496.     function getHolidayTitles($filter = null$locale = null)
  497.     {
  498.         if (is_null($filter)) {
  499.             $filter = new Date_Holidays_Filter_Blacklist(array());
  500.         elseif (is_array($filter)) {
  501.             $filter = new Date_Holidays_Filter_Whitelist($filter);
  502.         }
  503.  
  504.         $errorStack &Date_Holidays::getErrorStack();
  505.         $titles     = array();
  506.         $notFound   = array();
  507.  
  508.         foreach ($this->_internalNames as $internalName{
  509.             // check if the filter permits further processing
  510.             if ($filter->accept($internalName)) {
  511.                 continue;
  512.             }
  513.  
  514.             foreach ($this->_driverIds as $id{
  515.                 $title $this->_drivers[$id]->getHolidayTitle($internalName,
  516.                                                                $locale);
  517.                 if (Date_Holidays::isError($title)) {
  518.                     /**
  519.                      * current driver doesn't have this internalName, trying next
  520.                      * driver
  521.                      */
  522.                     array_push($notFound$internalName);
  523.                     continue;
  524.                 }
  525.                 /**
  526.                  * internal name found in highest priorized driver, stepping to
  527.                  * next internal name checks if internal name is existent in
  528.                  * $notFound array and unsets this entry as it has been found now
  529.                  */
  530.                 $notFound array_unique($notFound);
  531.                 if (in_array($internalName$notFound)) {
  532.                     unset($notFound[array_search($internalName$notFound)]);
  533.                 }
  534.                 $titles[$internalName$title;
  535.                 continue 2;
  536.             }
  537.         }
  538.  
  539.         if (empty($notFound)) {
  540.             foreach ($notFound as $internalName{
  541.                 $errorStack->push(DATE_HOLIDAYS_INVALID_INTERNAL_NAME,
  542.                                   'error',
  543.                                   array(),
  544.                                   'Invalid internal name: ' $internalName,
  545.                                   false,
  546.                                   debug_backtrace());
  547.             }
  548.         }
  549.  
  550.         if ($errorStack->hasErrors(&& empty($notFound)) {
  551.             return $errorStack;
  552.         }
  553.         return $titles;
  554.     }
  555.  
  556.     /**
  557.      * Using this method doesn't affect anything. If you have been able to add
  558.      * your driver to this compound, you should also be able to directly
  559.      * execute this action.
  560.      * This method is only available to keep abstraction working.
  561.      *
  562.      * @access   public
  563.      * @return   void 
  564.      */
  565.     function getYear()
  566.     {
  567.     }
  568.  
  569.     /**
  570.      * This (re)sets the year of every driver-object in the compound.
  571.      *
  572.      * Note that this will cause every attached driver to recalculate the holidays!
  573.      *
  574.      * @param int $year year
  575.      *
  576.      * @access   public
  577.      * @return   boolean true on success, otherwise a PEAR_ErrorStack object
  578.      * @throws   object PEAR_ErrorStack
  579.      */
  580.     function setYear($year)
  581.     {
  582.         $errors = false;
  583.  
  584.         foreach ($this->_driverIds as $id{
  585.             if ($this->_drivers[$id]->setYear($year!= true{
  586.                 $errors = true;
  587.             }
  588.   &nbs