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.
27 class CRM_Core_Form_Task_PDFLetterCommon
{
30 * @var CRM_Core_Form $form
32 public static function preProcess(&$form) {
33 CRM_Utils_System
::setTitle('Print/Merge Document');
37 * Build the form object.
39 * @var CRM_Core_Form $form
41 public static function buildQuickForm(&$form) {
42 // This form outputs a file so should never be submitted via ajax
43 $form->preventAjaxSubmit();
45 //Added for CRM-12682: Add activity subject and campaign fields
46 CRM_Campaign_BAO_Campaign
::addCampaign($form);
50 ts('Activity Subject'),
51 ['size' => 45, 'maxlength' => 255],
55 $form->addSelect('format_id', [
56 'label' => ts('Select Format'),
57 'placeholder' => ts('Default'),
58 'entity' => 'message_template',
59 'field' => 'pdf_format_id',
60 'option_url' => 'civicrm/admin/pdfFormats',
66 [0 => ts('- default -')] + CRM_Core_BAO_PaperSize
::getList(TRUE),
68 ['onChange' => "selectPaper( this.value ); showUpdateFormatChkBox();"]
74 CRM_Core_BAO_PdfFormat
::getPageOrientations(),
76 ['onChange' => "updatePaperDimensions(); showUpdateFormatChkBox();"]
81 ts('Unit of Measure'),
82 CRM_Core_BAO_PdfFormat
::getUnits(),
84 ['onChange' => "selectMetric( this.value );"]
90 ['size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"],
97 ['size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"],
104 ['size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"],
111 ['size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"],
115 $config = CRM_Core_Config
::singleton();
116 /** CRM-15883 Suppressing Stationery path field until we switch from DOMPDF to a library that supports it.
117 * if ($config->wkhtmltopdfPath == FALSE) {
121 * ts('Stationery (relative path to PDF you wish to use as the background)'),
122 * array('size' => 25, 'maxlength' => 900, 'onkeyup' => "showUpdateFormatChkBox();"),
127 $form->add('checkbox', 'bind_format', ts('Always use this Page Format with the selected Template'));
128 $form->add('checkbox', 'update_format', ts('Update Page Format (this will affect all templates that use this format)'));
130 $form->assign('useThisPageFormat', ts('Always use this Page Format with the new template?'));
131 $form->assign('useSelectedPageFormat', ts('Should the new template always use the selected Page Format?'));
132 $form->assign('totalSelectedContacts', !is_null($form->_contactIds
) ?
count($form->_contactIds
) : 0);
134 $form->add('select', 'document_type', ts('Document Type'), CRM_Core_SelectValues
::documentFormat());
136 $documentTypes = implode(',', CRM_Core_SelectValues
::documentApplicationType());
137 $form->addElement('file', "document_file", 'Upload Document', 'size=30 maxlength=255 accept="' . $documentTypes . '"');
138 $form->addUploadElement("document_file");
140 CRM_Mailing_BAO_Mailing
::commonCompose($form);
143 if ($form->get('action') != CRM_Core_Action
::VIEW
) {
146 'name' => ts('Download Document'),
148 'icon' => 'fa-download',
152 'name' => ts('Preview'),
153 'subName' => 'preview',
154 'icon' => 'fa-search',
155 'isDefault' => FALSE,
160 'name' => $form->get('action') == CRM_Core_Action
::VIEW ?
ts('Done') : ts('Cancel'),
162 $form->addButtons($buttons);
164 $form->addFormRule(['CRM_Core_Form_Task_PDFLetterCommon', 'formRule'], $form);
168 * Set default values.
170 public static function setDefaultValues() {
171 $defaultFormat = CRM_Core_BAO_PdfFormat
::getDefaultValues();
172 $defaultFormat['format_id'] = $defaultFormat['id'];
173 return $defaultFormat;
179 * @param array $fields
180 * The input form values.
181 * @param array $files
183 * Additional values form 'this'.
186 * TRUE if no errors, else array of errors.
188 public static function formRule($fields, $files, $self) {
190 $template = CRM_Core_Smarty
::singleton();
192 // If user uploads non-document file other than odt/docx
193 if (empty($fields['template']) &&
194 !empty($files['document_file']['tmp_name']) &&
195 array_search($files['document_file']['type'], CRM_Core_SelectValues
::documentApplicationType()) == NULL
197 $errors['document_file'] = ts('Invalid document file format');
200 if (!empty($fields['saveTemplate']) && empty($fields['saveTemplateName'])) {
201 $errors['saveTemplateName'] = ts("Enter name to save message template");
203 if (!is_numeric($fields['margin_left'])) {
204 $errors['margin_left'] = 'Margin must be numeric';
206 if (!is_numeric($fields['margin_right'])) {
207 $errors['margin_right'] = 'Margin must be numeric';
209 if (!is_numeric($fields['margin_top'])) {
210 $errors['margin_top'] = 'Margin must be numeric';
212 if (!is_numeric($fields['margin_bottom'])) {
213 $errors['margin_bottom'] = 'Margin must be numeric';
215 return empty($errors) ?
TRUE : $errors;
219 * Handle the template processing part of the form
221 * @param array $formValues
223 * @return string $html_message
225 * @throws \CiviCRM_API3_Exception
226 * @throws \Civi\API\Exception\UnauthorizedException
228 public static function processTemplate(&$formValues) {
229 $html_message = $formValues['html_message'] ??
NULL;
231 // process message template
232 if (!empty($formValues['saveTemplate']) ||
!empty($formValues['updateTemplate'])) {
235 'msg_html' => $formValues['html_message'],
236 'msg_subject' => NULL,
240 $messageTemplate['pdf_format_id'] = 'null';
241 if (!empty($formValues['bind_format']) && $formValues['format_id']) {
242 $messageTemplate['pdf_format_id'] = $formValues['format_id'];
244 if (!empty($formValues['saveTemplate']) && $formValues['saveTemplate']) {
245 $messageTemplate['msg_title'] = $formValues['saveTemplateName'];
246 CRM_Core_BAO_MessageTemplate
::add($messageTemplate);
249 if (!empty($formValues['updateTemplate']) && $formValues['template'] && $formValues['updateTemplate']) {
250 $messageTemplate['id'] = $formValues['template'];
252 unset($messageTemplate['msg_title']);
253 CRM_Core_BAO_MessageTemplate
::add($messageTemplate);
256 elseif (CRM_Utils_Array
::value('template', $formValues) > 0) {
257 if (!empty($formValues['bind_format']) && $formValues['format_id']) {
258 $query = "UPDATE civicrm_msg_template SET pdf_format_id = {$formValues['format_id']} WHERE id = {$formValues['template']}";
261 $query = "UPDATE civicrm_msg_template SET pdf_format_id = NULL WHERE id = {$formValues['template']}";
263 CRM_Core_DAO
::executeQuery($query);
265 $documentInfo = CRM_Core_BAO_File
::getEntityFile('civicrm_msg_template', $formValues['template']);
266 foreach ((array) $documentInfo as $info) {
267 list($html_message, $formValues['document_type']) = CRM_Utils_PDF_Document
::docReader($info['fullPath'], $info['mime_type']);
268 $formValues['document_file_path'] = $info['fullPath'];
271 // extract the content of uploaded document file
272 elseif (!empty($formValues['document_file'])) {
273 list($html_message, $formValues['document_type']) = CRM_Utils_PDF_Document
::docReader($formValues['document_file']['name'], $formValues['document_file']['type']);
274 $formValues['document_file_path'] = $formValues['document_file']['name'];
277 if (!empty($formValues['update_format'])) {
278 $bao = new CRM_Core_BAO_PdfFormat();
279 $bao->savePdfFormat($formValues, $formValues['format_id']);
282 return $html_message;
288 public static function formatMessage(&$message) {
289 $newLineOperators = [
292 'pattern' => '/<(\s+)?p(\s+)?>/m',
296 'pattern' => '/<(\s+)?br(\s+)?\/>/m',
300 $htmlMsg = preg_split($newLineOperators['p']['pattern'], $message);
301 foreach ($htmlMsg as $k => & $m) {
302 $messages = preg_split($newLineOperators['br']['pattern'], $m);
303 foreach ($messages as $key => & $msg) {
306 if (preg_match('/^( )+/', $msg, $matches)) {
307 $spaceLen = strlen($matches[0]) / 6;
308 $trimMsg = ltrim($msg, ' ');
309 $charLen = strlen($trimMsg);
310 $totalLen = $charLen +
$spaceLen;
311 if ($totalLen > 100) {
313 if ($spaceLen > 50) {
316 if ($charLen > 100) {
319 $msg = str_repeat(' ', $spacesCount) . $trimMsg;
323 $m = implode($newLineOperators['br']['oper'], $messages);
325 $message = implode($newLineOperators['p']['oper'], $htmlMsg);
329 * Render html from rows
332 * @param string $msgPart
333 * The name registered with the TokenProcessor
334 * @param array $formValues
335 * The values submitted through the form
338 * If formValues['is_unit_test'] is true, otherwise outputs document to browser
340 public static function renderFromRows($rows, $msgPart, $formValues) {
342 foreach ($rows as $row) {
343 $html[] = $row->render($msgPart);
346 if (!empty($formValues['is_unit_test'])) {
351 self
::outputFromHtml($formValues, $html);
356 * List the available tokens
357 * @return array of token name => label
359 public static function listTokens() {
360 $class = get_called_class();
361 if (method_exists($class, 'createTokenProcessor')) {
362 return $class::createTokenProcessor()->listTokens();
367 * Output the pdf or word document from the generated html.
369 * @param array $formValues
372 protected static function outputFromHtml($formValues, array $html) {
373 if ($formValues['document_type'] === 'pdf') {
374 CRM_Utils_PDF_Utils
::html2pdf($html, 'CiviLetter.pdf', FALSE, $formValues);
377 CRM_Utils_PDF_Document
::html2doc($html, 'CiviLetter.' . $formValues['document_type'], $formValues);