3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
19 * This is the base class for common PDF/Doc Merge functionality.
20 * Most CRM_*_Form_Task_PDFLetterCommon classes extend the Contact version
21 * but the assumptions there are not always appropriate for other classes
22 * resulting in code duplication and unexpected dependencies.
23 * The intention is that common functionality can be moved here and the other
25 * Keep old-style token handling out of this class.
29 class CRM_Core_Form_Task_PDFLetterCommon
{
32 * @var CRM_Core_Form $form
36 public static function preProcess(&$form) {
37 CRM_Core_Error
::deprecatedFunctionWarning('no alternative');
39 $form->setTitle('Print/Merge Document');
43 * Build the form object.
47 * @var CRM_Core_Form $form
48 * @throws \CRM_Core_Exception
50 public static function buildQuickForm(&$form) {
51 CRM_Core_Error
::deprecatedFunctionWarning('no supported alternative for non-core code');
52 // This form outputs a file so should never be submitted via ajax
53 $form->preventAjaxSubmit();
55 //Added for CRM-12682: Add activity subject and campaign fields
56 CRM_Campaign_BAO_Campaign
::addCampaign($form);
60 ts('Activity Subject'),
61 ['size' => 45, 'maxlength' => 255],
65 // Added for core#2121,
66 // To support sending a custom pdf filename before downloading.
67 $form->addElement('hidden', 'pdf_file_name');
69 $form->addSelect('format_id', [
70 'label' => ts('Select Format'),
71 'placeholder' => ts('Default'),
72 'entity' => 'message_template',
73 'field' => 'pdf_format_id',
74 'option_url' => 'civicrm/admin/pdfFormats',
80 [0 => ts('- default -')] + CRM_Core_BAO_PaperSize
::getList(TRUE),
82 ['onChange' => "selectPaper( this.value ); showUpdateFormatChkBox();"]
88 CRM_Core_BAO_PdfFormat
::getPageOrientations(),
90 ['onChange' => "updatePaperDimensions(); showUpdateFormatChkBox();"]
95 ts('Unit of Measure'),
96 CRM_Core_BAO_PdfFormat
::getUnits(),
98 ['onChange' => "selectMetric( this.value );"]
104 ['size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"],
111 ['size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"],
118 ['size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"],
125 ['size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"],
129 $config = CRM_Core_Config
::singleton();
130 /** CRM-15883 Suppressing Stationery path field until we switch from DOMPDF to a library that supports it.
131 * if ($config->wkhtmltopdfPath == FALSE) {
135 * ts('Stationery (relative path to PDF you wish to use as the background)'),
136 * array('size' => 25, 'maxlength' => 900, 'onkeyup' => "showUpdateFormatChkBox();"),
141 $form->add('checkbox', 'bind_format', ts('Always use this Page Format with the selected Template'));
142 $form->add('checkbox', 'update_format', ts('Update Page Format (this will affect all templates that use this format)'));
144 $form->assign('useThisPageFormat', ts('Always use this Page Format with the new template?'));
145 $form->assign('useSelectedPageFormat', ts('Should the new template always use the selected Page Format?'));
146 $form->assign('totalSelectedContacts', !is_null($form->_contactIds
) ?
count($form->_contactIds
) : 0);
148 $form->add('select', 'document_type', ts('Document Type'), CRM_Core_SelectValues
::documentFormat());
150 $documentTypes = implode(',', CRM_Core_SelectValues
::documentApplicationType());
151 $form->addElement('file', "document_file", 'Upload Document', 'size=30 maxlength=255 accept="' . $documentTypes . '"');
152 $form->addUploadElement("document_file");
154 CRM_Mailing_BAO_Mailing
::commonCompose($form);
157 if ($form->get('action') != CRM_Core_Action
::VIEW
) {
160 'name' => ts('Download Document'),
162 'icon' => 'fa-download',
166 'name' => ts('Preview'),
167 'subName' => 'preview',
168 'icon' => 'fa-search',
169 'isDefault' => FALSE,
174 'name' => $form->get('action') == CRM_Core_Action
::VIEW ?
ts('Done') : ts('Cancel'),
176 $form->addButtons($buttons);
178 $form->addFormRule(['CRM_Core_Form_Task_PDFLetterCommon', 'formRule'], $form);
182 * Set default values.
186 public static function setDefaultValues() {
187 CRM_Core_Error
::deprecatedFunctionWarning('no alternative');
188 $defaultFormat = CRM_Core_BAO_PdfFormat
::getDefaultValues();
189 $defaultFormat['format_id'] = $defaultFormat['id'];
190 return $defaultFormat;
196 * @param array $fields
197 * The input form values.
198 * @param array $files
200 * Additional values form 'this'.
203 * TRUE if no errors, else array of errors.
205 public static function formRule($fields, $files, $self) {
207 $deprecatedTokens = [
208 '{case.status_id}' => '{case.status_id:label}',
209 '{case.case_type_id}' => '{case.case_type_id:label}',
210 '{membership.status}' => '{membership.status_id:label}',
211 '{membership.type}' => '{membership.membership_type_id:label}',
212 '{contribution.campaign}' => '{contribution.campaign_id:label}',
213 '{contribution.payment_instrument}' => '{contribution.payment_instrument_id:label}',
214 '{contribution.contribution_id}' => '{contribution.id}',
215 '{contribution.contribution_source}' => '{contribution.source}',
218 foreach ($deprecatedTokens as $token => $replacement) {
219 if (strpos($fields['html_message'], $token) !== FALSE) {
220 $tokenErrors[] = ts('Token %1 is no longer supported - use %2 instead', [$token, $replacement]);
223 if (!empty($tokenErrors)) {
224 $errors['html_message'] = implode('<br>', $tokenErrors);
227 // If user uploads non-document file other than odt/docx
228 if (empty($fields['template']) &&
229 !empty($files['document_file']['tmp_name']) &&
230 array_search($files['document_file']['type'], CRM_Core_SelectValues
::documentApplicationType()) == NULL
232 $errors['document_file'] = ts('Invalid document file format');
235 if (!empty($fields['saveTemplate']) && empty($fields['saveTemplateName'])) {
236 $errors['saveTemplateName'] = ts("Enter name to save message template");
238 if (!is_numeric($fields['margin_left'])) {
239 $errors['margin_left'] = 'Margin must be numeric';
241 if (!is_numeric($fields['margin_right'])) {
242 $errors['margin_right'] = 'Margin must be numeric';
244 if (!is_numeric($fields['margin_top'])) {
245 $errors['margin_top'] = 'Margin must be numeric';
247 if (!is_numeric($fields['margin_bottom'])) {
248 $errors['margin_bottom'] = 'Margin must be numeric';
250 return empty($errors) ?
TRUE : $errors;
254 * Handle the template processing part of the form
256 * @param array $formValues
258 * @return string $html_message
262 * @throws \CRM_Core_Exception
263 * @throws \CiviCRM_API3_Exception
264 * @throws \Civi\API\Exception\UnauthorizedException
266 public static function processTemplate(&$formValues) {
267 CRM_Core_Error
::deprecatedFunctionWarning('no alternative');
269 $html_message = $formValues['html_message'] ??
NULL;
271 // process message template
272 if (!empty($formValues['saveTemplate']) ||
!empty($formValues['updateTemplate'])) {
275 'msg_html' => $formValues['html_message'],
276 'msg_subject' => NULL,
280 $messageTemplate['pdf_format_id'] = 'null';
281 if (!empty($formValues['bind_format']) && $formValues['format_id']) {
282 $messageTemplate['pdf_format_id'] = $formValues['format_id'];
284 if (!empty($formValues['saveTemplate'])) {
285 $messageTemplate['msg_title'] = $formValues['saveTemplateName'];
286 CRM_Core_BAO_MessageTemplate
::add($messageTemplate);
289 if ($formValues['template'] && !empty($formValues['updateTemplate'])) {
290 $messageTemplate['id'] = $formValues['template'];
292 unset($messageTemplate['msg_title']);
293 CRM_Core_BAO_MessageTemplate
::add($messageTemplate);
296 elseif (CRM_Utils_Array
::value('template', $formValues) > 0) {
297 if (!empty($formValues['bind_format']) && $formValues['format_id']) {
298 $query = "UPDATE civicrm_msg_template SET pdf_format_id = {$formValues['format_id']} WHERE id = {$formValues['template']}";
301 $query = "UPDATE civicrm_msg_template SET pdf_format_id = NULL WHERE id = {$formValues['template']}";
303 CRM_Core_DAO
::executeQuery($query);
305 $documentInfo = CRM_Core_BAO_File
::getEntityFile('civicrm_msg_template', $formValues['template']);
306 foreach ((array) $documentInfo as $info) {
307 [$html_message, $formValues['document_type']] = CRM_Utils_PDF_Document
::docReader($info['fullPath'], $info['mime_type']);
308 $formValues['document_file_path'] = $info['fullPath'];
311 // extract the content of uploaded document file
312 elseif (!empty($formValues['document_file'])) {
313 [$html_message, $formValues['document_type']] = CRM_Utils_PDF_Document
::docReader($formValues['document_file']['name'], $formValues['document_file']['type']);
314 $formValues['document_file_path'] = $formValues['document_file']['name'];
317 if (!empty($formValues['update_format'])) {
318 $bao = new CRM_Core_BAO_PdfFormat();
319 $bao->savePdfFormat($formValues, $formValues['format_id']);
322 return $html_message;
330 public static function formatMessage(&$message) {
331 $newLineOperators = [
334 'pattern' => '/<(\s+)?p(\s+)?>/m',
338 'pattern' => '/<(\s+)?br(\s+)?\/>/m',
342 $htmlMsg = preg_split($newLineOperators['p']['pattern'], $message);
343 foreach ($htmlMsg as $k => & $m) {
344 $messages = preg_split($newLineOperators['br']['pattern'], $m);
345 foreach ($messages as $key => & $msg) {
348 if (preg_match('/^( )+/', $msg, $matches)) {
349 $spaceLen = strlen($matches[0]) / 6;
350 $trimMsg = ltrim($msg, ' ');
351 $charLen = strlen($trimMsg);
352 $totalLen = $charLen +
$spaceLen;
353 if ($totalLen > 100) {
355 if ($spaceLen > 50) {
358 if ($charLen > 100) {
361 $msg = str_repeat(' ', $spacesCount) . $trimMsg;
365 $m = implode($newLineOperators['br']['oper'], $messages);
367 $message = implode($newLineOperators['p']['oper'], $htmlMsg);
371 * Render html from rows
374 * @param string $msgPart
375 * The name registered with the TokenProcessor
376 * @param array $formValues
377 * The values submitted through the form
381 public static function renderFromRows($rows, $msgPart, $formValues): void
{
382 CRM_Core_Error
::deprecatedFunctionWarning('no alternative');
384 foreach ($rows as $row) {
385 $html[] = $row->render($msgPart);
389 self
::outputFromHtml($formValues, $html);
394 * List the available tokens
395 * @return array of token name => label
399 public static function listTokens() {
400 CRM_Core_Error
::deprecatedFunctionWarning('no alternative');
401 $class = get_called_class();
402 if (method_exists($class, 'createTokenProcessor')) {
403 return $class::createTokenProcessor()->listTokens();
408 * Output the pdf or word document from the generated html.
412 * @param array $formValues
415 protected static function outputFromHtml($formValues, array $html) {
416 CRM_Core_Error
::deprecatedFunctionWarning('no alternative');
417 // Set the filename for the PDF using the Activity Subject, if defined. Remove unwanted characters and limit the length to 200 characters.
418 if (!empty($formValues['subject'])) {
419 $fileName = CRM_Utils_File
::makeFilenameWithUnicode($formValues['subject'], '_', 200);
422 $fileName = 'CiviLetter';
424 if ($formValues['document_type'] === 'pdf') {
425 CRM_Utils_PDF_Utils
::html2pdf($html, $fileName . '.pdf', FALSE, $formValues);
428 CRM_Utils_PDF_Document
::html2doc($html, $fileName . '.' . $formValues['document_type'], $formValues);