Added hack for scaping curly brackets on smarty LaTeX templates
[civicrm-core.git] / CRM / Contact / Form / Task / PDFLatexCommon.php
CommitLineData
cb25a178
LMM
1<?php
2/*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.3 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
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 +--------------------------------------------------------------------+
26*/
27
28/**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2013
32 * $Id$
33 *
34 */
35
36/**
37 * This class provides the common functionality for creating PDF letter for
38 * one or a group of contact ids.
39 */
40class CRM_Contact_Form_Task_PDFLatexCommon {
41
42 /**
43 * build all the data structures needed to build the form
44 *
45 * @return void
46 * @access public
47 */
48 static function preProcess(&$form) {
49 $messageText = array();
50 $messageSubject = array();
a4aea745 51 $dao = new CRM_Core_BAO_MessageTemplate();
cb25a178
LMM
52 $dao->is_active = 1;
53 $dao->find();
54 while ($dao->fetch()) {
55 $messageText[$dao->id] = $dao->msg_text;
56 $messageSubject[$dao->id] = $dao->msg_subject;
57 }
58
59 $form->assign('message', $messageText);
60 $form->assign('messageSubject', $messageSubject);
61 }
62
63 static function preProcessSingle(&$form, $cid) {
64 $form->_contactIds = array($cid);
65 // put contact display name in title for single contact mode
66 CRM_Contact_Page_View::setTitle($cid);
67 }
68
69 /**
70 * Build the form
71 *
72 * @access public
73 *
74 * @return void
75 */
76 static function buildQuickForm(&$form) {
77 $form->add('static', 'pdf_format_header', NULL, ts('Page Format'));
78 $form->add(
79 'select',
80 'format_id',
81 ts('Select Format'),
82 array(0 => ts('- default -')) + CRM_Core_BAO_PdfFormat::getList(TRUE),
83 FALSE,
84 array('onChange' => "selectFormat( this.value, false );")
85 );;
86 $form->add(
87 'select',
88 'paper_size',
89 ts('Paper Size'),
90 array(0 => ts('- default -')) + CRM_Core_BAO_PaperSize::getList(TRUE),
91 FALSE,
92 array('onChange' => "selectPaper( this.value ); showUpdateFormatChkBox();")
93 );
94 $form->add('static', 'paper_dimensions', NULL, ts('Width x Height'));
95 $form->add(
96 'select',
97 'orientation',
98 ts('Orientation'),
99 CRM_Core_BAO_PdfFormat::getPageOrientations(),
100 FALSE,
101 array('onChange' => "updatePaperDimensions(); showUpdateFormatChkBox();")
102 );
103 $form->add(
104 'select',
105 'metric',
106 ts('Unit of Measure'),
107 CRM_Core_BAO_PdfFormat::getUnits(),
108 FALSE,
109 array('onChange' => "selectMetric( this.value );")
110 );
111 $form->add(
112 'text',
113 'margin_left',
114 ts('Left Margin'),
115 array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
116 TRUE
117 );
118 $form->add(
119 'text',
120 'margin_right',
121 ts('Right Margin'),
122 array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
123 TRUE
124 );
125 $form->add(
126 'text',
127 'margin_top',
128 ts('Top Margin'),
129 array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
130 TRUE
131 );
132 $form->add(
133 'text',
134 'margin_bottom',
135 ts('Bottom Margin'),
136 array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
137 TRUE
138 );
139 $form->add('checkbox', 'bind_format', ts('Always use this Page Format with the selected Template'));
140 $form->add('checkbox', 'update_format', ts('Update Page Format (this will affect all templates that use this format)'));
141
142 $form->assign('useThisPageFormat', ts('Always use this Page Format with the new template?'));
143 $form->assign('useSelectedPageFormat', ts('Should the new template always use the selected Page Format?'));
144 $form->assign('totalSelectedContacts', count($form->_contactIds));
145
146 CRM_Mailing_BAO_Mailing::commonLetterCompose($form);
147
148 if ($form->_single) {
149 $cancelURL = CRM_Utils_System::url(
150 'civicrm/contact/view',
151 "reset=1&cid={$form->_cid}&selectedChild=activity",
152 FALSE,
153 NULL,
154 FALSE
155 );
156 if ($form->get('action') == CRM_Core_Action::VIEW) {
157 $form->addButtons(array(
158 array(
159 'type' => 'cancel',
160 'name' => ts('Done'),
161 'js' => array('onclick' => "location.href='{$cancelURL}'; return false;"),
162 ),
163 )
164 );
165 }
166 else {
167 $form->addButtons(array(
168 array(
169 'type' => 'submit',
170 'name' => ts('Make PDF Letter'),
171 'isDefault' => TRUE,
172 ),
173 array(
174 'type' => 'cancel',
175 'name' => ts('Done'),
176 'js' => array('onclick' => "location.href='{$cancelURL}'; return false;"),
177 ),
178 )
179 );
180 }
181 }
182 else {
183 $form->addDefaultButtons(ts('Make PDF Letters'));
184 }
185
186 $form->addFormRule(array('CRM_Contact_Form_Task_PDFLatexCommon', 'formRule'), $form);
187 }
188
189 /**
190 * Set default values
191 */
192 static function setDefaultValues() {
193 $defaultFormat = CRM_Core_BAO_PdfFormat::getDefaultValues();
194 $defaultFormat['format_id'] = $defaultFormat['id'];
195 return $defaultFormat;
196 }
197
198 /**
199 * form rule
200 *
201 * @param array $fields the input form values
202 * @param array $dontCare
203 * @param array $self additional values form 'this'
204 *
205 * @return true if no errors, else array of errors
206 * @access public
207 *
208 */
209 static function formRule($fields, $dontCare, $self) {
210 $errors = array();
211 $template = CRM_Core_Smarty::singleton();
212
213 //Added for CRM-1393
214 if (CRM_Utils_Array::value('saveTemplate', $fields) && empty($fields['saveTemplateName'])) {
215 $errors['saveTemplateName'] = ts("Enter name to save message template");
216 }
217 if (!is_numeric($fields['margin_left'])) {
218 $errors['margin_left'] = 'Margin must be numeric';
219 }
220 if (!is_numeric($fields['margin_right'])) {
221 $errors['margin_right'] = 'Margin must be numeric';
222 }
223 if (!is_numeric($fields['margin_top'])) {
224 $errors['margin_top'] = 'Margin must be numeric';
225 }
226 if (!is_numeric($fields['margin_bottom'])) {
227 $errors['margin_bottom'] = 'Margin must be numeric';
228 }
229 return empty($errors) ? TRUE : $errors;
230 }
231
232 /**
233 * part of the post process which prepare and extract information from the template
234 *
235 * @access protected
236 *
237 * @return array( $categories, $html_message, $messageToken, $returnProperties )
238 */
239 static protected function processMessageTemplate(&$form) {
240 $formValues = $form->controller->exportValues($form->getName());
241
242 // process message template
243 if (CRM_Utils_Array::value('saveTemplate', $formValues) || CRM_Utils_Array::value('updateTemplate', $formValues)) {
244 $messageTemplate = array(
245 'msg_text' => NULL,
246 'msg_html' => $formValues['html_message'],
247 'msg_subject' => NULL,
248 'is_active' => TRUE,
249 );
250
251 $messageTemplate['pdf_format_id'] = 'null';
252 if (CRM_Utils_Array::value('bind_format', $formValues) && $formValues['format_id'] > 0) {
253 $messageTemplate['pdf_format_id'] = $formValues['format_id'];
254 }
255 if (CRM_Utils_Array::value('saveTemplate', $formValues) && $formValues['saveTemplate']) {
256 $messageTemplate['msg_title'] = $formValues['saveTemplateName'];
a4aea745 257 CRM_Core_BAO_MessageTemplate::add($messageTemplate);
cb25a178
LMM
258 }
259
260 if (CRM_Utils_Array::value('updateTemplate', $formValues) && $formValues['template'] && $formValues['updateTemplate']) {
261 $messageTemplate['id'] = $formValues['template'];
262
263 unset($messageTemplate['msg_title']);
a4aea745 264 CRM_Core_BAO_MessageTemplate::add($messageTemplate);
cb25a178
LMM
265 }
266 }
267 elseif (CRM_Utils_Array::value('template', $formValues) > 0) {
268 if (CRM_Utils_Array::value('bind_format', $formValues) && $formValues['format_id'] > 0) {
269 $query = "UPDATE civicrm_msg_template SET pdf_format_id = {$formValues['format_id']} WHERE id = {$formValues['template']}";
270 }
271 else {
272 $query = "UPDATE civicrm_msg_template SET pdf_format_id = NULL WHERE id = {$formValues['template']}";
273 }
274 CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray);
275 }
276 if (CRM_Utils_Array::value('update_format', $formValues)) {
277 $bao = new CRM_Core_BAO_PdfFormat();
278 $bao->savePdfFormat($formValues, $formValues['format_id']);
279 }
280
281 $html = array();
282
283 $tokens = array();
284 CRM_Utils_Hook::tokens($tokens);
285 $categories = array_keys($tokens);
286
287 $html_message = $formValues['html_message'];
288
289 //time being hack to strip '&nbsp;'
290 //from particular letter line, CRM-6798
291 self::formatMessage($html_message);
292
293 $messageToken = CRM_Utils_Token::getTokens($html_message);
294
295 $returnProperties = array();
296 if (isset($messageToken['contact'])) {
297 foreach ($messageToken['contact'] as $key => $value) {
298 $returnProperties[$value] = 1;
299 }
300 }
301
302 return array($formValues, $categories, $html_message, $messageToken, $returnProperties);
303 }
304
305 /**
306 * process the form after the input has been submitted and validated
307 *
308 * @access public
309 *
310 * @return None
311 */
312 static function postProcess(&$form) {
313 list($formValues, $categories, $html_message, $messageToken, $returnProperties) = self::processMessageTemplate($form);
314
315 $skipOnHold = isset($form->skipOnHold) ? $form->skipOnHold : FALSE;
316 $skipDeceased = isset($form->skipDeceased) ? $form->skipDeceased : TRUE;
317
318 foreach ($form->_contactIds as $item => $contactId) {
319 $params = array('contact_id' => $contactId);
320
321 list($contact) = CRM_Utils_Token::getTokenDetails($params,
322 $returnProperties,
323 $skipOnHold,
324 $skipDeceased,
325 NULL,
326 $messageToken,
327 'CRM_Contact_Form_Task_PDFLatexCommon'
328 );
329 if (civicrm_error($contact)) {
330 $notSent[] = $contactId;
331 continue;
332 }
333
334 $tokenHtml = CRM_Utils_Token::replaceContactTokens($html_message, $contact[$contactId], TRUE, $messageToken);
335 $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $contact[$contactId], $categories, TRUE);
336
337 if (defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY) {
23acd489
RR
338 //$debugfile = fopen("/tmp/debug1","w+");
339 //fwrite($debugfile, $tokenHtml);
340 //fclose($debugfile);
341 $tokenHtml = str_replace('<{', '[ss]', $tokenHtml);
342 $tokenHtml = str_replace('}>', '[cs]', $tokenHtml);
343 $tokenHtml = str_replace('{', '[ob]', $tokenHtml);
344 $tokenHtml = str_replace('}', '[cb]', $tokenHtml);
345 $tokenHtml = str_replace('[ss]', '{', $tokenHtml);
346 $tokenHtml = str_replace('[cs]', '}', $tokenHtml);
cb25a178
LMM
347 $smarty = CRM_Core_Smarty::singleton();
348 // also add the contact tokens to the template
349 $smarty->assign_by_ref('contact', $contact);
350 $tokenHtml = $smarty->fetch("string:$tokenHtml");
23acd489
RR
351 $tokenHtml = str_replace('[ob]', '{', $tokenHtml);
352 $tokenHtml = str_replace('[cb]', '}', $tokenHtml);
cb25a178
LMM
353 }
354
355 $html[] = $tokenHtml;
356 }
357
358 self::createActivities($form, $html_message, $form->_contactIds);
359
360 CRM_Utils_PDF_Utils::latex2pdf($html, "CiviLatex.pdf", FALSE, $formValues);
361
362 $form->postProcessHook();
363
364 CRM_Utils_System::civiExit(1);
365 }
366
367 function createActivities($form, $html_message, $contactIds) {
368
369 $session = CRM_Core_Session::singleton();
370 $userID = $session->get('userID');
371 $activityTypeID = CRM_Core_OptionGroup::getValue('activity_type',
372 'Print PDF LaTeX Letter',
373 'name'
374 );
375 $activityParams = array(
376 'source_contact_id' => $userID,
377 'activity_type_id' => $activityTypeID,
378 'activity_date_time' => date('YmdHis'),
379 'details' => $html_message,
380 );
381 if (!empty($form->_activityId)) {
382 $activityParams += array('id' => $form->_activityId);
383 }
384 if ($form->_cid) {
385 $activity = CRM_Activity_BAO_Activity::create($activityParams);
386 }
387 else {
388 // create Print PDF activity for each selected contact. CRM-6886
389 $activityIds = array();
390 foreach ($contactIds as $contactId) {
391 $activityID = CRM_Activity_BAO_Activity::create($activityParams);
392 $activityIds[$contactId] = $activityID->id;
393 }
394 }
395
396 foreach ($form->_contactIds as $contactId) {
397 $activityTargetParams = array(
a4aea745 398 'contact_id' => $contactId,
cb25a178
LMM
399 'activity_id' => empty($activity->id) ? $activityIds[$contactId] : $activity->id,
400 'target_contact_id' => $contactId,
401 );
a4aea745 402 CRM_Activity_BAO_ActivityTarget::create($activityTargetParams);
cb25a178
LMM
403 }
404 }
405
406 function formatMessage(&$message) {
407 $newLineOperators = array(
408 'p' => array(
409 'oper' => '<p>',
410 'pattern' => '/<(\s+)?p(\s+)?>/m',
411 ),
412 'br' => array(
413 'oper' => '<br />',
414 'pattern' => '/<(\s+)?br(\s+)?\/>/m',
415 ),
416 );
417
418 $htmlMsg = preg_split($newLineOperators['p']['pattern'], $message);
419 foreach ($htmlMsg as $k => & $m) {
420 $messages = preg_split($newLineOperators['br']['pattern'], $m);
421 foreach ($messages as $key => & $msg) {
422 $msg = trim($msg);
423 $matches = array();
424 if (preg_match('/^(&nbsp;)+/', $msg, $matches)) {
425 $spaceLen = strlen($matches[0]) / 6;
426 $trimMsg = ltrim($msg, '&nbsp; ');
427 $charLen = strlen($trimMsg);
428 $totalLen = $charLen + $spaceLen;
429 if ($totalLen > 100) {
430 $spacesCount = 10;
431 if ($spaceLen > 50) {
432 $spacesCount = 20;
433 }
434 if ($charLen > 100) {
435 $spacesCount = 1;
436 }
437 $msg = str_repeat('&nbsp;', $spacesCount) . $trimMsg;
438 }
439 }
440 }
441 $m = implode($newLineOperators['br']['oper'], $messages);
442 }
443 $message = implode($newLineOperators['p']['oper'], $htmlMsg);
444 }
445}
446