我有两个域模型,名为Foo
和Bar
。对于它们两者,我有一个具有默认CRUD操作的控制器。在displayAction
Foo
中,有一个表单可用于创建新的Bar
(使用部分呈现)。感谢Helmut Hummels Extension" typoscript_rendering"我可以使用AJAX轻松地将该表单提交给BarController
。
但是,如果创建的Bar
- 对象的验证失败,则应调用newAction
的{{1}},以便用户可以解决问题。
但相反,BarController
的{{1}}被调用。发生这种情况,因为Fluid会自动将当前执行的操作作为引用者插入到表单中:
displayAction
是否有任何无黑客方式将__referrer更改为FooController
的{{1}}?
修改:根据要求,表单处于流畅状态。删除了不必要的标记,变量名称是匿名的,并且它是<input name="tx_myextension_display[__referrer][@extension]" value="MyExtension" type="hidden">
<input name="tx_myextension_display[__referrer][@vendor]" value="MyVendor" type="hidden">
<input name="tx_myextension_display[__referrer][@controller]" value="FooController" type="hidden">
<input name="tx_myextension_display[__referrer][@action]" value="display" type="hidden">
的{{1}}的一部分:
newAction
这只是一个08/15表格。
如果我使用无效数据提交,我会转发BarController
- displayAction
的行动,而不是FooController
- {namespace helhum=Helhum\TyposcriptRendering\ViewHelpers}
<f:form
name="bar"
object="{MyBar}"
action="create"
controller="Bar"
enctype="multipart/form-data"
additionalAttributes="{data-ajax-uri: '{helhum:uri.ajaxAction(action: \\'create\\', controller: \\'Bar\\')}'}"
>
<f:form.textarea property="b"/>
<f:form.submit value="Submit"/>
</f:form>
的行动。我想这是有道理的,只要表格不是由AJAX提交的。
答案 0 :(得分:2)
我找到了一个&#34;解决方案&#34;这仍然是hacky,因为它容易受到开放基类问题的影响。
它通过覆盖方法errorAction
来工作,因为如果发生验证错误则会调用它。它还会重定向到引用控制器。
我的覆盖如下:
/**
* If an error occurred while creating a new Bar with an
* AJAX request, redirect to the new action of this controller.
*/
public function errorAction() {
if ('createByAjaxAction' === $this->actionMethodName) {
$this->clearCacheOnError();
$this->addErrorFlashMessage();
$this->forward('new');
}
else {
parent::errorAction();
}
}
/*
* If an error occurred during this request, this adds
* a flash message describing the error to the flash
* message container.
* @TODO Remove after upgrade to 7.x
* @return void
*/
protected function addErrorFlashMessage() {
$errorFlashMessage = $this->getErrorFlashMessage();
if ($errorFlashMessage !== FALSE) {
$this->addFlashMessage($errorFlashMessage, '', \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
}
}
/**
* Create action that is supposed to be used by AJAX.
* @param \MyVendor\MyExt\Domain\Model\Bar
*/
public function createByAjaxAction($bar) {
$this->forward('create');
}
/**
* Normal create action.
* @param \MyVendor\MyExt\Domain\Model\Bar
*/
public function createAction($bar) {
// Normal entity creation stuff
}
我对此方法的问题是:如果来自extbase的errorAction
的原始ActionController
将来发生变化(与7.x中的变化一样,请参阅this change) ,这段代码很乐意破解。如果成员变量actionMethodName
发生变化,则相同。
因此,如果有人知道如何以更加面向未来的方式做到这一点,请添加答案。
答案 1 :(得分:2)
你的问题是在viewhelper f:form
中打开@todo * @todo filter out referrer information that is equal to the target (e.g. same packageKey)
*/
protected function renderHiddenReferrerFields()
...
我的副本和粘贴 - 解决方法是扩展viewhelper f:form。我在我的扩展中定义了一个子类。
<?php
namespace Porth\Positioner\ViewHelpers;
class FormViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\FormViewHelper {
/**
* Renders hidden form fields for referrer information about
* the current controller and action.
*
* Renders hidden form field for secured referrer information about the current controller and action.
*
* This method is called twice, to deal with subclasses of this class in a most compatible way
*
* @param string|null $action
* @param string|null $controller
* @param string|null $vendor
* @param string|null $extension
*
* @return string Hidden field with secured referrer information
* @todo filter out referrer information that is equal to the target (e.g. same packageKey)
*/
protected function renderHiddenReferrerFields($action =null, $controller = null, $vendor = null, $extension = null )
{
$request = $this->controllerContext->getRequest();
$extensionName = ((is_null($extension))? $request->getControllerExtensionName() : $extension);
$vendorName = ((is_null($vendor))? $request->getControllerVendorName() : $vendor);
$controllerName = ((is_null($controller)) ? $request->getControllerName() : $controller);
$actionName = ((is_null($action))? $request->getControllerActionName() : $action);
$result = LF;
$result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[@extension]') . '" value="' . $extensionName . '" />' . LF;
if ($vendorName !== null) {
$result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[@vendor]') . '" value="' . $vendorName . '" />' . LF;
}
$result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[@controller]') . '" value="' . $controllerName . '" />' . LF;
$result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[@action]') . '" value="' . $actionName . '" />' . LF;
$result .= '<input type="hidden" name="' . $this->prefixFieldName('__referrer[arguments]') . '" value="' . htmlspecialchars($this->hashService->appendHmac(base64_encode(serialize($request->getArguments())))) . '" />' . LF;
$result .= $this->renderHiddenSecuredReferrerField($actionName, $controllerName, $vendorName, $extensionName);
return $result;
}
/**
* Renders hidden form field for secured referrer information about the current controller and action.
*
* This method is called twice, to deal with subclasses of this class in a most compatible way
*
* @param string|null $action
* @param string|null $controller
* @param string|null $vendor
* @param string|null $extension
*
* @return string Hidden field with secured referrer information
*/
protected function renderHiddenSecuredReferrerField($action = null, $controller = null, $vendor = null, $extension = null )
{
if ($this->securedReferrerFieldRendered) {
return '';
}
$request = $this->renderingContext->getControllerContext()->getRequest();
$extensionName = ((is_null($extension))? $request->getControllerExtensionName() : $extension);
$vendorName = ((is_null($vendor))? $request->getControllerVendorName() : $vendor);
$controllerName = ((is_null($controller)) ? $request->getControllerName() : $controller);
$actionName = ((is_null($action))? $request->getControllerActionName() : $action);
$actionRequest = [
'@extension' => $extensionName,
'@controller' => $controllerName,
'@action' => $actionName,
];
if ($vendorName !== null) {
$actionRequest['@vendor'] = $vendorName;
}
$result = '<input type="hidden" name="' . $this->prefixFieldName('__referrer[@request]') . '" value="' . htmlspecialchars($this->hashService->appendHmac(serialize($actionRequest))) . '" />' . LF;
$this->securedReferrerFieldRendered = true;
return $result;
}
/**
* Render the form.
*
* @param string $action Target action
* @param array $arguments Arguments
* @param string $controller Target controller
* @param string $vendor Target vendor
* @param string $extensionName Target Extension Name (without "tx_" prefix and no underscores). If NULL the current extension name is used
* @param string $pluginName Target plugin. If empty, the current plugin name is used
* @param int $pageUid Target page uid
* @param mixed $object Object to use for the form. Use in conjunction with the "property" attribute on the sub tags
* @param int $pageType Target page type
* @param bool $noCache set this to disable caching for the target page. You should not need this.
* @param bool $noCacheHash set this to suppress the cHash query parameter created by TypoLink. You should not need this.
* @param string $section The anchor to be added to the action URI (only active if $actionUri is not set)
* @param string $format The requested format (e.g. ".html") of the target page (only active if $actionUri is not set)
* @param array $additionalParams additional action URI query parameters that won't be prefixed like $arguments (overrule $arguments) (only active if $actionUri is not set)
* @param bool $absolute If set, an absolute action URI is rendered (only active if $actionUri is not set)
* @param bool $addQueryString If set, the current query parameters will be kept in the action URI (only active if $actionUri is not set)
* @param array $argumentsToBeExcludedFromQueryString arguments to be removed from the action URI. Only active if $addQueryString = TRUE and $actionUri is not set
* @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
* @param string $actionUri can be used to overwrite the "action" attribute of the form tag
* @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
* @param string $hiddenFieldClassName
* @return string rendered form
*/
public function render($action = null, array $arguments = array(), $controller = null, $vendor = 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, $hiddenFieldClassName = null)
{
$this->setFormActionUri();
if (strtolower($this->arguments['method']) === 'get') {
$this->tag->addAttribute('method', 'get');
} else {
$this->tag->addAttribute('method', 'post');
}
$this->addFormObjectNameToViewHelperVariableContainer();
$this->addFormObjectToViewHelperVariableContainer();
$this->addFieldNamePrefixToViewHelperVariableContainer();
$this->addFormFieldNamesToViewHelperVariableContainer();
$formContent = $this->renderChildren();
if ($this->arguments['hiddenFieldClassName'] !== null) {
$content = LF . '<div class="' . htmlspecialchars($this->arguments['hiddenFieldClassName']) . '">';
} else {
$content = LF . '<div>';
}
$content .= $this->renderHiddenIdentityField($this->arguments['object'], $this->getFormObjectName());
$content .= $this->renderAdditionalIdentityFields();
$content .= $this->renderHiddenReferrerFields($action , $controller , $vendor , $extensionName );
// $content .= $this->renderHiddenSecuredReferrerField($action , $controller , $vendor , $extensionName );
// Render the trusted list of all properties after everything else has been rendered
$content .= $this->renderTrustedPropertiesField();
$content .= LF . '</div>' . LF;
$content .= $formContent;
$this->tag->setContent($content);
$this->removeFieldNamePrefixFromViewHelperVariableContainer();
$this->removeFormObjectFromViewHelperVariableContainer();
$this->removeFormObjectNameFromViewHelperVariableContainer();
$this->removeFormFieldNamesFromViewHelperVariableContainer();
$this->removeCheckboxFieldNamesFromViewHelperVariableContainer();
return $this->tag->render();
}
}