Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Batch actions form - Custom parameter fields enhancement #2744

Closed
mooror opened this issue Jul 5, 2022 · 11 comments
Closed

Batch actions form - Custom parameter fields enhancement #2744

mooror opened this issue Jul 5, 2022 · 11 comments

Comments

@mooror
Copy link
Contributor

mooror commented Jul 5, 2022

Background Information

When creating my own CMSBatchAction subclass I discovered that it had support for adding custom parameter fields via a getParameterFields() method, which is later processed by a BatchActionParameters() method in the CMSMain class. The strange thing is that this method is never called anywhere in the framework modules.

Enhancement

The goal of this enhancement (which I will create two PRs for shortly) is to implement the BatchActionParameters() method by adding an additional section to the BatchActionsForm in LeftAndMain which will display and submit parameter fields for each batch action that defines it's own fields via the getParameterFields() method.

With this change, developers will be able to easily create batch actions that take any number of inputs, allowing for more powerful actions like Adrexia's "Move to" action (Shout out to her for her past work on this 🎊)

Working Example

Custom Action

CMSBatchAction_PublishInLocal.php

<?php
use SilverStripe\Admin\CMSBatchAction;

/**
 * Example batch action that provides a dropdown
 * parameter field for selecting a language
 */
class CMSBatchAction_PublishInLocal extends CMSBatchAction
{

    public function getActionTitle()
    {
        return _t(__CLASS__ . '.PublishInLocalAction', 'Publish in Local');
    }

    //...

    function getParameterFields() {
        return FieldList::create(
            // This will be accessible to the run() method via $request->postVar('Language')
            DropdownField::create("Language", false, array(
                'en_us' => 'English (United States)',
                'de_de' => 'German (Germany)',
            ))
            ->setEmptyString('-- Select a Language --')
            ->setDescription("Choose the language you wish to publish pages in")
        );
    }
}

NOTE: This code is incomplete and just for example purposes, you would of course need to write run() and applicablePages() methods, register this action using CMSBatchActionHandler::register(), etc.

Resulting interface

Batch Actions Parameter Fields Enhancement

PRs

@mooror
Copy link
Contributor Author

mooror commented Jul 5, 2022

Currently writing the PRs for this now

@GuySartorelli
Copy link
Member

getParameterFields() is called:

