[ Index ]

PHP Cross Reference of Akelos Framework

title

Body

[close]

/AkActionView/helpers/ -> form_helper.php (source)

   1  <?php
   2  /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
   3  
   4  // +----------------------------------------------------------------------+
   5  // | Akelos Framework - http://www.akelos.org                             |
   6  // +----------------------------------------------------------------------+
   7  // | Copyright (c) 2002-2006, Akelos Media, S.L.  & Bermi Ferrer Martinez |
   8  // | Released under the GNU Lesser General Public License, see LICENSE.txt|
   9  // +----------------------------------------------------------------------+
  10  
  11  /**
  12   * @package ActionView
  13   * @subpackage Helpers
  14   * @author Bermi Ferrer <bermi a.t akelos c.om>
  15   * @copyright Copyright (c) 2002-2006, Akelos Media, S.L. http://www.akelos.org
  16   * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html>
  17   */
  18  
  19  
  20  require_once (AK_LIB_DIR.DS.'AkActionView'.DS.'helpers'.DS.'tag_helper.php');
  21  require_once (AK_LIB_DIR.DS.'AkActionView'.DS.'helpers'.DS.'form_tag_helper.php');
  22  require_once (AK_LIB_DIR.DS.'AkInflector.php');
  23  
  24  /**
  25  * Provides a set of methods for working with forms and especially forms related to objects assigned to the template.
  26  * The following is an example of a complete form for a person object that works for both creates and updates built
  27  * with all the form helpers. The <tt>$person</tt> object was assigned by an action on the controller:
  28  *   <form action="save_person" method="post">
  29  *     Name:
  30  *     <?= $form_helper->text_field("person", "name", array("size" => 20)) ?>
  31  *
  32  *     Password:
  33  *     <?= $form_helper->password_field("person", "password", array("maxsize" => 20)) ?>
  34  *
  35  *     Single?:
  36  *     <?= $form_helper->check_box("person", "single") ?>
  37  *
  38  *     Description:
  39  *     <?= $form_helper->text_area("person", "description", array("cols" => 20)) ?>
  40  *
  41  *     <input type="submit" value="Save" />
  42  *   </form>
  43  *
  44  * ...is the same as:
  45  *
  46  *   <form action="save_person" method="post">
  47  *     Name:
  48  *     <input type="text" id="person_name" name="person[name]"
  49  *       size="20" value="<?= $person->name ?>" />
  50  *
  51  *     Password:
  52  *     <input type="password" id="person_password" name="person[password]"
  53  *       size="20" maxsize="20" value="<?= $person->password ?>" />
  54  *
  55  *     Single?:
  56  *     <input type="checkbox" id="person_single" name="person[single]" value="1" />
  57  *
  58  *     Description:
  59  *     <textarea cols="20" rows="40" id="person_description" name="person[description]">
  60  *       <?= $person->description ?>
  61  *     </textarea>
  62  *
  63  *     <input type="submit" value="Save">
  64  *   </form>
  65  *
  66  * If the object name contains square brackets the id for the object will be inserted. Example:
  67  *
  68  *   <?= $form_helper->textfield("person[]", "name") ?> 
  69  * 
  70  * ...becomes:
  71  *
  72  *   <input type="text" id="person_<?= $person->id ?>_name" name="person[<?= $person->id ?>][name]" value="<?= $person->name ?>" />
  73  *
  74  * If the helper is being used to generate a repetitive sequence of similar form elements, for example in a partial
  75  * used by render_collection_of_partials, the "index" option may come in handy. Example:
  76  *
  77  *   <?= $form_helper->text_field("person", "name", "index" => 1) ?>
  78  *
  79  * becomes
  80  *
  81  *   <input type="text" id="person_1_name" name="person[1][name]" value="<?= $person->name ?>" />
  82  *
  83  * There's also methods for helping to build form tags in $form_options, $date and $active_record
  84  */
  85  
  86  
  87  class FormHelper extends AkActionViewHelper
  88  {
  89  
  90      /**
  91       * 
  92        * Creates a form and a scope around a specific model object, which is then used as a base for questioning about
  93        * values for the fields. Examples:
  94        *
  95        *   <?php $f = $form_helper->form_for('person', $Person, array('url' => array('action' => 'update'))); ?>
  96        *     First name: <?= $f->text_field('first_name'); ?>
  97        *     Last name : <?= $f->text_field('last_name'); ?>
  98        *     Biography : <?= $f->text_area('biography'); ?>
  99        *     Admin?    : <?= $f->check_box('admin'); ?>
 100        *   <?= $f->end_form_tag(); ?>
 101        *
 102        * The form_for yields a form_builder object, in this example as $f, which emulates the API for the stand-alone 
 103        * FormHelper methods, but without the object name. So instead of <tt>$form_helper->text_field('person', 'name');</tt>,
 104        * you get away with <tt>$f->text_field('name');</tt>. 
 105        *
 106        * That in itself is a modest increase in comfort. The big news is that form_for allows us to more easily escape the instance
 107        * variable convention, so while the stand-alone approach would require <tt>$form_helper->text_field('person', 'name', array('object' => $Person));</tt> 
 108        * to work with local variables instead of instance ones, the form_for calls remain the same. You simply declare once with 
 109        * <tt>'person', $Person</tt> and all subsequent field calls save <tt>'person'</tt> and <tt>'object' => $Person</tt>.
 110        *
 111        * Also note that form_for doesn't create an exclusive scope. It's still possible to use both the stand-alone FormHelper methods
 112        * and methods from FormTagHelper. Example:
 113        *
 114        *   <?php $f = $form_helper->form_for('person', $Person, array('url' => array('action' => 'update'))); ?>
 115        *     First name: <?= $f->text_field('first_name'); ?>
 116        *     Last name : <?= $f->text_field('last_name'); ?>
 117        *     Biography : <?= $f->text_area('person', $Biography); ?>
 118        *     Admin?    : <?= $form_helper->check_box_tag('person[admin]', $Person->company->isAdmin()); ?>
 119        *   <?= $f->end_form_tag(); ?>
 120        *
 121        * Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base.
 122        * Like collection_select and datetime_select.
 123        */
 124      function form_for($object_name, &$object, $options = array())
 125      {
 126          $url_for_options = $options['url'];
 127          echo $this->_controller->form_tag_helper->form_tag($url_for_options, $options);
 128          return $this->fields_for($object_name, $object);
 129      }
 130  
 131      /**
 132        * Creates a scope around a specific model object like form_for, but doesn't create the form tags themselves. This makes
 133        * fields_for suitable for specifying additional model objects in the same form. Example:
 134        *
 135        *   <?php $person_form = $this->form_for('person', $Person, array('url' => array('action'=>'update'))); ?>
 136        *     First name: <?= $person_form->text_field('first_name'); ?>
 137        *     Last name : <?= person_form->text_field('last_name'); ?>
 138        *     
 139        *     <?php $permission_fields = $form_helper->fields_for('permission', $Person->permission); ?>
 140        *       Admin?  : <?= $permission_fields->check_box('admin'); ?>
 141        *   <?= $person_form->end_form_tag(); ?>
 142        *
 143        * Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base.
 144        * Like collection_select and datetime_select.
 145        */
 146      function fields_for($object_name, &$object)
 147      {
 148          return  new AkFormHelperBuilder($object_name, $object, $this);
 149      }
 150  
 151      function end_form_tag()
 152      {
 153          return '</form>';
 154      }
 155      /**
 156        * Returns an input tag of the "text" type tailored for accessing a specified attribute (identified by +column_name+) on an object
 157        * assigned to the template (identified by +object+). Additional options on the input tag can be passed as an
 158        * array with +options+.
 159        *
 160        * Examples (call, result):
 161        *   $form_helper->text_field("post", "title", array("size" => 20));
 162        *     <input type="text" id="post_title" name="post[title]" size="20" value="{post.title}" />
 163        */
 164      function text_field($object_name, $column_name = null, $options = array())
 165      {
 166          return $this->_field($object_name, $column_name, $options,'text');
 167      }
 168  
 169      /**
 170        * Works just like text_field, but returns an input tag of the "password" type instead.
 171        */
 172      function password_field($object_name, $column_name = null, $options = array())
 173      {
 174          return $this->_field($object_name, $column_name, $options,'password');
 175      }
 176  
 177      /**
 178        * Works just like text_field, but returns an input tag of the "hidden" type instead.
 179        */
 180      function hidden_field($object_name, $column_name = null, $options = array())
 181      {
 182          return $this->_field($object_name, $column_name, $options,'hidden');
 183      }
 184  
 185      /**
 186        * Works just like text_field, but returns an input tag of the "file" type instead, which won't have a default value.
 187        */
 188      function file_field($object_name, $column_name = null, $options = array())
 189      {
 190          return $this->_field($object_name, $column_name, $options,'file');
 191      }
 192  
 193  
 194      /**
 195        * Returns a textarea opening and closing tag set tailored for accessing a specified attribute (identified by +column_name+)
 196        * on an object assigned to the template (identified by +object+). Additional options on the input tag can be passed as an
 197        * array with +options+.
 198        *
 199        * Example (call, result):
 200        *   $form_helper->text_area('post', 'body', array('cols' => 20, 'rows' => 40));
 201        *     <textarea cols="20" rows="40" id="post_body" name="post[body]">
 202        *       {post.body}
 203        *     </textarea>
 204        */
 205      function text_area($object_name, $column_name = null, $options = array())
 206      {
 207          return $this->_field($object_name, $column_name, $options,'text_area');
 208      }
 209  
 210      /**
 211        * Returns a checkbox tag tailored for accessing a specified attribute (identified by +column_name+) on an object
 212        * assigned to the template (identified by +object+). It's intended that +column_name+ returns an integer and if that
 213        * integer is above zero, then the checkbox is checked. Additional options on the input tag can be passed as an
 214        * array with +options+. The +checked_value+ defaults to 1 while the default +unchecked_value+
 215        * is set to 0 which is convenient for boolean values. Usually unchecked checkboxes don't post anything.
 216        * We work around this problem by adding a hidden value with the same name as the checkbox.
 217        *
 218        * Example (call, result). Imagine that $Post->validate() returns 1:
 219        *   $form_helper->check_box("post", "validate");
 220        *     <input type="checkbox" id="post_validate" name="post[validate]" value="1" checked="checked" />
 221        *     <input name="post[validated]" type="hidden" value="0" />
 222        *
 223        * Example (call, result). Imagine that $Puppy->gooddog() returns no:
 224        *   $form_helper->check_box("puppy", "gooddog", array(), "yes", "no");
 225        *     <input type="checkbox" id="puppy_gooddog" name="puppy[gooddog]" value="yes" />
 226        *     <input name="puppy[gooddog]" type="hidden" value="no" />
 227        */
 228      function check_box($object_name, $column_name = null, $options = array(), $checked_value = '1', $unchecked_value = '0')
 229      {
 230          return $this->_field($object_name, $column_name, $options,'check_box', $checked_value, $unchecked_value);
 231      }
 232  
 233      /**
 234        * Returns a radio button tag for accessing a specified attribute (identified by +column_name+) on an object
 235        * assigned to the template (identified by +object+). If the current value of +column_name+ is +tag_value+ the
 236        * radio button will be checked. Additional options on the input tag can be passed as an
 237        * array with +options+.
 238        * Example (call, result). Imagine that $Post->category() returns "PHP":
 239        *   $form_helper->radio_button("post", "category", "PHP");
 240        *   $form_helper->radio_button("post", "category", "Ruby");
 241        *     <input type="radio" id="post_category" name="post[category]" value="PHP" checked="checked" />
 242        *     <input type="radio" id="post_category" name="post[category]" value="Ruby" />
 243        */
 244      function radio_button($object_name, $column_name = null, $tag_value, $options = array())
 245      {
 246          return $this->_field($object_name, $column_name, $options,'radio_button', $tag_value);
 247      }
 248  
 249      /**
 250      * File field auxiliar function
 251      * @access private
 252      */
 253      function _field($object_name, $column_name, $options = array(), $type, $extra_param_1 = '', $extra_param_2 = '')
 254      {
 255          if(empty($column_name) && isset($this->object_name)){
 256              $column_name = $object_name;
 257              $object_name = $this->object_name;
 258          }
 259      
 260          $object = null;
 261          if(isset($options['object'])){
 262              if(is_object($options['object'])){
 263                  $object =& $options['object'];
 264                  if(empty($this->_remove_object_from_options)){
 265                      unset($options['object']);
 266                  }
 267              }
 268          }
 269          if(empty($object) && !empty($this->object)){
 270              $object =& $this->object;
 271              //$this->object =& $this->getObject($object_name);
 272          }
 273  
 274          $InstanceTag = new AkFormHelperInstanceTag($object_name, $column_name, $this, null, $object);
 275          switch ($type) {
 276              case 'file':
 277              case 'hidden':
 278              case 'password':
 279              case 'text':
 280              return $InstanceTag->to_input_field_tag($type,$options);
 281              break;
 282              case 'text_area':
 283              return $InstanceTag->to_text_area_tag($options);
 284              break;
 285              case 'radio_button':
 286              return $InstanceTag->to_radio_button_tag($extra_param_1, $options);
 287              break;
 288              case 'check_box':
 289              return $InstanceTag->to_check_box_tag($options, $extra_param_1, $extra_param_2);
 290              break;
 291              default:
 292              break;
 293          }
 294      }
 295  }
 296  
 297  class AkFormHelperInstanceTag extends TagHelper
 298  {
 299      var $default_field_options = array('size'=>30);
 300      var $default_radio_options = array();
 301      var $default_text_area_options = array('cols'=>40,'rows'=>20);
 302      var $default_date_options = array('discard_type'=>true);
 303      var $_column_name;
 304      var $_object_name;
 305      var $_auto_index;
 306  
 307  
 308      //AkFormHelperInstanceTag
 309  
 310      function AkFormHelperInstanceTag($object_name, $column_name, &$template_object, $local_binding = null, $object = null)
 311      {
 312          $this->object_name = $object_name;
 313          $this->_column_name = $column_name;
 314          $this->_template_object =& $template_object;
 315          $this->_local_binding = $local_binding;
 316  
 317          if(empty($object) && !empty($this->_template_object->_controller->{$this->object_name})){
 318              $this->object =& $this->_template_object->_controller->{$this->object_name};            
 319          }else{
 320              $this->object =& $object;
 321          }
 322  
 323          $_object_name = preg_replace('/\[\]$/','',$this->object_name);
 324          if($_object_name != $this->object_name){
 325              $this->_auto_index = $this->_template_object->{AkInflector::camelize($_object_name)}->id_before_type_cast;
 326          }
 327      }
 328  
 329      function to_input_field_tag($field_type, $options = array())
 330      {
 331          $options['size'] = !empty($options['size']) ? $options['size'] : (!empty($options['maxlength']) ? $options['maxlength'] : $this->default_field_options['size']);
 332          $options = array_merge($this->default_field_options,$options);
 333          if($field_type == 'hidden'){
 334              unset($options['size']);
 335          }
 336          $options['type'] = $field_type;
 337          if($field_type != 'file'){
 338              $options['value'] = !empty($options['value']) ? $options['value'] : $this->value_before_type_cast();
 339          }
 340          $this->add_default_name_and_id($options);
 341          return TagHelper::tag('input', $options);
 342      }
 343  
 344      function to_radio_button_tag($tag_value, $options = array())
 345      {
 346          $options = array_merge($this->default_radio_options,$options);
 347          $options['type'] = 'radio';
 348          $options['value'] = $tag_value;
 349          if($this->getValue() == $tag_value){
 350              $options['checked'] = 'checked';
 351          }
 352  
 353          $pretty_tag_value = strtolower(preg_replace('/\W/', '', preg_replace('/\s/', '_',$tag_value)));
 354          $options['id'] = $this->_auto_index ?
 355          "{$this->object_name}_{$this->_auto_index}_{$this->_column_name}_{$pretty_tag_value}" :
 356          "{$this->object_name}_{$this->_column_name}_{$pretty_tag_value}";
 357          $this->add_default_name_and_id($options);
 358          return TagHelper::tag('input', $options);
 359      }
 360  
 361      function to_text_area_tag($options = array())
 362      {
 363          $options = array_merge($this->default_text_area_options,$options);
 364          $this->add_default_name_and_id($options);
 365          return TagHelper::content_tag('textarea', TagHelper::escape_once($this->value_before_type_cast()), $options);
 366      }
 367  
 368      function to_check_box_tag($options = array(), $checked_value = '1', $unchecked_value = '0')
 369      {
 370          $options['type'] = 'checkbox';
 371          $options['value'] = $checked_value;
 372          $value = $this->getValue();
 373  
 374          if (is_numeric($value)){
 375              $checked = $value != 0;
 376          }elseif (is_string($value)){
 377              $checked = $value == $checked_value;
 378          }else{
 379              $checked = !empty($value);
 380          }
 381  
 382          if($checked || isset($options['checked']) && $options['checked'] == 'checked'){
 383              $options['checked'] = 'checked';
 384          }else{
 385              unset($options['checked']);
 386          }
 387          $this->add_default_name_and_id($options);
 388          return TagHelper::tag('input', array('name' => $options['name'], 'type' => 'hidden', 'value' => $unchecked_value)).TagHelper::tag('input', $options);
 389      }
 390  
 391      function to_date_tag()
 392      {
 393          require_once (AK_LIB_DIR.DS.'AkActionView'.DS.'helpers'.DS.'date_helper.php');
 394          $defaults = $this->default_date_options;
 395          $date = $this->getValue();
 396          $date = !empty($date) ? $date : Ak::getDate();
 397          return DateHelper::select_day($date, array_merge($defaults,array('prefix'=>"{$this->object_name}[{$this->_column_name}(3)]"))) .
 398          DateHelper::select_month($date, array_merge($defaults,array('prefix'=>"{$this->object_name}[{$this->_column_name}(2)]"))) .
 399          DateHelper::select_year($date, array_merge($defaults,array('prefix'=>"{$this->object_name}[{$this->_column_name}(1)]")));
 400      }
 401      
 402      function to_date_select_tag($options = array())
 403      {
 404          require_once (AK_LIB_DIR.DS.'AkActionView'.DS.'helpers'.DS.'date_helper.php');
 405          $DateHelper =& new DateHelper();
 406          $object_name = empty($this->_object_name) ? $this->object_name : $this->_object_name;
 407          if(isset($this->object)){
 408              $DateHelper->_object[$object_name] =& $this->object;
 409          }
 410          return $DateHelper->date_select($object_name, $this->_column_name, $options);          
 411      }
 412      
 413      function to_datetime_select_tag($options = array())
 414      {
 415          require_once (AK_LIB_DIR.DS.'AkActionView'.DS.'helpers'.DS.'date_helper.php');
 416          $DateHelper =& new DateHelper();
 417          $object_name = empty($this->_object_name) ? $this->object_name : $this->_object_name;
 418          if(isset($this->object)){
 419              $DateHelper->_object[$object_name] =& $this->object;
 420          }        
 421          return $DateHelper->datetime_select($object_name, $this->_column_name, $options);
 422      }
 423  
 424      function to_boolean_select_tag($options = array())
 425      {
 426          $this->add_default_name_and_id($options);
 427          return '<select'.
 428          TagHelper::_tag_options($options).
 429          '><option value="false"'.
 430          ($this->getValue() == false ? ' selected' : '').
 431          '>'.Ak::t('False',array(),'helpers/form').'</option><option value="true"'.
 432          ($this->getValue() ? ' selected' : '').
 433          '>'.Ak::t('True',array(),'helpers/form').'</option></select>';
 434      }
 435  
 436      function to_content_tag($tag_name, $options = array())
 437      {
 438          return TagHelper::content_tag($tag_name, $this->getValue(), $options);
 439      }
 440  
 441      function &getObject($object_name = null)
 442      {
 443          if(!empty($this->object)){
 444              return $this->object;
 445          }elseif (!empty($this->_template_object->{$this->object_name})){
 446              return $this->_template_object->{$this->object_name};
 447          }
 448          if(!empty($object_name) && !empty($this->_object[$object_name])){
 449              return $this->_object[$object_name];
 450          }
 451          return $this->object;
 452      }
 453  
 454      function getValue()
 455      {
 456          $object = $this->getObject();
 457          if(!empty($object)){
 458              return $object->get($this->_column_name);
 459          }
 460      }
 461  
 462      function value_before_type_cast()
 463      {
 464          $object =& $this->getObject();
 465          if(!empty($object)){
 466              return !empty($object->{$this->_column_name.'_before_type_cast'}) ?
 467              $object->{$this->_column_name.'_before_type_cast'} :
 468              $object->get($this->_column_name);
 469          }
 470      }
 471  
 472      function add_default_name_and_id(&$options)
 473      {
 474          if(isset($options['index'])){
 475              $options['name'] = empty($options['name']) ? $this->tag_name_with_index($options['index']) : $options['name'];
 476              $options['id'] = empty($options['id']) ? $this->tag_id_with_index($options['index']) : $options['id'];
 477              unset($options['index']);
 478          }elseif(!empty($this->_auto_index)){
 479              $options['name'] = empty($options['name'])? $this->tag_name_with_index($this->_auto_index) : $options['name'];
 480              $options['id'] = empty($options['id']) ? $this->tag_id_with_index($this->_auto_index) : $options['id'];
 481          }else{
 482              $options['name'] = empty($options['name']) ? $this->tag_name() : $options['name'];
 483              $options['id'] = empty($options['id']) ? $this->tag_id() : $options['id'];
 484          }
 485          
 486          if(!empty($options['multiple'])){
 487              if(substr($options['name'],-2) != '[]'){
 488                  $options['name'] = $options['name'].'[]';
 489              }
 490          }
 491      }
 492  
 493      function tag_name()
 494      {
 495          return "{$this->object_name}[{$this->_column_name}]";
 496      }
 497  
 498      function tag_name_with_index($index)
 499      {
 500          return "{$this->object_name}[{$index}][{$this->_column_name}]";
 501      }
 502  
 503      function tag_id()
 504      {
 505          return "{$this->object_name}_{$this->_column_name}";
 506      }
 507  
 508      function tag_id_with_index($index)
 509      {
 510          return "{$this->object_name}_{$index}_{$this->_column_name}";
 511      }
 512  }
 513  
 514  class AkFormHelperBuilder extends FormHelper
 515  {
 516      function AkFormHelperBuilder($object_name, &$object, &$template)
 517      {
 518          $this->object_name = $object_name;
 519          $this->object =& $object;
 520          $this->template =& $template;
 521          $this->proccessing = $object_name;
 522          $this->template->_remove_object_from_options = true;
 523      }
 524  }
 525  
 526  ?>


Generated: Mon Oct 27 12:43:49 2008 Cross-referenced by PHPXref 0.6