Как я уже писал ранее, Vtiger предоставляет удобный API по получению данных из CRM. Можно одним запросом достать и отфильтровать данные по любому модулю, получить связанные записи и прочее.
Однако, в стандартном API VtigerCRM есть один недостаток - нельзя получить, например, аватар контакта и связанные документы.
В этой статье я расскажу вам, как можно доработать стандартный API VtigerCRM, добавив в него возможность вывода привязанной к модулю картинки или связанных документов.
Давайте посмотрим, как у нас выводится картинка из контакта или товаров. В классе Vtiger_Record_Model у нас есть метод getImageDetails, который выдаёт нам всю информацию по аватару. По этой информации можно выстроить URL и получить нужный нам файл.
Аналогичным образом мы можем получить и список привязанных документов. В классе Vtiger_Record_Model есть метод getFileDetails. С его помощью мы можем получить массив привязанных к записи модуля документов.
Т.е. аватар или привязанные файлы создаются унифицированным образом. Но что делать, если вы хотите включить выдачу файлов и изображений только для определённых модулей, а не для всех. Нагружать API ненужными данными и запросами к базе - плохая идея.
Я нашёл следующий вариант. Добавляем два поля к нужному нам модулю:
- image_avatar - если мы хотим выводить аватар записи.
- images_list - если мы хотим выводить список связанных документов.
Эти поля будут системными. Обычно для этих целей я делаю отдельный блок, называю его "System Information" помещаю туда все поля, которые не должен видеть пользовать и скрываю его из системы.
Сделать это очень просто. Для этого переходим в файл modules/Vtiger/models/Block.php
В начале класса (строчка 14) Vtiger_Block_Model добавляем константу
public const SYSTEM_INFORMATION_LABEL = 'System Information';
Затем в функции getAllForModule (после строчки 118) в цикле foreach($blockObjects as $blockObject)
находим строчку
$blockModelList[] = self::getInstanceFromBlockObject($blockObject);
и меняем её на следующую:
$blockModel = self::getInstanceFromBlockObject($blockObject);
if ($blockModel->label === self::SYSTEM_INFORMATION_LABEL) {
continue;
}
$blockModelList[] = $blockModel;
Таким образом, если блок называется System Information, вы можете его полностью скрыть от пользователей. При необходимости можно добавить дополнительное условие и показываеть блок только администратору.
Переходим к следующему шагу. Создадим отдельный класс, который будем передавать нам список файлов и изображений. Создадим специальный сервис. Создаём файл modules/Vtiger/services/ImageReceiver.php со следующим содержимым:
<?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();
}
}
Теперь нам остаётся подключить этот класс к Vtiger. Переходим в файл include/Webservices/DataTransform.php и в самом начале этого файла подключаем наш класс, добавляя строчку:
require_once 'modules/Vtiger/services/ImageReceiver.php';
И затем в функции sanitizeDataWithColumn в самом её конце перед строчкой
return $newRow;
добавляем следующий блок
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();
}
Таким образом, если вы захотите теперь получить список контактов, в выводе API у вас добавится следующий массив:
"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"
}
]
Здесь стоит иметь в виду, что это сработает только в выводе списка записей модуля. Если вы хотите получить картинки при запросе записи по id, то добавьте таким же образом код в функцию filterAndSanitize:
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();
}
В качестве бонуса выкладываю скрипт по добавлению поля images_list в модуль Contacts. Поместите его в папку scripts и запустите:
<?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.";
}
?>
Если у вас остались вопросы или дополнительные потребности в доработке API VtigerCRM - обращайтесь.