[+BUGFIX] Fluid (ViewHelpers): tweaked SelectViewHelper to avoid fatal error on PHP 5.2
[Packages/TYPO3.CMS.git] / typo3 / sysext / fluid / Classes / ViewHelpers / Form / SelectViewHelper.php
1 <?php
2
3 /* *
4 * This script belongs to the FLOW3 package "Fluid". *
5 * *
6 * It is free software; you can redistribute it and/or modify it under *
7 * the terms of the GNU Lesser General Public License as published by the *
8 * Free Software Foundation, either version 3 of the License, or (at your *
9 * option) any later version. *
10 * *
11 * This script is distributed in the hope that it will be useful, but *
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- *
13 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
14 * General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU Lesser General Public *
17 * License along with the script. *
18 * If not, see http://www.gnu.org/licenses/lgpl.html *
19 * *
20 * The TYPO3 project - inspiring people to share! *
21 * */
22
23 /**
24 * This view helper generates a <select> dropdown list for the use with a form.
25 *
26 * = Basic usage =
27 *
28 * The most straightforward way is to supply an associative array as the "options" parameter.
29 * The array key is used as option key, and the value is used as human-readable name.
30 *
31 * <code title="Basic usage">
32 * <f:form.select name="paymentOptions" options="{payPal: 'PayPal International Services', visa: 'VISA Card'}" />
33 * </code>
34 *
35 * = Pre-select a value =
36 *
37 * To pre-select a value, set "value" to the option key which should be selected.
38 * <code title="Default value">
39 * <f:form.select name="paymentOptions" options="{payPal: 'PayPal International Services', visa: 'VISA Card'}" value="visa" />
40 * </code>
41 * Generates a dropdown box like above, except that "VISA Card" is selected.
42 *
43 * If the select box is a multi-select box (multiple="true"), then "value" can be an array as well.
44 *
45 * = Usage on domain objects =
46 *
47 * If you want to output domain objects, you can just pass them as array into the "options" parameter.
48 * To define what domain object value should be used as option key, use the "optionValueField" variable. Same goes for optionLabelField.
49 * If neither is given, the Identifier (UID/uid) and the __toString() method are tried as fallbacks.
50 *
51 * If the optionValueField variable is set, the getter named after that value is used to retrieve the option key.
52 * If the optionLabelField variable is set, the getter named after that value is used to retrieve the option value.
53 *
54 * <code title="Domain objects">
55 * <f:form.select name="users" options="{userArray}" optionValueField="id" optionLabelField="firstName" />
56 * </code>
57 * In the above example, the userArray is an array of "User" domain objects, with no array key specified.
58 *
59 * So, in the above example, the method $user->getId() is called to retrieve the key, and $user->getFirstName() to retrieve the displayed value of each entry.
60 *
61 * The "value" property now expects a domain object, and tests for object equivalence.
62 *
63 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
64 * @api
65 */
66 class Tx_Fluid_ViewHelpers_Form_SelectViewHelper extends Tx_Fluid_ViewHelpers_Form_AbstractFormFieldViewHelper {
67
68 /**
69 * @var string
70 */
71 protected $tagName = 'select';
72
73 /**
74 * @var mixed the selected value
75 */
76 protected $selectedValue = NULL;
77
78 /**
79 * Initialize arguments.
80 *
81 * @return void
82 * @author Sebastian Kurfürst <sebastian@typo3.org>
83 * @api
84 */
85 public function initializeArguments() {
86 parent::initializeArguments();
87 $this->registerUniversalTagAttributes();
88 $this->registerTagAttribute('multiple', 'string', 'if set, multiple select field');
89 $this->registerTagAttribute('size', 'string', 'Size of input field');
90 $this->registerTagAttribute('disabled', 'string', 'Specifies that the input element should be disabled when the page loads');
91 $this->registerArgument('options', 'array', 'Associative array with internal IDs as key, and the values are displayed in the select box', TRUE);
92 $this->registerArgument('optionValueField', 'string', 'If specified, will call the appropriate getter on each object to determine the value.');
93 $this->registerArgument('optionLabelField', 'string', 'If specified, will call the appropriate getter on each object to determine the label.');
94 $this->registerArgument('sortByOptionLabel', 'boolean', 'If true, List will be sorted by label.', FALSE, FALSE);
95 $this->registerArgument('selectAllByDefault', 'boolean', 'If specified options are selected if none was set before.', FALSE, FALSE);
96 $this->registerArgument('errorClass', 'string', 'CSS class to set if there are errors for this view helper', FALSE, 'f3-form-error');
97 }
98
99 /**
100 * Render the tag.
101 *
102 * @return string rendered tag.
103 * @author Sebastian Kurfürst <sebastian@typo3.org>
104 * @author Bastian Waidelich <bastian@typo3.org>
105 * @api
106 */
107 public function render() {
108 $name = $this->getName();
109 if ($this->arguments->hasArgument('multiple')) {
110 $name .= '[]';
111 }
112
113 $this->tag->addAttribute('name', $name);
114
115 $options = $this->getOptions();
116 if (empty($options)) {
117 $options = array('' => '');
118 }
119 $this->tag->setContent($this->renderOptionTags($options));
120
121 $this->setErrorClassAttribute();
122
123 $content = '';
124
125 // register field name for token generation.
126 // in case it is a multi-select, we need to register the field name
127 // as often as there are elements in the box
128 if ($this->arguments->hasArgument('multiple') && $this->arguments['multiple'] !== '') {
129 $content .= $this->renderHiddenFieldForEmptyValue();
130 for ($i=0; $i<count($options); $i++) {
131 $this->registerFieldNameForFormTokenGeneration($name);
132 }
133 } else {
134 $this->registerFieldNameForFormTokenGeneration($name);
135 }
136
137 $content .= $this->tag->render();
138 return $content;
139 }
140
141 /**
142 * Render the option tags.
143 *
144 * @param array $options the options for the form.
145 * @return string rendered tags.
146 * @author Bastian Waidelich <bastian@typo3.org>
147 */
148 protected function renderOptionTags($options) {
149 $output = '';
150
151 foreach ($options as $value => $label) {
152 $isSelected = $this->isSelected($value);
153 $output.= $this->renderOptionTag($value, $label, $isSelected) . chr(10);
154 }
155 return $output;
156 }
157
158 /**
159 * Render the option tags.
160 *
161 * @return array an associative array of options, key will be the value of the option tag
162 * @author Bastian Waidelich <bastian@typo3.org>
163 * @author Karsten Dambekalns <karsten@typo3.org>
164 */
165 protected function getOptions() {
166 if (!is_array($this->arguments['options']) && !($this->arguments['options'] instanceof Traversable)) {
167 return array();
168 }
169 $options = array();
170 $optionsArgument = $this->arguments['options'];
171 foreach ($optionsArgument as $key => $value) {
172 if (is_object($value)) {
173
174 if ($this->arguments->hasArgument('optionValueField')) {
175 $key = Tx_Extbase_Reflection_ObjectAccess::getProperty($value, $this->arguments['optionValueField']);
176 if (is_object($key)) {
177 if (method_exists($key, '__toString')) {
178 $key = (string)$key;
179 } else {
180 throw new Tx_Fluid_Core_ViewHelper_Exception('Identifying value for object of class "' . get_class($value) . '" was an object.' , 1247827428);
181 }
182 }
183 } elseif ($this->persistenceManager->getBackend()->getIdentifierByObject($value) !== NULL) {
184 $key = $this->persistenceManager->getBackend()->getIdentifierByObject($value);
185 } elseif (method_exists($value, '__toString')) {
186 $key = (string)$value;
187 } else {
188 throw new Tx_Fluid_Core_ViewHelper_Exception('No identifying value for object of class "' . get_class($value) . '" found.' , 1247826696);
189 }
190
191 if ($this->arguments->hasArgument('optionLabelField')) {
192 $value = Tx_Extbase_Reflection_ObjectAccess::getProperty($value, $this->arguments['optionLabelField']);
193 if (is_object($value)) {
194 if (method_exists($value, '__toString')) {
195 $value = (string)$value;
196 } else {
197 throw new Tx_Fluid_Core_ViewHelper_Exception('Label value for object of class "' . get_class($value) . '" was an object without a __toString() method.' , 1247827553);
198 }
199 }
200 } elseif (method_exists($value, '__toString')) {
201 $value = (string)$value;
202 } elseif ($this->persistenceManager->getBackend()->getIdentifierByObject($value) !== NULL) {
203 $value = $this->persistenceManager->getBackend()->getIdentifierByObject($value);
204 }
205 }
206 $options[$key] = $value;
207 }
208 if ($this->arguments['sortByOptionLabel']) {
209 asort($options);
210 }
211 return $options;
212 }
213
214 /**
215 * Render the option tags.
216 *
217 * @return boolean TRUE if the value should be marked a s selected; FALSE otherwise
218 * @author Bastian Waidelich <bastian@typo3.org>
219 * @author Jochen Rau <jochen.rau@typoplanet.de>
220 */
221 protected function isSelected($value) {
222 $selectedValue = $this->getSelectedValue();
223 if ($value === $selectedValue || (string)$value === $selectedValue) {
224 return TRUE;
225 }
226 if ($this->arguments->hasArgument('multiple')) {
227 if (is_null($selectedValue) && $this->arguments['selectAllByDefault'] === TRUE) {
228 return TRUE;
229 } elseif (is_array($selectedValue) && in_array($value, $selectedValue)) {
230 return TRUE;
231 }
232 }
233 return FALSE;
234 }
235
236 /**
237 * Retrieves the selected value(s)
238 *
239 * @return mixed value string or an array of strings
240 * @author Bastian Waidelich <bastian@typo3.org>
241 */
242 protected function getSelectedValue() {
243 $value = $this->getValue();
244 if (!$this->arguments->hasArgument('optionValueField')) {
245 return $value;
246 }
247 if (!is_array($value) && !($value instanceof Iterator)) {
248 if (is_object($value)) {
249 return Tx_Extbase_Reflection_ObjectAccess::getProperty($value, $this->arguments['optionValueField']);
250 } else {
251 return $value;
252 }
253 }
254 $selectedValues = array();
255 foreach($value as $selectedValueElement) {
256 if (is_object($selectedValueElement)) {
257 $selectedValues[] = Tx_Extbase_Reflection_ObjectAccess::getProperty($selectedValueElement, $this->arguments['optionValueField']);
258 } else {
259 $selectedValues[] = $selectedValueElement;
260 }
261 }
262 return $selectedValues;
263 }
264
265 /**
266 * Render one option tag
267 *
268 * @param string $value value attribute of the option tag (will be escaped)
269 * @param string $label content of the option tag (will be escaped)
270 * @param boolean $isSelected specifies wheter or not to add selected attribute
271 * @return string the rendered option tag
272 * @author Bastian Waidelich <bastian@typo3.org>
273 */
274 protected function renderOptionTag($value, $label, $isSelected) {
275 $output = '<option value="' . htmlspecialchars($value) . '"';
276 if ($isSelected) {
277 $output.= ' selected="selected"';
278 }
279 $output.= '>' . htmlspecialchars($label) . '</option>';
280
281 return $output;
282 }
283 }
284
285 ?>