Error occurs when clicking custom button in suitecrm 8

Hey there,

I have a custom button created in the detail view of the Account module. But the problem is that when I click on it, it gets called in the request payload but the error object is showing in the preview and an internal server error is coming in it.

Along with that, there is another problem when I click on the custom button then an unexpected error when calling action error.

So how can I fix this problem as soon as possible?

Thanks !!

Hello @gogeek

Regarding the issues you’ve mentioned:

Add a custom button in the detailview - Action tab.

  • To add the button you need to add a new entry to the new recordActions in detailviewdefs.

  • There are important things to have in mind:

    1. The key (add-custom-button) should be a unique name, as it will also be used to identify the process that is going to handle that action.

    2. Make sure to set ‘asyncProcess’ => true, as you want a process that is handled in the backend. By the way by asyncProcess, it means a process that is handled in the backend.

    3. The modes define if the button should be displayed in detail and edit or just in one.

    4. You can remove the params

  • The following are the steps;

Step 1: Add a button in the detailviewdef.php file
public/legacy/custom/modules/Accounts/metadata/detailviewdefs.php

'recordActions' => [
    'actions' => [
      ....
      'add-custom-button' => [
          'key' => 'add-custom-button',
          'labelKey' => 'LBL_ADD_CUSTOM_BUTTON',
          'asyncProcess' => true,
          'modes' => ['detail']
      ]
      ....
    ]
],

Step 2: Add a label for the add-custom-button
public/legacy/custom/Extension/application/Ext/Language/en_us.lang.php

Step 3: Perform quick repair & rebuild from admin, button should appear.

Add the service to handle the backend

  • Add your service to something like:

    1. for services used in multiple modules
      extensions/<extension-name>/backend/<domain>/Services
      - domain is the scope of the change you want to do ex: its languages, statistics, etc

    2. for services that are module-specific
      extensions/<extension-name>/modules/<Module>/Services

  • You can find an example of an action in
    core/backend/Process/Service/RecordActions/PrintAsPdfAction.php

  • Regarding the path where to place the it “doesn’t matter”, it will be autowired by symfony.

  • It’s more a matter of convention and having a standard, to make the code easier to find and maintain.

  • The only rules that need to be followed are:

    1. Add it to extensions/<your-extension>

    2. The namespace needs to start with App\Extension\

    3. The namespace needs to follow the psr rules.

    4. Your class needs to ProcessHandlerInterface

    5. getProcessType() on your class needs to return the same value that you set on the key, in your case add-custom-button. (EDIT: This should be prefixed with record-, so it should be record-add-custom-button)

  • One thing to have in mind is that the namespace must match the path where you added the file, and it’s case-sensitive.

  • In your case, if the class is in extensions/customButton/modules/Accounts/Service/AddCustomButtonAction.php.

  • The namespace should be namespace App\Extension\customButton\modules\Accounts\Service;

  • Regarding the method yes, it should implement in the interface. and the one that runs the code is run()

  • Regarding acl and aclModule are just needed if you want to hide/show according to acls

Step 1: To create backend services you need to create a file in following path;

extensions/customButton/modules/Accounts/Service/AddCustomButtonAction.php

<?php

namespace App\Extension\cstmButton\modules\Accounts\Service;

use ApiPlatform\Core\Exception\InvalidArgumentException;
use App\Process\Entity\Process;
use App\Module\Service\ModuleNameMapperInterface;
use App\Process\Service\ProcessHandlerInterface;

use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;

class AddCustomButtonAction implements ProcessHandlerInterface, LoggerAwareInterface
{
    protected const MSG_OPTIONS_NOT_FOUND = 'Process options is not defined';
    protected const PROCESS_TYPE = 'record-add-custom-button';

    
    private $moduleNameMapper;
    protected $logger;

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

    public function getProcessType(): string {
        return self::PROCESS_TYPE;
    }

    public function requiredAuthRole(): string {
        return 'ROLE_USER';
    }

    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);
    }

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

    public function run(Process $process)
    {
        $process->setStatus('success');
        $process->setMessages([]);
        $process->setData([]);
    }

    public function setLogger(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
}

Step 2: Set a redirect action handler.

On your backend process handler (the AddCustomButtomAction class, or whatever you want to call it). You can be defined the response as a frontend handler. The handler is going to be called on the front after the response from the backend.

There is a redirect handler that you can call, the only thing you need is to pass the route to redirect to.

Something like;

  public function run(Process $process)
  {
      $options = $process->getOptions();
      $module =  $options['module']; // or "your-module"
      
      $responseData = [
          'handler' => 'redirect',
          'params' => [
              'route' => "$module/example",  //example - is a custom view called
              'queryParams' => [
              ]
          ]
      ];

      $process->setStatus('success');
      $process->setMessages([]);
      $process->setData($responseData);
  }

If you want to redirect somewhere like a component, entry point, view, etc then replace the run function you wrote earlier with this run function…otherwise no need.

Step 3: Rebuild your extension
you can use watch like yarn run build-dev:myExt --watch in a terminal.

I hope this is helpful.

Thank you.

3 Likes