Hello there,
I am working on SuiteCRM 8. And I am having a problem.
I am trying to export the records of a list view via an entry point by creating a custom button similar to the default export button. But I get the same problem every time.
I have created a custom button and back-end service for this list view using this forum question. The custom button works fine but when I turn on the export functionality on it the problem shown above occurs.
I have placed the file for the custom button in the following path;
public/legacy/custom/modules/Accounts/metadata/listviewdefs.php
And also placed a custom button language file on the following path;
public/legacy/custom/Extension/application/Ext/Language/en_us.lang.php
Add a service to handle the backend of the custom button.
As mentioned in the answer to this forum question, I created the file for the service at the following path. I am confused about whether this path is correct or not.
extensions/my-ext/backend/Process/Service/AddListCustomButtonAction.php
And below is the code of that file;
<?php
namespace App\Extension\myExt\backend\Process\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 AddListCustomButtonAction implements ProcessHandlerInterface, LoggerAwareInterface
{
protected const MSG_OPTIONS_NOT_FOUND = 'Process options is not defined';
protected const PROCESS_TYPE = 'bulk-add-custom-button';
/**
* @var ModuleNameMapperInterface
*/
private $moduleNameMapper;
/**
* @var LoggerInterface
*/
protected $logger;
/**
* @var LegacyFilterMapper
*/
private $legacyFilterMapper;
/**
* CsvExportBulkAction constructor.
* @param ModuleNameMapperInterface $moduleNameMapper
* @param LegacyFilterMapper $legacyFilterMapper
*/
public function __construct(ModuleNameMapperInterface $moduleNameMapper, LegacyFilterMapper $legacyFilterMapper)
{
$this->moduleNameMapper = $moduleNameMapper;
$this->legacyFilterMapper = $legacyFilterMapper;
}
/**
* @inheritDoc
*/
public function getProcessType(): string
{
return self::PROCESS_TYPE;
}
/**
* @inheritDoc
*/
public function requiredAuthRole(): string
{
return 'ROLE_USER';
}
/**
* @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);
}
if (empty($options['fields'])) {
throw new InvalidArgumentException(self::MSG_OPTIONS_NOT_FOUND);
}
if (empty($options['ids']) && empty($options['criteria'])) {
throw new InvalidArgumentException(self::MSG_OPTIONS_NOT_FOUND);
}
}
/**
* @inheritDoc
*/
public function run(Process $process)
{
$options = $process->getOptions();
$responseData = $this->getDownloadData($options);
$process->setStatus('success');
$process->setMessages([]);
$process->setData($responseData);
}
/**
* @param array|null $options
* @return array
*/
protected function getDownloadData(?array $options): array
{
$responseData = [
'handler' => 'export',
'params' => [
'url' => 'legacy/index.php?entryPoint=exportCustom',
'formData' => []
]
];
if (!empty($options['ids'])) {
$responseData = $this->getIdBasedRequestData($options, $responseData);
return $responseData;
}
if (!empty($options['criteria'])) {
$responseData = $this->getCriteriaBasedRequestData($options, $responseData);
}
return $responseData;
}
/**
* Get request data based on a list of ids
* @param array|null $options
* @param array $responseData
* @return array
*/
protected function getIdBasedRequestData(?array $options, array $responseData): array
{
$responseData['params']['formData'] = [
'uid' => implode(',', $options['ids']),
'module' => $this->moduleNameMapper->toLegacy($options['module']),
'action' => 'index'
];
return $responseData;
}
/**
* Get Request data based on search criteria
* @param array|null $options
* @param array $responseData
* @return array
*/
protected function getCriteriaBasedRequestData(?array $options, array $responseData): array
{
$responseData['params']['url'] .= '&module=' . $this->moduleNameMapper->toLegacy($options['module']);
$downloadData = [
'module' => $this->moduleNameMapper->toLegacy($options['module']),
'action' => 'index',
"searchFormTab" => "advanced_search",
"query" => "true",
"saved_search_name" => "",
"search_module" => "",
"saved_search_action" => "",
"displayColumns" => strtoupper(implode('|', $options['fields'])),
"orderBy" => strtoupper($this->legacyFilterMapper->getOrderBy($options['sort'])),
"sortOrder" => $this->legacyFilterMapper->getSortOrder($options['sort']),
"button" => "Search"
];
$type = $options['criteria']['type'] ?? 'advanced';
$mapped = $this->legacyFilterMapper->mapFilters($options['criteria'], $type);
$downloadData = array_merge($downloadData, $mapped);
$responseData['params']['formData'] = [
'current_post' => json_encode($downloadData)
];
return $responseData;
}
/**
* @inheritDoc
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
}
So how can I create a custom export button service for one module and the same for all modules?
What is the use of the 'handler' => 'export',
entry for the run()
?
So how can I do it? Can you help me with this?
Thanks.