Merge pull request #4875 from civicrm/minor-fix
[civicrm-core.git] / CRM / Badge / BAO / Badge.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | This file is a part of CiviCRM. |
7 | |
8 | CiviCRM is free software; you can copy, modify, and distribute it |
9 | under the terms of the GNU Affero General Public License |
10 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
11 | |
12 | CiviCRM is distributed in the hope that it will be useful, but |
13 | WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
15 | See the GNU Affero General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU Affero General Public |
18 | License and the CiviCRM Licensing Exception along |
19 | with this program; if not, contact CiviCRM LLC |
20 | at info[AT]civicrm[DOT]org. If you have questions about the |
21 | GNU Affero General Public License or the licensing of CiviCRM, |
22 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
23 +--------------------------------------------------------------------+
24 */
25
26 /**
27 *
28 * @package CRM
29 * @copyright CiviCRM LLC (c) 2004-2014
30 * $Id$
31 *
32 */
33
34 /**
35 * Class CRM_Badge_Format_Badge
36 *
37 * parent class for building name badges
38 */
39 class CRM_Badge_BAO_Badge {
40
41 public $debug = FALSE;
42
43 public $border = 0;
44
45 /**
46 * This function is called to create name label pdf
47 *
48 * @param array $participants
49 * Associated array with participant info.
50 * @param array $layoutInfo
51 * Associated array which contains meta data about format/layout.
52 *
53 * @return void
54 */
55 public function createLabels(&$participants, &$layoutInfo) {
56 $this->pdf = new CRM_Utils_PDF_Label($layoutInfo['format'], 'mm');
57 $this->pdf->Open();
58 $this->pdf->setPrintHeader(FALSE);
59 $this->pdf->setPrintFooter(FALSE);
60 $this->pdf->AddPage();
61 $this->pdf->SetGenerator($this, "generateLabel");
62
63 // this is very useful for debugging, by default set to FALSE
64 if ($this->debug) {
65 $this->border = "LTRB";
66 }
67
68 foreach ($participants as $participant) {
69 $formattedRow = self::formatLabel($participant, $layoutInfo);
70 $this->pdf->AddPdfLabel($formattedRow);
71 }
72
73 $this->pdf->Output(CRM_Utils_String::munge($layoutInfo['title'], '_', 64) . '.pdf', 'D');
74 CRM_Utils_System::civiExit(1);
75 }
76
77 /**
78 * Funtion to create structure and add meta data according to layout
79 *
80 * @param array $row
81 * Row element that needs to be formatted.
82 * @param array $layout
83 * Layout meta data.
84 *
85 * @return array
86 * row with meta data
87 */
88 public static function formatLabel(&$row, &$layout) {
89 $formattedRow = array('labelFormat' => $layout['label_format_name']);
90 $formattedRow['labelTitle'] = $layout['title'];
91 $formattedRow['labelId'] = $layout['id'];
92
93 if (!empty($layout['data']['rowElements'])) {
94 foreach ($layout['data']['rowElements'] as $key => $element) {
95 $value = '';
96 if ($element) {
97 $value = $row[$element];
98 // hack to fix date field display format
99 if (strpos($element, '_date')) {
100 $value = CRM_Utils_Date::customFormat($value, "%B %E%f");
101 }
102 }
103
104 $formattedRow['token'][$key] = array(
105 'value' => $value,
106 'font_name' => $layout['data']['font_name'][$key],
107 'font_size' => $layout['data']['font_size'][$key],
108 'font_style' => $layout['data']['font_style'][$key],
109 'text_alignment' => $layout['data']['text_alignment'][$key],
110 'token' => $layout['data']['token'][$key],
111 );
112 }
113 }
114
115 if (!empty($layout['data']['image_1'])) {
116 $formattedRow['image_1'] = $layout['data']['image_1'];
117 }
118 if (!empty($layout['data']['width_image_1'])) {
119 $formattedRow['width_image_1'] = $layout['data']['width_image_1'];
120 }
121 if (!empty($layout['data']['height_image_1'])) {
122 $formattedRow['height_image_1'] = $layout['data']['height_image_1'];
123 }
124
125 if (!empty($layout['data']['image_2'])) {
126 $formattedRow['image_2'] = $layout['data']['image_2'];
127 }
128 if (!empty($layout['data']['width_image_2'])) {
129 $formattedRow['width_image_2'] = $layout['data']['width_image_2'];
130 }
131 if (!empty($layout['data']['height_image_2'])) {
132 $formattedRow['height_image_2'] = $layout['data']['height_image_2'];
133 }
134 if (!empty($row['image_URL']) && !empty($layout['data']['show_participant_image'])) {
135 $formattedRow['participant_image'] = $row['image_URL'];
136 }
137 if (!empty($layout['data']['width_participant_image'])) {
138 $formattedRow['width_participant_image'] = $layout['data']['width_participant_image'];
139 }
140 if (!empty($layout['data']['height_participant_image'])) {
141 $formattedRow['height_participant_image'] = $layout['data']['height_participant_image'];
142 }
143 if (!empty($layout['data']['alignment_participant_image'])) {
144 $formattedRow['alignment_participant_image'] = $layout['data']['alignment_participant_image'];
145 }
146
147 if (!empty($layout['data']['add_barcode'])) {
148 $formattedRow['barcode'] = array(
149 'alignment' => $layout['data']['barcode_alignment'],
150 'type' => $layout['data']['barcode_type'],
151 );
152 }
153
154 // finally assign all the row values, so that we can use it for barcode etc
155 $formattedRow['values'] = $row;
156
157 return $formattedRow;
158 }
159
160 /**
161 * @param $formattedRow
162 */
163 public function generateLabel($formattedRow) {
164 switch ($formattedRow['labelFormat']) {
165 case 'A6 Badge Portrait 150x106':
166 case 'Hanging Badge 3-3/4" x 4-3"/4':
167 self::labelCreator($formattedRow, 5);
168 break;
169
170 case 'Avery 5395':
171 default:
172 self::labelCreator($formattedRow);
173 break;
174 }
175 }
176
177 /**
178 * @param $formattedRow
179 * @param int $cellspacing
180 */
181 public function labelCreator(&$formattedRow, $cellspacing = 0) {
182 $this->lMarginLogo = 18;
183 $this->tMarginName = 20;
184
185 $x = $this->pdf->GetAbsX();
186 $y = $this->pdf->getY();
187
188 //call hook alterBadge
189 CRM_Utils_Hook::alterBadge($formattedRow['labelTitle'], $this, $formattedRow, $formattedRow['values']);
190
191 $startOffset = 0;
192 if (!empty($formattedRow['image_1'])) {
193 $this->printImage($formattedRow['image_1'], NULL, NULL, CRM_Utils_Array::value('width_image_1', $formattedRow),
194 CRM_Utils_Array::value('height_image_1', $formattedRow));
195 }
196
197 if (!empty($formattedRow['image_2'])) {
198 $this->printImage($formattedRow['image_2'], $x + 68, NULL, CRM_Utils_Array::value('width_image_2', $formattedRow),
199 CRM_Utils_Array::value('height_image_2', $formattedRow));
200 }
201
202 if ((CRM_Utils_Array::value('height_image_1', $formattedRow) >
203 CRM_Utils_Array::value('height_image_2', $formattedRow)) && !empty($formattedRow['height_image_1'])
204 ) {
205 $startOffset = CRM_Utils_Array::value('height_image_1', $formattedRow);
206 }
207 elseif (!empty($formattedRow['height_image_2'])) {
208 $startOffset = CRM_Utils_Array::value('height_image_2', $formattedRow);
209 }
210
211 if (CRM_Utils_Array::value('participant_image', $formattedRow)) {
212 $imageAlign = 0;
213 switch (CRM_Utils_Array::value('alignment_participant_image', $formattedRow)) {
214 case 'R':
215 $imageAlign = 68;
216 break;
217
218 case 'L':
219 $imageAlign = 0;
220 break;
221
222 default:
223 break;
224 }
225 $this->pdf->Image($formattedRow['participant_image'], $x + $imageAlign, $y + $startOffset, CRM_Utils_Array::value('width_participant_image', $formattedRow), CRM_Utils_Array::value('height_participant_image', $formattedRow));
226 if ($startOffset == NULL && CRM_Utils_Array::value('height_participant_image', $formattedRow)) {
227 $startOffset = CRM_Utils_Array::value('height_participant_image', $formattedRow);
228 }
229 }
230
231 $this->pdf->SetLineStyle(array(
232 'width' => 0.1,
233 'cap' => 'round',
234 'join' => 'round',
235 'dash' => '2,2',
236 'color' => array(0, 0, 200),
237 ));
238
239 $rowCount = CRM_Badge_Form_Layout::FIELD_ROWCOUNT;
240 for ($i = 1; $i <= $rowCount; $i++) {
241 if (!empty($formattedRow['token'][$i]['token'])) {
242 $value = '';
243 if ($formattedRow['token'][$i]['token'] != 'spacer') {
244 $value = $formattedRow['token'][$i]['value'];
245 }
246
247 $xAlign = $x;
248 $rowWidth = $this->pdf->width;
249 if (!empty($formattedRow['participant_image']) && !empty($formattedRow['width_participant_image'])) {
250 $rowWidth = $this->pdf->width - $formattedRow['width_participant_image'];
251 if ($formattedRow['alignment_participant_image'] == 'L') {
252 $xAlign = $x + $formattedRow['width_participant_image'] + $imageAlign;
253 }
254 }
255 $offset = $this->pdf->getY() + $startOffset + $cellspacing;
256
257 $this->pdf->SetFont($formattedRow['token'][$i]['font_name'], $formattedRow['token'][$i]['font_style'],
258 $formattedRow['token'][$i]['font_size']);
259 $this->pdf->MultiCell($rowWidth, 0, $value,
260 $this->border, $formattedRow['token'][$i]['text_alignment'], 0, 1, $xAlign, $offset);
261
262 // set this to zero so that it is added only for first element
263 $startOffset = 0;
264 }
265 }
266
267 if (!empty($formattedRow['barcode'])) {
268 $data = $formattedRow['values'];
269
270 if ($formattedRow['barcode']['type'] == 'barcode') {
271 $data['current_value'] =
272 $formattedRow['values']['contact_id'] . '-' . $formattedRow['values']['participant_id'];
273 }
274 else {
275 // view participant url
276 $data['current_value'] = CRM_Utils_System::url('civicrm/contact/view/participant',
277 'action=view&reset=1&cid=' . $formattedRow['values']['contact_id'] . '&id='
278 . $formattedRow['values']['participant_id'],
279 TRUE,
280 NULL,
281 FALSE
282 );
283 }
284
285 // call hook alterBarcode
286 CRM_Utils_Hook::alterBarcode($data, $formattedRow['barcode']['type']);
287
288 if ($formattedRow['barcode']['type'] == 'barcode') {
289 // barcode position
290 $xAlign = $x;
291
292 switch ($formattedRow['barcode']['alignment']) {
293 case 'L':
294 $xAlign += -14;
295 break;
296
297 case 'R':
298 $xAlign += 27;
299 break;
300
301 case 'C':
302 $xAlign += 9;
303 break;
304 }
305
306 $style = array(
307 'position' => '',
308 'align' => '',
309 'stretch' => FALSE,
310 'fitwidth' => TRUE,
311 'cellfitalign' => '',
312 'border' => FALSE,
313 'hpadding' => 13.5,
314 'vpadding' => 'auto',
315 'fgcolor' => array(0, 0, 0),
316 'bgcolor' => FALSE,
317 'text' => FALSE,
318 'font' => 'helvetica',
319 'fontsize' => 8,
320 'stretchtext' => 0,
321 );
322
323 $this->pdf->write1DBarcode($data['current_value'], 'C128', $xAlign, $y + $this->pdf->height - 10, '70',
324 12, 0.4, $style, 'B');
325 }
326 else {
327 // qr code position
328 $xAlign = $x;
329
330 switch ($formattedRow['barcode']['alignment']) {
331 case 'L':
332 $xAlign += -5;
333 break;
334
335 case 'R':
336 $xAlign += 56;
337 break;
338
339 case 'C':
340 $xAlign += 29;
341 break;
342 }
343
344 $style = array(
345 'border' => FALSE,
346 'hpadding' => 13.5,
347 'vpadding' => 'auto',
348 'fgcolor' => array(0, 0, 0),
349 'bgcolor' => FALSE,
350 'position' => '',
351 );
352
353 $this->pdf->write2DBarcode($data['current_value'], 'QRCODE,H', $xAlign, $y + $this->pdf->height - 26, 30,
354 30, $style, 'B');
355 }
356 }
357 }
358
359 /**
360 * Helper function to print images
361 *
362 * @param string $img
363 * Image url.
364 *
365 * @param string $x
366 * @param string $y
367 * @param null $w
368 * @param null $h
369 *
370 * @return void
371 */
372 public function printImage($img, $x = '', $y = '', $w = NULL, $h = NULL) {
373 if (!$x) {
374 $x = $this->pdf->GetAbsX();
375 }
376
377 if (!$y) {
378 $y = $this->pdf->GetY();
379 }
380
381 $this->imgRes = 300;
382
383 if ($img) {
384 list($w, $h) = self::getImageProperties($img, $this->imgRes, $w, $h);
385 $this->pdf->Image($img, $x, $y, $w, $h, '', '', '', FALSE, 72, '', FALSE,
386 FALSE, $this->debug, FALSE, FALSE, FALSE);
387 }
388 $this->pdf->SetXY($x, $y);
389 }
390
391 /**
392 * @param $img
393 * @param int $imgRes
394 * @param null $w
395 * @param null $h
396 *
397 * @return array
398 */
399 public static function getImageProperties($img, $imgRes = 300, $w = NULL, $h = NULL) {
400 $imgsize = getimagesize($img);
401 $f = $imgRes / 25.4;
402 $w = !empty($w) ? $w : $imgsize[0] / $f;
403 $h = !empty($h) ? $h : $imgsize[1] / $f;
404 return array($w, $h);
405 }
406
407 /**
408 * Build badges parameters before actually creating badges.
409 *
410 * @param array $params
411 * Associated array of submitted values.
412 * @param CRM_Core_Form $form
413 *
414 * @return void
415 * @static
416 */
417 public static function buildBadges(&$params, &$form) {
418 // get name badge layout info
419 $layoutInfo = CRM_Badge_BAO_Layout::buildLayout($params);
420
421 // split/get actual field names from token and individual contact image URLs
422 $returnProperties = array();
423 if (!empty($layoutInfo['data']['token'])) {
424 foreach ($layoutInfo['data']['token'] as $index => $value) {
425 $element = '';
426 if ($value) {
427 $token = CRM_Utils_Token::getTokens($value);
428 if (key($token) == 'contact') {
429 $element = $token['contact'][0];
430 }
431 elseif (key($token) == 'event') {
432 $element = $token['event'][0];
433 //FIX ME - we need to standardize event token names
434 if (substr($element, 0, 6) != 'event_') {
435 $element = 'event_' . $element;
436 }
437 }
438 elseif (key($token) == 'participant') {
439 $element = $token['participant'][0];
440 }
441
442 // build returnproperties for query
443 $returnProperties[$element] = 1;
444 }
445
446 // add actual field name to row element
447 $layoutInfo['data']['rowElements'][$index] = $element;
448 }
449 }
450
451 // add additional required fields for query execution
452 $additionalFields = array('participant_register_date', 'participant_id', 'event_id', 'contact_id', 'image_URL');
453 foreach ($additionalFields as $field) {
454 $returnProperties[$field] = 1;
455 }
456
457 if ($form->_single) {
458 $queryParams = NULL;
459 }
460 else {
461 $queryParams = $form->get('queryParams');
462 }
463
464 $query = new CRM_Contact_BAO_Query($queryParams, $returnProperties, NULL, FALSE, FALSE,
465 CRM_Contact_BAO_Query::MODE_EVENT
466 );
467
468 list($select, $from, $where, $having) = $query->query();
469 if (empty($where)) {
470 $where = "WHERE {$form->_componentClause}";
471 }
472 else {
473 $where .= " AND {$form->_componentClause}";
474 }
475
476 $sortOrder = NULL;
477 if ($form->get(CRM_Utils_Sort::SORT_ORDER)) {
478 $sortOrder = $form->get(CRM_Utils_Sort::SORT_ORDER);
479 if (!empty($sortOrder)) {
480 $sortOrder = " ORDER BY $sortOrder";
481 }
482 }
483 $queryString = "$select $from $where $having $sortOrder";
484
485 $dao = CRM_Core_DAO::executeQuery($queryString);
486 $rows = array();
487 while ($dao->fetch()) {
488 $query->convertToPseudoNames($dao);
489 $rows[$dao->participant_id] = array();
490 foreach ($returnProperties as $key => $dontCare) {
491 $rows[$dao->participant_id][$key] = isset($dao->$key) ? $dao->$key : NULL;
492 }
493 }
494
495 $eventBadgeClass = new CRM_Badge_BAO_Badge();
496 $eventBadgeClass->createLabels($rows, $layoutInfo);
497 }
498 }