As I wrote earlier, Vtiger provides a convenient API for getting data from CRM. You can get and filter data by any module with one request, get related records, and so on.
However, there is one drawback in the standard VtigerCRM API - you cannot get, for example, a contact's avatar and related documents.
In this article, I will tell you how you can modify the standard VtigerCRM API by adding the ability to display a picture or related documents attached to the module.
Let's see how we display a picture from a contact or products. In the Vtiger_Record_Model class, we have a getImageDetails method that gives us all the information about the avatar. Based on this information, you can build a URL and get the file we need.
In a similar way, we can get a list of linked documents. The Vtiger_Record_Model class has a getFileDetails method. With its help, we can get an array of documents bound to the record of the module.
Those, avatar or attached files are created in a uniform manner. But what if you want to enable the delivery of files and images only for certain modules, and not for all. Loading the API with unnecessary data and database queries is a bad idea.
I found the following option. Add two fields to the module we need:
- image_avatar - if we want to display the post's avatar.
- images_list - if we want to display a list of related documents.
These fields will be systems. Usually for these purposes I make a separate block, I call it "System Information", put all the fields there that I shouldn't see the user and hide it from the system.
This is very easy to do. To do this, go to the modules/Vtiger/models/Block.php file
At the beginning of the class (line 14) Vtiger_Block_Model add a constant
public const SYSTEM_INFORMATION_LABEL = 'System Information';
Then in function getAllForModule (after line 118) in foreach($blockObjects as $blockObject)
find line
$blockModelList[] = self::getInstanceFromBlockObject($blockObject);
and change it to following:
$blockModel = self::getInstanceFromBlockObject($blockObject);
if ($blockModel->label === self::SYSTEM_INFORMATION_LABEL) {
continue;
}
$blockModelList[] = $blockModel;
Thus, if the block is called System Information, you can completely hide it from users. If necessary, you can add an additional condition and show the block only to the administrator.
Let's move on to the next step. Let's create a separate class that will pass us a list of files and images. Let's create a special service. Create a file modules/Vtiger/services/ImageReceiver.php with the following content:
<?php
class Vtiger_ImageReceiver_Service
{
public const AVATAR_FIELD = 'image_avatar';
public const DOCUMENTS_FIELD = 'images_list';
protected string $column;
protected ?string $value;
protected int $record_id;
public function __construct(int $record_id, string $column, ?string $value)
{
$this->record_id = $record_id;
$this->column = $column;
$this->value = $value;
}
public function getAvatar(): array
{
if ($this->record_id < 1) {
return [];
}
/** @var Contacts_Record_Model $recordModel */
$recordModel = Vtiger_Record_Model::getInstanceById($this->record_id);
if (!$recordModel) {
return [];
}
return $recordModel->getImageDetails();
}
public function getImages(): array
{
if ($this->record_id < 1) {
return [];
}
/** @var Vtiger_Record_Model $recordModel */
$recordModel = Vtiger_Record_Model::getInstanceById($this->record_id);
if (!$recordModel) {
return [];
}
return $recordModel->getFileDetails();
}
}
Now we just need to connect this class to Vtiger. Go to the file include/Webservices/DataTransform.php and at the very beginning of this file we include our class by adding the line:
require_once 'modules/Vtiger/services/ImageReceiver.php';
And then in the sanitizeDataWithColumn function at the very end, before the line
return $newRow;
add following:
if (array_key_exists(Vtiger_ImageReceiver_Service::AVATAR_FIELD, $row)) {
$receiverService = new Vtiger_ImageReceiver_Service((int) $row[$meta->getIdColumn()], Vtiger_ImageReceiver_Service::AVATAR_FIELD, $row[Vtiger_ImageReceiver_Service::AVATAR_FIELD]);
$newRow['avatar'] = $receiverService->getAvatar();
}
if (array_key_exists(Vtiger_ImageReceiver_Service::DOCUMENTS_FIELD, $row)) {
$receiverService = new Vtiger_ImageReceiver_Service((int) $row[$meta->getIdColumn()], Vtiger_ImageReceiver_Service::DOCUMENTS_FIELD, $row[Vtiger_ImageReceiver_Service::DOCUMENTS_FIELD]);
$newRow['images'] = $receiverService->getImages();
}
Thus, if you now want to get a list of contacts, the following array will be added to the API output:
"avatar": [
{
"id": "74",
"orgname": "2021-06-28_10-30.png",
"path": "storage\/2021\/August\/week1\/74",
"name": "2021-06-28_10-30.png",
"url": "http:\/\/crm.kindergou.test\/public.php?fid=74&key=2021-06-28_10-30.png"
}
],
"images": [
{
"0": "74",
"attachmentsid": "74",
"1": "2021-06-28_10-30.png",
"name": "2021-06-28_10-30.png",
"2": "",
"description": "",
"3": "image\/png",
"type": "image\/png",
"4": "storage\/2021\/August\/week1\/",
"path": "storage\/2021\/August\/week1\/",
"5": "89061811daaad0ac66dd2dfa0d331903.png",
"storedname": "89061811daaad0ac66dd2dfa0d331903.png",
"6": null,
"subject": null,
"7": "70",
"crmid": "70",
"8": "74"
}
]
It should be borne in mind here that this will only work in displaying the list of module entries. If you want to get images when requesting a record by id, then add the code in the same way to the filterAndSanitize function:
if (array_key_exists(Vtiger_ImageReceiver_Service::AVATAR_FIELD, $row)) {
$receiverService = new Vtiger_ImageReceiver_Service((int) vtws_getCRMEntityId($row['id']), Vtiger_ImageReceiver_Service::AVATAR_FIELD, $row[Vtiger_ImageReceiver_Service::AVATAR_FIELD]);
$row['avatar'] = $receiverService->getAvatar();
}
if (array_key_exists(Vtiger_ImageReceiver_Service::DOCUMENTS_FIELD, $row)) {
$receiverService = new Vtiger_ImageReceiver_Service((int) vtws_getCRMEntityId($row['id']), Vtiger_ImageReceiver_Service::DOCUMENTS_FIELD, $row[Vtiger_ImageReceiver_Service::DOCUMENTS_FIELD]);
$row['images'] = $receiverService->getImages();
}
As a bonus, I attached script for adding field images_list to Contacts module. Just create file in scripts folder and run it:
<?php
/*
* Скрипт добавляет поле в модуль через API тигры.
* Удобно тем, что можно задать понятное название поле вместо стандартного cf_3443
* Также используется для создания одинаковых полей между девом и продом. Один и тот же скрипт запускается на деве и проде.
* Скрипты для удобство класть в vtiger/scripts/
* Перед запуском проверить, чтобы у файла были полномочия на запуск от сервере апаче
* Перед запуском проверить путь к файлам, которые добавлены через require_once
* Для правильного пути добавлена функция chdir('../')
*/
$Vtiger_Utils_Log = true;
chdir('../');
require_once('vtlib/Vtiger/Menu.php');
require_once('vtlib/Vtiger/Module.php');
require_once('vtlib/Vtiger/Block.php');
require_once('vtlib/Vtiger/Field.php');
$module = Vtiger_Module::getInstance('Contacts'); // Имя модуля из таблицы vtiger_tab
if ($module) {
$block = Vtiger_Block::getInstance('LBL_CUSTOM_INFORMATION', $module); // Название блока из таблицы vtiger_blocks
if ($block) {
$field = Vtiger_Field::getInstance('images_list', $module); // Название поля без пробелов через нижнее подчеркивание
if (!$field) {
$field = new Vtiger_Field();
$field->name = 'images_list'; // Название поля без пробелов через нижнее подчеркивание
$field->table = $module->basetable;
$field->label = 'LBL_IMAGES_LIST'; // Лейбл на английском. Переводить на русский через файлы-переводов.
$field->column = 'images_list'; // Название поля без пробелов через нижнее подчеркивание
$field->columntype = 'VARCHAR(255)'; // Посмотреть тип у похожих полей в таблице vtiger_навание-модуля
// Посмотреть тип у похожих полей в таблице vtiger_field
// 1 - текстовое поле
// 15 - поле-список)
$field->uitype = 1;
$field->displaytype = 1; // Посмотреть тип у похожих полей в таблице vtiger_field
// Посмотреть тип у похожих полей в таблице vtiger_field
// V~O~LE~100 - текстовое поле
// V~O - поле список
$field->typeofdata = 'V~O~LE~100';
$field->presence = 2; // Посмотреть тип у похожих полей в таблице vtiger_field
$field->quickcreate = 1; // Посмотреть тип у похожих полей в таблице vtiger_field
$field->generatedtype = 2; // Посмотреть тип у похожих полей в таблице vtiger_field
$block->addField($field);
//Для создания поля-списка раскомментировать эти две строки и прописать значения на английском. Переводить на русский через файлы-переводов.
//$pickListValues = array('Active', 'Inactive', 'Standby');
//$field->setPicklistValues($pickListValues);
echo "Поле успешно добавлено.";
}
} else {
echo "Не найден блок. Сверьте название блока в таблице vtiger_blocks.";
}
} else {
echo "Не найден модуль. Сверьте название модуля в таблице vtiger_tab.";
}
?>
If you have any questions or additional needs for the revision of the VtigerCRM API, please contact.