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

186 lines
8.3 KiB
PHP

<?php
/**
* Generate document from template: merge placeholders, optional PDF conversion, download or save to Documents.
*/
class OnlyOfficeTemplates_CreateFromTemplate_Action extends Vtiger_Action_Controller
{
public function checkPermission(Vtiger_Request $request)
{
$record = $request->get('record');
$module = $request->get('source_module') ?: getSalesEntityType($record);
if (!isPermitted($module, 'DetailView', $record)) {
throw new AppException('LBL_PERMISSION_DENIED');
}
}
public function process(Vtiger_Request $request)
{
$recordId = (int)$request->get('record');
$templateId = (int)$request->get('template_id');
$format = strtolower($request->get('format') ?: 'pdf'); // pdf | docx
$mode = strtolower($request->get('mode') ?: 'download'); // download | save_to_documents
$module = $request->get('source_module') ?: getSalesEntityType($recordId);
if (!$recordId || !$templateId) {
echo json_encode(['success' => false, 'error' => 'Missing record or template_id']);
return;
}
require_once dirname(__DIR__) . '/models/OnlyOfficeTemplates_Model.php';
require_once dirname(__DIR__) . '/resources/S3Helper.php';
require_once dirname(__DIR__) . '/resources/MergeService.php';
require_once dirname(__DIR__) . '/resources/ConvertService.php';
$model = new OnlyOfficeTemplates_Model();
$template = $model->getTemplateById($templateId);
if (!$template) {
echo json_encode(['success' => false, 'error' => 'Template not found or access denied']);
return;
}
$config = $model->getConfig();
$s3 = new OnlyOfficeTemplates_S3Helper($config);
$mergeService = new OnlyOfficeTemplates_MergeService($s3, $config);
$convertService = new OnlyOfficeTemplates_ConvertService($config);
$placeholders = $mergeService->buildPlaceholders($module, $recordId);
$tempDir = null;
$docxPath = null;
$pdfPath = null;
try {
$docxPath = $mergeService->mergeToFile($template['s3_key'], $placeholders);
$tempDir = dirname($docxPath);
$baseName = pathinfo($template['file_name'], PATHINFO_FILENAME);
$outExt = ($format === 'pdf') ? 'pdf' : 'docx';
$outFileName = $baseName . '_' . $recordId . '.' . $outExt;
if ($format === 'pdf') {
$docxUrl = $this->putMergedDocxForConversion($s3, $config, $docxPath, $recordId, $templateId);
if (!$docxUrl) {
echo json_encode(['success' => false, 'error' => 'Could not expose DOCX URL for conversion']);
return;
}
$result = $convertService->convertToPdf($docxUrl, $template['file_name']);
if (!$result['success']) {
echo json_encode(['success' => false, 'error' => $result['error']]);
return;
}
$pdfPath = $result['pdfPath'];
}
if ($mode === 'save_to_documents') {
$fileToSave = ($format === 'pdf') ? $pdfPath : $docxPath;
$docId = $this->saveToDocuments($request, $module, $recordId, $fileToSave, $outFileName, $config);
$this->cleanupTemp($tempDir, $docxPath, $pdfPath);
echo json_encode(['success' => true, 'document_id' => $docId, 'message' => 'Saved to Documents']);
return;
}
$downloadPath = ($format === 'pdf') ? $pdfPath : $docxPath;
$mime = ($format === 'pdf') ? 'application/pdf' : 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
header('Content-Type: ' . $mime);
header('Content-Disposition: attachment; filename="' . basename($outFileName) . '"');
header('Content-Length: ' . filesize($downloadPath));
readfile($downloadPath);
$this->cleanupTemp($tempDir, $docxPath, $pdfPath);
} catch (Exception $e) {
$this->cleanupTemp($tempDir, $docxPath, $pdfPath);
if ($request->get('ajax')) {
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
} else {
throw $e;
}
}
}
/**
* Upload merged DOCX to S3 temp and return public URL for OnlyOffice converter.
*/
private function putMergedDocxForConversion(OnlyOfficeTemplates_S3Helper $s3, array $config, $localPath, $recordId, $templateId)
{
$key = $s3->getTempKey($recordId, $templateId, 'docx');
$s3->uploadFile($localPath, $key, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
$bucket = $s3->getBucket();
$endpoint = $config['s3']['endpoint'] ?? '';
$base = preg_replace('#^https?://#', 'https://', $endpoint);
if (empty($base)) {
$base = 'https://s3.twcstorage.ru';
}
return rtrim($base, '/') . '/' . $bucket . '/' . $key;
}
/**
* Save file as Document record and link to parent. Use Documents S3 structure if FilePathManager available.
*/
private function saveToDocuments(Vtiger_Request $request, $module, $recordId, $localPath, $fileName, array $config)
{
$adb = PearDatabase::getInstance();
$currentUser = Users_Record_Model::getCurrentUserModel();
$ownerId = $currentUser->getId();
$docPrefix = $config['documents_s3_prefix'] ?? 'crm2/CRM_Active_Files/Documents';
$bucket = $config['s3_bucket'] ?? $config['s3']['bucket'];
$notesId = $adb->getUniqueID('vtiger_crmentity');
if (!$notesId) {
$r = $adb->pquery("SELECT MAX(crmid) AS m FROM vtiger_crmentity", []);
$notesId = (int)$adb->query_result($r, 0, 'm') + 1;
}
$title = pathinfo($fileName, PATHINFO_FILENAME);
$now = date('Y-m-d H:i:s');
$s3Key = $docPrefix . '/' . $module . '/' . $module . '_' . $recordId . '/' . $title . '_' . $notesId . '.' . pathinfo($fileName, PATHINFO_EXTENSION);
$s3 = new OnlyOfficeTemplates_S3Helper($config);
$contentType = (pathinfo($fileName, PATHINFO_EXTENSION) === 'pdf') ? 'application/pdf' : 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
$s3->uploadFile($localPath, $s3Key, $contentType);
$fileUrl = 'https://' . ($config['s3']['endpoint'] ?? 's3.twcstorage.ru');
$fileUrl = preg_replace('#^https?://#', '', $fileUrl);
$fileUrl = 'https://' . $fileUrl . '/' . $bucket . '/' . $s3Key;
$fileSize = filesize($localPath);
$adb->pquery(
"INSERT INTO vtiger_crmentity (crmid, smownerid, smcreatorid, modifiedby, setype, description, createdtime, modifiedtime, presence, deleted) VALUES (?,?,?,?,?,?,?,?,?,?)",
[$notesId, $ownerId, $ownerId, $ownerId, 'Documents', '', $now, $now, 1, 0]
);
$adb->pquery(
"INSERT INTO vtiger_notes (notesid, title, filename, filesize, filetype, filelocationtype, filedownloadcount, createdtime, modifiedtime, folderid, notecontent) VALUES (?,?,?,?,?,?,?,?,?,?,?)",
[$notesId, $title, $fileUrl, $fileSize, $contentType, 'E', 0, $now, $now, 0, '']
);
if (method_exists($adb, 'pquery')) {
$adb->pquery("INSERT INTO vtiger_senotesrel (crmid, notesid) VALUES (?,?)", [$recordId, $notesId]);
}
$adb->pquery("INSERT INTO vtiger_notescf (notesid) VALUES (?)", [$notesId]);
if ($this->hasS3Columns($adb)) {
$adb->pquery("UPDATE vtiger_notes SET s3_bucket = ?, s3_key = ? WHERE notesid = ?", [$bucket, $s3Key, $notesId]);
}
return $notesId;
}
private function hasS3Columns($adb)
{
static $has = null;
if ($has === null) {
$r = @$adb->pquery("SHOW COLUMNS FROM vtiger_notes LIKE 's3_key'", []);
$has = $r && $adb->num_rows($r) > 0;
}
return $has;
}
private function cleanupTemp($tempDir, $docxPath, $pdfPath)
{
if ($pdfPath && is_file($pdfPath)) {
@unlink($pdfPath);
}
if ($docxPath && is_file($docxPath)) {
@unlink($docxPath);
}
if ($tempDir && is_dir($tempDir)) {
@rmdir($tempDir);
}
}
}