2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
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 // +----------------------------------------------------------------------+
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>
20 require_once(AK_LIB_DIR
.DS
.'AkActionView'.DS
.'helpers'.DS
.'form_helper.php');
23 * Provides a number of methods for turning different kinds of containers into a set of option tags.
25 * The <tt>collection_select</tt>, <tt>country_select</tt>, <tt>select</tt>,
26 * and <tt>time_zone_select</tt> methods take an <tt>options</tt> parameter,
29 * * <tt>include_blank</tt> - set to true if the first option element of the select element is a blank. Useful if there is not a default value required for the select element. For example,
31 * $form_options_helper->select('post','category', $Post->categories, array('include_blank'=>true));
35 * <select name="post[category]">
37 * <option>joke</option>
38 * <option>poem</option>
41 * * <tt>prompt</tt> - set to true or a prompt string. When the select element doesn't have a value yet, this prepends an option with a generic prompt -- "Please select" -- or the given prompt string.
43 * Another common case is a select tag for an <tt>belongs_to</tt>-associated object. For example,
45 * $form_options_helper->select('post', 'person_id', $Person->collect($Person->find(), 'name', 'id'));
49 * <select name="post[person_id]">
50 * <option value="1">David</option>
51 * <option value="2">Sam</option>
52 * <option value="3">Tobias</option>
55 class FormOptionsHelper
extends AkActionViewHelper
60 * Create a select tag and a series of contained option tags for the provided object and method.
61 * The option currently held by the object will be selected, provided that the object is available.
62 * See options_for_select for the required format of the choices parameter.
64 * Example with $Post->person_id => 1:
65 * $form_options_helper->select('post', 'person_id', $Person->collect($Person->find(), 'name', 'id'), array(), array('include_blank'=>true));
69 * <select name="post[person_id]">
71 * <option value="1" selected="selected">David</option>
72 * <option value="2">Sam</option>
73 * <option value="3">Tobias</option>
76 * This can be used to provide a default set of options in the standard way: before rendering the create form, a
77 * new model instance is assigned the default options and bound to $this->model_name. Usually this model is not saved
78 * to the database. Instead, a second model object is created when the create request is received.
79 * This allows the user to submit a form page more than once with the expected results of creating multiple records.
80 * In addition, this allows a single partial to be used to generate form inputs for both edit and create forms.
82 * By default, $post.person_id is the selected option. Specify 'selected' => value to use a different selection
83 * or 'selected' => null to leave all options unselected.
85 function select($object_name, $column_name, $choices, $options = array(), $html_options = array())
87 $InstanceTag = new AkFormHelperOptionsInstanceTag($object_name, $column_name, $this, null, $this->_object
[$object_name]);
88 return $InstanceTag->to_select_tag($choices, Ak
::delete($options,'object'), $html_options);
92 * Return select and option tags for the given object and column_name using options_from_collection_for_select to generate the list of option tags.
94 function collection_select($object_name, $column_name, $collection, $value_column_name, $text_column_name, $options = array(), $html_options = array())
96 $InstanceTag = new AkFormHelperOptionsInstanceTag($object_name, $column_name, $this, null, $this->_object
[$object_name]);
97 return $InstanceTag->to_collection_select_tag($collection, $value_column_name, $text_column_name, Ak
::delete($options,'object'), $html_options);
101 * Return select and option tags for the given object and column_name, using country_options_for_select to generate the list of option tags.
103 function country_select($object_name, $column_name, $priority_countries = null, $options = array(), $html_options = array())
105 $InstanceTag = new AkFormHelperOptionsInstanceTag($object_name, $column_name, $this, null, $this->_object
[$object_name]);
106 return $InstanceTag->to_country_select_tag($priority_countries, Ak
::delete($options,'object'), $html_options);
110 * Return select and option tags for the given object and column_name, using
111 * #time_zone_options_for_select to generate the list of option tags.
113 * In addition to the <tt>include_blank</tt> option documented above,
114 * this method also supports a <tt>model</tt> option, which defaults
115 * to TimeZone. This may be used by users to specify a different time
116 * zone model object. (See #time_zone_options_for_select for more
119 function time_zone_select($object_name, $column_name, $priority_zones = array(), $options = array(), $html_options = array())
121 $InstanceTag = new AkFormHelperOptionsInstanceTag($object_name, $column_name, $this, null, $this->_object
[$object_name]);
122 return $InstanceTag->to_time_zone_select_tag($priority_zones, Ak
::delete($options,'object'), $html_options);
126 * Accepts a container array and returns a string of option tags. Given a container where the elements respond to first and
127 * last (such as a two-element array), the "lasts" serve as option values and the "firsts" as option text. Arrays are turned
128 * into this form automatically, so the keys become "firsts" and values become lasts. If +selected+ is specified, the matching
129 * "last" or element will get the selected option-tag. +Selected+ may also be an array of values to be selected when using
132 * Examples (call, result):
133 * $form_options_helper->options_for_select(array('Dollar'=>'$', 'Kroner'=>'DKK'));
134 * <option value="$">Dollar</option><option value="DKK">Kroner</option>
136 * $form_options_helper->options_for_select(array('VISA', 'MasterCard'), 'MasterCard');
137 * <option value="VISA">VISA</option><option selected="selected" value="MasterCard">MasterCard</option>
139 * $form_options_helper->options_for_select(array('Basic'=>'$20','Plus'=>'$40'), '$40');
140 * <option value="$20">Basic</option><option selected="selected" value="$40">Plus</option>
142 * $form_options_helper->options_for_select(array('VISA','MasterCard','Discover'), array('VISA','Discover'));
143 * <option selected="selected" value="VISA">VISA</option>
144 * <option value="MasterCard">MasterCard</option>
145 * <option selected="selected" value="Discover">Discover</option>
147 * NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
149 function options_for_select($container, $selected = array(), $options = array())
151 $container = (array)$container;
152 if (empty($container)) {
155 $container = array_map('strval',$container);
157 $text_is_value = count(array_diff(range(0,count($container)-1),array_keys($container))) == 0;
159 $selected = (array)$selected;
160 $options_for_select = '';
162 $compare_captions = !empty($selected) ?
is_string(key(array_slice($selected,0,1))) : false;
164 foreach ($container as $text=>$value){
165 $options_for_select .= TagHelper
::content_tag('option',$text_is_value ?
$value : $text,
166 array_merge($options, ($compare_captions ?
167 (isset($selected[$text]) && $selected[$text] == $value) :
168 in_array($value, $selected)) ?
array('value'=>$value,'selected'=>'selected') : array('value'=>$value))
171 return $options_for_select;
175 * Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning the
176 * the result of a call to the +value_column_name+ as the option value and the +text_column_name+ as the option text.
177 * If +$selected_value+ is specified, the element returning a match on +value_column_name+ will get the selected option tag.
179 * Example (call, result). Imagine a loop iterating over each +person+ in <tt>$Project->People</tt> to generate an input tag:
180 * $form_options_helper->options_from_collection_for_select($Project->People,'id','name');
181 * <option value="{$Person->id}">{$Person->name}</option>
183 * NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
185 function options_from_collection_for_select($collection, $value_column_name, $text_column_name = null, $selected_value = array(), $options = array())
187 $text_column_name = is_null($text_column_name) ?
$value_column_name : $text_column_name;
188 $collection_options = array();
189 if($value_column_name[0] == '_' ||
$text_column_name[0] == '_'){
190 trigger_error(Ak
::t('You cannot call private methods from %helper_name helper',array('%helper_name'=>'options_from_collection_for_select'),'helpers/form'), E_USER_ERROR
);
193 foreach ($collection as $item){
194 $name = method_exists($item,$text_column_name) ?
$item->$text_column_name() : $item->get($text_column_name);
195 $collection_options[$name] = method_exists($item,$value_column_name) ?
$item->$value_column_name() : $item->get($value_column_name);
197 return $this->options_for_select($collection_options,$selected_value,$options);
202 * Returns a string of option tags, like options_from_collection_for_select, but surrounds them with <optgroup> tags.
204 * An array of group objects are passed. Each group should return an array of options when calling group_method
205 * Each group should return its name when calling group_label_method.
207 * $form_options_helper->option_groups_from_collection_for_select($continents, 'getCountries', 'getContinentName', 'getCountryId', 'getCountryName', $selected_country->id);
210 * <optgroup label="Africa">
211 * <option value="EGP">Egipt</option>
212 * <option value="RWD">Rwanda</option>
216 * <optgroup label="Asia">
217 * <option value="ZHN">China</option>
218 * <option value="IND">India</option>
219 * <option selected="selected" value="JPN">Japan</option>
223 * with objects of the following classes:
225 * function Continent($p_name, $p_countries){ $this->continent_name = $p_name; $this->countries = $p_countries;}
226 * function getContinentName(){ return $this->continent_name; }
227 * function getCountries(){ return $this->countries; }
230 * function Country($id, $name){ $this->id = $id; $this->name = $name; }
231 * function getCountryId(){ return $this->id; }
232 * function getCountryName(){ return $this->name;}
235 * NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
237 function option_groups_from_collection_for_select($collection, $group_method, $group_label_method, $option_key_method, $option_value_method, $selected_key = null)
240 if($group_label_method[0] == '_' ||
$group_label_method[0] == '_' ||
$option_key_method[0] == '_' ||
$option_value_method[0] == '_'){
241 trigger_error(Ak
::t('You cannot call private methods from %helper_name helper',array('%helper_name'=>'option_groups_from_collection_for_select'),'helpers/form'), E_USER_ERROR
);
243 $options_for_select = '';
244 foreach ($collection as $group){
246 if(method_exists($group, $group_method)){
247 $options_group = $group->{$group_method}();
248 }elseif(isset($group->$group_method)){
249 $options_group =& $group->$group_method;
252 $options_for_select .= TagHelper
::content_tag('optgroup',
253 $this->options_from_collection_for_select($options_group, $option_key_method, $option_value_method, $selected_key),
255 method_exists($group, $group_label_method) ?
256 $group->{$group_label_method}() :
257 $group->get($group_label_method)
260 return $options_for_select;
266 * Returns a string of option tags for pretty much any country in the world. Supply a country name as +selected+ to
267 * have it marked as the selected option tag. You can also supply an array of countries as +priority_countries+, so
268 * that they will be listed above the rest of the (long) list.
270 * NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
272 function country_options_for_select($selected = null, $priority_countries = array(), $model = 'AkCountries', $options = array())
274 $country_options = '';
276 if($model == 'AkCountries'){
277 require_once(AK_LIB_DIR
.DS
.'AkLocalize'.DS
.'AkCountries.php');
278 $countries_form_method = AkCountries
::all();
280 $countries_form_method = $model->all();
283 if (!empty($priority_countries)){
284 $country_options .= $this->options_for_select($priority_countries, $selected, $options);
285 $country_options .= '<option value="">-------------</option>'."\n";
288 if (!empty($priority_countries) && in_array($selected,$priority_countries)){
289 $country_options .= $this->options_for_select(array_diff($countries_form_method, $priority_countries), $selected, $options);
291 $country_options .= $this->options_for_select($countries_form_method, $selected, $options);
293 return $country_options;
297 * Returns a string of option tags for pretty much any time zone in the
298 * world. Supply a TimeZone name as +selected+ to have it marked as the
299 * selected option tag. You can also supply an array of TimeZones
300 * as +$priority_zones+, so that they will be listed above the rest of the
303 * The +selected+ parameter must be either +null+, or a string that names
306 * By default, +model+ is an AkTimeZone instance. The only requirement is that the
307 * +model+ parameter be an object that responds to #all, and returns
308 * an object with a toString() method and the TimeZone name provided by a 'name'
311 * For a list of supported timezones see: http://www.php.net/manual/en/timezones.php
313 * NOTE: Only the option tags are returned, you have to wrap this call in
314 * a regular HTML select tag.
316 function time_zone_options_for_select($selected = null, $priority_zones = array(), $model = 'AkTimeZone')
319 if($model == 'AkTimeZone'){
320 require_once(AK_LIB_DIR
.DS
.'AkLocalize'.DS
.'AkTimeZone.php');
321 $Zones = AkTimeZone
::all();
323 $Zones = $model->all();
326 $zones_for_options = array();
327 foreach (array_keys($Zones) as $k){
328 $zones_for_options[$Zones[$k]->toString()] = $Zones[$k]->name
;
331 if (!empty($priority_zones)){
332 $zone_options .= $this->options_for_select($priority_zones, $selected);
333 $zone_options .= '<option value="">-------------</option>'."\n";
336 $zone_options .= $this->options_for_select(array_diff_assoc($zones_for_options,$priority_zones), $selected);
337 return $zone_options;
343 class AkFormHelperOptionsInstanceTag
extends AkFormHelperInstanceTag
345 function AkFormHelperOptionsInstanceTag($object_name, $column_name, &$template_object, $local_binding = null, &$object)
347 $this->AkFormHelperInstanceTag($object_name, $column_name, $template_object, $local_binding, $object);
350 function to_select_tag($choices, $options=array(), $html_options = array())
352 $this->add_default_name_and_id($html_options);
353 $selected_value = !empty($options['selected']) ?
$options['selected'] : $this->getValue();
355 return TagHelper
::content_tag('select', $this->_addOptions($this->_template_object
->options_for_select($choices, $selected_value, $options),
356 $html_options, $this->getValue()), Ak
::delete($html_options,'prompt','include_blank'));
359 function to_collection_select_tag($collection, $value_column_name, $text_column_name = null, $options = array(), $html_options = array())
361 $this->add_default_name_and_id($html_options);
363 return TagHelper
::content_tag('select', $this->_addOptions(
364 $this->_template_object
->options_from_collection_for_select($collection, $value_column_name, $text_column_name, $this->getValue(), array_diff($options,array('prompt'=>true))),
365 $options, $this->getValue()), $html_options);
368 function to_country_select_tag($priority_countries = array(), $options = array(), $html_options = array())
370 $this->add_default_name_and_id($html_options);
371 return TagHelper
::content_tag('select', $this->_addOptions($this->_template_object
->country_options_for_select($this->getValue(), $priority_countries, 'AkCountries', $options),
372 $options, $this->getValue()), $html_options);
375 function to_time_zone_select_tag($priority_zones = array(), $options = array(), $html_options = array())
377 $this->add_default_name_and_id($html_options);
379 return TagHelper
::content_tag('select',
380 $this->_addOptions($this->_template_object
->time_zone_options_for_select(
381 $this->getValue(),$priority_zones,(empty($options['model'])?
'AkTimeZone':$options['model'])),$options,$this->getValue()),$html_options);
384 function _addOptions($option_tags, $options, $value = null)
386 $option_tags = (!empty($options['include_blank']) ?
"<option value=\"\"></option>\n" : '').$option_tags;
387 if(empty($value) && !empty($options['prompt'])){
388 return '<option value="">'.(is_string($options['prompt']) ?
$options['prompt'] : Ak
::t('Please select',array(),'helpers/form'))."</option>\n".$option_tags;
395 class AkFormOptionsHelperBuilder
extends FormOptionsHelper
398 function AkFormOptionsHelperBuilder($object_name, $object, &$template)
400 $this->object_name
= $object_name;
401 $this->object = $object;
402 $this->template
=& $template;
403 $this->proccessing
= $object_name;
404 $this->template
->_remove_object_from_options
= true;
407 function select($column_name, $choices, $options = array(), $html_options = array())
409 return $this->template
->select($this->object_name
, $column_name, $choices, array_merge($options, array('object' => $this->object)), $html_options);
412 function collection_select($column_name, $collection, $value_column_name, $text_column_name, $options = array(), $html_options = array())
414 return $this->template
->collection_select($this->object_name
, $column_name, $collection, $value_column_name, $text_column_name, array_merge($options, array('object' => $this->object)), $html_options);
417 function country_select($column_name, $priority_countries = null, $options = array(), $html_options = array())
419 return $this->template
->country_select($this->object_name
, $column_name, $priority_countries, array_merge($options, array('object' => $this->object)), $html_options);
422 function time_zone_select($column_name, $priority_zones = null, $options = array(), $html_options = array())
424 return $this->template
->time_zone_select($this->object_name
, $column_name, $priority_zones, array_merge($options, array('object' => $this->object)), $html_options);