| [ Index ] |
PHP Cross Reference of Akelos Framework |
[Summary view] [Print] [Text view]
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 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Oct 27 12:43:49 2008 | Cross-referenced by PHPXref 0.6 |