a8905fa44430bd200112d4fd9776d90f79baba44
[civicrm-core.git] / CRM / Contact / Form / Task / Label.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
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 |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17
18 /**
19 * This class helps to print the labels for contacts.
20 */
21 class CRM_Contact_Form_Task_Label extends CRM_Contact_Form_Task {
22
23 /**
24 * Build all the data structures needed to build the form.
25 */
26 public function preProcess() {
27 $this->set('contactIds', $this->_contactIds);
28 parent::preProcess();
29 }
30
31 /**
32 * Build the form object.
33 */
34 public function buildQuickForm() {
35 self::buildLabelForm($this);
36 }
37
38 /**
39 * Common Function to build Mailing Label Form.
40 *
41 * @param CRM_Core_Form $form
42 */
43 public static function buildLabelForm($form) {
44 $form->setTitle(ts('Make Mailing Labels'));
45
46 //add select for label
47 $label = CRM_Core_BAO_LabelFormat::getList(TRUE);
48
49 $form->add('select', 'label_name', ts('Select Label'), ['' => ts('- select label -')] + $label, TRUE);
50
51 // add select for Location Type
52 $form->addElement('select', 'location_type_id', ts('Select Location'),
53 [
54 '' => ts('Primary'),
55 ] + CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id'), TRUE
56 );
57
58 // checkbox for SKIP contacts with Do Not Mail privacy option
59 $form->addElement('checkbox', 'do_not_mail', ts('Do not print labels for contacts with "Do Not Mail" privacy option checked'));
60
61 $form->add('checkbox', 'merge_same_address', ts('Merge labels for contacts with the same address'), NULL);
62 $form->add('checkbox', 'merge_same_household', ts('Merge labels for contacts belonging to the same household'), NULL);
63
64 $form->addButtons([
65 [
66 'type' => 'submit',
67 'name' => ts('Make Mailing Labels'),
68 'isDefault' => TRUE,
69 ],
70 [
71 'type' => 'cancel',
72 'name' => ts('Done'),
73 ],
74 ]);
75 }
76
77 /**
78 * Set default values for the form.
79 *
80 * @return array
81 * array of default values
82 */
83 public function setDefaultValues() {
84 $defaults = [];
85 $format = CRM_Core_BAO_LabelFormat::getDefaultValues();
86 $defaults['label_name'] = $format['name'] ?? NULL;
87 $defaults['do_not_mail'] = 1;
88
89 return $defaults;
90 }
91
92 /**
93 * Process the form after the input has been submitted and validated.
94 *
95 * @param array|null $params
96 */
97 public function postProcess($params = NULL) {
98 $fv = $params ?: $this->controller->exportValues($this->_name);
99 $locName = NULL;
100 //get the address format sequence from the config file
101 $mailingFormat = Civi::settings()->get('mailing_format');
102
103 $sequence = CRM_Utils_Address::sequence($mailingFormat);
104
105 foreach ($sequence as $v) {
106 $address[$v] = 1;
107 }
108
109 if (array_key_exists('postal_code', $address)) {
110 $address['postal_code_suffix'] = 1;
111 }
112
113 //build the returnproperties
114 $returnProperties = ['display_name' => 1, 'contact_type' => 1, 'prefix_id' => 1];
115 $mailingFormat = Civi::settings()->get('mailing_format');
116
117 $mailingFormatProperties = [];
118 if ($mailingFormat) {
119 $mailingFormatProperties = CRM_Utils_Token::getReturnProperties($mailingFormat);
120 $returnProperties = array_merge($returnProperties, $mailingFormatProperties);
121 }
122 //we should not consider addressee for data exists, CRM-6025
123 if (array_key_exists('addressee', $mailingFormatProperties)) {
124 unset($mailingFormatProperties['addressee']);
125 }
126
127 $customFormatProperties = [];
128 if (stristr($mailingFormat, 'custom_')) {
129 foreach ($mailingFormatProperties as $token => $true) {
130 if (substr($token, 0, 7) == 'custom_') {
131 if (empty($customFormatProperties[$token])) {
132 $customFormatProperties[$token] = $mailingFormatProperties[$token];
133 }
134 }
135 }
136 }
137
138 if (!empty($customFormatProperties)) {
139 $returnProperties = array_merge($returnProperties, $customFormatProperties);
140 }
141
142 if (isset($fv['merge_same_address'])) {
143 // we need first name/last name for summarising to avoid spillage
144 $returnProperties['first_name'] = 1;
145 $returnProperties['last_name'] = 1;
146 }
147
148 /*
149 * CRM-8338: replace ids of household members with the id of their household
150 * so we can merge labels by household.
151 */
152 if (isset($fv['merge_same_household'])) {
153 $this->mergeContactIdsByHousehold();
154 }
155
156 //get the contacts information
157 $params = [];
158 if (!empty($fv['location_type_id'])) {
159 $locType = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
160 $locName = $locType[$fv['location_type_id']];
161 $location = ['location' => ["{$locName}" => $address]];
162 $returnProperties = array_merge($returnProperties, $location);
163 $params[] = ['location_type', '=', [1 => $fv['location_type_id']], 0, 0];
164 $primaryLocationOnly = FALSE;
165 }
166 else {
167 $returnProperties = array_merge($returnProperties, $address);
168 $primaryLocationOnly = TRUE;
169 }
170
171 $rows = [];
172 foreach ($this->_contactIds as $key => $contactID) {
173 $params[] = [
174 CRM_Core_Form::CB_PREFIX . $contactID,
175 '=',
176 1,
177 0,
178 0,
179 ];
180 }
181
182 // fix for CRM-2651
183 if (!empty($fv['do_not_mail'])) {
184 $params[] = ['do_not_mail', '=', 0, 0, 0];
185 }
186 // fix for CRM-2613
187 $params[] = ['is_deceased', '=', 0, 0, 0];
188
189 $custom = [];
190 foreach ($returnProperties as $name => $dontCare) {
191 $cfID = CRM_Core_BAO_CustomField::getKeyID($name);
192 if ($cfID) {
193 $custom[] = $cfID;
194 }
195 }
196
197 //get the total number of contacts to fetch from database.
198 $numberofContacts = count($this->_contactIds);
199 [$details] = CRM_Contact_BAO_Query::apiQuery($params, $returnProperties, NULL, NULL, 0, $numberofContacts, TRUE, FALSE, TRUE, CRM_Contact_BAO_Query::MODE_CONTACTS, NULL, $primaryLocationOnly);
200 $messageToken = CRM_Utils_Token::getTokens($mailingFormat);
201
202 // $details is an array of [ contactID => contactDetails ]
203 // also get all token values
204 CRM_Utils_Hook::tokenValues($details,
205 $this->_contactIds,
206 NULL,
207 $messageToken,
208 'CRM_Contact_Form_Task_Label'
209 );
210
211 $tokens = [];
212 CRM_Utils_Hook::tokens($tokens);
213 $tokenFields = [];
214 foreach ($tokens as $category => $catTokens) {
215 foreach ($catTokens as $token => $tokenName) {
216 $tokenFields[] = $token;
217 }
218 }
219
220 foreach ($this->_contactIds as $value) {
221 foreach ($custom as $cfID) {
222 if (isset($details[$value]["custom_{$cfID}"])) {
223 $details[$value]["custom_{$cfID}"] = CRM_Core_BAO_CustomField::displayValue($details[$value]["custom_{$cfID}"], $cfID);
224 }
225 }
226 $contact = $details[$value] ?? NULL;
227
228 if (is_a($contact, 'CRM_Core_Error')) {
229 return NULL;
230 }
231
232 // we need to remove all the "_id"
233 unset($contact['contact_id']);
234
235 if ($locName && !empty($contact[$locName])) {
236 // If location type is not primary, $contact contains
237 // one more array as "$contact[$locName] = array( values... )"
238
239 if (!self::tokenIsFound($contact, $mailingFormatProperties, $tokenFields)) {
240 continue;
241 }
242
243 $contact = array_merge($contact, $contact[$locName]);
244 unset($contact[$locName]);
245
246 if (!empty($contact['county_id'])) {
247 unset($contact['county_id']);
248 }
249
250 foreach ($contact as $field => $fieldValue) {
251 $rows[$value][$field] = $fieldValue;
252 }
253
254 $valuesothers = [];
255 $paramsothers = ['contact_id' => $value];
256 $valuesothers = CRM_Core_BAO_Location::getValues($paramsothers, $valuesothers);
257 if (!empty($fv['location_type_id'])) {
258 foreach ($valuesothers as $vals) {
259 if (CRM_Utils_Array::value('location_type_id', $vals) ==
260 CRM_Utils_Array::value('location_type_id', $fv)
261 ) {
262 foreach ($vals as $k => $v) {
263 if (in_array($k, [
264 'email',
265 'phone',
266 'im',
267 'openid',
268 ])) {
269 if ($k === 'im') {
270 $rows[$value][$k] = $v['1']['name'];
271 }
272 else {
273 $rows[$value][$k] = $v['1'][$k];
274 }
275 $rows[$value][$k . '_id'] = $v['1']['id'];
276 }
277 }
278 }
279 }
280 }
281 }
282 else {
283 if (!self::tokenIsFound($contact, $mailingFormatProperties, $tokenFields)) {
284 continue;
285 }
286
287 if (!empty($contact['addressee_display'])) {
288 $contact['addressee_display'] = trim($contact['addressee_display']);
289 }
290 if (!empty($contact['addressee'])) {
291 $contact['addressee'] = $contact['addressee_display'];
292 }
293
294 // now create the rows for generating mailing labels
295 foreach ($contact as $field => $fieldValue) {
296 $rows[$value][$field] = $fieldValue;
297 }
298 }
299 }
300
301 if (isset($fv['merge_same_address'])) {
302 CRM_Core_BAO_Address::mergeSameAddress($rows);
303 }
304
305 // format the addresses according to CIVICRM_ADDRESS_FORMAT (CRM-1327)
306 foreach ($rows as $id => $row) {
307 if ($commMethods = CRM_Utils_Array::value('preferred_communication_method', $row)) {
308 $val = array_filter(explode(CRM_Core_DAO::VALUE_SEPARATOR, $commMethods));
309 $comm = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'preferred_communication_method');
310 $temp = [];
311 foreach ($val as $vals) {
312 $temp[] = $comm[$vals];
313 }
314 $row['preferred_communication_method'] = implode(', ', $temp);
315 }
316 $row['id'] = $id;
317 $formatted = CRM_Utils_Address::format($row, 'mailing_format', FALSE, TRUE, $tokenFields);
318 $rows[$id] = [$formatted];
319 }
320
321 if (!empty($fv['is_unit_testing'])) {
322 return $rows;
323 }
324
325 //call function to create labels
326 $this->createLabel($rows, $fv['label_name']);
327 CRM_Utils_System::civiExit();
328 }
329
330 /**
331 * Check for presence of tokens to be swapped out.
332 *
333 * @param array $contact
334 * @param array $mailingFormatProperties
335 * @param array $tokenFields
336 *
337 * @return bool
338 */
339 public static function tokenIsFound($contact, $mailingFormatProperties, $tokenFields) {
340 foreach (array_merge($mailingFormatProperties, array_fill_keys($tokenFields, 1)) as $key => $dontCare) {
341 //we should not consider addressee for data exists, CRM-6025
342 if ($key != 'addressee' && !empty($contact[$key])) {
343 return TRUE;
344 }
345 }
346 return FALSE;
347 }
348
349 /**
350 * Create labels (pdf).
351 *
352 * @param array $contactRows
353 * Associated array of contact data.
354 * @param string $format
355 * Format in which labels needs to be printed.
356 * @param string $fileName
357 * The name of the file to save the label in.
358 */
359 private function createLabel($contactRows, $format, $fileName = 'MailingLabels_CiviCRM.pdf') {
360 $pdf = new CRM_Utils_PDF_Label($format, 'mm');
361 $pdf->Open();
362 $pdf->AddPage();
363
364 //build contact string that needs to be printed
365 $val = NULL;
366 foreach ($contactRows as $value) {
367 foreach ($value as $v) {
368 $val .= "$v\n";
369 }
370
371 $pdf->AddPdfLabel($val);
372 $val = '';
373 }
374 $pdf->Output($fileName, 'D');
375 }
376
377 }