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