TYPO3 API  SVNRelease
FormViewHelper.php
Go to the documentation of this file.
00001 <?php
00002 
00003 /*                                                                        *
00004  * This script belongs to the FLOW3 package "Fluid".                      *
00005  *                                                                        *
00006  * It is free software; you can redistribute it and/or modify it under    *
00007  * the terms of the GNU General Public License as published by the Free   *
00008  * Software Foundation, either version 3 of the License, or (at your      *
00009  * option) any later version.                                             *
00010  *                                                                        *
00011  * This script is distributed in the hope that it will be useful, but     *
00012  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-    *
00013  * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General      *
00014  * Public License for more details.                                       *
00015  *                                                                        *
00016  * You should have received a copy of the GNU General Public License      *
00017  * along with the script.                                                 *
00018  * If not, see http://www.gnu.org/licenses/gpl.html                       *
00019  *                                                                        *
00020  * The TYPO3 project - inspiring people to share!                         *
00021  *                                                                        */
00022 
00023 /**
00024  */
00025 
00026 /**
00027  * Form view helper. Generates a <form> Tag.
00028  *
00029  * = Basic usage =
00030  *
00031  * Use <f:form> to output an HTML <form> tag which is targeted at the specified action, in the current controller and package.
00032  * It will submit the form data via a POST request. If you want to change this, use method="get" as an argument.
00033  * <code title="Example">
00034  * <f:form action="...">...</f:form>
00035  * </code>
00036  *
00037  * = A complex form with a specified encoding type =
00038  *
00039  * <code title="Form with enctype set">
00040  * <f:form action=".." controller="..." package="..." enctype="multipart/form-data">...</f:form>
00041  * </code>
00042  *
00043  * = A Form which should render a domain object =
00044  *
00045  * <code title="Binding a domain object to a form">
00046  * <f:form action="..." name="customer" object="{customer}">
00047  *   <f:form.hidden property="id" />
00048  *   <f:form.textbox property="name" />
00049  * </f:form>
00050  * </code>
00051  * This automatically inserts the value of {customer.name} inside the textbox and adjusts the name of the textbox accordingly.
00052  *
00053  * @license http://opensource.org/licenses/gpl-license.php GNU Public License, version 2
00054  */
00055 class Tx_Fluid_ViewHelpers_FormViewHelper extends Tx_Fluid_ViewHelpers_Form_AbstractFormViewHelper {
00056 
00057     /**
00058      * @var string
00059      */
00060     protected $tagName = 'form';
00061 
00062     /**
00063      * @var Tx_Extbase_Security_Channel_RequestHashService
00064      */
00065     protected $requestHashService;
00066 
00067     /**
00068      * We need the arguments of the formActionUri on requesthash calculation
00069      * therefore we will store them in here right after calling uriBuilder
00070      *
00071      * @var array
00072      */
00073     protected $formActionUriArguments;
00074 
00075     /**
00076      * Inject a request hash service
00077      *
00078      * @param Tx_Extbase_Security_Channel_RequestHashService $requestHashService The request hash service
00079      * @return void
00080      * @author Sebastian Kurfürst <sebastian@typo3.org>
00081      */
00082     public function injectRequestHashService(Tx_Extbase_Security_Channel_RequestHashService $requestHashService) {
00083         $this->requestHashService = $requestHashService;
00084     }
00085 
00086     /**
00087      * Initialize arguments.
00088      *
00089      * @return void
00090      */
00091     public function initializeArguments() {
00092         $this->registerTagAttribute('enctype', 'string', 'MIME type with which the form is submitted');
00093         $this->registerTagAttribute('method', 'string', 'Transfer type (GET or POST)');
00094         $this->registerTagAttribute('name', 'string', 'Name of form');
00095         $this->registerTagAttribute('onreset', 'string', 'JavaScript: On reset of the form');
00096         $this->registerTagAttribute('onsubmit', 'string', 'JavaScript: On submit of the form');
00097 
00098         $this->registerUniversalTagAttributes();
00099     }
00100 
00101     /**
00102      * Render the form.
00103      *
00104      * @param string $action Target action
00105      * @param array $arguments Arguments
00106      * @param string $controller Target controller
00107      * @param string $extensionName Target Extension Name (without "tx_" prefix and no underscores). If NULL the current extension name is used
00108      * @param string $pluginName Target plugin. If empty, the current plugin name is used
00109      * @param integer $pageUid Target page uid
00110      * @param mixed $object Object to use for the form. Use in conjunction with the "property" attribute on the sub tags
00111      * @param integer $pageType Target page type
00112      * @param boolean $noCache set this to disable caching for the target page. You should not need this.
00113      * @param boolean $noCacheHash set this to supress the cHash query parameter created by TypoLink. You should not need this.
00114      * @param string $section The anchor to be added to the action URI (only active if $actionUri is not set)
00115      * @param string $format The requested format (e.g. ".html") of the target page (only active if $actionUri is not set)
00116      * @param array $additionalParams additional action URI query parameters that won't be prefixed like $arguments (overrule $arguments) (only active if $actionUri is not set)
00117      * @param boolean $absolute If set, an absolute action URI is rendered (only active if $actionUri is not set)
00118      * @param boolean $addQueryString If set, the current query parameters will be kept in the action URI (only active if $actionUri is not set)
00119      * @param array $argumentsToBeExcludedFromQueryString arguments to be removed from the action URI. Only active if $addQueryString = TRUE and $actionUri is not set
00120      * @param string $fieldNamePrefix Prefix that will be added to all field names within this form. If not set the prefix will be tx_yourExtension_plugin
00121      * @param string $actionUri can be used to overwrite the "action" attribute of the form tag
00122      * @param string $objectName name of the object that is bound to this form. If this argument is not specified, the name attribute of this form is used to determine the FormObjectName
00123      * @return string rendered form
00124      */
00125     public function render($action = NULL, array $arguments = array(), $controller = NULL, $extensionName = NULL, $pluginName = NULL, $pageUid = NULL, $object = NULL, $pageType = 0, $noCache = FALSE, $noCacheHash = FALSE, $section = '', $format = '', array $additionalParams = array(), $absolute = FALSE, $addQueryString = FALSE, array $argumentsToBeExcludedFromQueryString = array(), $fieldNamePrefix = NULL, $actionUri = NULL, $objectName = NULL) {
00126         $this->setFormActionUri();
00127 
00128         if (strtolower($this->arguments['method']) === 'get') {
00129             $this->tag->addAttribute('method', 'get');
00130         } else {
00131             $this->tag->addAttribute('method', 'post');
00132         }
00133 
00134         $this->addFormObjectNameToViewHelperVariableContainer();
00135         $this->addFormObjectToViewHelperVariableContainer();
00136         $this->addFieldNamePrefixToViewHelperVariableContainer();
00137         $this->addFormFieldNamesToViewHelperVariableContainer();
00138 
00139         $formContent = $this->renderChildren();
00140 
00141         $content = chr(10) . '<div style="display: none">';
00142         $content .= $this->renderHiddenIdentityField($this->arguments['object'], $this->getFormObjectName());
00143         $content .= $this->renderAdditionalIdentityFields();
00144         $content .= $this->renderHiddenReferrerFields();
00145         $content .= $this->renderRequestHashField(); // Render hmac after everything else has been rendered
00146         $content .= chr(10) . '</div>' . chr(10);
00147         $content .= $formContent;
00148 
00149         $this->tag->setContent($content);
00150 
00151         $this->removeFieldNamePrefixFromViewHelperVariableContainer();
00152         $this->removeFormObjectFromViewHelperVariableContainer();
00153         $this->removeFormObjectNameFromViewHelperVariableContainer();
00154         $this->removeFormFieldNamesFromViewHelperVariableContainer();
00155         $this->removeCheckboxFieldNamesFromViewHelperVariableContainer();
00156 
00157         return $this->tag->render();
00158     }
00159 
00160     /**
00161      * Sets the "action" attribute of the form tag
00162      *
00163      * @return void
00164      */
00165     protected function setFormActionUri() {
00166         if ($this->arguments->hasArgument('actionUri')) {
00167             $formActionUri = $this->arguments['actionUri'];
00168         } else {
00169             $uriBuilder = $this->controllerContext->getUriBuilder();
00170             $formActionUri = $uriBuilder
00171                 ->reset()
00172                 ->setTargetPageUid($this->arguments['pageUid'])
00173                 ->setTargetPageType($this->arguments['pageType'])
00174                 ->setNoCache($this->arguments['noCache'])
00175                 ->setUseCacheHash(!$this->arguments['noCacheHash'])
00176                 ->setSection($this->arguments['section'])
00177                 ->setCreateAbsoluteUri($this->arguments['absolute'])
00178                 ->setArguments((array)$this->arguments['additionalParams'])
00179                 ->setAddQueryString($this->arguments['addQueryString'])
00180                 ->setArgumentsToBeExcludedFromQueryString((array)$this->arguments['argumentsToBeExcludedFromQueryString'])
00181                 ->setFormat($this->arguments['format'])
00182                 ->uriFor($this->arguments['action'], $this->arguments['arguments'], $this->arguments['controller'], $this->arguments['extensionName'], $this->arguments['pluginName']);
00183             $this->formActionUriArguments = $uriBuilder->getArguments();
00184         }
00185         $this->tag->addAttribute('action', $formActionUri);
00186     }
00187 
00188     /**
00189      * Render additional identity fields which were registered by form elements.
00190      * This happens if a form field is defined like property="bla.blubb" - then we might need an identity property for the sub-object "bla".
00191      *
00192      * @return string HTML-string for the additional identity properties
00193      * @author Sebastian Kurfürst <sebastian@typo3.org>
00194      */
00195     protected function renderAdditionalIdentityFields() {
00196         if ($this->viewHelperVariableContainer->exists('Tx_Fluid_ViewHelpers_FormViewHelper', 'additionalIdentityProperties')) {
00197             $additionalIdentityProperties = $this->viewHelperVariableContainer->get('Tx_Fluid_ViewHelpers_FormViewHelper', 'additionalIdentityProperties');
00198             $output = '';
00199             foreach ($additionalIdentityProperties as $identity) {
00200                 $output .= chr(10) . $identity;
00201             }
00202             return $output;
00203         }
00204         return '';
00205     }
00206 
00207     /**
00208      * Renders hidden form fields for referrer information about
00209      * the current controller and action.
00210      *
00211      * @return string Hidden fields with referrer information
00212      * @todo filter out referrer information that is equal to the target (e.g. same packageKey)
00213      */
00214     protected function renderHiddenReferrerFields() {
00215         $request = $this->controllerContext->getRequest();
00216         $extensionName = $request->getControllerExtensionName();
00217         $controllerName = $request->getControllerName();
00218         $actionName = $request->getControllerActionName();
00219 
00220         $result = chr(10);
00221         $result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[extensionName]') . '" value="' . $extensionName . '" />' . chr(10);
00222         $result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[controllerName]') . '" value="' . $controllerName . '" />' . chr(10);
00223         $result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[actionName]') . '" value="' . $actionName . '" />' . chr(10);
00224         return $result;
00225     }
00226 
00227     /**
00228      * Adds the form object name to the ViewHelperVariableContainer if "objectName" argument or "name" attribute is specified.
00229      *
00230      * @return void
00231      */
00232     protected function addFormObjectNameToViewHelperVariableContainer() {
00233         $formObjectName = $this->getFormObjectName();
00234         if ($formObjectName !== NULL) {
00235             $this->viewHelperVariableContainer->add('Tx_Fluid_ViewHelpers_FormViewHelper', 'formObjectName', $formObjectName);
00236         }
00237     }
00238 
00239     /**
00240      * Removes the form name from the ViewHelperVariableContainer.
00241      *
00242      * @return void
00243      */
00244     protected function removeFormObjectNameFromViewHelperVariableContainer() {
00245         $formObjectName = $this->getFormObjectName();
00246         if ($formObjectName !== NULL) {
00247             $this->viewHelperVariableContainer->remove('Tx_Fluid_ViewHelpers_FormViewHelper', 'formObjectName');
00248         }
00249     }
00250 
00251     /**
00252      * Returns the name of the object that is bound to this form.
00253      * If the "objectName" argument has been specified, this is returned. Otherwise the name attribute of this form.
00254      * If neither objectName nor name arguments have been set, NULL is returned.
00255      *
00256      * @return string specified Form name or NULL if neither $objectName nor $name arguments have been specified
00257      * @author Bastian Waidelich <bastian@typo3.org>
00258      */
00259     protected function getFormObjectName() {
00260         $formObjectName = NULL;
00261         if ($this->arguments->hasArgument('objectName')) {
00262             $formObjectName = $this->arguments['objectName'];
00263         } elseif ($this->arguments->hasArgument('name')) {
00264             $formObjectName = $this->arguments['name'];
00265         }
00266         return $formObjectName;
00267     }
00268     /**
00269      * Adds the object that is bound to this form to the ViewHelperVariableContainer if the formObject attribute is specified.
00270      *
00271      * @return void
00272      */
00273     protected function addFormObjectToViewHelperVariableContainer() {
00274         if ($this->arguments->hasArgument('object')) {
00275             $this->viewHelperVariableContainer->add('Tx_Fluid_ViewHelpers_FormViewHelper', 'formObject', $this->arguments['object']);
00276             $this->viewHelperVariableContainer->add('Tx_Fluid_ViewHelpers_FormViewHelper', 'additionalIdentityProperties', array());
00277         }
00278     }
00279 
00280     /**
00281      * Removes the form object from the ViewHelperVariableContainer.
00282      *
00283      * @return void
00284      */
00285     protected function removeFormObjectFromViewHelperVariableContainer() {
00286         if ($this->arguments->hasArgument('object')) {
00287             $this->viewHelperVariableContainer->remove('Tx_Fluid_ViewHelpers_FormViewHelper', 'formObject');
00288             $this->viewHelperVariableContainer->remove('Tx_Fluid_ViewHelpers_FormViewHelper', 'additionalIdentityProperties');
00289         }
00290     }
00291 
00292     /**
00293      * Adds the field name prefix to the ViewHelperVariableContainer
00294      *
00295      * @return void
00296      */
00297     protected function addFieldNamePrefixToViewHelperVariableContainer() {
00298         $fieldNamePrefix = $this->getFieldNamePrefix();
00299         $this->viewHelperVariableContainer->add('Tx_Fluid_ViewHelpers_FormViewHelper', 'fieldNamePrefix', $fieldNamePrefix);
00300     }
00301 
00302     /**
00303      * Get the field name prefix
00304      *
00305      * @return string
00306      */
00307     protected function getFieldNamePrefix() {
00308         if ($this->arguments->hasArgument('fieldNamePrefix')) {
00309             return $this->arguments['fieldNamePrefix'];
00310         } else {
00311             return $this->getDefaultFieldNamePrefix();
00312         }
00313     }
00314 
00315     /**
00316      * Removes field name prefix from the ViewHelperVariableContainer
00317      *
00318      * @return void
00319      */
00320     protected function removeFieldNamePrefixFromViewHelperVariableContainer() {
00321         $this->viewHelperVariableContainer->remove('Tx_Fluid_ViewHelpers_FormViewHelper', 'fieldNamePrefix');
00322     }
00323 
00324     /**
00325      * Adds a container for form field names to the ViewHelperVariableContainer
00326      *
00327      * @return void
00328      * @author Sebastian Kurfürst <sebastian@typo3.org>
00329      */
00330     protected function addFormFieldNamesToViewHelperVariableContainer() {
00331         $this->viewHelperVariableContainer->add('Tx_Fluid_ViewHelpers_FormViewHelper', 'formFieldNames', array());
00332     }
00333 
00334     /**
00335      * Removes the container for form field names from the ViewHelperVariableContainer
00336      *
00337      * @return void
00338      * @author Sebastian Kurfürst <sebastian@typo3.org>
00339      */
00340     protected function removeFormFieldNamesFromViewHelperVariableContainer() {
00341         $this->viewHelperVariableContainer->remove('Tx_Fluid_ViewHelpers_FormViewHelper', 'formFieldNames');
00342     }
00343 
00344     /**
00345      * Render the request hash field
00346      *
00347      * @return string the hmac field
00348      * @author Sebastian Kurfürst <sebastian@typo3.org>
00349      */
00350     protected function renderRequestHashField() {
00351         $formFieldNames = $this->viewHelperVariableContainer->get('Tx_Fluid_ViewHelpers_FormViewHelper', 'formFieldNames');
00352         $this->postProcessUriArgumentsForRequesthash($this->formActionUriArguments, $formFieldNames);
00353         $requestHash = $this->requestHashService->generateRequestHash($formFieldNames, $this->getFieldNamePrefix());
00354         // in v4, we need to prefix __hmac as well to make it show up in the request object.
00355         return '<input type="hidden" name="' . $this->prefixFieldName('__hmac') . '" value="' . htmlspecialchars($requestHash) . '" />';
00356     }
00357 
00358     /**
00359      * Add the URI arguments after postprocessing to the request hash as well.
00360      */
00361     protected function postProcessUriArgumentsForRequestHash($arguments, &$results, $currentPrefix = '', $level = 0) {
00362         if (!count($arguments)) return;
00363         foreach ($arguments as $argumentName => $argumentValue) {
00364             if (is_array($argumentValue)) {
00365                 $prefix = ($level==0 ? $argumentName : $currentPrefix . '[' . $argumentName . ']');
00366                 $this->postProcessUriArgumentsForRequestHash($argumentValue, $results, $prefix, $level+1);
00367             } else {
00368                 $results[] = ($level==0 ? $argumentName : $currentPrefix . '[' . $argumentName . ']');
00369             }
00370         }
00371     }
00372 
00373     /**
00374      * Retrieves the default field name prefix for this form
00375      *
00376      * @return string default field name prefix
00377      */
00378     protected function getDefaultFieldNamePrefix() {
00379         $request = $this->controllerContext->getRequest();
00380         if ($this->arguments->hasArgument('extensionName')) {
00381             $extensionName = $this->arguments['extensionName'];
00382         } else {
00383             $extensionName = $request->getControllerExtensionName();
00384         }
00385         if ($this->arguments->hasArgument('pluginName')) {
00386             $pluginName = $this->arguments['pluginName'];
00387         } else {
00388             $pluginName = $request->getPluginName();
00389         }
00390 
00391         return Tx_Extbase_Utility_Extension::getPluginNamespace($extensionName, $pluginName);
00392     }
00393 
00394     /**
00395      * Remove Checkbox field names from ViewHelper variable container, to start from scratch when a new form starts.
00396      */
00397     protected function removeCheckboxFieldNamesFromViewHelperVariableContainer() {
00398         if ($this->viewHelperVariableContainer->exists('Tx_Fluid_ViewHelpers_Form_CheckboxViewHelper', 'checkboxFieldNames')) {
00399             $this->viewHelperVariableContainer->remove('Tx_Fluid_ViewHelpers_Form_CheckboxViewHelper', 'checkboxFieldNames');
00400         }
00401     }
00402 }
00403 
00404 ?>