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