PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/typo3/sysext/fluid/Classes/ViewHelpers/Form/SelectViewHelper.php

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