3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
19 * This class helps to print the labels for contacts.
21 class CRM_Contact_Form_Task_Label
extends CRM_Contact_Form_Task
{
24 * Build all the data structures needed to build the form.
26 public function preProcess() {
27 $this->set('contactIds', $this->_contactIds
);
32 * Build the form object.
34 public function buildQuickForm() {
35 self
::buildLabelForm($this);
39 * Common Function to build Mailing Label Form.
41 * @param CRM_Core_Form $form
43 public static function buildLabelForm($form) {
44 CRM_Utils_System
::setTitle(ts('Make Mailing Labels'));
46 //add select for label
47 $label = CRM_Core_BAO_LabelFormat
::getList(TRUE);
49 $form->add('select', 'label_name', ts('Select Label'), ['' => ts('- select label -')] +
$label, TRUE);
51 // add select for Location Type
52 $form->addElement('select', 'location_type_id', ts('Select Location'),
55 ] + CRM_Core_PseudoConstant
::get('CRM_Core_DAO_Address', 'location_type_id'), TRUE
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'));
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);
67 'name' => ts('Make Mailing Labels'),
78 * Set default values for the form.
81 * array of default values
83 public function setDefaultValues() {
85 $format = CRM_Core_BAO_LabelFormat
::getDefaultValues();
86 $defaults['label_name'] = $format['name'] ??
NULL;
87 $defaults['do_not_mail'] = 1;
93 * Process the form after the input has been submitted and validated.
95 * @param array|NULL $params
97 public function postProcess($params = NULL) {
98 $fv = $params ?
: $this->controller
->exportValues($this->_name
);
99 $config = CRM_Core_Config
::singleton();
101 //get the address format sequence from the config file
102 $mailingFormat = Civi
::settings()->get('mailing_format');
104 $sequence = CRM_Utils_Address
::sequence($mailingFormat);
106 foreach ($sequence as $v) {
110 if (array_key_exists('postal_code', $address)) {
111 $address['postal_code_suffix'] = 1;
114 //build the returnproperties
115 $returnProperties = ['display_name' => 1, 'contact_type' => 1, 'prefix_id' => 1];
116 $mailingFormat = Civi
::settings()->get('mailing_format');
118 $mailingFormatProperties = [];
119 if ($mailingFormat) {
120 $mailingFormatProperties = CRM_Utils_Token
::getReturnProperties($mailingFormat);
121 $returnProperties = array_merge($returnProperties, $mailingFormatProperties);
123 //we should not consider addressee for data exists, CRM-6025
124 if (array_key_exists('addressee', $mailingFormatProperties)) {
125 unset($mailingFormatProperties['addressee']);
128 $customFormatProperties = [];
129 if (stristr($mailingFormat, 'custom_')) {
130 foreach ($mailingFormatProperties as $token => $true) {
131 if (substr($token, 0, 7) == 'custom_') {
132 if (empty($customFormatProperties[$token])) {
133 $customFormatProperties[$token] = $mailingFormatProperties[$token];
139 if (!empty($customFormatProperties)) {
140 $returnProperties = array_merge($returnProperties, $customFormatProperties);
143 if (isset($fv['merge_same_address'])) {
144 // we need first name/last name for summarising to avoid spillage
145 $returnProperties['first_name'] = 1;
146 $returnProperties['last_name'] = 1;
149 $individualFormat = FALSE;
152 * CRM-8338: replace ids of household members with the id of their household
153 * so we can merge labels by household.
155 if (isset($fv['merge_same_household'])) {
156 $this->mergeContactIdsByHousehold();
157 $individualFormat = TRUE;
160 //get the contacts information
162 if (!empty($fv['location_type_id'])) {
163 $locType = CRM_Core_PseudoConstant
::get('CRM_Core_DAO_Address', 'location_type_id');
164 $locName = $locType[$fv['location_type_id']];
165 $location = ['location' => ["{$locName}" => $address]];
166 $returnProperties = array_merge($returnProperties, $location);
167 $params[] = ['location_type', '=', [1 => $fv['location_type_id']], 0, 0];
168 $primaryLocationOnly = FALSE;
171 $returnProperties = array_merge($returnProperties, $address);
172 $primaryLocationOnly = TRUE;
176 foreach ($this->_contactIds
as $key => $contactID) {
178 CRM_Core_Form
::CB_PREFIX
. $contactID,
187 if (!empty($fv['do_not_mail'])) {
188 $params[] = ['do_not_mail', '=', 0, 0, 0];
191 $params[] = ['is_deceased', '=', 0, 0, 0];
194 foreach ($returnProperties as $name => $dontCare) {
195 $cfID = CRM_Core_BAO_CustomField
::getKeyID($name);
201 //get the total number of contacts to fetch from database.
202 $numberofContacts = count($this->_contactIds
);
203 $query = new CRM_Contact_BAO_Query($params, $returnProperties);
204 $details = $query->apiQuery($params, $returnProperties, NULL, NULL, 0, $numberofContacts, TRUE, FALSE, TRUE, CRM_Contact_BAO_Query
::MODE_CONTACTS
, NULL, $primaryLocationOnly);
205 $messageToken = CRM_Utils_Token
::getTokens($mailingFormat);
207 // also get all token values
208 CRM_Utils_Hook
::tokenValues($details[0],
212 'CRM_Contact_Form_Task_Label'
216 CRM_Utils_Hook
::tokens($tokens);
218 foreach ($tokens as $category => $catTokens) {
219 foreach ($catTokens as $token => $tokenName) {
220 $tokenFields[] = $token;
224 foreach ($this->_contactIds
as $value) {
225 foreach ($custom as $cfID) {
226 if (isset($details[0][$value]["custom_{$cfID}"])) {
227 $details[0][$value]["custom_{$cfID}"] = CRM_Core_BAO_CustomField
::displayValue($details[0][$value]["custom_{$cfID}"], $cfID);
230 $contact = $details['0'][$value] ??
NULL;
232 if (is_a($contact, 'CRM_Core_Error')) {
236 // we need to remove all the "_id"
237 unset($contact['contact_id']);
239 if ($locName && !empty($contact[$locName])) {
240 // If location type is not primary, $contact contains
241 // one more array as "$contact[$locName] = array( values... )"
243 if (!self
::tokenIsFound($contact, $mailingFormatProperties, $tokenFields)) {
247 $contact = array_merge($contact, $contact[$locName]);
248 unset($contact[$locName]);
250 if (!empty($contact['county_id'])) {
251 unset($contact['county_id']);
254 foreach ($contact as $field => $fieldValue) {
255 $rows[$value][$field] = $fieldValue;
259 $paramsothers = ['contact_id' => $value];
260 $valuesothers = CRM_Core_BAO_Location
::getValues($paramsothers, $valuesothers);
261 if (!empty($fv['location_type_id'])) {
262 foreach ($valuesothers as $vals) {
263 if (CRM_Utils_Array
::value('location_type_id', $vals) ==
264 CRM_Utils_Array
::value('location_type_id', $fv)
266 foreach ($vals as $k => $v) {
274 $rows[$value][$k] = $v['1']['name'];
277 $rows[$value][$k] = $v['1'][$k];
279 $rows[$value][$k . '_id'] = $v['1']['id'];
287 if (!self
::tokenIsFound($contact, $mailingFormatProperties, $tokenFields)) {
291 if (!empty($contact['addressee_display'])) {
292 $contact['addressee_display'] = trim($contact['addressee_display']);
294 if (!empty($contact['addressee'])) {
295 $contact['addressee'] = $contact['addressee_display'];
298 // now create the rows for generating mailing labels
299 foreach ($contact as $field => $fieldValue) {
300 $rows[$value][$field] = $fieldValue;
305 if (isset($fv['merge_same_address'])) {
306 CRM_Core_BAO_Address
::mergeSameAddress($rows);
307 $individualFormat = TRUE;
310 // format the addresses according to CIVICRM_ADDRESS_FORMAT (CRM-1327)
311 foreach ($rows as $id => $row) {
312 if ($commMethods = CRM_Utils_Array
::value('preferred_communication_method', $row)) {
313 $val = array_filter(explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $commMethods));
314 $comm = CRM_Core_PseudoConstant
::get('CRM_Contact_DAO_Contact', 'preferred_communication_method');
316 foreach ($val as $vals) {
317 $temp[] = $comm[$vals];
319 $row['preferred_communication_method'] = implode(', ', $temp);
322 $formatted = CRM_Utils_Address
::format($row, 'mailing_format', FALSE, TRUE, $tokenFields);
324 // CRM-2211: UFPDF doesn't have bidi support; use the PECL fribidi package to fix it.
325 // On Ubuntu (possibly Debian?) be aware of http://pecl.php.net/bugs/bug.php?id=12366
326 // Due to FriBidi peculiarities, this can't be called on
327 // a multi-line string, hence the explode+implode approach.
328 if (function_exists('fribidi_log2vis')) {
329 $lines = explode("\n", $formatted);
330 foreach ($lines as $i => $line) {
331 $lines[$i] = fribidi_log2vis($line, FRIBIDI_AUTO
, FRIBIDI_CHARSET_UTF8
);
333 $formatted = implode("\n", $lines);
335 $rows[$id] = [$formatted];
338 if (!empty($fv['is_unit_testing'])) {
342 //call function to create labels
343 self
::createLabel($rows, $fv['label_name']);
344 CRM_Utils_System
::civiExit();
348 * Check for presence of tokens to be swapped out.
350 * @param array $contact
351 * @param array $mailingFormatProperties
352 * @param array $tokenFields
356 public static function tokenIsFound($contact, $mailingFormatProperties, $tokenFields) {
357 foreach (array_merge($mailingFormatProperties, array_fill_keys($tokenFields, 1)) as $key => $dontCare) {
358 //we should not consider addressee for data exists, CRM-6025
359 if ($key != 'addressee' && !empty($contact[$key])) {
367 * Create labels (pdf).
369 * @param array $contactRows
370 * Associated array of contact data.
371 * @param string $format
372 * Format in which labels needs to be printed.
373 * @param string $fileName
374 * The name of the file to save the label in.
376 public function createLabel(&$contactRows, &$format, $fileName = 'MailingLabels_CiviCRM.pdf') {
377 $pdf = new CRM_Utils_PDF_Label($format, 'mm');
381 //build contact string that needs to be printed
383 foreach ($contactRows as $row => $value) {
384 foreach ($value as $k => $v) {
388 $pdf->AddPdfLabel($val);
391 $pdf->Output($fileName, 'D');