Custom Bulk Action with Custom model

Hello Everyone,

I have successfully added a custom button to the list view for bulk actions. However, I am facing an issue with triggering my custom modal upon clicking the button. Could anyone provide guidance or suggestions on how to implement this functionality?

Check out this video:

1 Like

@rsp thanks for sharing the video. For learning purpose, I have added a simple bulk action in the Accounts module. Sharing here the steps here as it might help others.

  1. Add app strings for Action Label and Success Message
    file path: \public\legacy\custom\include\language\en_us.lang.php (create this file if doesn’t exist)
<?php

$app_strings['LBL_SEND_BULK_SMS']='Send Bulk SMS Message';
$app_strings['LBL_SEND_BULK_SMS_SUCCESS']='Sent SMS messages to these accounts successfully!';
  1. Add bulk action definition with a key ‘send-bulk-sms-list’ in listviewdefs for the required module in custom folder

file path: custom/modules/Accounts/metadata/listviewdefs.php

 'bulkActions' => [
            'actions' => [
			...
			...
                 'send-bulk-sms-list' => [
                    'key' => 'send-bulk-sms-list',
                    'labelKey' => 'LBL_SEND_BULK_SMS',
                    'modes' => ['list'],
                    'params' => [
                        'allowAll' => false,
                        'max' => 200
                    ]
                 ],

image

  1. Add bulk action logic by creating a file in \core\backend\Process\Service\BulkActions directory
    The PROCESS_TYPE is prefixed with ‘bulk-’
    file path: \core\backend\Process\Service\BulkActions\SendSMSBulkAction.php

(referred \core\backend\Process\Service\BulkActions\DeleteRecordsBulkAction.php)

<?php

namespace App\Process\Service\BulkActions;

use ApiPlatform\Exception\InvalidArgumentException;
use App\Data\Service\RecordDeletionServiceInterface;
use App\Module\Service\ModuleNameMapperInterface;
use App\Process\Entity\Process;
use App\Process\Service\ProcessHandlerInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;

class SendSMSBulkAction implements ProcessHandlerInterface, LoggerAwareInterface
{
    protected const MSG_OPTIONS_NOT_FOUND = 'Process options is not defined';

    protected const PROCESS_TYPE = 'bulk-send-bulk-sms-list';

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var ModuleNameMapperInterface
     */
    private $moduleNameMapper;

    /**
     * @var RecordDeletionServiceInterface
     */
    private $recordDeletionProvider;


    public function __construct(
        ModuleNameMapperInterface $moduleNameMapper
    ) {
        $this->moduleNameMapper = $moduleNameMapper;
    }

    /**
     * @inheritDoc
     */
    public function getProcessType(): string
    {
        return self::PROCESS_TYPE;
    }

    /**
     * @inheritDoc
     */
    public function requiredAuthRole(): string
    {
        return 'ROLE_USER';
    }

    /**
     * @inheritDoc
     */
    public function getRequiredACLs(Process $process): array
    {
        $options = $process->getOptions();
        $module = $options['module'] ?? '';
        $ids = $options['ids'] ?? [];

        return [
            $module => [
                [
                    'action' => 'list',
                    'ids' => $ids
                ]
            ]
        ];
    }

    /**
     * @inheritDoc
     */
    public function configure(Process $process): void
    {
        //This process is synchronous
        //We aren't going to store a record on db
        //thus we will use process type as the id
        $process->setId(self::PROCESS_TYPE);
        $process->setAsync(false);
    }

    /**
     * @inheritDoc
     */
    public function validate(Process $process): void
    {
        if (empty($process->getOptions())) {
            throw new InvalidArgumentException(self::MSG_OPTIONS_NOT_FOUND);
        }

        $options = $process->getOptions();

        if (empty($options['module']) || empty($options['action'])) {
            throw new InvalidArgumentException(self::MSG_OPTIONS_NOT_FOUND);
        }
    }

    /**
     * @inheritDoc
     */
    public function run(Process $process)
    {
        $result = $this->sendSMSToRecords($process);
		
		$responseData = [
            'reload' => false,
        ];
		
		if($result>0){
			$process->setStatus('success');
			$process->setMessages(['LBL_SEND_BULK_SMS_SUCCESS']);
		}
		else {
            $process->setStatus('error');
            $process->setMessages(['LBL_ACTION_ERROR']);
        }

        $process->setData($responseData);
		
    }

    /**
     * @param Process $process
     * @return bool
     */
    protected function sendSMSToRecords(Process $process): int
    {
        $options = $process->getOptions();
        if (is_array($options['ids']) && count($options['ids'])) {
           $module = $this->moduleNameMapper->toLegacy($options['module']);
           $ids = $options['ids'];
		   //send sms logic
		   return count($ids);
        }
        return 0;
    }

    /**
     * @inheritDoc
     */
    public function setLogger(LoggerInterface $logger): void
    {
        $this->logger = $logger;
    }
}

This is very simple example. We can improve this solution if required or any issue in the code. Thanks

3 Likes

Hello Harshad,

Thanks for sharing the details
but when I follow the same steps I face the below issue.

Also how do I open the model on click of the bulk.

I think the following can help get rid of this error

  1. Delete {Root}/cache/prod
  2. Please do quick repair & rebuild
  3. Clear browser cache as well.

Thanks!

Thanks for the help its working now.

Can you guide me to open the new model when I click on bulk.

Please refer to the oob ‘Add Records To Target List’ from the Accounts module

public/legacy/modules/Accounts/metadata/listviewdefs.php

actions' => [
                'records-to-target-list' => [
                    'key' => 'records-to-target-list',
                    'labelKey' => 'LBL_ADD_TO_PROSPECT_LIST_BUTTON_LABEL',
                    'modes' => ['list'],
                    'acl' => ['edit'],
                    'aclModule' => 'prospect-lists',
                    'params' => [
                        'selectModal' => [
                            'module' => 'ProspectLists'
                        ],
                        'allowAll' => false,
                        'max' => 200
                    ]
                ],

core/backend/Process/LegacyHandler/AddRecordsToTargetListBulkActionHandler.php

Also please mark above code as solution as it might help all. Thanks!

1 Like

(@Harshad please see my edit to your post to learn how to use code blocks in these forums, you will find it is very helpful to keep formatting and do syntax highlighting :+1: )

1 Like