Silverstripe 4 - Добавление FormAction через getCMSFields - PullRequest
1 голос
/ 06 августа 2020

Цель:

У меня есть DataObject под названием «Событие». Это управляемая_модель для «EventsAdmin» (расширяющая ModelAdmin). При редактировании события мне нужна вкладка в записи под названием «Модерация», которая имеет несколько полей и две кнопки: «Утвердить» и «Отклонить». Эти две кнопки вызывают действие, каждая из которых выполняет соответствующие действия.

Событие расширяет 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 (И где они должны go)

Я нашел документы, которые побудили меня добавить кнопки на панель действий внизу страницы CMS через updateFormActions (). Но это не то, что я хочу, поскольку другие поля, которые я добавляю над кнопками, являются частью процесса утверждения / отклонения. Вот код этого метода. Это отлично работает, если кнопки не находятся в логическом месте для процесса, который я пытаюсь создать.

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 лет go, но он для SS3, и ответ у меня не работает.

1 Ответ

1 голос
/ 11 августа 2020

Короткий ответ : вам нужно добавить пользовательские FormActions через расширение на контроллере, который управляет формой (или в самой форме

Длинный ответ :

Немного предыстории о том, как SilverStripe делает формы:

Вообще говоря, формы всегда обслуживаются через контроллеры / RequestHandlers (они должны быть доступны на каком-то маршруте, обычно это действие на контроллере, которое часто называется Form, EditForm, ItemEditoForm, ... ).

  1. Поля Внутри CMS вам редко когда-либо приходится создавать свою собственную форму, это делается с помощью CMS, встроенных в Controllers / RequestHandlers для области администрирования (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() (не уверен, что эти 2 все еще используются в 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() позволяет легко добавлять поля формы (и действия формы) в тело формы. Но он не предоставляет средств для добавления метода для обработки отправки.

Вот почему для настраиваемых действий вам необходимо изменить Контроллер (GridFieldDetailForm_ItemRequest в данном случае). Вы делаете это, создавая Extension, который вы прикрепляете к GridFieldDetailForm_ItemRequest. Любой метод в вашем Extension добавляется к тому, к чему он прикреплен, поэтому, если вы добавите метод с именем updateFormActions, он станет как бы GridFieldDetailForm_ItemRequest->updateFormActions(). И если вы помните ранее, контроллер вызовет $this->updateFormActions() во время создания формы. Кроме того, как я объяснял ранее, когда FormAction называется doApproveEvent, он будет искать GridFieldDetailForm_ItemRequest->doApproveEvent(), который теперь существует, потому что вы добавили его через этот Extension.

Итак, в итоге: у вас есть для добавления настраиваемых FormActions через расширение на контроллере, который управляет формой (или в самой форме

PS: старый пост из bummzack, на который вы ссылались, работал в 3.x, потому что Контроллер в его примере, создавший форму, был экземпляром LeftAndMain.

...