Merge pull request #8347 from eileenmcnaughton/tidy-up
[civicrm-core.git] / CRM / Contact / Form / Task / PDFLetterCommon.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
fa938177 6 | Copyright CiviCRM LLC (c) 2004-2016 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
fa938177 31 * @copyright CiviCRM LLC (c) 2004-2016
6a488035
TO
32 */
33
34/**
424029e3 35 * This class provides the common functionality for creating PDF letter for one or a group of contact ids.
6a488035
TO
36 */
37class CRM_Contact_Form_Task_PDFLetterCommon {
38
39 /**
fe482240 40 * Build all the data structures needed to build the form.
6a488035 41 *
c490a46a 42 * @param CRM_Core_Form $form
6a488035 43 */
00be9182 44 public static function preProcess(&$form) {
353ffa53 45 $messageText = array();
6a488035 46 $messageSubject = array();
353ffa53 47 $dao = new CRM_Core_BAO_MessageTemplate();
6a488035
TO
48 $dao->is_active = 1;
49 $dao->find();
50 while ($dao->fetch()) {
51 $messageText[$dao->id] = $dao->msg_text;
52 $messageSubject[$dao->id] = $dao->msg_subject;
53 }
54
55 $form->assign('message', $messageText);
56 $form->assign('messageSubject', $messageSubject);
cd095eae 57 CRM_Utils_System::setTitle('Print/Merge Document');
6a488035
TO
58 }
59
86538308 60 /**
c490a46a 61 * @param CRM_Core_Form $form
100fef9d 62 * @param int $cid
86538308 63 */
00be9182 64 public static function preProcessSingle(&$form, $cid) {
6a488035
TO
65 $form->_contactIds = array($cid);
66 // put contact display name in title for single contact mode
cd095eae 67 CRM_Utils_System::setTitle(ts('Print/Merge Document for %1', array(1 => CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'display_name'))));
6a488035
TO
68 }
69
70 /**
fe482240 71 * Build the form object.
6a488035 72 *
cae80d9f 73 * @var CRM_Core_Form $form
6a488035 74 */
00be9182 75 public static function buildQuickForm(&$form) {
cae80d9f
CW
76 // This form outputs a file so should never be submitted via ajax
77 $form->preventAjaxSubmit();
78
4c71ccb4
RN
79 //Added for CRM-12682: Add activity subject and campaign fields
80 CRM_Campaign_BAO_Campaign::addCampaign($form);
81 $form->add(
82 'text',
83 'subject',
84 ts('Activity Subject'),
85 array('size' => 45, 'maxlength' => 255),
86 FALSE
87 );
88
a7916823
CW
89 $form->add('static', 'pdf_format_header', NULL, ts('Page Format: %1', array(1 => '<span class="pdf-format-header-label"></span>')));
90 $form->addSelect('format_id', array(
91 'label' => ts('Select Format'),
92 'placeholder' => ts('Default'),
93 'entity' => 'message_template',
94 'field' => 'pdf_format_id',
95 'option_url' => 'civicrm/admin/pdfFormats',
96 ));
ed106721
DL
97 $form->add(
98 'select',
99 'paper_size',
100 ts('Paper Size'),
101 array(0 => ts('- default -')) + CRM_Core_BAO_PaperSize::getList(TRUE),
102 FALSE,
6a488035
TO
103 array('onChange' => "selectPaper( this.value ); showUpdateFormatChkBox();")
104 );
105 $form->add('static', 'paper_dimensions', NULL, ts('Width x Height'));
ed106721
DL
106 $form->add(
107 'select',
108 'orientation',
109 ts('Orientation'),
110 CRM_Core_BAO_PdfFormat::getPageOrientations(),
111 FALSE,
6a488035
TO
112 array('onChange' => "updatePaperDimensions(); showUpdateFormatChkBox();")
113 );
ed106721
DL
114 $form->add(
115 'select',
116 'metric',
117 ts('Unit of Measure'),
118 CRM_Core_BAO_PdfFormat::getUnits(),
119 FALSE,
6a488035
TO
120 array('onChange' => "selectMetric( this.value );")
121 );
ed106721
DL
122 $form->add(
123 'text',
124 'margin_left',
125 ts('Left Margin'),
126 array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
127 TRUE
6a488035 128 );
ed106721
DL
129 $form->add(
130 'text',
131 'margin_right',
132 ts('Right Margin'),
133 array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
134 TRUE
6a488035 135 );
ed106721
DL
136 $form->add(
137 'text',
138 'margin_top',
139 ts('Top Margin'),
140 array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
141 TRUE
6a488035 142 );
ed106721
DL
143 $form->add(
144 'text',
145 'margin_bottom',
146 ts('Bottom Margin'),
147 array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
148 TRUE
6a488035 149 );
bdfa67c3 150
151 $config = CRM_Core_Config::singleton();
828659cf 152 /** CRM-15883 Suppressing Stationery path field until we switch from DOMPDF to a library that supports it.
ab8a593e 153 if ($config->wkhtmltopdfPath == FALSE) {
828659cf
DG
154 $form->add(
155 'text',
156 'stationery',
157 ts('Stationery (relative path to PDF you wish to use as the background)'),
158 array('size' => 25, 'maxlength' => 900, 'onkeyup' => "showUpdateFormatChkBox();"),
159 FALSE
160 );
bdfa67c3 161 }
828659cf 162 */
6a488035
TO
163 $form->add('checkbox', 'bind_format', ts('Always use this Page Format with the selected Template'));
164 $form->add('checkbox', 'update_format', ts('Update Page Format (this will affect all templates that use this format)'));
165
166 $form->assign('useThisPageFormat', ts('Always use this Page Format with the new template?'));
167 $form->assign('useSelectedPageFormat', ts('Should the new template always use the selected Page Format?'));
168 $form->assign('totalSelectedContacts', count($form->_contactIds));
169
0aeb5a1e
CW
170 $form->add('select', 'document_type', ts('Document Type'), CRM_Core_SelectValues::documentFormat());
171
36d27c19 172 CRM_Mailing_BAO_Mailing::commonCompose($form);
6a488035 173
fc942baa
CW
174 $buttons = array();
175 if ($form->get('action') != CRM_Core_Action::VIEW) {
a37ec997
DG
176 $buttons[] = array(
177 'type' => 'submit',
cd095eae 178 'name' => ts('Download Document'),
188bad99 179 'isDefault' => TRUE,
0aeb5a1e 180 'icon' => 'fa-download',
a37ec997 181 );
fc942baa
CW
182 $buttons[] = array(
183 'type' => 'submit',
188bad99
CW
184 'name' => ts('Preview'),
185 'subName' => 'preview',
0291a521 186 'icon' => 'fa-search',
188bad99 187 'isDefault' => FALSE,
6a488035 188 );
6a488035 189 }
fc942baa
CW
190 $buttons[] = array(
191 'type' => 'cancel',
192 'name' => $form->get('action') == CRM_Core_Action::VIEW ? ts('Done') : ts('Cancel'),
193 );
194 $form->addButtons($buttons);
6a488035
TO
195
196 $form->addFormRule(array('CRM_Contact_Form_Task_PDFLetterCommon', 'formRule'), $form);
197 }
198
199 /**
fe482240 200 * Set default values.
6a488035 201 */
00be9182 202 public static function setDefaultValues() {
6a488035
TO
203 $defaultFormat = CRM_Core_BAO_PdfFormat::getDefaultValues();
204 $defaultFormat['format_id'] = $defaultFormat['id'];
205 return $defaultFormat;
206 }
207
208 /**
fe482240 209 * Form rule.
6a488035 210 *
77c5b619
TO
211 * @param array $fields
212 * The input form values.
6a488035 213 * @param array $dontCare
77c5b619
TO
214 * @param array $self
215 * Additional values form 'this'.
6a488035 216 *
4eeb9a5b
TO
217 * @return bool
218 * TRUE if no errors, else array of errors.
6a488035 219 */
00be9182 220 public static function formRule($fields, $dontCare, $self) {
6a488035
TO
221 $errors = array();
222 $template = CRM_Core_Smarty::singleton();
223
224 //Added for CRM-1393
a7488080 225 if (!empty($fields['saveTemplate']) && empty($fields['saveTemplateName'])) {
6a488035
TO
226 $errors['saveTemplateName'] = ts("Enter name to save message template");
227 }
228 if (!is_numeric($fields['margin_left'])) {
229 $errors['margin_left'] = 'Margin must be numeric';
230 }
231 if (!is_numeric($fields['margin_right'])) {
232 $errors['margin_right'] = 'Margin must be numeric';
233 }
234 if (!is_numeric($fields['margin_top'])) {
235 $errors['margin_top'] = 'Margin must be numeric';
236 }
237 if (!is_numeric($fields['margin_bottom'])) {
238 $errors['margin_bottom'] = 'Margin must be numeric';
239 }
240 return empty($errors) ? TRUE : $errors;
241 }
242
243 /**
fe482240 244 * Part of the post process which prepare and extract information from the template.
6a488035 245 *
6a488035 246 *
c490a46a 247 * @param CRM_Core_Form $form
dbddfb08 248 *
72b3a70c
CW
249 * @return array
250 * [$categories, $html_message, $messageToken, $returnProperties]
6a488035
TO
251 */
252 static protected function processMessageTemplate(&$form) {
253 $formValues = $form->controller->exportValues($form->getName());
254
255 // process message template
8cc574cf 256 if (!empty($formValues['saveTemplate']) || !empty($formValues['updateTemplate'])) {
6a488035
TO
257 $messageTemplate = array(
258 'msg_text' => NULL,
259 'msg_html' => $formValues['html_message'],
260 'msg_subject' => NULL,
261 'is_active' => TRUE,
262 );
263
264 $messageTemplate['pdf_format_id'] = 'null';
a7916823 265 if (!empty($formValues['bind_format']) && $formValues['format_id']) {
6a488035
TO
266 $messageTemplate['pdf_format_id'] = $formValues['format_id'];
267 }
a7488080 268 if (!empty($formValues['saveTemplate']) && $formValues['saveTemplate']) {
6a488035 269 $messageTemplate['msg_title'] = $formValues['saveTemplateName'];
c6327d7d 270 CRM_Core_BAO_MessageTemplate::add($messageTemplate);
6a488035
TO
271 }
272
a7488080 273 if (!empty($formValues['updateTemplate']) && $formValues['template'] && $formValues['updateTemplate']) {
6a488035
TO
274 $messageTemplate['id'] = $formValues['template'];
275
276 unset($messageTemplate['msg_title']);
c6327d7d 277 CRM_Core_BAO_MessageTemplate::add($messageTemplate);
6a488035
TO
278 }
279 }
280 elseif (CRM_Utils_Array::value('template', $formValues) > 0) {
a7916823 281 if (!empty($formValues['bind_format']) && $formValues['format_id']) {
6a488035
TO
282 $query = "UPDATE civicrm_msg_template SET pdf_format_id = {$formValues['format_id']} WHERE id = {$formValues['template']}";
283 }
284 else {
285 $query = "UPDATE civicrm_msg_template SET pdf_format_id = NULL WHERE id = {$formValues['template']}";
286 }
33621c4f 287 CRM_Core_DAO::executeQuery($query);
6a488035 288 }
a7488080 289 if (!empty($formValues['update_format'])) {
6a488035
TO
290 $bao = new CRM_Core_BAO_PdfFormat();
291 $bao->savePdfFormat($formValues, $formValues['format_id']);
292 }
293
294 $html = array();
295
296 $tokens = array();
297 CRM_Utils_Hook::tokens($tokens);
298 $categories = array_keys($tokens);
299
300 $html_message = $formValues['html_message'];
301
302 //time being hack to strip '&nbsp;'
303 //from particular letter line, CRM-6798
304 self::formatMessage($html_message);
305
306 $messageToken = CRM_Utils_Token::getTokens($html_message);
307
308 $returnProperties = array();
309 if (isset($messageToken['contact'])) {
310 foreach ($messageToken['contact'] as $key => $value) {
311 $returnProperties[$value] = 1;
312 }
313 }
314
315 return array($formValues, $categories, $html_message, $messageToken, $returnProperties);
316 }
317
318 /**
fe482240 319 * Process the form after the input has been submitted and validated.
6a488035 320 *
c490a46a 321 * @param CRM_Core_Form $form
6a488035 322 */
00be9182 323 public static function postProcess(&$form) {
6a488035 324 list($formValues, $categories, $html_message, $messageToken, $returnProperties) = self::processMessageTemplate($form);
a37ec997 325 $buttonName = $form->controller->getButtonName();
6a488035
TO
326 $skipOnHold = isset($form->skipOnHold) ? $form->skipOnHold : FALSE;
327 $skipDeceased = isset($form->skipDeceased) ? $form->skipDeceased : TRUE;
0aeb5a1e 328 $html = array();
6a488035
TO
329
330 foreach ($form->_contactIds as $item => $contactId) {
331 $params = array('contact_id' => $contactId);
332
333 list($contact) = CRM_Utils_Token::getTokenDetails($params,
334 $returnProperties,
335 $skipOnHold,
336 $skipDeceased,
337 NULL,
338 $messageToken,
339 'CRM_Contact_Form_Task_PDFLetterCommon'
340 );
341 if (civicrm_error($contact)) {
342 $notSent[] = $contactId;
343 continue;
344 }
345
346 $tokenHtml = CRM_Utils_Token::replaceContactTokens($html_message, $contact[$contactId], TRUE, $messageToken);
07945b3c
CW
347 if (!empty($form->_caseId)) {
348 $tokenHtml = CRM_Utils_Token::replaceCaseTokens($form->_caseId, $html_message, $messageToken);
349 }
6a488035
TO
350 $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $contact[$contactId], $categories, TRUE);
351
352 if (defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY) {
353 $smarty = CRM_Core_Smarty::singleton();
354 // also add the contact tokens to the template
355 $smarty->assign_by_ref('contact', $contact);
356 $tokenHtml = $smarty->fetch("string:$tokenHtml");
357 }
358
359 $html[] = $tokenHtml;
360 }
361
a37ec997
DG
362 // CRM-16725 Skip creation of activities if user is previewing their PDF letter(s)
363 if ($buttonName == '_qf_PDF_submit') {
364 self::createActivities($form, $html_message, $form->_contactIds);
365 }
6a488035 366
0aeb5a1e
CW
367 $type = $formValues['document_type'];
368
369 if ($type == 'pdf') {
370 CRM_Utils_PDF_Utils::html2pdf($html, "CiviLetter.pdf", FALSE, $formValues);
371 }
372 else {
373 CRM_Utils_PDF_Document::html2doc($html, "CiviLetter.$type", $formValues);
374 }
6a488035
TO
375
376 $form->postProcessHook();
377
378 CRM_Utils_System::civiExit(1);
379 }
380
86538308 381 /**
c490a46a 382 * @param CRM_Core_Form $form
86538308
EM
383 * @param $html_message
384 * @param $contactIds
385 *
386 * @throws CRM_Core_Exception
387 */
00be9182 388 public static function createActivities($form, $html_message, $contactIds) {
4c71ccb4 389 //Added for CRM-12682: Add activity subject and campaign fields
353ffa53 390 $formValues = $form->controller->exportValues($form->getName());
6a488035 391
353ffa53
TO
392 $session = CRM_Core_Session::singleton();
393 $userID = $session->get('userID');
1d85d241
DL
394 $activityTypeID = CRM_Core_OptionGroup::getValue(
395 'activity_type',
6a488035
TO
396 'Print PDF Letter',
397 'name'
398 );
399 $activityParams = array(
4c71ccb4 400 'subject' => $formValues['subject'],
85d25c8f 401 'campaign_id' => CRM_Utils_Array::value('campaign_id', $formValues),
6a488035
TO
402 'source_contact_id' => $userID,
403 'activity_type_id' => $activityTypeID,
404 'activity_date_time' => date('YmdHis'),
405 'details' => $html_message,
406 );
407 if (!empty($form->_activityId)) {
408 $activityParams += array('id' => $form->_activityId);
409 }
410 if ($form->_cid) {
411 $activity = CRM_Activity_BAO_Activity::create($activityParams);
623ba9d2
CW
412 if (!empty($form->_caseId)) {
413 $caseActivityParams = array('activity_id' => $activity->id, 'case_id' => $form->_caseId);
414 CRM_Case_BAO_Case::processCaseActivity($caseActivityParams);
415 }
6a488035
TO
416 }
417 else {
418 // create Print PDF activity for each selected contact. CRM-6886
419 $activityIds = array();
420 foreach ($contactIds as $contactId) {
421 $activityID = CRM_Activity_BAO_Activity::create($activityParams);
422 $activityIds[$contactId] = $activityID->id;
423 }
424 }
425
e7e657f0 426 $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
9e74e3ce 427 $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
8ef12e64 428
383c047b 429 //@todo why are we using $form->_contactIds here & contactIds above - need comment
6a488035
TO
430 foreach ($form->_contactIds as $contactId) {
431 $activityTargetParams = array(
432 'activity_id' => empty($activity->id) ? $activityIds[$contactId] : $activity->id,
1d85d241 433 'contact_id' => $contactId,
21dfd5f5 434 'record_type_id' => $targetID,
6a488035 435 );
1d85d241 436 CRM_Activity_BAO_ActivityContact::create($activityTargetParams);
6a488035
TO
437 }
438 }
439
86538308
EM
440 /**
441 * @param $message
442 */
00be9182 443 public static function formatMessage(&$message) {
6a488035
TO
444 $newLineOperators = array(
445 'p' => array(
446 'oper' => '<p>',
447 'pattern' => '/<(\s+)?p(\s+)?>/m',
448 ),
449 'br' => array(
450 'oper' => '<br />',
451 'pattern' => '/<(\s+)?br(\s+)?\/>/m',
452 ),
453 );
454
455 $htmlMsg = preg_split($newLineOperators['p']['pattern'], $message);
456 foreach ($htmlMsg as $k => & $m) {
457 $messages = preg_split($newLineOperators['br']['pattern'], $m);
458 foreach ($messages as $key => & $msg) {
459 $msg = trim($msg);
460 $matches = array();
461 if (preg_match('/^(&nbsp;)+/', $msg, $matches)) {
462 $spaceLen = strlen($matches[0]) / 6;
353ffa53
TO
463 $trimMsg = ltrim($msg, '&nbsp; ');
464 $charLen = strlen($trimMsg);
6a488035
TO
465 $totalLen = $charLen + $spaceLen;
466 if ($totalLen > 100) {
467 $spacesCount = 10;
468 if ($spaceLen > 50) {
469 $spacesCount = 20;
470 }
471 if ($charLen > 100) {
472 $spacesCount = 1;
473 }
474 $msg = str_repeat('&nbsp;', $spacesCount) . $trimMsg;
475 }
476 }
477 }
478 $m = implode($newLineOperators['br']['oper'], $messages);
479 }
480 $message = implode($newLineOperators['p']['oper'], $htmlMsg);
481 }
96025800 482
6a488035 483}