【问题标题】:Silverstripe 4 - Adding a FormAction via getCMSFieldsSilverstripe 4 - 通过 getCMSFields 添加 FormAction
【发布时间】:2020-08-06 20:08:04
【问题描述】:

目标:

我有一个名为“事件”的数据对象。这是在“EventsAdmin”(扩展 ModelAdmin)的 managed_model 中。编辑事件时,我想要一个名为“审核”的记录选项卡,它有几个字段和两个按钮:“批准”和“拒绝”。这两个按钮分别调用一个执行相关操作的操作。

事件扩展 DataObject

public function getCMSFields() {
    $fields = parent::getCMSFields();

    $eventStatus = $fields->dataFieldByName("EventStatus")
        ->setTitle('Current Status')
        ->setDisabled(true);

    $approveButton = FormAction::create('doApproveEvent', _t('SiteBlockAdmin.Approve', 'Approve'))
        ->setUseButtonTag(true)
        ->addExtraClass('btn-outline-success font-icon-check-mark-circle');

    $rejectButton = FormAction::create('doRejectEvent', _t('SiteBlockAdmin.Reject', 'Reject'))
        ->setUseButtonTag(true)
        ->addExtraClass('btn-outline-danger font-icon-cancel-circled');

    $fields->addFieldsToTab('Root.Moderation', [
        $eventStatus,
        $approveButton,
        $rejectButton
    ]);

    return $fields;
}

这可以很好地显示按钮。但他们什么都不做。所以我想弄清楚他们如何插入动作方法 doApproveEvent 和 doRejectEvent (以及他们应该去哪里)

我确实找到了引导我通过 updateFormActions() 将按钮添加到 CMS 页面底部的操作栏的文档。但这不是我想要的,因为我在按钮上方添加的其他字段是批准/拒绝过程的一部分。这是此方法的代码。除非按钮不在我尝试创建的进程的逻辑位置,否则这很好用。

class CMSActionButtonExtension extends DataExtension
{
    public function updateFormActions(FieldList $actions)
    {
        $record = $this->owner->getRecord();

        if (!$record instanceof Event || !$record->exists()) {
            return;
        }

        $approveButton = FormAction::create('doApproveEvent', _t('SiteBlockAdmin.Approve', 'Approve'))
            ->setUseButtonTag(true)
            ->addExtraClass('btn-outline-success font-icon-check-mark-circle');

        $rejectButton = FormAction::create('doRejectEvent', _t('SiteBlockAdmin.Reject', 'Reject'))
            ->setUseButtonTag(true)
            ->addExtraClass('btn-outline-danger font-icon-cancel-circled');

        $actions->push($approveButton);
        $actions->push($rejectButton);

    }

    public function doApproveEvent($data, $form) {
        $record = $this->owner->getRecord();

        // Approve logic
    }

    public function doRejectEvent($data, $form) {
        $record = $this->owner->getRecord();

        // Reject logic
    }

}

上面的扩展附加到GridFieldDetailForm_ItemRequest

extension.yml

SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest:
  extensions:
    - My\Namespace\CMSActionButtonExtension

有趣的是,如果我在页面上同时拥有两组按钮,那么 updateFormActions 选项会起作用,而我想要的选项仍然不起作用。尽管按钮具有相同的标记并且位于完全相同的表单标签内。我认为这与 Silverstripe 加载主内容面板和 DOM 的方式有关。

对实现这一目标有什么想法吗?有人在我可以查看的模块中看到添加到主 CMS 面板的按钮吗?我找到了 5 年前的 this 帖子,但它是针对 SS3 的,答案对我不起作用。

【问题讨论】:

  • 我假设 CMSActionButtonExtension 附加到表单或网格域组件?您能否还包括您使用的 config.yml?
  • @Zauberfisch 是的,没错。确切地说是 GridFieldDetailForm_ItemRequest。我已经用配置更新了我的帖子。

标签: silverstripe silverstripe-4


【解决方案1】:

简答
您必须通过控制表单(或表单本身)的控制器上的扩展来添加自定义 FormActions

长答案

关于 SilverStripe 如何处理表单的一些背景知识:

一般来说,表单总是通过 Controllers/RequestHandlers 提供服务(它们需要在某些路由上可访问,通常是控制器上的一个 Action,通常命名为 Form、EditForm、ItemEditoForm,...)。

  1. 字段
    在 CMS 中,您很少需要创建自己的表单,这是由用于管理区域的 Controllers/RequestHandlers 中内置的 CMS 完成的(在本例中为GridFieldDetailForm_ItemRequest)。

    基本上(这里是伪代码),这些控制器所做的是:

    public function EditForm() {
       $fields = $myCurrentlyEditingDataObject->getCMSFields();
       $actions = ...;
       $validator = ...;
       $this->updateFormActions(&$actions);
       $form = new Form('ItemRequestForm', $fields, $actions, $validator);
       $this->updateItemEditForm(&$form); // or $this->updateEditForm()
       return $form;
    }
    

    所以,getCMSFields() 和在某些情况下getCMSActions()/getCMSValidator()(不确定这两个是否仍在 SilverStripe 4.x 中使用),您可以向表单添加内容,而无需看到表单对象。

    此外,getCMSFields() 将始终放在表单的 ``` 部分,这就是为什么您的按钮位于所有字段而不是其他操作的中间位置的原因。

  2. 提交
    当一个表单被提交时(例如/admin/pages/edit/EditForm/265/field/NameOfMyGridField/item/542/ItemEditForm),它将调用动作GridFieldDetailForm_ItemRequest->ItemEditForm(),它返回Form对象,随后FormRequestHandler->httpSubmission()被调用。然后,这将查看提交的数据以找出点击了什么操作(例如$_REQUEST['action_doApproveEvent'])并尝试找到该操作。
    它试图找到它的方法是检查它本身是否有一个名为doApproveEvent 的方法,如果失败,它将尝试Form->getController()->doApproveEvent() 或类似的东西。对于GridField,该控制器是GridFieldDetailForm_ItemRequest,这意味着它将尝试调用GridFieldDetailForm_ItemRequest->doApproveEvent()


也就是说,DataObject->getCMSFields() 让您可以轻松地将 FormFields(和 FormActions)添加到表单正文中。
但它没有提供添加方法来处理提交的方法。

这就是为什么,对于自定义操作,您需要修改控制器(在这种情况下为GridFieldDetailForm_ItemRequest)。
您通过创建附加到GridFieldDetailForm_ItemRequestExtension 来执行此操作。 Extension 中的任何方法都会添加到它所附加的对象中,因此如果添加一个名为 updateFormActions 的方法,它就会变成 GridFieldDetailForm_ItemRequest->updateFormActions()
如果您还记得之前的情况,控制器将在创建表单期间调用$this->updateFormActions()
此外,正如我之前解释的,当 FormAction 命名为 doApproveEvent 时,它会查找 GridFieldDetailForm_ItemRequest->doApproveEvent(),它现在存在是因为您通过 Extension 添加了它。

因此,总而言之:您必须通过在控制表单的控制器(或表单本身)上的扩展添加自定义 FormActions


PS:旧帖来自 您链接到的 bummzack 在 3.x 中工作,因为在他的示例中创建表单的控制器是 LeftAndMain 的实例。

【讨论】:

    猜你喜欢
    • 2014-10-01
    • 2012-11-29
    • 2022-07-05
    • 2021-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多