if ($SNG_action->canView() && $fieldset = $SNG_action->getParameterFields()) {

Don't know if that changes anything for the PRs but seemed worth pointing out.

@mooror
Copy link
Contributor Author

mooror commented Jul 6, 2022

@GuySartorelli I apologize if my wording was confusing. To clarify, when I said

"The strange thing is that this method is never called anywhere in the framework modules"

In context I was referring to the BatchActionParameters() method in the CMSMain class that calls the getParameterFields() method of each batch action.

But by all means if you can find a reference or call to BatchActionParameters() please let me know as that may effect my PR #2746

@GuySartorelli
Copy link
Member

Ahhhh that makes sense. Yeah I can't find any references to BatchActionParameters outside the method declaration itself.

@mooror
Copy link
Contributor Author

mooror commented Jul 6, 2022

No Problem Guy @GuySartorelli. I'm glad to hear that you also were unable to find any references as that will lessen the impact of my PR

@mooror
Copy link
Contributor Author

mooror commented Jul 7, 2022

Hey Guy @GuySartorelli, I wrote up a test batch action subclass to hopefully help reduce the time investment for testing my PRs

It's pretty simple and doesn't actually make any changes to the selected pages, but it will add three parameter fields to the interface (a dropdown, textfield, and checkbox field) and then when you run the action the values are retrieved in the run() method and logged out to the returned JSON string (which can be viewed using the developer tools network/request viewer)

CMSBatchAction_ParameterAction.php

<?php

namespace Sitelease\OpenCore\BatchActions;

use SilverStripe\ORM\SS_List;
use SilverStripe\ORM\DataObject;
use SilverStripe\Control\Controller;

use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\DropdownField;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\CheckboxField;

use SilverStripe\Admin\CMSBatchAction;
/**
 * An example action to test parameter fields
 */
class CMSBatchAction_ParameterAction extends CMSBatchAction
{

    public function getActionTitle()
    {
        return _t(__CLASS__ . '.ParameterAction', 'Parameter Action');
    }

    public function run(SS_List $pages)
    {
        $request = Controller::curr()->getRequest();
        $dropdownValue = $request->postVar('ExampleDropdown');
        $textValue = $request->postVar('ExampleTextField');
        $checkboxValue = $request->postVar('ExampleCheckbox') ?? false;

        return $this->mockBatchAction($pages, array(
            $dropdownValue,
            $textValue,
            $checkboxValue ? 'checked' : 'unchecked'
        ));
    }

    public function mockBatchAction(SS_List $objs, $parameters)
    {
        $status = array('modified' => array(), 'error' => array(), 'deleted' => array(), 'success' => array(), 'parameters' => $parameters);

        foreach ($objs as $obj) {
            // Perform the action
            $id = $obj->ID;
            $status['success'][$id] = $id;

            // Now make sure the tree title is appropriately updated
            $publishedRecord = DataObject::get_by_id($this->managedClass, $id);
            if ($publishedRecord) {
                $status['modified'][$id] = array(
                    'TreeTitle' => $publishedRecord->TreeTitle,
                );
            } else {
                $status['deleted'][$id] = $id;
            }
            $obj->destroy();
            unset($obj);
        }

        return $this->response("Success Message", $status);
    }

    /**
     * {@see SiteTree::canEdit()}
     *
     * @param array $ids
     * @return array
     */
    public function applicablePages($ids)
    {
        return $this->applicablePagesHelper($ids, 'canView');
    }

    /**
     * Returns a FieldList containing extra fields for this action
     *
     * @return FieldList
     */
    function getParameterFields() {                
        return FieldList::create(
            DropdownField::create("ExampleDropdown", false, array(
                "option_1" => "Option 1",
                "option_2" => "Option 2",
                "option_3" => "Option 3",
            ))
            ->setEmptyString('-- Select an Option --')
            ->setDescription("A filler description for the dropdown field"),
            TextField::create(
                'ExampleTextField',
                false
            )
            ->setAttribute("placeholder", "Example field"),
            CheckboxField::create(
                'ExampleCheckbox',
                'Enable Something - Will enable something if checked'
            )
        );
    }
}

_config.php

use SilverStripe\Admin\CMSBatchActionHandler;
use Some\Namespace\CMSBatchAction_ParameterAction;

CMSBatchActionHandler::register('parameteraction', CMSBatchAction_ParameterAction::class);

I attached some screenshots showing the test values passed in and the expected output in the developer tools (in firefox)
Example Values
Network Tab Debug Values

@GuySartorelli
Copy link
Member

Thank you! That will help a lot.

@mooror
Copy link
Contributor Author

mooror commented Jul 7, 2022

Glad to hear it 💯

@mooror
Copy link
Contributor Author

mooror commented Jul 8, 2022

Warning: Fan-boy moment

Just gotta share this moment of satisfaction with you all. We have the batch action parameters working on one of our production systems, and use it with an action we created that adds reusable blocks to multiple pages at once.

So after spending a bunch of time implementing this, here is the super satisfying "add a reusable block to 15 pages at once" moment
Power of action parameters

(And no that ugly white space isn't there. I just redacted the site name 😅 )

@GuySartorelli
Copy link
Member

PRs merged. Thank you for contributing this.

@mooror
Copy link
Contributor Author

mooror commented Jul 12, 2022

Fantastic, Thank you Guy @GuySartorelli and Michal @michalkleiner for all the time you guys spent on looking this over and testing it. I appreciate it 🎊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants