Ian province abbreviation patch - issue 724
[civicrm-core.git] / CRM / Contact / Form / Task / PDFLetterCommon.php
... / ...
CommitLineData
1<?php
2/*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
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-2015
32 */
33
34/**
35 * This class provides the common functionality for creating PDF letter for one or a group of contact ids.
36 */
37class CRM_Contact_Form_Task_PDFLetterCommon {
38
39 /**
40 * Build all the data structures needed to build the form.
41 *
42 * @param CRM_Core_Form $form
43 */
44 public static function preProcess(&$form) {
45 $messageText = array();
46 $messageSubject = array();
47 $dao = new CRM_Core_BAO_MessageTemplate();
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);
57 CRM_Utils_System::setTitle('Create Printable Letters (PDF)');
58 }
59
60 /**
61 * @param CRM_Core_Form $form
62 * @param int $cid
63 */
64 public static function preProcessSingle(&$form, $cid) {
65 $form->_contactIds = array($cid);
66 // put contact display name in title for single contact mode
67 CRM_Utils_System::setTitle(ts('Create Printable Letter (PDF) for %1', array(1 => CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'display_name'))));
68 }
69
70 /**
71 * Build the form object.
72 *
73 * @var CRM_Core_Form $form
74 */
75 public static function buildQuickForm(&$form) {
76 // This form outputs a file so should never be submitted via ajax
77 $form->preventAjaxSubmit();
78
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
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 ));
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,
103 array('onChange' => "selectPaper( this.value ); showUpdateFormatChkBox();")
104 );
105 $form->add('static', 'paper_dimensions', NULL, ts('Width x Height'));
106 $form->add(
107 'select',
108 'orientation',
109 ts('Orientation'),
110 CRM_Core_BAO_PdfFormat::getPageOrientations(),
111 FALSE,
112 array('onChange' => "updatePaperDimensions(); showUpdateFormatChkBox();")
113 );
114 $form->add(
115 'select',
116 'metric',
117 ts('Unit of Measure'),
118 CRM_Core_BAO_PdfFormat::getUnits(),
119 FALSE,
120 array('onChange' => "selectMetric( this.value );")
121 );
122 $form->add(
123 'text',
124 'margin_left',
125 ts('Left Margin'),
126 array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
127 TRUE
128 );
129 $form->add(
130 'text',
131 'margin_right',
132 ts('Right Margin'),
133 array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
134 TRUE
135 );
136 $form->add(
137 'text',
138 'margin_top',
139 ts('Top Margin'),
140 array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
141 TRUE
142 );
143 $form->add(
144 'text',
145 'margin_bottom',
146 ts('Bottom Margin'),
147 array('size' => 8, 'maxlength' => 8, 'onkeyup' => "showUpdateFormatChkBox();"),
148 TRUE
149 );
150
151 $config = CRM_Core_Config::singleton();
152 /** CRM-15883 Suppressing Stationery path field until we switch from DOMPDF to a library that supports it.
153 if ($config->wkhtmltopdfPath == FALSE) {
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 );
161 }
162 */
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
170 CRM_Mailing_BAO_Mailing::commonCompose($form);
171
172 $buttons = array();
173 if ($form->get('action') != CRM_Core_Action::VIEW) {
174 $buttons[] = array(
175 'type' => 'submit',
176 'name' => $form->_single ? ts('Make PDF') : ts('Make PDFs'),
177 'isDefault' => TRUE,
178 );
179 }
180 $buttons[] = array(
181 'type' => 'cancel',
182 'name' => $form->get('action') == CRM_Core_Action::VIEW ? ts('Done') : ts('Cancel'),
183 );
184 $form->addButtons($buttons);
185
186 $form->addFormRule(array('CRM_Contact_Form_Task_PDFLetterCommon', 'formRule'), $form);
187 }
188
189 /**
190 * Set default values.
191 */
192 public 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
202 * The input form values.
203 * @param array $dontCare
204 * @param array $self
205 * Additional values form 'this'.
206 *
207 * @return bool
208 * TRUE if no errors, else array of errors.
209 */
210 public static function formRule($fields, $dontCare, $self) {
211 $errors = array();
212 $template = CRM_Core_Smarty::singleton();
213
214 //Added for CRM-1393
215 if (!empty($fields['saveTemplate']) && empty($fields['saveTemplateName'])) {
216 $errors['saveTemplateName'] = ts("Enter name to save message template");
217 }
218 if (!is_numeric($fields['margin_left'])) {
219 $errors['margin_left'] = 'Margin must be numeric';
220 }
221 if (!is_numeric($fields['margin_right'])) {
222 $errors['margin_right'] = 'Margin must be numeric';
223 }
224 if (!is_numeric($fields['margin_top'])) {
225 $errors['margin_top'] = 'Margin must be numeric';
226 }
227 if (!is_numeric($fields['margin_bottom'])) {
228 $errors['margin_bottom'] = 'Margin must be numeric';
229 }
230 return empty($errors) ? TRUE : $errors;
231 }
232
233 /**
234 * Part of the post process which prepare and extract information from the template.
235 *
236 *
237 * @param CRM_Core_Form $form
238 *
239 * @return array
240 * [$categories, $html_message, $messageToken, $returnProperties]
241 */
242 static protected function processMessageTemplate(&$form) {
243 $formValues = $form->controller->exportValues($form->getName());
244
245 // process message template
246 if (!empty($formValues['saveTemplate']) || !empty($formValues['updateTemplate'])) {
247 $messageTemplate = array(
248 'msg_text' => NULL,
249 'msg_html' => $formValues['html_message'],
250 'msg_subject' => NULL,
251 'is_active' => TRUE,
252 );
253
254 $messageTemplate['pdf_format_id'] = 'null';
255 if (!empty($formValues['bind_format']) && $formValues['format_id']) {
256 $messageTemplate['pdf_format_id'] = $formValues['format_id'];
257 }
258 if (!empty($formValues['saveTemplate']) && $formValues['saveTemplate']) {
259 $messageTemplate['msg_title'] = $formValues['saveTemplateName'];
260 CRM_Core_BAO_MessageTemplate::add($messageTemplate);
261 }
262
263 if (!empty($formValues['updateTemplate']) && $formValues['template'] && $formValues['updateTemplate']) {
264 $messageTemplate['id'] = $formValues['template'];
265
266 unset($messageTemplate['msg_title']);
267 CRM_Core_BAO_MessageTemplate::add($messageTemplate);
268 }
269 }
270 elseif (CRM_Utils_Array::value('template', $formValues) > 0) {
271 if (!empty($formValues['bind_format']) && $formValues['format_id']) {
272 $query = "UPDATE civicrm_msg_template SET pdf_format_id = {$formValues['format_id']} WHERE id = {$formValues['template']}";
273 }
274 else {
275 $query = "UPDATE civicrm_msg_template SET pdf_format_id = NULL WHERE id = {$formValues['template']}";
276 }
277 CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray);
278 }
279 if (!empty($formValues['update_format'])) {
280 $bao = new CRM_Core_BAO_PdfFormat();
281 $bao->savePdfFormat($formValues, $formValues['format_id']);
282 }
283
284 $html = array();
285
286 $tokens = array();
287 CRM_Utils_Hook::tokens($tokens);
288 $categories = array_keys($tokens);
289
290 $html_message = $formValues['html_message'];
291
292 //time being hack to strip '&nbsp;'
293 //from particular letter line, CRM-6798
294 self::formatMessage($html_message);
295
296 $messageToken = CRM_Utils_Token::getTokens($html_message);
297
298 $returnProperties = array();
299 if (isset($messageToken['contact'])) {
300 foreach ($messageToken['contact'] as $key => $value) {
301 $returnProperties[$value] = 1;
302 }
303 }
304
305 return array($formValues, $categories, $html_message, $messageToken, $returnProperties);
306 }
307
308 /**
309 * Process the form after the input has been submitted and validated.
310 *
311 * @param CRM_Core_Form $form
312 */
313 public static function postProcess(&$form) {
314 list($formValues, $categories, $html_message, $messageToken, $returnProperties) = self::processMessageTemplate($form);
315
316 $skipOnHold = isset($form->skipOnHold) ? $form->skipOnHold : FALSE;
317 $skipDeceased = isset($form->skipDeceased) ? $form->skipDeceased : TRUE;
318
319 foreach ($form->_contactIds as $item => $contactId) {
320 $params = array('contact_id' => $contactId);
321
322 list($contact) = CRM_Utils_Token::getTokenDetails($params,
323 $returnProperties,
324 $skipOnHold,
325 $skipDeceased,
326 NULL,
327 $messageToken,
328 'CRM_Contact_Form_Task_PDFLetterCommon'
329 );
330 if (civicrm_error($contact)) {
331 $notSent[] = $contactId;
332 continue;
333 }
334
335 $tokenHtml = CRM_Utils_Token::replaceContactTokens($html_message, $contact[$contactId], TRUE, $messageToken);
336 $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $contact[$contactId], $categories, TRUE);
337
338 if (defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY) {
339 $smarty = CRM_Core_Smarty::singleton();
340 // also add the contact tokens to the template
341 $smarty->assign_by_ref('contact', $contact);
342 $tokenHtml = $smarty->fetch("string:$tokenHtml");
343 }
344
345 $html[] = $tokenHtml;
346 }
347
348 self::createActivities($form, $html_message, $form->_contactIds);
349
350 CRM_Utils_PDF_Utils::html2pdf($html, "CiviLetter.pdf", FALSE, $formValues);
351
352 $form->postProcessHook();
353
354 CRM_Utils_System::civiExit(1);
355 }
356
357 /**
358 * @param CRM_Core_Form $form
359 * @param $html_message
360 * @param $contactIds
361 *
362 * @throws CRM_Core_Exception
363 */
364 public static function createActivities($form, $html_message, $contactIds) {
365 //Added for CRM-12682: Add activity subject and campaign fields
366 $formValues = $form->controller->exportValues($form->getName());
367
368 $session = CRM_Core_Session::singleton();
369 $userID = $session->get('userID');
370 $activityTypeID = CRM_Core_OptionGroup::getValue(
371 'activity_type',
372 'Print PDF Letter',
373 'name'
374 );
375 $activityParams = array(
376 'subject' => $formValues['subject'],
377 'campaign_id' => CRM_Utils_Array::value('campaign_id', $formValues),
378 'source_contact_id' => $userID,
379 'activity_type_id' => $activityTypeID,
380 'activity_date_time' => date('YmdHis'),
381 'details' => $html_message,
382 );
383 if (!empty($form->_activityId)) {
384 $activityParams += array('id' => $form->_activityId);
385 }
386 if ($form->_cid) {
387 $activity = CRM_Activity_BAO_Activity::create($activityParams);
388 if (!empty($form->_caseId)) {
389 $caseActivityParams = array('activity_id' => $activity->id, 'case_id' => $form->_caseId);
390 CRM_Case_BAO_Case::processCaseActivity($caseActivityParams);
391 }
392 }
393 else {
394 // create Print PDF activity for each selected contact. CRM-6886
395 $activityIds = array();
396 foreach ($contactIds as $contactId) {
397 $activityID = CRM_Activity_BAO_Activity::create($activityParams);
398 $activityIds[$contactId] = $activityID->id;
399 }
400 }
401
402 $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
403 $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
404
405 //@todo why are we using $form->_contactIds here & contactIds above - need comment
406 foreach ($form->_contactIds as $contactId) {
407 $activityTargetParams = array(
408 'activity_id' => empty($activity->id) ? $activityIds[$contactId] : $activity->id,
409 'contact_id' => $contactId,
410 'record_type_id' => $targetID,
411 );
412 CRM_Activity_BAO_ActivityContact::create($activityTargetParams);
413 }
414 }
415
416 /**
417 * @param $message
418 */
419 public static function formatMessage(&$message) {
420 $newLineOperators = array(
421 'p' => array(
422 'oper' => '<p>',
423 'pattern' => '/<(\s+)?p(\s+)?>/m',
424 ),
425 'br' => array(
426 'oper' => '<br />',
427 'pattern' => '/<(\s+)?br(\s+)?\/>/m',
428 ),
429 );
430
431 $htmlMsg = preg_split($newLineOperators['p']['pattern'], $message);
432 foreach ($htmlMsg as $k => & $m) {
433 $messages = preg_split($newLineOperators['br']['pattern'], $m);
434 foreach ($messages as $key => & $msg) {
435 $msg = trim($msg);
436 $matches = array();
437 if (preg_match('/^(&nbsp;)+/', $msg, $matches)) {
438 $spaceLen = strlen($matches[0]) / 6;
439 $trimMsg = ltrim($msg, '&nbsp; ');
440 $charLen = strlen($trimMsg);
441 $totalLen = $charLen + $spaceLen;
442 if ($totalLen > 100) {
443 $spacesCount = 10;
444 if ($spaceLen > 50) {
445 $spacesCount = 20;
446 }
447 if ($charLen > 100) {
448 $spacesCount = 1;
449 }
450 $msg = str_repeat('&nbsp;', $spacesCount) . $trimMsg;
451 }
452 }
453 }
454 $m = implode($newLineOperators['br']['oper'], $messages);
455 }
456 $message = implode($newLineOperators['p']['oper'], $htmlMsg);
457 }
458
459}