4f5ff7320fea1ccae0e7f77a1bfe8416a415a541
[Packages/TYPO3.CMS.git] / typo3 / sysext / fluid / Classes / ViewHelpers / Form / AbstractFormFieldViewHelper.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 * Abstract Form View Helper. Bundles functionality related to direct property access of objects in other Form ViewHelpers.
25 *
26 * If you set the "property" attribute to the name of the property to resolve from the object, this class will
27 * automatically set the name and value of a form element.
28 *
29 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
30 * @api
31 */
32 abstract class Tx_Fluid_ViewHelpers_Form_AbstractFormFieldViewHelper extends Tx_Fluid_ViewHelpers_Form_AbstractFormViewHelper {
33
34 /**
35 * Initialize arguments.
36 *
37 * @return void
38 * @author Sebastian Kurfürst <sebastian@typo3.org>
39 * @api
40 */
41 public function initializeArguments() {
42 parent::initializeArguments();
43 $this->registerArgument('name', 'string', 'Name of input tag');
44 $this->registerArgument('value', 'mixed', 'Value of input tag');
45 $this->registerArgument('property', 'string', 'Name of Object Property. If used in conjunction with <f:form object="...">, "name" and "value" properties will be ignored.');
46 }
47
48 /**
49 * Get the name of this form element.
50 * Either returns arguments['name'], or the correct name for Object Access.
51 *
52 * In case property is something like bla.blubb (hierarchical), then [bla][blubb] is generated.
53 *
54 * @return string Name
55 * @author Sebastian Kurfürst <sebastian@typo3.org>
56 * @author Robert Lemke <robert@typo3.org>
57 * @author Karsten Dambekalns <karsten@typo3.org>
58 * @author Bastian Waidelich <bastian@typo3.org>
59 */
60 protected function getName() {
61 $name = $this->getNameWithoutPrefix();
62 return $this->prefixFieldName($name);
63 }
64
65 /**
66 * Get the name of this form element, without prefix.
67 *
68 * @return string name
69 * @author Sebastian Kurfürst <sebastian@typo3.org>
70 * @author Robert Lemke <robert@typo3.org>
71 * @author Karsten Dambekalns <karsten@typo3.org>
72 * @author Bastian Waidelich <bastian@typo3.org>
73 */
74 protected function getNameWithoutPrefix() {
75 if ($this->isObjectAccessorMode()) {
76 $formObjectName = $this->viewHelperVariableContainer->get('Tx_Fluid_ViewHelpers_FormViewHelper', 'formObjectName');
77 if (!empty($formObjectName)) {
78 $propertySegments = explode('.', $this->arguments['property']);
79 $propertyPath = '';
80 foreach ($propertySegments as $segment) {
81 $propertyPath .= '[' . $segment . ']';
82 }
83 $name = $formObjectName . $propertyPath;
84 } else {
85 $name = $this->arguments['property'];
86 }
87 } else {
88 $name = $this->arguments['name'];
89 }
90 if ($this->arguments->hasArgument('value') && is_object($this->arguments['value'])) {
91 if (NULL !== $this->persistenceManager->getBackend()->getIdentifierByObject($this->arguments['value'])
92 && (!$this->persistenceManager->getBackend()->isNewObject($this->arguments['value']))) {
93 $name .= '[__identity]';
94 }
95 }
96
97 return $name;
98 }
99
100 /**
101 * Get the value of this form element.
102 * Either returns arguments['value'], or the correct value for Object Access.
103 *
104 * @return mixed Value
105 * @author Sebastian Kurfürst <sebastian@typo3.org>
106 * @author Robert Lemke <robert@typo3.org>
107 * @author Bastian Waidelich <bastian@typo3.org>
108 */
109 protected function getValue() {
110 $value = NULL;
111 if ($this->arguments->hasArgument('value')) {
112 $value = $this->arguments['value'];
113 } elseif ($this->isObjectAccessorMode() && $this->viewHelperVariableContainer->exists('Tx_Fluid_ViewHelpers_FormViewHelper', 'formObject')) {
114 $this->addAdditionalIdentityPropertiesIfNeeded();
115 $value = $this->getPropertyValue();
116 }
117 if (is_object($value)) {
118 $identifier = $this->persistenceManager->getBackend()->getIdentifierByObject($value);
119 if ($identifier !== NULL) {
120 $value = $identifier;
121 }
122 }
123 return $value;
124 }
125
126 /**
127 * Add additional identity properties in case the current property is hierarchical (of the form "bla.blubb").
128 * Then, [bla][__identity] has to be generated as well.
129 *
130 * @author Sebastian Kurfuerst <sebastian@typo3.org>
131 * @return void
132 */
133 protected function addAdditionalIdentityPropertiesIfNeeded() {
134 $propertySegments = explode('.', $this->arguments['property']);
135 if (count($propertySegments) >= 2) {
136 // hierarchical property. If there is no "." inside (thus $propertySegments == 1), we do not need to do anything
137 $formObject = $this->viewHelperVariableContainer->get('Tx_Fluid_ViewHelpers_FormViewHelper', 'formObject');
138
139 $objectName = $this->viewHelperVariableContainer->get('Tx_Fluid_ViewHelpers_FormViewHelper', 'formObjectName');
140 // If Count == 2 -> we need to go through the for-loop exactly once
141 for ($i=1; $i < count($propertySegments); $i++) {
142 $object = Tx_Extbase_Reflection_ObjectAccess::getPropertyPath($formObject, implode('.', array_slice($propertySegments, 0, $i)));
143 $objectName .= '[' . $propertySegments[$i-1] . ']';
144 $hiddenIdentityField = $this->renderHiddenIdentityField($object, $objectName);
145
146 // Add the hidden identity field to the ViewHelperVariableContainer
147 $additionalIdentityProperties = $this->viewHelperVariableContainer->get('Tx_Fluid_ViewHelpers_FormViewHelper', 'additionalIdentityProperties');
148 $additionalIdentityProperties[$objectName] = $hiddenIdentityField;
149 $this->viewHelperVariableContainer->addOrUpdate('Tx_Fluid_ViewHelpers_FormViewHelper', 'additionalIdentityProperties', $additionalIdentityProperties);
150 }
151 }
152 }
153
154 /**
155 * Get the current property of the object bound to this form.
156 *
157 * @return mixed Value
158 * @author Bastian Waidelich <bastian@typo3.org>
159 */
160 protected function getPropertyValue() {
161
162 $formObject = $this->viewHelperVariableContainer->get('Tx_Fluid_ViewHelpers_FormViewHelper', 'formObject');
163 $propertyName = $this->arguments['property'];
164
165 if (is_array($formObject)) {
166 return isset($formObject[$propertyName]) ? $formObject[$propertyName] : NULL;
167 }
168 return Tx_Extbase_Reflection_ObjectAccess::getPropertyPath($formObject, $propertyName);
169 }
170
171 /**
172 * Internal method which checks if we should evaluate a domain object or just output arguments['name'] and arguments['value']
173 *
174 * @return boolean TRUE if we should evaluate the domain object, FALSE otherwise.
175 * @author Sebastian Kurfürst <sebastian@typo3.org>
176 */
177 protected function isObjectAccessorMode() {
178 return $this->arguments->hasArgument('property')
179 && $this->viewHelperVariableContainer->exists('Tx_Fluid_ViewHelpers_FormViewHelper', 'formObjectName');
180 }
181
182 /**
183 * Add an CSS class if this view helper has errors
184 *
185 * @return void
186 * @author Christopher Hlubek <hlubek@networkteam.com>
187 * @author Bastian Waidelich <bastian@typo3.org>
188 */
189 protected function setErrorClassAttribute() {
190 if ($this->arguments->hasArgument('class')) {
191 $cssClass = $this->arguments['class'] . ' ';
192 } else {
193 $cssClass = '';
194 }
195 $errors = $this->getErrorsForProperty();
196 if (count($errors) > 0) {
197 if ($this->arguments->hasArgument('errorClass')) {
198 $cssClass .= $this->arguments['errorClass'];
199 } else {
200 $cssClass .= 'error';
201 }
202 $this->tag->addAttribute('class', $cssClass);
203 }
204 }
205
206 /**
207 * Get errors for the property and form name of this view helper
208 *
209 * @return array An array of Tx_Fluid_Error_Error objects
210 * @author Christopher Hlubek <hlubek@networkteam.com>
211 * @author Bastian Waidelich <bastian@typo3.org>
212 */
213 protected function getErrorsForProperty() {
214 if (!$this->isObjectAccessorMode()) {
215 return array();
216 }
217 $errors = $this->controllerContext->getRequest()->getErrors();
218 $formObjectName = $this->viewHelperVariableContainer->get('Tx_Fluid_ViewHelpers_FormViewHelper', 'formObjectName');
219 $propertyName = $this->arguments['property'];
220 $formErrors = array();
221 foreach ($errors as $error) {
222 if ($error instanceof Tx_Extbase_Validation_PropertyError && $error->getPropertyName() === $formObjectName) {
223 $formErrors = $error->getErrors();
224 foreach ($formErrors as $formError) {
225 if ($formError instanceof Tx_Extbase_Validation_PropertyError && $formError->getPropertyName() === $propertyName) {
226 return $formError->getErrors();
227 }
228 }
229 }
230 }
231 return array();
232 }
233
234 /**
235 * Renders a hidden field with the same name as the element, to make sure the empty value is submitted
236 * in case nothing is selected. This is needed for checkbox and multiple select fields
237 *
238 * @return string the hidden field.
239 * @author Sebastian Kurfürst <sebastian@typo3.org>
240 * @author Bastian Waidelich <bastian@typo3.org>
241 */
242 protected function renderHiddenFieldForEmptyValue() {
243 $hiddenFieldNames = array();
244 if ($this->viewHelperVariableContainer->exists('Tx_Fluid_ViewHelpers_FormViewHelper', 'renderedHiddenFields')) {
245 $hiddenFieldNames = $this->viewHelperVariableContainer->get('Tx_Fluid_ViewHelpers_FormViewHelper', 'renderedHiddenFields');
246 }
247
248 $fieldName = $this->getName();
249 if (substr($fieldName, -2) === '[]') {
250 $fieldName = substr($fieldName, 0, -2);
251 }
252 if (!in_array($fieldName, $hiddenFieldNames)) {
253 $hiddenFieldNames[] = $fieldName;
254 $this->viewHelperVariableContainer->addOrUpdate('Tx_Fluid_ViewHelpers_FormViewHelper', 'renderedHiddenFields', $hiddenFieldNames);
255
256 return '<input type="hidden" name="' . htmlspecialchars($fieldName) . '" value="" />';
257 }
258 return '';
259 }
260 }
261
262 ?>