[REF] dev/core#2790 deprecate preProcessSingle
[civicrm-core.git] / CRM / Contact / Form / Task / PDFLetterCommon.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
TO
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 |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035
TO
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
16 */
17
18/**
424029e3 19 * This class provides the common functionality for creating PDF letter for one or a group of contact ids.
6a488035 20 */
958060c1 21class CRM_Contact_Form_Task_PDFLetterCommon extends CRM_Core_Form_Task_PDFLetterCommon {
6a488035 22
2fe8b920 23 protected static $tokenCategories;
24
cc144465
TO
25 /**
26 * @return array
27 * Array(string $machineName => string $label).
28 */
29 public static function getLoggingOptions() {
be2fb01f 30 return [
cc144465
TO
31 'none' => ts('Do not record'),
32 'multiple' => ts('Multiple activities (one per contact)'),
33 'combined' => ts('One combined activity'),
34 'combined-attached' => ts('One combined activity plus one file attachment'),
35 // 'multiple-attached' <== not worth the work
be2fb01f 36 ];
cc144465
TO
37 }
38
6a488035 39 /**
fe482240 40 * Build all the data structures needed to build the form.
6a488035 41 *
c97bfeff
EM
42 * @deprecated
43 *
c490a46a 44 * @param CRM_Core_Form $form
6a488035 45 */
00be9182 46 public static function preProcess(&$form) {
c97bfeff 47 CRM_Core_Error::deprecatedFunctionWarning('no alternative');
ca5f0b93 48 $defaults = [];
0008e8aa 49 $form->_fromEmails = CRM_Core_BAO_Email::getFromEmail();
ca5f0b93
EM
50 if (is_numeric(key($form->_fromEmails))) {
51 $emailID = (int) key($form->_fromEmails);
52 $defaults = CRM_Core_BAO_Email::getEmailSignatureDefaults($emailID);
53 }
54 if (!Civi::settings()->get('allow_mail_from_logged_in_contact')) {
55 $defaults['from_email_address'] = current(CRM_Core_BAO_Domain::getNameAndEmail(FALSE, TRUE));
56 }
57 $form->setDefaults($defaults);
0008e8aa 58 $form->setTitle('Print/Merge Document');
6a488035
TO
59 }
60
86538308 61 /**
972171bb 62 * @deprecated
c490a46a 63 * @param CRM_Core_Form $form
100fef9d 64 * @param int $cid
86538308 65 */
00be9182 66 public static function preProcessSingle(&$form, $cid) {
972171bb 67 CRM_Core_Error::deprecatedFunctionWarning('no alternative');
fe61faf3 68 $form->_contactIds = explode(',', $cid);
6a488035 69 // put contact display name in title for single contact mode
fe61faf3 70 if (count($form->_contactIds) === 1) {
be2fb01f 71 CRM_Utils_System::setTitle(ts('Print/Merge Document for %1', [1 => CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'display_name')]));
fe61faf3 72 }
6a488035
TO
73 }
74
6a488035 75 /**
fe482240 76 * Part of the post process which prepare and extract information from the template.
6a488035 77 *
6a488035 78 *
2bd6b6cf 79 * @param array $formValues
dbddfb08 80 *
72b3a70c
CW
81 * @return array
82 * [$categories, $html_message, $messageToken, $returnProperties]
6a488035 83 */
2bd6b6cf 84 public static function processMessageTemplate($formValues) {
958060c1 85 $html_message = self::processTemplate($formValues);
6a488035 86
2fe8b920 87 $categories = self::getTokenCategories();
6a488035 88
6a488035
TO
89 //time being hack to strip '&nbsp;'
90 //from particular letter line, CRM-6798
91 self::formatMessage($html_message);
92
93 $messageToken = CRM_Utils_Token::getTokens($html_message);
94
be2fb01f 95 $returnProperties = [];
6a488035
TO
96 if (isset($messageToken['contact'])) {
97 foreach ($messageToken['contact'] as $key => $value) {
98 $returnProperties[$value] = 1;
99 }
100 }
101
be2fb01f 102 return [$formValues, $categories, $html_message, $messageToken, $returnProperties];
6a488035
TO
103 }
104
105 /**
fe482240 106 * Process the form after the input has been submitted and validated.
6a488035 107 *
c490a46a 108 * @param CRM_Core_Form $form
2fe8b920 109 * @throws \CRM_Core_Exception
b69df99f 110 * @throws \CiviCRM_API3_Exception
6a488035 111 */
00be9182 112 public static function postProcess(&$form) {
2bd6b6cf 113 $formValues = $form->controller->exportValues($form->getName());
114 list($formValues, $categories, $html_message, $messageToken, $returnProperties) = self::processMessageTemplate($formValues);
2e1f50d6
CW
115 $skipOnHold = $form->skipOnHold ?? FALSE;
116 $skipDeceased = $form->skipDeceased ?? TRUE;
be2fb01f 117 $html = $activityIds = [];
ad7fdc34 118
119 // CRM-16725 Skip creation of activities if user is previewing their PDF letter(s)
752cee47 120 if (self::isLiveMode($form)) {
fe61faf3 121 $activityIds = self::createActivities($form, $html_message, $form->_contactIds, $formValues['subject'], CRM_Utils_Array::value('campaign_id', $formValues));
ad7fdc34 122 }
123
124 if (!empty($formValues['document_file_path'])) {
9eae09f1 125 list($html_message, $zip) = CRM_Utils_PDF_Document::unzipDoc($formValues['document_file_path'], $formValues['document_type']);
ad7fdc34 126 }
6a488035
TO
127
128 foreach ($form->_contactIds as $item => $contactId) {
8ffa3b7c 129 $caseId = NULL;
be2fb01f 130 $params = ['contact_id' => $contactId];
6a488035 131
b69df99f
CW
132 $caseId = $form->getVar('_caseId');
133 if (empty($caseId) && !empty($form->_caseIds[$item])) {
134 $caseId = $form->_caseIds[$item];
135 }
136 if ($caseId) {
137 $params['case_id'] = $caseId;
138 }
139
6a488035
TO
140 list($contact) = CRM_Utils_Token::getTokenDetails($params,
141 $returnProperties,
142 $skipOnHold,
143 $skipDeceased,
144 NULL,
145 $messageToken,
146 'CRM_Contact_Form_Task_PDFLetterCommon'
147 );
2c8a6e63 148
6a488035
TO
149 if (civicrm_error($contact)) {
150 $notSent[] = $contactId;
151 continue;
152 }
153
154 $tokenHtml = CRM_Utils_Token::replaceContactTokens($html_message, $contact[$contactId], TRUE, $messageToken);
b69df99f 155
8ffa3b7c 156 if ($caseId) {
157 $tokenHtml = CRM_Utils_Token::replaceCaseTokens($caseId, $tokenHtml, $messageToken);
07945b3c 158 }
6a488035
TO
159 $tokenHtml = CRM_Utils_Token::replaceHookTokens($tokenHtml, $contact[$contactId], $categories, TRUE);
160
161 if (defined('CIVICRM_MAIL_SMARTY') && CIVICRM_MAIL_SMARTY) {
162 $smarty = CRM_Core_Smarty::singleton();
163 // also add the contact tokens to the template
164 $smarty->assign_by_ref('contact', $contact);
165 $tokenHtml = $smarty->fetch("string:$tokenHtml");
166 }
167
168 $html[] = $tokenHtml;
169 }
170
38faa439 171 $tee = NULL;
dd8e53c4 172 if (self::isLiveMode($form) && Civi::settings()->get('recordGeneratedLetters') === 'combined-attached') {
bdac10d8
TO
173 if (count($activityIds) !== 1) {
174 throw new CRM_Core_Exception("When recordGeneratedLetters=combined-attached, there should only be one activity.");
175 }
38faa439 176 $tee = CRM_Utils_ConsoleTee::create()->start();
3c48a60c
TO
177 }
178
0aeb5a1e 179 $type = $formValues['document_type'];
3c48a60c 180 $mimeType = self::getMimeType($type);
3ed92c14 181 // ^^ Useful side-effect: consistently throws error for unrecognized types.
0aeb5a1e 182
61d0bf1f
DB
183 $fileName = self::getFileName($form);
184 $fileName = "$fileName.$type";
185
0aeb5a1e 186 if ($type == 'pdf') {
3c48a60c 187 CRM_Utils_PDF_Utils::html2pdf($html, $fileName, FALSE, $formValues);
0aeb5a1e 188 }
ad7fdc34 189 elseif (!empty($formValues['document_file_path'])) {
63c8a9ba
TO
190 $fileName = pathinfo($formValues['document_file_path'], PATHINFO_FILENAME) . '.' . $type;
191 CRM_Utils_PDF_Document::printDocuments($html, $fileName, $type, $zip);
ad7fdc34 192 }
0aeb5a1e 193 else {
3c48a60c
TO
194 CRM_Utils_PDF_Document::html2doc($html, $fileName, $formValues);
195 }
196
38faa439
TO
197 if ($tee) {
198 $tee->stop();
199 $content = file_get_contents($tee->getFileName(), NULL, NULL, NULL, 5);
3c48a60c
TO
200 if (empty($content)) {
201 throw new \CRM_Core_Exception("Failed to capture document content (type=$type)!");
202 }
203 foreach ($activityIds as $activityId) {
be2fb01f 204 civicrm_api3('Attachment', 'create', [
3c48a60c
TO
205 'entity_table' => 'civicrm_activity',
206 'entity_id' => $activityId,
207 'name' => $fileName,
208 'mime_type' => $mimeType,
be2fb01f 209 'options' => [
38faa439 210 'move-file' => $tee->getFileName(),
be2fb01f
CW
211 ],
212 ]);
3c48a60c 213 }
0aeb5a1e 214 }
6a488035
TO
215
216 $form->postProcessHook();
217
292c8687 218 CRM_Utils_System::civiExit();
6a488035
TO
219 }
220
61d0bf1f
DB
221 /**
222 * Returns the filename for the pdf by striping off unwanted characters and limits the length to 200 characters.
223 *
224 * @param CRM_Core_Form $form
225 *
226 * @return string
227 * The name of the file.
228 */
229 private static function getFileName(CRM_Core_Form $form) {
230 if (!empty($form->getSubmittedValue('pdf_file_name'))) {
31c6c663 231 $fileName = CRM_Utils_File::makeFilenameWithUnicode($form->getSubmittedValue('pdf_file_name'), '_', 200);
61d0bf1f
DB
232 }
233 elseif (!empty($form->getSubmittedValue('subject'))) {
31c6c663 234 $fileName = CRM_Utils_File::makeFilenameWithUnicode($form->getSubmittedValue('subject'), '_', 200);
61d0bf1f
DB
235 }
236 else {
91cf31e8 237 $fileName = 'CiviLetter';
61d0bf1f 238 }
91cf31e8 239 $fileName = self::isLiveMode($form) ? $fileName : $fileName . '_preview';
61d0bf1f
DB
240
241 return $fileName;
242 }
243
86538308 244 /**
c490a46a 245 * @param CRM_Core_Form $form
818b4373
TO
246 * @param string $html_message
247 * @param array $contactIds
3280f327 248 * @param string $subject
249 * @param int $campaign_id
250 * @param array $perContactHtml
251 *
818b4373
TO
252 * @return array
253 * List of activity IDs.
254 * There may be 1 or more, depending on the system-settings
255 * and use-case.
86538308
EM
256 *
257 * @throws CRM_Core_Exception
258 */
be2fb01f 259 public static function createActivities($form, $html_message, $contactIds, $subject, $campaign_id, $perContactHtml = []) {
6a488035 260
be2fb01f 261 $activityParams = [
3280f327 262 'subject' => $subject,
263 'campaign_id' => $campaign_id,
2dbdb9b9 264 'source_contact_id' => CRM_Core_Session::getLoggedInContactID(),
3280f327 265 'activity_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Print PDF Letter'),
6a488035
TO
266 'activity_date_time' => date('YmdHis'),
267 'details' => $html_message,
be2fb01f 268 ];
6a488035 269 if (!empty($form->_activityId)) {
be2fb01f 270 $activityParams += ['id' => $form->_activityId];
6a488035 271 }
818b4373 272
be2fb01f 273 $activityIds = [];
818b4373
TO
274 switch (Civi::settings()->get('recordGeneratedLetters')) {
275 case 'none':
be2fb01f 276 return [];
818b4373
TO
277
278 case 'multiple':
279 // One activity per contact.
fe61faf3 280 foreach ($contactIds as $i => $contactId) {
be2fb01f 281 $fullParams = [
6d3827cb 282 'target_contact_id' => $contactId,
be2fb01f 283 ] + $activityParams;
fe61faf3
CW
284 if (!empty($form->_caseId)) {
285 $fullParams['case_id'] = $form->_caseId;
286 }
287 elseif (!empty($form->_caseIds[$i])) {
288 $fullParams['case_id'] = $form->_caseIds[$i];
289 }
290
3280f327 291 if (isset($perContactHtml[$contactId])) {
292 $fullParams['details'] = implode('<hr>', $perContactHtml[$contactId]);
293 }
294 $activity = civicrm_api3('Activity', 'create', $fullParams);
295 $activityIds[$contactId] = $activity['id'];
818b4373
TO
296 }
297
298 break;
299
300 case 'combined':
301 case 'combined-attached':
302 // One activity with all contacts.
be2fb01f 303 $fullParams = [
6d3827cb 304 'target_contact_id' => $contactIds,
be2fb01f 305 ] + $activityParams;
fe61faf3
CW
306 if (!empty($form->_caseId)) {
307 $fullParams['case_id'] = $form->_caseId;
308 }
309 elseif (!empty($form->_caseIds)) {
310 $fullParams['case_id'] = $form->_caseIds;
311 }
312 $activity = civicrm_api3('Activity', 'create', $fullParams);
313 $activityIds[] = $activity['id'];
818b4373
TO
314 break;
315
316 default:
317 throw new CRM_Core_Exception("Unrecognized option in recordGeneratedLetters: " . Civi::settings()->get('recordGeneratedLetters'));
6a488035 318 }
818b4373 319
818b4373 320 return $activityIds;
6a488035
TO
321 }
322
86538308 323 /**
3c48a60c
TO
324 * Convert from a vague-type/file-extension to mime-type.
325 *
326 * @param string $type
327 * @return string
328 * @throws \CRM_Core_Exception
329 */
330 private static function getMimeType($type) {
be2fb01f 331 $mimeTypes = [
4b54b8bb 332 'pdf' => 'application/pdf',
3c48a60c
TO
333 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
334 'odt' => 'application/vnd.oasis.opendocument.text',
335 'html' => 'text/html',
be2fb01f 336 ];
3c48a60c
TO
337 if (isset($mimeTypes[$type])) {
338 return $mimeTypes[$type];
339 }
340 else {
341 throw new \CRM_Core_Exception("Cannot determine mime type");
342 }
343 }
344
2fe8b920 345 /**
346 * Get the categories required for rendering tokens.
347 *
348 * @return array
349 */
350 protected static function getTokenCategories() {
3280f327 351 if (!isset(Civi::$statics[__CLASS__]['token_categories'])) {
be2fb01f 352 $tokens = [];
2fe8b920 353 CRM_Utils_Hook::tokens($tokens);
3280f327 354 Civi::$statics[__CLASS__]['token_categories'] = array_keys($tokens);
2fe8b920 355 }
3280f327 356 return Civi::$statics[__CLASS__]['token_categories'];
2fe8b920 357 }
358
752cee47 359 /**
360 * Is the form in live mode (as opposed to being run as a preview).
361 *
362 * Returns true if the user has clicked the Download Document button on a
363 * Print/Merge Document (PDF Letter) search task form, or false if the Preview
364 * button was clicked.
365 *
366 * @param CRM_Core_Form $form
367 *
368 * @return bool
369 * TRUE if the Download Document button was clicked (also defaults to TRUE
370 * if the form controller does not exist), else FALSE
371 */
372 protected static function isLiveMode($form) {
373 // CRM-21255 - Hrm, CiviCase 4+5 seem to report buttons differently...
374 $buttonName = $form->controller->getButtonName();
375 $c = $form->controller->container();
376 $isLiveMode = ($buttonName == '_qf_PDF_upload') || isset($c['values']['PDF']['buttons']['_qf_PDF_upload']);
377 return $isLiveMode;
378 }
379
6a488035 380}