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