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

Source for file date_helper.php

Documentation is available at date_helper.php

  1. <?php
  2. /**
  3.  *  File containing the DateHelper class and support functions
  4.  *
  5.  *  (PHP 5)
  6.  *
  7.  *  @package PHPonTrax
  8.  *  @version $Id: date_helper.php 230 2006-07-18 18:47:39Z john $
  9.  *  @copyright (c) 2005 John Peterson
  10.  *
  11.  *   Permission is hereby granted, free of charge, to any person obtaining
  12.  *   a copy of this software and associated documentation files (the
  13.  *   "Software"), to deal in the Software without restriction, including
  14.  *   without limitation the rights to use, copy, modify, merge, publish,
  15.  *   distribute, sublicense, and/or sell copies of the Software, and to
  16.  *   permit persons to whom the Software is furnished to do so, subject to
  17.  *   the following conditions:
  18.  *
  19.  *   The above copyright notice and this permission notice shall be
  20.  *   included in all copies or substantial portions of the Software.
  21.  *
  22.  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  23.  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  24.  *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  25.  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  26.  *   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  27.  *   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  28.  *   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29.  */
  30.  
  31. /**
  32.  *  Utility to help build HTML pulldown menus for date and time
  33.  */
  34. class DateHelper extends Helpers {
  35.  
  36.     /**
  37.      *  Year values parsed from $_REQUEST
  38.      *
  39.      *  Set by {@link check_request_for_value()}.  An array whose keys
  40.      *  are the names of attributes of the {@link ActiveRecord}
  41.      *  subclass named by {@link $object_name}, and whose values are
  42.      *  the strings parsed from $_REQUEST.
  43.      *  @var string[] 
  44.      */
  45.     public $request_years;
  46.  
  47.     /**
  48.      *  Month values parsed from $_REQUEST
  49.      *
  50.      *  Set by {@link check_request_for_value()}.  An array whose keys
  51.      *  are the names of attributes of the {@link ActiveRecord}
  52.      *  subclass named by {@link $object_name}, and whose values are
  53.      *  the strings parsed from $_REQUEST.
  54.      *  @var string[] 
  55.      */
  56.     public $request_months = array();
  57.  
  58.     /**
  59.      *  Day of month values parsed from $_REQUEST
  60.      *
  61.      *  Set by {@link check_request_for_value()}.  An array whose keys
  62.      *  are the names of attributes of the {@link ActiveRecord}
  63.      *  subclass named by {@link $object_name}, and whose values are
  64.      *  the strings parsed from $_REQUEST.
  65.      *  @var string[] 
  66.      */
  67.     public $request_days;
  68.  
  69.     /**
  70.      *  Hour values parsed from $_REQUEST
  71.      *
  72.      *  Set by {@link check_request_for_value()}.  An array whose keys
  73.      *  are the names of attributes of the {@link ActiveRecord}
  74.      *  subclass named by {@link $object_name}, and whose values are
  75.      *  the strings parsed from $_REQUEST.
  76.      *  @var string[] 
  77.      */
  78.     public $request_hours;
  79.  
  80.     /**
  81.      *  Minute values parsed from $_REQUEST
  82.      *
  83.      *  Set by {@link check_request_for_value()}.  An array whose keys
  84.      *  are the names of attributes of the {@link ActiveRecord}
  85.      *  subclass named by {@link $object_name}, and whose values are
  86.      *  the strings parsed from $_REQUEST.
  87.      *  @var string[] 
  88.      */
  89.     public $request_minutes;
  90.  
  91.     /**
  92.      *  Second values parsed from $_REQUEST
  93.      *
  94.      *  Set by {@link check_request_for_value()}.  An array whose keys
  95.      *  are the names of attributes of the {@link ActiveRecord}
  96.      *  subclass named by {@link $object_name}, and whose values are
  97.      *  the strings parsed from $_REQUEST.
  98.      *  @var string[] 
  99.      */
  100.     public $request_seconds;
  101.  
  102.     /**
  103.      *  <b>FIXME:</b>  Dead code?
  104.      */
  105.     public $selected_years = array();
  106.  
  107.     /**
  108.      *  Constructor
  109.      *
  110.      *  Construct an instance of Helpers with the same arguments
  111.      *  @param string Name of an ActiveRecord subclass
  112.      *  @param string Name of an attribute of $object
  113.      */
  114.     function __construct($object_name null$attribute_name null{
  115.         parent::__construct($object_name$attribute_name);
  116.     }
  117.     
  118.     /**
  119.      *  Check whether $_REQUEST holds value for this attribute
  120.      *
  121.      *  Called with the name of an ActiveRecord subclass in
  122.      *  $this->object_name and the name of one of its attributes in
  123.      *  $this->attribute_name.  Check whether $_REQUEST contains a
  124.      *  value for this attribute; if so return it.
  125.      *  @return mixed String value if attribute was found in
  126.      *                 $_REQUEST, otherwise false
  127.      *  @uses attribute_name
  128.      *  @uses object_name
  129.      *  @uses request_years
  130.      *  @uses request_months
  131.      *  @uses request_days
  132.      *  @uses request_hours
  133.      *  @uses request_minutes
  134.      *  @uses request_seconds
  135.      */
  136.     private function check_request_for_value({
  137.         //error_log("check_request_for_value().  object name='"
  138.         //          . $this->object_name ."'  attribute name = '"
  139.         //          . $this->attribute_name ."'");
  140.  
  141.         //  If $_REQUEST[$this->object_name] does not exist,
  142.         //  return false immediately
  143.         if (!isset($_REQUEST|| !is_array($_REQUEST)
  144.             || !array_key_exists($this->object_name$_REQUEST)) {
  145.             return false;
  146.         }
  147.  
  148.         //  $_REQUEST[$this->object_name] exists.
  149.         //  Look for the requested attribute
  150.         if (array_key_exists($this->attribute_name,
  151.                              $_REQUEST[$this->object_name])) {
  152.  
  153.             //  Requested attribute found, return it
  154.             return $_REQUEST[$this->object_name][$this->attribute_name];
  155.         }
  156.  
  157.         //  There is an element $_REQUEST[$this->object_name] but not
  158.         //  $_REQUEST[$this->object_name][$this->attribute_name] so
  159.         //  check for the individual components of a date/time
  160.  
  161.         //  Keep track of whether we find any components
  162.         $found false;
  163.  
  164.         //    Check for year component
  165.         if (array_key_exists($this->attribute_name."(1i)",
  166.                              $_REQUEST[$this->object_name])) {
  167.             $this->request_years[$this->attribute_name=
  168.                 $_REQUEST[$this->object_name][$this->attribute_name."(1i)"];
  169.             $found true;
  170.         }
  171.  
  172.         //    Check for month component
  173.         if (array_key_exists($this->attribute_name."(2i)",
  174.                              $_REQUEST[$this->object_name])) {
  175.             $this->request_months[$this->attribute_name=
  176.                 $_REQUEST[$this->object_name][$this->attribute_name."(2i)"];
  177.             $found true;
  178.         }
  179.  
  180.         //    Check for day component
  181.         if (array_key_exists($this->attribute_name."(3i)",
  182.                              $_REQUEST[$this->object_name])) {
  183.             $this->request_days[$this->attribute_name=
  184.                 $_REQUEST[$this->object_name][$this->attribute_name."(3i)"];
  185.             $found true;
  186.         }
  187.  
  188.         //    Check for hour component
  189.         if (array_key_exists($this->attribute_name."(4i)",
  190.                              $_REQUEST[$this->object_name])) {
  191.             $this->request_hours[$this->attribute_name=
  192.                 $_REQUEST[$this->object_name][$this->attribute_name."(4i)"];
  193.             $found true;
  194.         }   
  195.  
  196.         //    Check for minute component
  197.         if (array_key_exists($this->attribute_name."(5i)",
  198.                              $_REQUEST[$this->object_name])) {
  199.             $this->request_minutes[$this->attribute_name=
  200.                 $_REQUEST[$this->object_name][$this->attribute_name."(5i)"];
  201.             $found true;
  202.         }              
  203.  
  204.         //    Check for second component
  205.         if (array_key_exists($this->attribute_name."(6i)",
  206.                              $_REQUEST[$this->object_name])) {
  207.             $this->request_seconds[$this->attribute_name=
  208.                 $_REQUEST[$this->object_name][$this->attribute_name."(6i)"];
  209.             $found true;
  210.         }                                                                   
  211.         return $found;
  212.     }
  213.  
  214.     /**
  215.      *  Generate HTML/XML for select to enclose option list
  216.      *
  217.      *  @param string   Name attribute for <samp><select name=... ></samp>
  218.      *  @param string   <samp><option>...</option><samp> list
  219.      *  @param string   Prefix of name attribute, to be enclosed in
  220.      *                   square brackets
  221.      *  @param boolean  Whether to include a blank in the list of
  222.      *                   select options
  223.      *  @param boolean  Whether to discard the type
  224.      *  @return string  Generated HTML
  225.      */
  226.     private function select_html($type$options$prefix null,
  227.                                  $include_blank false,
  228.                                  $discard_type false{
  229.         $select_html  "<select name=\"$prefix";       
  230.         if(!$discard_type{
  231.             if($prefix$select_html .= "["
  232.             $select_html .= $type;
  233.             if($prefix$select_html .= "]"
  234.         }
  235.         $select_html .= "\">\n";
  236.         if($include_blank$select_html .= "<option value=\"\"></option>\n";
  237.         $select_html .= $options;
  238.         $select_html .= "</select>\n";
  239.         return $select_html;
  240.     }
  241.  
  242.     /**
  243.      *  Prefix a leading zero to single digit numbers
  244.      *  @param string   A number
  245.      *  @return string  Number with zero prefix if value <= 9
  246.      */
  247.     private function leading_zero_on_single_digits($number{
  248.         return $number $number "0$number";
  249.     }
  250.  
  251.     /**
  252.      *  Get attribute value from $_REQUEST if there, otherwise from database
  253.      *
  254.      *  When called, {@link $object_name} describes the
  255.      *  {@link ActiveRecord} subclass and {@link $attribute_name}
  256.      *  describes the attribute whose value is desired.
  257.      *
  258.      *  An attempt is made to find the value in $_REQUEST, where it
  259.      *  would be found after the browser POSTed a form.  If no value
  260.      *  is found there, then the database is accessed for the value.
  261.      *  When accessing the database, the assumption is made that the
  262.      *  {@link ActionController} object refers to a single
  263.      *  {@link ActiveRecord} subclass object which correctly
  264.      *  identifies the table and record containing the attribute
  265.      *  value.
  266.      *  @return mixed Attribute value if found
  267.      *  @uses check_request_for_value()
  268.      *  @uses attribute_name
  269.      *  @uses object()
  270.      *  @uses ActiveRecord::send()
  271.      */
  272.     protected function value({
  273.         //error_log("DateHelper::value()  object name={$this->object_name}"
  274.         //          . "   attribute name={$this->attribute_name}");
  275.  
  276.         //  First try to get attribute value from $_REQUEST
  277.         if(!$value $this->check_request_for_value()) {
  278.  
  279.             //  Value not found in $_REQUEST so we need to
  280.             //  go to the database.  Assume that the controller
  281.             //  points to the right ActiveRecord object
  282.             $object $this->object();
  283.             if(is_object($object&& $this->attribute_name{
  284.                 $value $object->send($this->attribute_name);
  285.             }
  286.         }
  287.         return $value;
  288.     }
  289.     
  290.     /**
  291.      *  Call to_expiration_date_select_tag()
  292.      *
  293.      *  Alias for {@link to_expiration_date_select_tag()}
  294.      *  @param mixed[]  Output format options
  295.      *  @return string Generated HTML
  296.      *  @uses to_expiration_date_select_tag()
  297.      */
  298.     function expiration_date_select($options array()) {
  299.         return $this->to_expiration_date_select_tag($options);      
  300.     }
  301.         
  302.     /**
  303.      *  Call to_datetime_select_tag()
  304.      *
  305.      *  Alias for {@link to_datetime_select_tag()}
  306.      *  @param mixed[]  Output format options
  307.      *  @return string Generated HTML
  308.      *  @uses to_datetime_select_tag()
  309.      */
  310.     function datetime_select($options array()) {     
  311.         return $this->to_datetime_select_tag($options);
  312.     
  313.     
  314.     /**
  315.      *  Call to_date_select_tag()
  316.      *
  317.      *  Alias for {@link to_date_select_tag()}
  318.      *  @param mixed[]  Output format options
  319.      *  @return string Generated HTML
  320.      *  @uses to_date_select_tag()
  321.      */
  322.     function date_select($options array()) {   
  323.         //error_log("date_select() object=$this->object_name"
  324.         //          . "   attribute=$this->attribute_name");
  325.         return $this->to_date_select_tag($options);
  326.     }  
  327.     
  328.     /**
  329.      *  Generate HTML/XML for expiration month and year selector
  330.      *  pulldowns
  331.      *
  332.      *  Generates HTML for a month and year pulldown.  The year
  333.      *  pulldown has a range of years from the initially selected year
  334.      *  to seven years after.
  335.      *
  336.      *  When called, $_REQUEST[] may have initial date values in
  337.      *  fields with default names of 'expiration_month' and
  338.      *  'expiration_year'.  If these values exist they override the
  339.      *  first parameter.
  340.      *  @param string   Date to display as initially selected if none
  341.      *     was found in $_REQUEST[].  If omitted, default value is the
  342.      *     current calendar date.<b>FIXME:</b> this doesn't work
  343.      *  @param mixed[]  Output format options:
  344.      *   <ul>
  345.      *     <li><samp>'field_separator' => '</samp><i>somestring</i><samp>'</samp><br />
  346.      *       String to insert between the month and year selectors.  If
  347.      *       none is specified, default value is <samp>' / '</samp></li>
  348.      *     <li><samp>'month_before_year' => 'false'<br />
  349.      *       Output year selector first, then month selector.
  350.      *       If option not specified, the month selector will be output
  351.      *       first.</li>
  352.      *     <li><samp>'month_name' =>'</samp><i>somestring</i><samp>'</samp><br />
  353.      *       Set the name of the generated month selector to
  354.      *       <i>somestring</i>.  If option not specified, default name is
  355.      *       <samp>expiration_month</samp></li>
  356.      *     <li><samp>'year_name' => '</samp><i>somestring</i><samp>'</samp><br />
  357.      *       Set the name of the generated year selector to
  358.      *       <i>somestring</i>.  If option not specified, default name is
  359.      *       <samp>expiration_year</samp></li>
  360.      *   </ul>
  361.      *  @return string Generated HTML
  362.      *  @uses select_html()
  363.      *  @uses select_month()
  364.      *  @uses select_year()
  365.      */
  366.     function select_expiration_date($date null$options array()) {
  367. //        error_log("select_expiration_date('"
  368. //                  . (is_null($date) ? 'null' : $date)
  369. //                  ."', " . var_export($options,true));
  370.         $options['month_before_year'true;      
  371.         $options['use_month_numbers'true;   
  372.         $options['start_year'date("Y");
  373.         $options['end_year'date("Y"7;
  374.         $options['field_separator'" / ";        
  375.  
  376.         //  Find name and initial value of year field,
  377.         //  then generate year selector pulldown
  378.         $options['field_name'array_key_exists('year_name',$options)
  379.             ? $options['year_name'"expiration_year"
  380.         $date array_key_exists($options['field_name']$_REQUEST)
  381.             ? date("Y-m-d",
  382.                    strtotime($_REQUEST[$options['field_name']]."-01-01"))
  383.             : date("Y-m-d");
  384.         $year_select $this->select_year($date$options);
  385.  
  386.         //  Find name and initial value of month field,
  387.         //  then generate year selector pulldown
  388.         $options['field_name'array_key_exists('month_name',$options)
  389.             ? $options['month_name'"expiration_month";
  390.         $date array_key_exists($options['field_name']$_REQUEST)
  391.             ? date("Y-m-d",
  392.                    strtotime("2006-".$_REQUEST[$options['field_name']]."-01"))
  393.             : date("Y-m-d");
  394.         $month_select $this->select_month($date$options);
  395.  
  396.         //  Output month and year selectors in desired order
  397.         if($options['month_before_year']{
  398.             $select_html =  $month_select $options['field_separator']
  399.                 .  $year_select;     
  400.         else {
  401.             $select_html =  $year_select $options['field_separator']
  402.                 .  $month_select;
  403.         }
  404.         return $select_html;
  405.     }               
  406.  
  407.     /**
  408.      *  Generate HTML/XML for year, month and day selector pull-down menus
  409.      *
  410.      *  Returns <samp><select>...</select></samp> HTML with options
  411.      *  for a number of years, months and days.  The first argument,
  412.      *  if present, specifies the initially selected date.  The second
  413.      *  argument controls the format of the generated HTML.
  414.      *
  415.      *  Examples:
  416.      *  <ul>
  417.      *   <li><samp>select_date();</samp><br /> Generates a group of
  418.      *     three pulldown menus in the order year, month and day with
  419.      *     the current date initially selected.</li>
  420.      *   <li>
  421.      *  <samp>select_date('August 4, 1998');</samp><br /> Generates a
  422.      *    group of   three pulldown menus in the order year, month and
  423.      *    day with the date August 4, 1998 initially selected.</li>
  424.      *  </ul>
  425.      *
  426.      *  @param string   Date to display as initially selected if none
  427.      *     was found in
  428.      *     {@link $request_years}[{@link $attribute_name}],
  429.      *     {@link $request_months}[{@link $attribute_name}] and
  430.      *     {@link $request_days}[{@link $attribute_name}].
  431.      *     Character string is any US English date representation
  432.      *     supported by {@link strtotime()}.  If omitted, the
  433.      *     current date is initially selected.
  434.      *
  435.      *  @param mixed[] Output format options are all of the options of
  436.      *     {@link select_year()}{@link select_month()} and
  437.      *     {@link select_day()}.
  438.      *  @return string  Generated HTML
  439.      *  @uses select_day()
  440.      *  @uses select_month()
  441.      *  @uses select_year()
  442.      */
  443.     function select_date($date null$options array()) {
  444.         $date is_null($datedate("Y-m-d"$date;
  445.         return $this->select_year($date$options.
  446.                 $this->select_month($date$options.
  447.                 $this->select_day($date$options);
  448.     }
  449.  
  450.     /**
  451.      *  Generate HTML/XML for year-month-day-hour-minute selector pulldowns
  452.      *
  453.      *  Returns <samp><select>...</select></samp> HTML with options
  454.      *  for a number of years, months, days, hours and minutes.  The
  455.      *  first argument, if present, specifies the initially selected
  456.      *  date.  The second argument controls the format of the
  457.      *  generated HTML.
  458.      *
  459.      *  Examples:
  460.      *  <ul>
  461.      *   <li><samp>select_datetime();</samp><br /> Generates a group of
  462.      *     five pulldown menus in the order year, month, day, hour and
  463.      *     minute with the current date and time initially
  464.      *    selected.</li>
  465.      *   <li>
  466.      *  <samp>select_datetime('1998-04-08 13:21:17');</samp><br />
  467.      *    Generates a group of five pulldown menus in the order year,
  468.      *    month, day, hour and minute with the date/time
  469.      *    1998 August 4 13:21 initially selected.</li>
  470.      *  </ul>
  471.      *
  472.      *  @param string   Date/time to display as initially selected.
  473.      *     Character string is any US English date representation
  474.      *     supported by {@link strtotime()}.  If omitted, the
  475.      *     current date/time is initially selected.
  476.      *
  477.      *  @param mixed[] Output format options are all of the options of
  478.      *     {@link select_year()}{@link select_month()},
  479.      *     {@link select_day()}{@link select_hour()} and
  480.      *     {@link select_minute()}.
  481.      *  @return string  Generated HTML
  482.      *  @uses select_day()
  483.      *  @uses select_hour()
  484.      *  @uses select_minute()
  485.      *  @uses select_month()
  486.      *  @uses select_year()
  487.      */
  488.     function select_datetime($datetime null$options array()) {
  489.         $datetime is_null($datetimedate("Y-m-d H:i:s"$datetime;
  490.         return $this->select_year($datetime$options.
  491.                 $this->select_month($datetime$options.
  492.                 $this->select_day($datetime$options.
  493.                 $this->select_hour($datetime$options.
  494.                 $this->select_minute($datetime$options);
  495.     }
  496.  
  497.     /**
  498.      *  Generate HTML/XML for hour, minute and second selector pull-down menus
  499.      *
  500.      *  Returns <samp><select>...</select></samp> HTML with options
  501.      *  for a number of hours, minutes and seconds.  The first argument,
  502.      *  if present, specifies the initially selected time.  The second
  503.      *  argument controls the format of the generated HTML.
  504.      *
  505.      *  Examples:
  506.      *  <ul>
  507.      *   <li><samp>select_time();</samp><br /> Generates two pulldown
  508.      *     menus in the order hour : minute with
  509.      *     the current time initially selected.</li>
  510.      *   <li>
  511.      *  <samp>select_time('August 4, 1998 8:12');</samp><br /> Generates
  512.      *    two pulldown menus in the order hour : minute with the
  513.      *    time 8:12 initially selected.</li>
  514.      *  </ul>
  515.      *
  516.      *  @param string   Time to display as initially selected if none
  517.      *     was found in
  518.      *     {@link $request_hours}[{@link $attribute_name}],
  519.      *     {@link $request_minutes}[{@link $attribute_name}] and
  520.      *     {@link $request_seconds}[{@link $attribute_name}].
  521.      *     Character string is any US English date/time representation
  522.      *     supported by {@link strtotime()}.  If omitted, the
  523.      *     current time is initially selected.
  524.      *
  525.      *  @param mixed[] Output format options are all of the options of
  526.      *     {@link select_hour()}{@link select_minute()} and
  527.      *     {@link select_second()}.
  528.      *  @return string  Generated HTML
  529.      *  @uses select_hour()
  530.      *  @uses select_minute()
  531.      *  @uses select_second()
  532.      */
  533.     function select_time($datetime null$options array()) {
  534.         $datetime is_null($datetimedate("Y-m-d H:i:s"$datetime;
  535.         return $this->select_hour($datetime$options.
  536.                $this->select_minute($datetime$options.
  537.             (array_key_exists('include_seconds'$options)
  538.              && $options['include_seconds']
  539.              ? $this->select_second($datetime$options'');
  540.     }
  541.  
  542.     /**
  543.      *  Generate HTML/XML for second selector pull-down menu
  544.      *
  545.      *  Returns <samp><select>...</select></samp> HTML with an option
  546.      *  for each of the sixty seconds.  The first argument, if
  547.      *  present, specifies the initially selected second.  The second
  548.      *  argument controls the format of the generated HTML.
  549.      *
  550.      *  Examples:
  551.      *  <ul>
  552.      *   <li><samp>select_second();</samp><br />
  553.      *     Generates menu '00', '01', ..., '59'.  Initially selected
  554.      *     second is the second in
  555.      *     {@link $request_seconds}[{@link $attribute_name}], or if that
  556.      *     is not defined, the current second.</li>
  557.      *   <li><samp>select_second(null,array('include_blank' => true));</samp>
  558.      *    <br />Generates menu ' ', '00', '01',..., '59'.  Initially
  559.      *    selected second same as above.</li>
  560.      *  </ul>
  561.      *
  562.      *  @param string  Initially selected second as two-digit number.
  563.      *   If a value for this field is specified in
  564.      *   {@link $request_seconds}[{@link $attribute_name}], then that second
  565.      *   is initially selected regardless of the value of this argument.
  566.      *   Otherwise, if the first argument is present and is a character
  567.      *   string of two decimal digits with a value in the range
  568.      *   '00'..'59' then that second is initially selected.  If this
  569.      *   argument is absent or invalid, the current second is
  570.      *   initially selected.
  571.      *  @param mixed[] Output format options:
  572.      *   <ul>
  573.      *     <li><samp>'include_blank' => true</samp> Show a blank
  574.      *       as the first option.</li>
  575.      *     <li><samp>'field_name' => '</samp><i>somestring</i><samp>'</samp>
  576.      *       Generate output<br />
  577.      *       <samp><select name="</samp><i>somestring</i><samp>">...</select></samp> .
  578.      *       <br />If absent, generate output<br />
  579.      *       <samp><select name="second">...</select></samp>.</li>
  580.      *     <li><samp>'discard_type' => ???</samp> FIXME</li>
  581.      *     <li><samp>'prefix' => ???</samp> FIXME</li>
  582.      *   </ul>
  583.      *
  584.      *  @return string  Generated HTML
  585.      *  @uses attribute_name
  586.      *  @uses leading_zero_on_single_digits()
  587.      *  @uses request_seconds
  588.      *  @uses select_html()
  589.      */
  590.     function select_second($datetime=null$options array()) {
  591.         //error_log("select_second() \$datetime=$datetime  \$options="
  592.         //          .var_export($options,true));
  593.         $second_options "";
  594.         
  595.         if($this->request_seconds[$this->attribute_name]{
  596.             $datetime_sec $this->request_seconds[$this->attribute_name];    
  597.         elseif(strlen($datetime== && is_numeric($datetime)) {
  598.             $datetime_sec $datetime;
  599.         else {                  
  600.             $datetime $options['value'$options['value':
  601.                 ($datetime $datetime date("Y-m-d H:i:s"))
  602.             $datetime_sec date("s",strtotime($datetime));
  603.         }
  604.         
  605.         for($second 0$second <= 59$second++{          
  606.             $second_options .= ($datetime && ($datetime_sec == $second)) ?
  607.             "<option value=\"".$this->leading_zero_on_single_digits($second)."\"  selected=\"selected\">".$this->leading_zero_on_single_digits($second)."</option>\n" :
  608.             "<option value=\"".$this->leading_zero_on_single_digits($second)."\">".$this->leading_zero_on_single_digits($second)."</option>\n";
  609.         }
  610.         $field_name array_key_exists('field_name',$options)
  611.                        ? $options['field_name''second';
  612.         return $this->select_html($field_name$second_options,
  613.                                   array_key_exists('prefix',$options)
  614.                                   ? $options['prefix'null,
  615.                                   array_key_exists('include_blank',$options)
  616.                                   ? $options['include_blank'false,
  617.                                   array_key_exists('discard_type',$options)
  618.                                   ? $options['discard_type'false);
  619.     }
  620.  
  621.     /**
  622.      *  Generate HTML/XML for minute selector pull-down menu
  623.      *
  624.      *  Returns <samp><select>...</select></samp> HTML with an option
  625.      *  for each of the sixty minutes.  The first argument, if
  626.      *  present, specifies the initially selected minute.  The second
  627.      *  argument controls the format of the generated HTML.
  628.      *
  629.      *  Examples:
  630.      *  <ul>
  631.      *   <li><samp>select_minute();</samp><br />
  632.      *     Generates menu '00', '01', ..., '59'.  Initially selected
  633.      *     minute is the minute in
  634.      *     {@link $request_minutes}[{@link $attribute_name}], or if that
  635.      *     is not defined, the current minute.</li>
  636.      *   <li><samp>select_minute(null,array('include_blank' => true));</samp>
  637.      *    <br />Generates menu ' ', '00', '01',..., '59'.  Initially
  638.      *    selected minute same as above.</li>
  639.      *  </ul>
  640.      *
  641.      *  @param string  Initially selected minute as two-digit number.
  642.      *   If a value for this field is specified in
  643.      *   {@link $request_minutes}[{@link $attribute_name}], then that minute
  644.      *   is initially selected regardless of the value of this argument.
  645.      *   Otherwise, if the first argument is present and is a character
  646.      *   string of two decimal digits with a value in the range
  647.      *   '00'..'59' then that minute is initially selected.  If this
  648.      *   argument is absent or invalid, the current minute is
  649.      *   initially selected.
  650.      *  @param mixed[] Output format options:
  651.      *   <ul>
  652.      *     <li><samp>'include_blank' => true</samp> Show a blank
  653.      *       as the first option.</li>
  654.      *     <li><samp>'field_name' => '</samp><i>somestring</i><samp>'</samp>
  655.      *       Generate output<br />
  656.      *       <samp><select name="</samp><i>somestring</i><samp>">...</select></samp> .
  657.      *       <br />If absent, generate output<br />
  658.      *       <samp><select name="minute">...</select></samp>.</li>
  659.      *     <li><samp>'discard_type' => ???</samp> FIXME</li>
  660.      *     <li><samp>'prefix' => ???</samp> FIXME</li>
  661.      *   </ul>
  662.      *
  663.      *  @return string  Generated HTML
  664.      *  @uses attribute_name
  665.      *  @uses leading_zero_on_single_digits()
  666.      *  @uses request_minutes
  667.      *  @uses select_html()
  668.      */
  669.     function select_minute($datetime=null$options array()) {
  670.         $minute_options "";
  671.         
  672.         if($this->request_minutes[$this->attribute_name]{
  673.             $datetime_min $this->request_minutes[$this->attribute_name];    
  674.         elseif(strlen($datetime== && is_numeric($datetime)) {
  675.             $datetime_min $datetime;
  676.         else {                  
  677.             #$datetime = $datetime ? $datetime : date("Y-m-d H:i:s"); 
  678.             $datetime $options['value'$options['value':
  679.                 ($datetime $datetime date("Y-m-d H:i:s"));            
  680.             $datetime_min date("i",strtotime($datetime));
  681.         }
  682.         
  683.         for($minute 0$minute <= 59$minute++{        
  684.             $minute_options .= ($datetime && ($datetime_min == $minute)) ?
  685.             "<option value=\"".$this->leading_zero_on_single_digits($minute)."\"  selected=\"selected\">".$this->leading_zero_on_single_digits($minute)."</option>\n" :
  686.             "<option value=\"".$this->leading_zero_on_single_digits($minute)."\">".$this->leading_zero_on_single_digits($minute)."</option>\n";
  687.         }
  688.         $field_name array_key_exists('field_name'$options)
  689.             ? $options['field_name''minute';
  690.         return $this->select_html($field_name$minute_options,
  691.                                   array_key_exists('prefix'$options)
  692.                                   ? $options['prefix'null,
  693.                                   array_key_exists('include_blank'$options)
  694.                                   ? $options['include_blank'false,
  695.                                   array_key_exists('discard_type'$options)
  696.                                   ? $options['discard_type'false);
  697.     }
  698.  
  699.     /**
  700.      *  Generate HTML/XML for hour selector pull-down menu
  701.      *
  702.      *  Returns <samp><select>...</select></samp> HTML with an option
  703.      *  for each of the twenty-four hours.  The first argument, if
  704.      *  present, specifies the initially selected hour.  The second
  705.      *  argument controls the format of the generated HTML.
  706.      *
  707.      *  Examples:
  708.      *  <ul>
  709.      *   <li><samp>select_hour();</samp><br />
  710.      *     Generates menu '00', '01', ..., '23'.  Initially selected
  711.      *     hour is the hour in
  712.      *     {@link $request_hours}[{@link $attribute_name}], or if that
  713.      *     is not defined, the current hour.</li>
  714.      *   <li><samp>select_hour(null,array('include_blank' => true));</samp>
  715.      *    <br />Generates menu ' ', '00', '01',..., '23'.  Initially
  716.      *    selected hour same as above.</li>
  717.      *  </ul>
  718.      *
  719.      *  @param string  Initially selected hour as two-digit number.
  720.      *   If a value for this field is specified in
  721.      *   {@link $request_hours}[{@link $attribute_name}], then that hour
  722.      *   is initially selected regardless of the value of this argument.
  723.      *   Otherwise, if the first argument is present and is a character
  724.      *   string of two decimal digits with a value in the range
  725.      *   '00'..'23' then that hour is initially selected.  If this
  726.      *   argument is absent or invalid, the current hour is
  727.      *   initially selected.
  728.      *  @param mixed[] Output format options:
  729.      *   <ul>
  730.      *     <li><samp>'include_blank' => true</samp> Show a blank
  731.      *       as the first option.</li>
  732.      *     <li><samp>'field_name' => '</samp><i>somestring</i><samp>'</samp>
  733.      *       Generate output<br />
  734.      *       <samp><select name="</samp><i>somestring</i><samp>">...</select></samp> .
  735.      *       <br />If absent, generate output<br />
  736.      *       <samp><select name="hour">...</select></samp>.</li>
  737.      *     <li><samp>'discard_type' => ???</samp> FIXME</li>
  738.      *     <li><samp>'prefix' => ???</samp> FIXME</li>
  739.      *   </ul>
  740.      *
  741.      *  @return string  Generated HTML
  742.      *  @uses attribute_name
  743.      *  @uses leading_zero_on_single_digits()
  744.      *  @uses request_hours
  745.      *  @uses select_html()
  746.      */
  747.     function select_hour($datetime=null$options array()) {
  748.         //error_log("DateTime::select_hour() \$datetime=$datetime \$options="
  749.         //          .var_export($options,true));
  750.         $hour_options "";
  751.         
  752.         //  If a value for this attribute was parsed from $_REQUEST,
  753.         //  use it as initially selected and ignore first argument
  754.         if($this->request_hours[$this->attribute_name]{
  755.             $datetime_hour $this->request_hours[$this->attribute_name];    
  756.         }
  757.  
  758.         //  No value in $_REQUEST so look at the first argument.
  759.         //  If it is valid use it as initially selected
  760.         elseif(strlen($datetime== && is_numeric($datetime)) {
  761.             $datetime_hour $datetime;
  762.         }
  763.  
  764.         //  First argument is missing or invalid,
  765.         //  initially select current hour
  766.         else {                  
  767.             #$datetime = $datetime ? $datetime : date("Y-m-d H:i:s"); 
  768.             $datetime $options['value'$options['value':
  769.                 ($datetime $datetime date("Y-m-d H:i:s"));
  770.             $datetime_hour date("H",strtotime($datetime))
  771.         }
  772.  
  773.         //  Generate <option>...</option> HTML for each hour
  774.         for($hour 0$hour <= 23$hour++{
  775.             $hour_options .= ($datetime && ($datetime_hour == $hour)) ?
  776.             "<option value=\"".$this->leading_zero_on_single_digits($hour)."\"  selected=\"selected\">".$this->leading_zero_on_single_digits($hour)."</option>\n" :
  777.             "<option value=\"".$this->leading_zero_on_single_digits($hour)."\">".$this->leading_zero_on_single_digits($hour)."</option>\n";
  778.         }
  779.  
  780.         //  Return finished HTML
  781.         $field_name array_key_exists('field_name'$options)
  782.             ? $options['field_name''hour';
  783.         return $this->select_html($field_name$hour_options,
  784.                                   array_key_exists('prefix'$options)
  785.                                   ? $options['prefix'null,
  786.                                   array_key_exists('include_blank'$options)
  787.                                   ? $options['include_blank'false,
  788.                                   array_key_exists('discard_type'$options)
  789.                                   ? $options['discard_type'false);
  790.     }
  791.  
  792.     /**
  793.      *  Generate HTML/XML for day selector pull-down menu
  794.      *
  795.      *  Returns <samp><select>...</select></samp> HTML with an option
  796.      *  for each of the thirty-one days.  The first argument, if
  797.      *  present, specifies the initially selected day.  The second
  798.      *  argument controls the format of the generated HTML.
  799.      *
  800.      *
  801.      *  Examples:
  802.      *  <ul>
  803.      *   <li><samp>select_day();</samp><br />
  804.      *     Generates menu '01', '02', ..., '31'.  Initially selected
  805.      *     day is the day in
  806.      *     {@link $request_days}[{@link $attribute_name}], or if that
  807.      *     is not defined, the current calendar day.</li>
  808.      *   <li><samp>select_day(null,array('include_blank' => true));</samp>
  809.      *    <br />Generates menu ' ', '01', '02',..., '31'.  Initially
  810.      *    selected day same as above.</li>
  811.      *  </ul>
  812.      *
  813.      *  @param string  Initially selected day as two-digit number.
  814.      *   If a value for this field is specified in
  815.      *   {@link $request_days}[{@link $attribute_name}], then that day
  816.      *   is initially selected regardless of the value of this argument.
  817.      *   Otherwise, if the first argument is present and is a character
  818.      *   string of two decimal digits with a value in the range
  819.      *   '01'..'31' then that day is initially selected.  Otherwise, if
  820.      *   the first argument is a date in some US English date format,
  821.      *   the day of the month from that date is initially selected.  If
  822.      *   this argument is absent or invalid, the current calendar day
  823.      *   is initially selected.
  824.      *  @param mixed[] Output format options:
  825.      *   <ul>
  826.      *     <li><samp>'include_blank' => true</samp> Show a blank
  827.      *       as the first option.</li>
  828.      *     <li><samp>'field_name' => '</samp><i>somestring</i><samp>'</samp>
  829.      *       Generate output<br />
  830.      *       <samp><select name="</samp><i>somestring</i><samp>">...</select></samp> .
  831.      *       <br />If absent, generate output<br />
  832.      *       <samp><select name="day">...</select></samp>.</li>
  833.      *     <li><samp>'discard_type' => ???</samp> FIXME</li>
  834.      *     <li><samp>'prefix' => ???</samp> FIXME</li>
  835.      *   </ul>
  836.      *
  837.      *  @return string  Generated HTML
  838.      *  @uses attribute_name
  839.      *  @uses leading_zero_on_single_digits()
  840.      *  @uses request_days
  841.      *  @uses select_html()
  842.      */
  843.     function select_day($datetime=null$options array()) {
  844.         $day_options "";
  845.         
  846.         //  If a value for this attribute was parsed from $_REQUEST,
  847.         //  use it as initially selected and ignore first argument
  848.         if($this->request_days[$this->attribute_name]{
  849.             $datetime_day $this->request_days[$this->attribute_name];    
  850.         }
  851.  
  852.         //  No value in $_REQUEST so look at the first argument.
  853.         //  If it is valid use it as initially selected
  854.         elseif(strlen($datetime== && is_numeric($datetime)) {
  855.             $datetime_day $datetime;
  856.         }
  857.  
  858.         //  First argument is missing or invalid,
  859.         //  initially select current day
  860.         else {                  
  861.             #$datetime = $datetime ? $datetime : date("Y-m-d H:i:s");
  862.             $datetime $options['value'$options['value':
  863.                 ($datetime $datetime date("Y-m-d H:i:s"));
  864.             $datetime_day date("d",strtotime($datetime));  
  865.         }
  866.         
  867.         //  Generate <option>...</option> HTML for each day
  868.         for($day 1$day <= 31$day++{        
  869.             $day_options .= ($datetime && ($datetime_day == $day)) ?
  870.             "<option value=\"".$this->leading_zero_on_single_digits($day)."\"  selected=\"selected\">".$this->leading_zero_on_single_digits($day)."</option>\n" :
  871.             "<option value=\"".$this->leading_zero_on_single_digits($day)."\">".$this->leading_zero_on_single_digits($day)."</option>\n";
  872.         }
  873.  
  874.         //  Return finished HTML
  875.         $field_name array_key_exists('field_name'$options)
  876.             ? $options['field_name''day';
  877.         return $this->select_html($field_name$day_options,
  878.                                   array_key_exists('prefix',$options)
  879.                                   ? $options['prefix'null,
  880.                                   array_key_exists('include_blank'$options)
  881.                                   ? $options['include_blank'false,
  882.                                   array_key_exists('discard_type'$options)
  883.                                   ? $options['discard_type'false);
  884.     }
  885.  
  886.     /**
  887.      *  Generate HTML/XML for month selector pull-down menu
  888.      *
  889.      *  Returns <samp><select>...</select></samp> HTML with an option
  890.      *  for each of the twelve months.  The first argument, if
  891.      *  present, specifies the initially selected month.  The second
  892.      *  argument controls the format of the generated HTML.
  893.      *
  894.      *
  895.      *  Examples:
  896.      *  <ul>
  897.      *   <li><samp>select_month();</samp> Generates menu January,
  898.      *    February etc.</li>
  899.      *   <li><samp>select_month(null,array('use_month_number' => true));</samp>
  900.      *    Generates menu 1, 2 etc.</li>
  901.      *   <li><samp>select_month(null,array('add_month_number' => true));</samp>
  902.      *    Generates menu 1 - January, 2 - February etc.</li>
  903.      *  </ul>
  904.      *
  905.      *  @param string  Initially selected month as two-digit number.
  906.      *   If a value for this field is specified in
  907.      *   {@link $request_months}[{@link $attribute_name}], then that month
  908.      *   is initially selected regardless of the value of this argument.
  909.      *   Otherwise, if the first argument is present and is a character
  910.      *   string of two decimal digits with a value in the range
  911.      *   '01'..'12' then that month is initially selected.  Otherwise,
  912.      *   if the first argument is a date in some US English date
  913.      *   format, the month from that date is initially selected. If
  914.      *   this argument is absent or invalid, the current calendar month
  915.      *   is initially selected.
  916.      *  @param mixed[] Output format options:
  917.      *   <ul>
  918.      *     <li><samp>'include_blank' => true</samp> Show a blank
  919.      *       as the first option.</li>
  920.      *     <li><samp>'use_month_number' => true</samp> Show months in
  921.      *       the menu by their month number (1, 2 ...).  Default is to
  922.      *       show English month name (January, February ...).</li>
  923.      *     <li><samp>'add_month_number' => true</samp> Show both month
  924.      *       number and month name in the menu.</li>
  925.      *     <li><samp>'field_name' => '</samp><i>somestring</i><samp>'</samp>
  926.      *       Generate output<br />
  927.      *       <samp><select name="</samp><i>somestring</i><samp>">...</select></samp> .
  928.      *       <br />If absent, generate output<br />
  929.      *       <samp><select name="month">...</select></samp>.</li>
  930.      *     <li><samp>'discard_type' => ???</samp> FIXME</li>
  931.      *     <li><samp>'prefix' => ???</samp> FIXME</li>
  932.      *   </ul>
  933.      *   In all cases the value sent to the server is the two digit
  934.      *   month number in the range '01'..'12'.
  935.      *
  936.      *  @return string  Generated HTML
  937.      *  @uses attribute_name
  938.      *  @uses leading_zero_on_single_digits()
  939.      *  @uses request_months
  940.      *  @uses select_html
  941.      */
  942.     function select_month($date null$options array()) {
  943.         $month_options "";    // will accumulate <option>s
  944.         
  945.         //  If a value for this attribute was parsed from $_REQUEST,
  946.         //  use it as initially selected and ignore first argument
  947.         if(array_key_exists($this->attribute_name,$this->request_months)) {
  948.             $date_month $this->request_months[$this->attribute_name];    
  949.         }
  950.  
  951.         //  No value in $_REQUEST so look at the first argument.
  952.         //  If it is valid use it as initially selected
  953.         elseif(strlen($date== && is_numeric($date)
  954.                && $date >=&& $date <= 12 {
  955.             $date_month $date;
  956.         }
  957.  
  958.         //  Parse initially selected month from US English description
  959.         //  in first argument if present, otherwise select current month
  960.         else {
  961.             $date $options['value'$options['value':
  962.                 ($date $date date("Y-m-d H:i:s"));
  963.             $date_month date("m",strtotime($date));  
  964.         }
  965.    
  966.         //  Generate <option>...</option> HTML for each month
  967.         for($month_number 1$month_number <= 12$month_number++{
  968.             if(array_key_exists('use_month_numbers',$options)) {
  969.                 $month_name $month_number;
  970.             elseif(array_key_exists('add_month_numbers',$options)) {
  971.                 $month_name $month_number' - '
  972.                     . date("F",strtotime("2005-" $month_number
  973.                                        . "-01"));
  974.             else {
  975.                 $month_name date("F",strtotime("2005-" $month_number
  976.                                                  ."-01"));
  977.             }
  978.  
  979.             $month_options .= ($date_month == $month_number ?
  980.                                "<option value=\""
  981.                           .$this->leading_zero_on_single_digits($month_number)
  982.                        ."\" selected=\"selected\">$month_name</option>\n:
  983.                                "<option value=\""
  984.                           .$this->leading_zero_on_single_digits($month_number)
  985.                                ."\">$month_name</option>\n");
  986.         }
  987.  
  988.         //  Return finished HTML
  989.         $field_name array_key_exists('field_name'$options)
  990.                        ? $options['field_name''month';
  991.         return $this->select_html($field_name$month_options,
  992.                                   array_key_exists('prefix'$options)
  993.                                   ? $options['prefix'null,
  994.                                   array_key_exists('include_blank'$options)
  995.                                   ? $options['include_blank'false,
  996.                                   array_key_exists('discard_type'$options)
  997.                                   ? $options['discard_type'false);
  998.     }
  999.  
  1000.     /**
  1001.      *  Generate HTML/XML for year selector pull-down menu
  1002.      *
  1003.      *  Returns <samp><select>...</select></samp> HTML with options
  1004.      *  for a number of years.  The first argument, if present,
  1005.      *  specifies the initially selected year.  The second
  1006.      *  argument controls the format of the generated HTML.
  1007.      *
  1008.      *  Examples:
  1009.      *  <ul>
  1010.      *   <li><samp>select_year();</samp><br /> Generates a pulldown menu with
  1011.      *     with a range of +/- five years.  If a year is specified in
  1012.      *     {@link $request_years}[{@link $attribute_name}] then it is
  1013.      *     selected initially, otherwise the current calendar year is
  1014.      *     selected.</li>
  1015.      *   <li>
  1016.      *  <samp>select_year(null,array('start_year' => '1900));</samp><br />
  1017.      *    Generates year options from 1900 to five years after the
  1018.      *    initially selected year, which is chosen as in the previous
  1019.      *    example.</li>
  1020.      *   <li><samp>select_year(null,array('start_year'=>date('Y')+5, 'end_year'=>date('Y')-5);</samp><br />
  1021.      *    Generates year options starting five years after the current year,
  1022.      *    ending five years before the current year.
  1023.      *  </ul>
  1024.      *
  1025.      *  @param string   Year to display as initially selected if none
  1026.      *     was found in {@link $request_years}[{@link $attribute_name}].
  1027.      *     Character string is either exactly four decimal
  1028.      *     digits or some English date representation.  If omitted, the
  1029.      *     current year is initially selected.
  1030.      *
  1031.      *  @param mixed[] Output format options:
  1032.      *   <ul>
  1033.      *     <li><samp>'start_year'=>'</samp><i>startyear</i><samp>'</samp>
  1034.      *       If specified, <i>startyear</i> will be the first year in
  1035.      *       the output menu, otherwise the first year in the menu will
  1036.      *       be five years before the initially selected year.</li>
  1037.      *     <li><samp>'end_year'=>'</samp><i>endyear</i><samp>'</samp>
  1038.      *       If specified, <i>endyear</i> will be the last year in
  1039.      *       the output menu, otherwise the last year in the menu will
  1040.      *       be five years after the initially selected year.</li>
  1041.      *     <li><samp>'field_name' => '</samp><i>somestring</i><samp>'</samp>
  1042.      *       Generate output<br />
  1043.      *       <samp><select name="</samp><i>somestring</i><samp>">...</select></samp> .
  1044.      *       <br />If absent, generate output<br />
  1045.      *       <samp><select name="year">...</select></samp>.</li>
  1046.      *     <li><samp>'discard_type' => ???</samp> FIXME</li>
  1047.      *     <li><samp>'prefix' => ???</samp> FIXME</li>
  1048.      *   </ul>
  1049.      *   To generate a list with most recent year first, define that
  1050.      *   year as the start year and the oldest year as the end year.
  1051.      *  @return string  Generated HTML
  1052.      *  @uses attribute_name
  1053.      *  @uses request_years
  1054.      *  @uses select_html
  1055.      *  @uses year_option()
  1056.      */
  1057.     function select_year($date=null$options array()) {
  1058.         //error_log("select_year('" . (is_null($date) ? 'null' : $date)
  1059.         //          ."', " . var_export($options,true));
  1060.         //error_log('request_years='
  1061.         //     .var_export($this->request_years[$this->attribute_name],true));
  1062.         $year_options "";
  1063.  
  1064.         //  Find the year to display.
  1065.         if($this->request_years[$this->attribute_name]{
  1066.  
  1067.             //  There was a value for this attribute in $_REQUEST
  1068.             //  so display it as the initial choice
  1069.             $date_year $this->request_years[$this->attribute_name];    
  1070.         elseif(strlen($date== && is_numeric($date)) {
  1071.  
  1072.             //  The first argument is exactly four decimal digits
  1073.             //  so interpret that as a year
  1074.             $date_year $date;     
  1075.         else {
  1076.  
  1077.             //  If a first argument was specified, assume that it is
  1078.             //  some English date representation and convert it for
  1079.             //  use as the initial value.
  1080.             //  If first argument was null, use the current year for
  1081.             //  the initial value.
  1082.             $date $options['value'$options['value':
  1083.                 ($date $date date("Y-m-d H:i:s"));
  1084.             $date_year date("Y",strtotime($date));
  1085.         
  1086.  
  1087.         //  Set first year to appear in the option list
  1088.         $start_year array_key_exists('start_year',$options)
  1089.                        ? $options['start_year'$date_year 5;
  1090.  
  1091.         //  Set last year to appear in the option list
  1092.         $end_year array_key_exists('end_year',$options)
  1093.                      ? $options['end_year'$date_year 5;
  1094.  
  1095.         if ($start_year $end_year{
  1096.             for($year $start_year$year <= $end_year$year++{
  1097.                 $year_options .= $this->year_option($year$date_year);
  1098.             }
  1099.         else {
  1100.             for($year $start_year$year >= $end_year$year--{
  1101.                 $year_options .= $this->year_option($year$date_year);
  1102.             }
  1103.         }
  1104.  
  1105.         $field_name array_key_exists('field_name',$options)
  1106.                       ? $options['field_name''year';
  1107.         return $this->select_html($field_name$year_options,
  1108.                                   array_key_exists('prefix',$options)
  1109.                                   ? $options['prefix'null,
  1110.                                   array_key_exists('include_blank',$options)
  1111.                                   ? $options['include_blank'false,
  1112.                                   array_key_exists('discard_type',$options)
  1113.                                   ? $options['discard_type'false);
  1114.  
  1115.     }
  1116.  
  1117.     /**
  1118.      *  Return one HTML/XML year option, selected if so specified
  1119.      *  @param integer Year to put in the option
  1120.      *  @param integer Year that should be selected
  1121.      *  @return string HTML for one year option
  1122.      */
  1123.     function year_option($year$date_year{
  1124.         return "<option value=\"$year\""
  1125.             . (($date_year == $year"  selected=\"selected\">" ">")
  1126.             . "$year</option>\n";
  1127.     }
  1128.  
  1129.     /**
  1130.      *  Generate HTML/XML for day/month/year selector pull-down menus
  1131.      *
  1132.      *  When called, {@link $object_name} describes the
  1133.      *  {@link ActiveRecord} subclass and {@link $attribute_name}
  1134.      *  describes the attribute whose value will be set by the
  1135.      *  generated pull-down menus.  The value to be displayed
  1136.      *  initially in each menu is from $_REQUEST if present, otherwise
  1137.      *  from the database.
  1138.      *
  1139.      *  @param mixed[] Output format options
  1140.      *   <ul>
  1141.      *     <li><samp>'discard_day' => true</samp> Don't show a day of
  1142.      *       month menu. If absent or false, day menu will be output.</li>
  1143.      *     <li><samp>'discard_month' => true</samp> Don't show a month
  1144.      *       or day of the month menu.  If absent or false, month menu
  1145.      *       will be output.</li>
  1146.      *     <li><samp>'discard_type' => true</samp> (true is the
  1147.      *       default) Don't show name of individual field, for example
  1148.      *       <samp>[year]</samp>, as part of the <samp>name</samp> value
  1149.      *       of the generated <samp><select ...></samp>.  The
  1150.      *       information to identify the field is available as a suffix
  1151.      *       <samp>(</samp><i>n</i><samp>i)</samp> of the attribute
  1152.      *       name.</li>
  1153.      *     <li><samp>'discard_year' => true</samp> Don't show a year
  1154.      *       menu.  If absent or false, year menu will be output.</li>
  1155.      *     <li><samp>'field_separator' => '</samp><i>string</i><samp>'</samp>
  1156.      *       String to insert between the submenus in the output.  If
  1157.      *       absent, one blank will be inserted.</li>
  1158.      *     <li><samp>'include_blank' => true</samp> Initially show a blank
  1159.      *       selection in the menu.  If absent or false, the current
  1160.      *       date will be shown as the initial selection.  If a value
  1161.      *       was parsed from $_REQUEST, it will be used for the initial
  1162.      *       selection regardless of this option.</li>
  1163.      *     <li><samp>'month_before_year' => true</samp>  Equivalent to
  1164.      *       <samp>'order' => array('month', 'day', 'year')</samp></li>
  1165.      *     <li><samp>'order' => array(</samp><i>elements</i><samp>)</samp>
  1166.      *       A list of the elements <samp>'month', 'day'</samp> and
  1167.      *       <samp>'year'</samp> in the order in which the menus should
  1168.      *       appear in the output. Default is
  1169.      *       <samp>'year', 'month', 'day'</samp></li>
  1170.      *     <li><b>Also:</b> options provided by {@link select_month()},
  1171.      *       {@link select_day()} and {@link select_year()}
  1172.      *   </ul>
  1173.      *  @return string Generated HTML
  1174.      *  @uses select_day()
  1175.      *  @uses select_month()
  1176.      *  @uses select_year()
  1177.      *  @uses value()
  1178.      */
  1179.     function to_date_select_tag($options array()) {
  1180. //        error_log("to_date_select_tag() object='$this->object_name'"
  1181. //                  . " attribute='$this->attribute_name'");
  1182. //        error_log("options=".var_export($options,true));
  1183.  
  1184.         //  Handle historically misspelled options
  1185.         if (array_key_exists('field_seperator'$options)) {
  1186.             $options['field_separator'$options['field_seperator'];
  1187.             unset($options['field_seperator']);
  1188.         }
  1189.         $defaults array('discard_type' => true);
  1190.         $options  array_merge($defaults$options);
  1191.         $options_with_prefix array();
  1192.  
  1193.         //  Set the name of each submenu in the form
  1194.         for($i=$i <= $i++{
  1195.             $options_with_prefix[$iarray_merge($optionsarray('prefix' =>
  1196.                   "{$this->object_name}[{$this->attribute_name}({$i}i)]"));
  1197.         }        
  1198.         
  1199.         //  Test for output option 'include_blank' == true
  1200.         if(array_key_exists('include_blank', $options)
  1201.            && $options['include_blank']) {
  1202.  
  1203.             //  'include_blank' is present so if no value for this
  1204.             //  attribute was parsed from $_REQUEST, show blank initially
  1205.             //  FIXME: this doesn't actually work
  1206.             $value = $this->value();
  1207.             $date $value $value null;
  1208.         } else {
  1209.  
  1210.             //  'include_blank' is not present so if no value for this
  1211.             //  attribute was parsed from $_REQUEST, show today's date
  1212.             //  initially
  1213.             $value = $this->value();
  1214.             $date $value $value date("Y-m-d");
  1215.         }
  1216.  
  1217.         //  Test for output option 'month_before_year' == true
  1218.         $date_select = array();
  1219.         if(array_key_exists('month_before_year', $options)
  1220.            && $options['month_before_year']) {
  1221.  
  1222.             //  'month_before_year' is present so set the default
  1223.             //  ordering of output menus accordingly
  1224.             $options['order'] = array('month', 'year', 'day');
  1225.         } elseif(!array_key_exists('order',$options)
  1226.                  ||!$options['order']) {
  1227.  
  1228.             //  If 'order' option not present set order from default
  1229.             $options['order'] = array('year', 'month', 'day');
  1230.         }
  1231.  
  1232.         $position = array('year' => 1, 'month' => 2, 'day' => 3);
  1233.  
  1234.         //  Evaluate 'discard_field' options to see which fields
  1235.         //  should not be represented by menus in the output
  1236.         $discard = array();
  1237.         if(array_key_exists('discard_year',$options)
  1238.            && $options['discard_year']) $discard['year']  = true;
  1239.         if(array_key_exists('discard_month',$options)
  1240.            && $options['discard_month']) $discard['month'] = true;
  1241.         if( (array_key_exists('discard_day',$options)
  1242.              &&$options['discard_day'])
  1243.             || (array_key_exists('discard_month',$options)
  1244.                 && $options['discard_month'])) $discard['day'] = true;
  1245.  
  1246.         //  Build HTML for menus in the order determined above,
  1247.         //  except for fields to be discarded.
  1248.         foreach($options['order'] as $param) {
  1249.             if(!array_key_exists($param,$discard) || !$discard[$param]) {
  1250.                 $date_select[] = call_user_func(array($this, "select_$param"),
  1251.                               $date, $options_with_prefix[$position[$param]]);
  1252.             }
  1253.         }
  1254.         
  1255.         //  HTML for each menu is in an element of $date_select[].
  1256.         //  Join the pieces of HTML with an optional field separator
  1257.         //  (default blank)
  1258.         if(count($date_select)) {
  1259.             $separator = array_key_exists('field_separator',$options)
  1260.                 ? $options['field_separator'] : " ";
  1261.             $date_select = implode($separator, $date_select);            
  1262.         }
  1263.  
  1264.         return $date_select;
  1265.     }
  1266.  
  1267.     /**
  1268.      *  Generate HTML/XML for date/time pulldown menus
  1269.      *
  1270.      *  Returns <samp><select>...</select></samp> HTML with options
  1271.      *  for a number of years, months, days, hours and minutes.  The
  1272.      *  first argument, if present, specifies the initially selected
  1273.      *  date.  The second argument controls the format of the
  1274.      *  generated HTML.
  1275.      *
  1276.      *  Examples:
  1277.      *  <ul>
  1278.      *   <li><samp>to_datetime_select_tag();</samp><br /> Generates a
  1279.      *     group of five pulldown menus in the order year, month, day,
  1280.      *     hour and minute with the current date and time initially
  1281.      *     selected.</li> 
  1282.      *   <li>
  1283.      *   <li><samp>to_datetime_select_tag(array('discard_second' => false);</samp><br />
  1284.      *     Generates a group of six pulldown menus in the order year,
  1285.      *     month, day, hour, minute and second with the current date
  1286.      *     and time initially selected.</li> 
  1287.      *   <li>
  1288.      *  <samp>to_datetime_select_tag('1998-04-08 13:21:17');</samp><br />
  1289.      *    Generates a group of five pulldown menus in the order year,
  1290.      *    month, day, hour and minute with the date/time
  1291.      *    1998 August 4 13:21 initially selected.</li> 
  1292.      *  </ul>
  1293.      *
  1294.      *  @param string   Date/time to display as initially selected.
  1295.      *    Character string is any US English date representation
  1296.      *    supported by {@link strtotime()}.  If omitted, the
  1297.      *    current date/time is initially selected.
  1298.      *
  1299.      *  @param mixed[] Output format options:
  1300.      *  <ul>
  1301.      *    <li><samp>'discard_month' => true</samp><br />
  1302.      *      Output selector for only the year.</li>
  1303.      *    <li><samp>'discard_day' => true</samp><br />
  1304.      *      Output selector for only the year and month.</li>
  1305.      *    <li><samp>'discard_hour' => true</samp><br />
  1306.      *      Output selector for only the year, month and day.</li>
  1307.      *    <li><samp>'discard_minute' => true</samp><br />
  1308.      *      Output selector for only the year, month, day and
  1309.      *      hour.</li> 
  1310.      *    <li><samp>'discard_second' => false</samp><br />
  1311.      *      Output selector for year, month, day, hour, minute and
  1312.      *      second.</li> 
  1313.      *  </ul>
  1314.      *  @return string Generated HTML
  1315.      *  @uses request_days
  1316.      *  @uses request_hours
  1317.      *  @uses request_minutes
  1318.      *  @uses request_months
  1319.      *  @uses request_seconds
  1320.      *  @uses request_years
  1321.      *  @uses select_day()
  1322.      *  @uses select_hour()
  1323.      *  @uses select_minute()
  1324.      *  @uses select_month()
  1325.      *  @uses select_second()
  1326.      *  @uses select_year()
  1327.      *  @uses value()
  1328.      */
  1329.     function to_datetime_select_tag($options = array()) {
  1330.         $defaults = array('discard_type'   => true,
  1331.                           'discard_second' => true);
  1332.         $options = array_merge($defaults, $options);
  1333.         $options_with_prefix = array();
  1334.         for($i=1 ; $i <= 6 ; $i++) {
  1335.             $options_with_prefix[$i] =
  1336.                 array_merge($options, array('prefix' =>
  1337.                    "{$this->object_name}[{$this->attribute_name}({$i}i)]"));
  1338.         }
  1339.  
  1340.         //  FIXME: this doesn't work
  1341.         if(array_key_exists('include_blank', $options)
  1342.            && $options['include_blank']) {
  1343.             $value = $this->value();
  1344.             $datetime $value $value null;
  1345.         } else {
  1346.             $value = $this->value();
  1347.             $datetime $value $value date("Y-m-d H:i:s");
  1348.         }
  1349.     
  1350.         //  Generate year pulldown
  1351.         $datetime_select = $this->select_year($datetime,
  1352.                                               $options_with_prefix[1]);
  1353.  
  1354.         //  Generate month pulldown if not discarded
  1355.         if(!array_key_exists('discard_month'$options)
  1356.            || !$options['discard_month']{
  1357.             $datetime_select .= $this->select_month($datetime,
  1358.                                                     $options_with_prefix[2]);
  1359.  
  1360.             //  Generate day pulldown if not discarded
  1361.             if(!array_key_exists('discard_day'$options)
  1362.                || !($options['discard_day'|| $options['discard_month'])) {
  1363.                 $datetime_select .= $this->select_day($datetime,
  1364.                                                       $options_with_prefix[3]);
  1365.  
  1366.                 //  Generate hour pulldown if not discarded
  1367.                 if(!array_key_exists('discard_hour'$options)
  1368.                    || !$options['discard_hour']{
  1369.                     $datetime_select .= ' &mdash; '
  1370.                         . $this->select_hour($datetime,
  1371.                                          $options_with_prefix[4]);
  1372.  
  1373.                     //  Generate minute pulldown if not discarded
  1374.                     if(!array_key_exists('discard_minute'$options)
  1375.                        || !$options['discard_minute']{
  1376.                         $datetime_select .= ' : '
  1377.                             . $this->select_minute($datetime,
  1378.                                                    $options_with_prefix[5]);
  1379.  
  1380.                         //  Generate second pulldown if not discarded
  1381.                         if(!array_key_exists('discard_second'$options)
  1382.                            || !$options['discard_second']{
  1383.                             $datetime_select .= ' : '
  1384.                                 . $this->select_second($datetime,
  1385.                                                     $options_with_prefix[6]);
  1386.                         }  // second
  1387.                     }      // minute
  1388.                 }          // hour
  1389.             }              // day
  1390.         }                  // month
  1391.         return $datetime_select;
  1392.     }
  1393.     
  1394.     /**
  1395.      *  Generate HTML/XML for expiration month and year pulldown.
  1396.      *
  1397.      *  Calls {@link to_date_select_tag()} with options for month with
  1398.      *  number, followed by year starting this year and going seven
  1399.      *  years in the future.
  1400.      *  @param mixed[] Output format options
  1401.      *  @return string Generated HTML
  1402.      *  @uses to_date_select_tag()
  1403.      */
  1404.     function to_expiration_date_select_tag($options = array()) {
  1405.         $options['discard_day'] = true; 
  1406.         $options['month_before_year'] = true;      
  1407.         $options['use_month_numbers'] = true;   
  1408.         $options['start_year'] = date("Y");
  1409.         $options['end_year'] = date("Y") + 7;
  1410.         $options['field_separator'] = " / ";
  1411.         return $this->to_date_select_tag($options);               
  1412.     }  
  1413.  
  1414.     /**
  1415.      *  Generate HTML/XML for time pulldown
  1416.      *
  1417.      *  When called, {@link $object_name} describes the
  1418.      *  {@link ActiveRecord} subclass and {@link $attribute_name}
  1419.      *  describes the attribute whose value will be set by the
  1420.      *  generated pull-down menu.  The value to be displayed initially
  1421.      *  is from $_REQUEST if present, otherwise from the database.
  1422.      *
  1423.      *  @param mixed[] Output format options
  1424.      *  @return string Generated HTML
  1425.      *  @uses request_hours
  1426.      *  @uses request_minutes
  1427.      *  @uses request_seconds
  1428.      *  @uses select_time()
  1429.      *  @uses value()
  1430.      */
  1431.     function time_select($options=array()) {
  1432.         $defaults = array('discard_type' => true,
  1433.                           'discard_second' => true);
  1434.         $options = array_merge($defaults,$options);
  1435.         $options_with_prefix = array();
  1436.         for($i=4 ; $i <= 6 ; $i++) {
  1437.             $options_with_prefix[$i] =
  1438.                 array_merge($options, array('prefix' =>
  1439.                  "{$this->object_name}[{$this->attribute_name}({$i}i)]"));
  1440.         }
  1441.  
  1442.         //  If no value for this attribute found in $_REQUEST
  1443.         //  or the model, show current time initially 
  1444.         $time = $this->value();
  1445.         $time $time $time date('H:i:s');
  1446.  
  1447.         //  Generate HTML for hour
  1448.         $time_select $this->select_hour($time$options_with_prefix[4]);
  1449.  
  1450.         //  Generate HTML for minute if not discarded
  1451.         if (!(array_key_exists('discard_minute'$options)
  1452.               && $options['discard_minute'])) {
  1453.             $time_select .= ' : '
  1454.                 . $this->select_minute($time$options_with_prefix[5]);
  1455.  
  1456.             //  Generate HTML for second if not discarded
  1457.             if (!(array_key_exists('discard_second'$options)
  1458.                   && $options['discard_second'])) {
  1459.                 $time_select .= ' : '
  1460.                     . $this->select_second($time$options_with_prefix[6]);
  1461.             }
  1462.         }
  1463.         return $time_select;
  1464.     }
  1465.  
  1466.     /**
  1467.      *  Generate HTML/XML for year pulldown
  1468.      *
  1469.      *  When called, {@link $object_name} describes the
  1470.      *  {@link ActiveRecord} subclass and {@link $attribute_name}
  1471.      *  describes the attribute whose value will be set by the
  1472.      *  generated pull-down menu.  The value to be displayed initially
  1473.      *  is from $_REQUEST if present, otherwise from the database.
  1474.      *
  1475.      *  @param mixed[] Output format options
  1476.      *  @return string Generated HTML
  1477.      *  @uses select_year()
  1478.      *  @uses value()
  1479.      */
  1480.     function year_select($options=array()) {
  1481.         $defaults = array('discard_type' => true,
  1482.              'prefix' =>
  1483.                    "{$this->object_name}[{$this->attribute_name}(1i)]");
  1484.         $options = array_merge($defaults,$options);
  1485.  
  1486.         //  If no value for this attribute found in $_REQUEST
  1487.         //  or the model, show today's date initially 
  1488.         $year = $this->value();
  1489.         if (!$year{
  1490.             $year =
  1491.             (is_array($this->request_years)
  1492.              && array_key_exists($this->attribute_name,$this->request_years))
  1493.             ? $this->request_years[$this->attribute_name]
  1494.             : date("Y");
  1495.         }
  1496.         return $this->select_year($year.'-01-01',$options);
  1497.     }
  1498. }
  1499.  
  1500. /**
  1501.  *  Make a new DateHelper object and call its select_date() method
  1502.  *  @uses DateHelper::select_date()
  1503.   */
  1504. function select_date() {
  1505.     $date_helper = new DateHelper();
  1506.     $args = func_get_args();
  1507.     return call_user_func_array(array($date_helper, 'select_date'), $args);
  1508. }
  1509.  
  1510. /**
  1511.  *  Make a new DateHelper object and call its select_datetime() method
  1512.  *  @uses DateHelper::select_datetime()
  1513.  */
  1514. function select_datetime() {
  1515.     $date_helper = new DateHelper();
  1516.     $args = func_get_args();
  1517.     return call_user_func_array(array($date_helper, 'select_datetime'), $args);
  1518. }
  1519.  
  1520. /**
  1521.  *  Make a new DateHelper object and call its select_expiration_date() method
  1522.  *  @uses DateHelper::select_expiration_date()
  1523.  */
  1524. function select_expiration_date() {
  1525.     $date_helper = new DateHelper();
  1526.     $args = func_get_args();
  1527.     return call_user_func_array(array($date_helper, 'select_expiration_date'), $args);        
  1528. }
  1529.  
  1530. /**
  1531.  *  Make a new DateHelper object and call its datetime_select() method
  1532.  *  @param string Name of an ActiveRecord subclass
  1533.  *  @param string Name of an attribute of $object
  1534.  *  @param mixed[] Format options
  1535.  *  @uses DateHelper::datetime_select()
  1536.  *  @see ActiveRecordHelper::to_scaffold_tag()
  1537.  */
  1538. function datetime_select($object, $attribute, $options = array()) {
  1539.     $date_helper = new DateHelper($object, $attribute);
  1540.     return $date_helper->datetime_select($options);    
  1541. }
  1542.  
  1543. /**
  1544.  *  Make a new DateHelper object and call its date_select() method
  1545.  *  @param string Name of an ActiveRecord subclass
  1546.  *  @param string Name of an attribute of $object
  1547.  *  @param mixed[]  Output format options
  1548.  *  @return string Generated HTML
  1549.  *  @uses DateHelper::date_select()
  1550.  *  @see ActiveRecordHelper::to_scaffold_tag()
  1551.  */
  1552. function date_select($object, $attribute, $options = array()) {
  1553.     $date_helper = new DateHelper($object, $attribute);
  1554.     return $date_helper->date_select($options);    
  1555. }
  1556.  
  1557. /**
  1558.  *  Make a new DateHelper object and call its year_select() method
  1559.  *  @param string Name of an ActiveRecord subclass
  1560.  *  @param string Name of an attribute of $object
  1561.  *  @param mixed[] Format options
  1562.  *  @uses DateHelper::year_select()
  1563.  *  @see ActiveRecordHelper::to_scaffold_tag()
  1564.  */
  1565. function year_select($object, $attribute, $options = array()) {
  1566.     $date_helper = new DateHelper($object, $attribute);
  1567.     return $date_helper->year_select($options);    
  1568. }
  1569.  
  1570. /**
  1571.  *  Make a new DateHelper object and call its select_time() method
  1572.  *  @param string Name of an ActiveRecord subclass
  1573.  *  @param string Name of an attribute of $object
  1574.  *  @param mixed[] Format options
  1575.  *  @uses DateHelper::select_time()
  1576.  *  @see ActiveRecordHelper::to_scaffold_tag()
  1577.  */
  1578. function time_select($object, $attribute, $options = array()) {
  1579.     $date_helper = new DateHelper($object, $attribute);
  1580.     return $date_helper->time_select($options);    
  1581. }
  1582.  
  1583. /**
  1584.  *  Make a new DateHelper object and call its expiration_date_select() method
  1585.  *  @param string Name of an ActiveRecord subclass
  1586.  *  @param string Name of an attribute of $object
  1587.  *  @param mixed[] Format options
  1588.  *  @uses DateHelper::expiration_date_select()
  1589.  */
  1590. function expiration_date_select($object, $attribute, $options = array()) {
  1591.     $date_helper = new DateHelper($object, $attribute);
  1592.     return $date_helper->expiration_date_select($options);        
  1593. }
  1594.  
  1595. /**
  1596.  *  Make a new DateHelper object and call its select_month() method
  1597.  *
  1598.  *  Generate HTML/XML for month selector pull-down menu using only
  1599.  *  explicit month specification.<br />
  1600.  *  <b>NB:</b>  An attempt to get value of an attribute will always
  1601.  *  fail because there is no way to set
  1602.  *  {@link DateHelper::object_name} and
  1603.  *  {@link DateHelper::attribute_name}.
  1604.  *  @uses DateHelper::select_month()
  1605.  */
  1606. function select_month() {
  1607.     $date_helper = new DateHelper();
  1608.     $args = func_get_args();
  1609.     return call_user_func_array(array($date_helper, 'select_month'), $args);    
  1610. }
  1611.  
  1612. /**
  1613.  *  Make a new DateHelper object and call its select_day() method
  1614.  *  @uses DateHelper::select_day()
  1615.  */
  1616. function select_day() {
  1617.     $date_helper = new DateHelper();
  1618.     $args = func_get_args();
  1619.     return call_user_func_array(array($date_helper, 'select_day'), $args);    
  1620. }
  1621.  
  1622. // -- set Emacs parameters --
  1623. // Local variables:
  1624. // tab-width: 4
  1625. // c-basic-offset: 4
  1626. // c-hanging-comment-ender-p: nil
  1627. // indent-tabs-mode: nil
  1628. // End:

Documentation generated on Mon, 21 May 2007 22:28:21 -0600 by phpDocumentor 1.3.2