Files
crm.clientright.ru/modules/OnlyOfficeTemplates/resources/MergeService.php
2026-02-16 09:27:19 +03:00

173 lines
6.1 KiB
PHP

<?php
/**
* Merge DOCX template: load from S3, substitute {{field}} and {{ModuleName__field}}, output DOCX.
*/
class OnlyOfficeTemplates_MergeService
{
protected $s3;
protected $config;
public function __construct(OnlyOfficeTemplates_S3Helper $s3, array $config)
{
$this->s3 = $s3;
$this->config = $config;
}
/**
* Build placeholder map for a record: current module fields + related (Account, Contact, etc.).
*
* @param string $module
* @param int $recordId
* @return array [ 'fieldname' => value, 'Account__accountname' => value, ... ]
*/
public function buildPlaceholders($module, $recordId)
{
$adb = PearDatabase::getInstance();
$focus = CRMEntity::getInstance($module);
$focus->id = $recordId;
$focus->retrieve_entity_info($recordId, $module);
$fields = $focus->column_fields;
$map = [];
foreach ($fields as $k => $v) {
if ($v === null || $v === '') {
$v = '';
}
$map[$k] = is_string($v) ? $v : (string)$v;
}
$map = array_merge($map, $this->getRelatedModuleFields($module, $recordId, $focus));
return $map;
}
/**
* Get related entity fields (Account, Contact, etc.) for placeholder {{ModuleName__fieldname}}.
*/
protected function getRelatedModuleFields($module, $recordId, CRMEntity $focus)
{
$map = [];
$relFields = $this->getRelationFieldNames($module);
foreach ($relFields as $relModule => $fieldName) {
$relId = isset($focus->column_fields[$fieldName]) ? $focus->column_fields[$fieldName] : null;
if (empty($relId)) {
continue;
}
$relFocus = CRMEntity::getInstance($relModule);
$relFocus->retrieve_entity_info($relId, $relModule);
foreach ($relFocus->column_fields as $k => $v) {
if ($v === null || $v === '') {
$v = '';
}
$map[$relModule . '__' . $k] = is_string($v) ? $v : (string)$v;
}
}
return $map;
}
/**
* Common relation field names per module (account_id, contact_id, related_to, parent_id, etc.).
*/
/** @return array [ 'RelatedModule' => 'local_field_name', ... ] */
protected function getRelationFieldNames($module)
{
$known = [
'Project' => ['Accounts' => 'account_id', 'Contacts' => 'contact_id'],
'Contacts' => ['Accounts' => 'account_id'],
'Leads' => ['Accounts' => 'account_id'],
'Potentials' => ['Accounts' => 'related_to', 'Contacts' => 'contact_id'],
'Invoice' => ['Accounts' => 'account_id', 'Contacts' => 'contact_id'],
'Quotes' => ['Accounts' => 'account_id', 'Contacts' => 'contact_id'],
'SalesOrder' => ['Accounts' => 'account_id', 'Contacts' => 'contact_id'],
'PurchaseOrder' => ['Vendors' => 'vendor_id', 'Contacts' => 'contact_id'],
'HelpDesk' => ['Accounts' => 'parent_id', 'Contacts' => 'contact_id'],
'Accounts' => [],
];
if (isset($known[$module])) {
return $known[$module];
}
$out = [];
if (in_array($module, ['Contacts', 'Leads', 'Potentials', 'Invoice', 'Quotes', 'SalesOrder'])) {
$out['Accounts'] = 'account_id';
if ($module !== 'Accounts') {
$out['Contacts'] = 'contact_id';
}
}
return $out;
}
/**
* Merge template: download from S3, replace placeholders, save to temp file.
*
* @param string $s3Key template S3 key
* @param array $placeholders [ 'field' => 'value', 'Account__name' => 'value' ]
* @return string path to merged DOCX file
*/
public function mergeToFile($s3Key, array $placeholders)
{
$path = dirname(dirname(dirname(__DIR__)));
if (!class_exists('PhpOffice\PhpWord\IOFactory')) {
if (is_file($path . '/vendor/autoload.php')) {
require_once $path . '/vendor/autoload.php';
}
}
$tempDir = sys_get_temp_dir() . '/oot_' . uniqid();
if (!is_dir($tempDir)) {
mkdir($tempDir, 0755, true);
}
$templatePath = $tempDir . '/template.docx';
$this->s3->downloadToFile($s3Key, $templatePath);
$phpWord = \PhpOffice\PhpWord\IOFactory::load($templatePath);
$this->replaceInPhpWord($phpWord, $placeholders);
$outPath = $tempDir . '/merged.docx';
$writer = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
$writer->save($outPath);
@unlink($templatePath);
return $outPath;
}
/**
* Replace {{placeholder}} in all text elements.
*/
protected function replaceInPhpWord(\PhpOffice\PhpWord\PhpWord $phpWord, array $placeholders)
{
foreach ($phpWord->getSections() as $section) {
foreach ($section->getElements() as $element) {
$this->replaceInElement($element, $placeholders);
}
}
}
protected function replaceInElement($element, array $placeholders)
{
if ($element instanceof \PhpOffice\PhpWord\Element\Text) {
$text = $element->getText();
$text = $this->replacePlaceholders($text, $placeholders);
$element->setText($text);
return;
}
if ($element instanceof \PhpOffice\PhpWord\Element\TextRun) {
foreach ($element->getElements() as $el) {
$this->replaceInElement($el, $placeholders);
}
return;
}
if ($element instanceof \PhpOffice\PhpWord\Element\TextBreak) {
return;
}
if (method_exists($element, 'getElements')) {
foreach ($element->getElements() as $el) {
$this->replaceInElement($el, $placeholders);
}
}
}
protected function replacePlaceholders($text, array $placeholders)
{
foreach ($placeholders as $key => $value) {
$text = str_replace('{{' . $key . '}}', $value, $text);
}
return $text;
}
}