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
18 use Civi\Token\TokenProcessor
;
21 * Class CRM_Badge_Format_Badge.
23 * parent class for building name badges
25 class CRM_Badge_BAO_Badge
{
30 public $debug = FALSE;
38 * This function is called to create name label pdf.
40 * @param array $participants
41 * Associated array with participant info.
42 * @param array $layoutInfo
43 * Associated array which contains meta data about format/layout.
45 public function createLabels($participants, &$layoutInfo) {
46 $this->pdf
= new CRM_Utils_PDF_Label($layoutInfo['format'], 'mm');
48 $this->pdf
->setPrintHeader(FALSE);
49 $this->pdf
->setPrintFooter(FALSE);
50 $this->pdf
->AddPage();
51 $this->pdf
->SetGenerator($this, "generateLabel");
53 // this is very useful for debugging, by default set to FALSE
55 $this->border
= "LTRB";
58 foreach ($participants as $participant) {
59 $formattedRow = self
::formatLabel($participant, $layoutInfo);
60 $this->pdf
->AddPdfLabel($formattedRow);
63 if (CIVICRM_UF
=== 'UnitTests') {
64 throw new CRM_Core_Exception_PrematureExitException('pdf output called', ['formattedRow' => $formattedRow]);
66 $this->pdf
->Output(CRM_Utils_String
::munge($layoutInfo['title'], '_', 64) . '.pdf', 'D');
67 CRM_Utils_System
::civiExit();
71 * Function to create structure and add meta data according to layout.
74 * Row element that needs to be formatted.
75 * @param array $layout
81 public static function formatLabel(&$row, &$layout) {
82 $formattedRow = ['labelFormat' => $layout['label_format_name']];
83 $formattedRow['labelTitle'] = $layout['title'];
84 $formattedRow['labelId'] = $layout['id'];
86 if (!empty($layout['data']['rowElements'])) {
87 foreach ($layout['data']['rowElements'] as $key => $element) {
90 $value = $row[$element];
91 // hack to fix date field display format
92 if (in_array($element, ['event_start_date', 'event_end_date'], TRUE)) {
93 $value = CRM_Utils_Date
::customFormat($value, "%B %E%f");
97 $formattedRow['token'][$key] = [
99 'font_name' => $layout['data']['font_name'][$key],
100 'font_size' => $layout['data']['font_size'][$key],
101 'font_style' => $layout['data']['font_style'][$key],
102 'text_alignment' => $layout['data']['text_alignment'][$key],
103 'token' => $layout['data']['token'][$key],
108 if (!empty($layout['data']['image_1'])) {
109 $formattedRow['image_1'] = $layout['data']['image_1'];
111 if (!empty($layout['data']['width_image_1'])) {
112 $formattedRow['width_image_1'] = $layout['data']['width_image_1'];
114 if (!empty($layout['data']['height_image_1'])) {
115 $formattedRow['height_image_1'] = $layout['data']['height_image_1'];
118 if (!empty($layout['data']['image_2'])) {
119 $formattedRow['image_2'] = $layout['data']['image_2'];
121 if (!empty($layout['data']['width_image_2'])) {
122 $formattedRow['width_image_2'] = $layout['data']['width_image_2'];
124 if (!empty($layout['data']['height_image_2'])) {
125 $formattedRow['height_image_2'] = $layout['data']['height_image_2'];
127 if (!empty($row['image_URL']) && !empty($layout['data']['show_participant_image'])) {
128 $formattedRow['participant_image'] = $row['image_URL'];
130 if (!empty($layout['data']['width_participant_image'])) {
131 $formattedRow['width_participant_image'] = $layout['data']['width_participant_image'];
133 if (!empty($layout['data']['height_participant_image'])) {
134 $formattedRow['height_participant_image'] = $layout['data']['height_participant_image'];
136 if (!empty($layout['data']['alignment_participant_image'])) {
137 $formattedRow['alignment_participant_image'] = $layout['data']['alignment_participant_image'];
140 if (!empty($layout['data']['add_barcode'])) {
141 $formattedRow['barcode'] = [
142 'alignment' => $layout['data']['barcode_alignment'],
143 'type' => $layout['data']['barcode_type'],
147 // finally assign all the row values, so that we can use it for barcode etc
148 $formattedRow['values'] = $row;
150 return $formattedRow;
154 * @param $formattedRow
156 public function generateLabel($formattedRow) {
157 switch ($formattedRow['labelFormat']) {
158 case 'A6 Badge Portrait 150x106':
159 case 'Hanging Badge 3-3/4" x 4-3"/4':
160 self
::labelCreator($formattedRow, 5);
165 self
::labelCreator($formattedRow);
171 * @param $formattedRow
172 * @param int $cellspacing
174 public function labelCreator(&$formattedRow, $cellspacing = 0) {
175 $this->lMarginLogo
= 18;
176 $this->tMarginName
= 20;
178 $x = $this->pdf
->GetAbsX();
179 $y = $this->pdf
->getY();
181 //call hook alterBadge
182 CRM_Utils_Hook
::alterBadge($formattedRow['labelTitle'], $this, $formattedRow, $formattedRow['values']);
185 if (!empty($formattedRow['image_1'])) {
186 $this->printImage($formattedRow['image_1'], NULL, NULL, CRM_Utils_Array
::value('width_image_1', $formattedRow),
187 CRM_Utils_Array
::value('height_image_1', $formattedRow));
190 if (!empty($formattedRow['image_2'])) {
191 $this->printImage($formattedRow['image_2'], $x +
68, NULL, CRM_Utils_Array
::value('width_image_2', $formattedRow),
192 CRM_Utils_Array
::value('height_image_2', $formattedRow));
195 if ((CRM_Utils_Array
::value('height_image_1', $formattedRow) >
196 CRM_Utils_Array
::value('height_image_2', $formattedRow)) && !empty($formattedRow['height_image_1'])
198 $startOffset = $formattedRow['height_image_1'] ??
NULL;
200 elseif (!empty($formattedRow['height_image_2'])) {
201 $startOffset = $formattedRow['height_image_2'] ??
NULL;
204 if (!empty($formattedRow['participant_image'])) {
206 switch (CRM_Utils_Array
::value('alignment_participant_image', $formattedRow)) {
218 $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));
219 if ($startOffset == NULL && !empty($formattedRow['height_participant_image'])) {
220 $startOffset = $formattedRow['height_participant_image'];
224 $this->pdf
->SetLineStyle([
229 'color' => [0, 0, 200],
232 $rowCount = CRM_Badge_Form_Layout
::FIELD_ROWCOUNT
;
233 for ($i = 1; $i <= $rowCount; $i++
) {
234 if (!empty($formattedRow['token'][$i]['token'])) {
236 if ($formattedRow['token'][$i]['token'] != 'spacer') {
237 $value = $formattedRow['token'][$i]['value'];
241 $rowWidth = $this->pdf
->width
;
242 if (!empty($formattedRow['participant_image']) && !empty($formattedRow['width_participant_image'])) {
243 $rowWidth = $this->pdf
->width
- $formattedRow['width_participant_image'];
244 if ($formattedRow['alignment_participant_image'] == 'L') {
245 $xAlign = $x +
$formattedRow['width_participant_image'] +
$imageAlign;
248 $offset = $this->pdf
->getY() +
$startOffset +
$cellspacing;
250 $this->pdf
->SetFont($formattedRow['token'][$i]['font_name'], $formattedRow['token'][$i]['font_style'],
251 $formattedRow['token'][$i]['font_size']);
252 $this->pdf
->MultiCell($rowWidth, 0, $value,
253 $this->border
, $formattedRow['token'][$i]['text_alignment'], 0, 1, $xAlign, $offset);
255 // set this to zero so that it is added only for first element
260 if (!empty($formattedRow['barcode'])) {
261 $data = $formattedRow['values'];
263 if ($formattedRow['barcode']['type'] == 'barcode') {
264 $data['current_value'] = $formattedRow['values']['contact_id'] . '-' . $formattedRow['values']['participant_id'];
267 // view participant url
268 $data['current_value'] = CRM_Utils_System
::url('civicrm/contact/view/participant',
269 'action=view&reset=1&cid=' . $formattedRow['values']['contact_id'] . '&id='
270 . $formattedRow['values']['participant_id'],
277 // call hook alterBarcode
278 CRM_Utils_Hook
::alterBarcode($data, $formattedRow['barcode']['type']);
280 if ($formattedRow['barcode']['type'] == 'barcode') {
284 switch ($formattedRow['barcode']['alignment']) {
303 'cellfitalign' => '',
306 'vpadding' => 'auto',
307 'fgcolor' => [0, 0, 0],
310 'font' => 'helvetica',
315 $this->pdf
->write1DBarcode($data['current_value'], 'C128', $xAlign, $y +
$this->pdf
->height
- 10, '70',
316 12, 0.4, $style, 'B');
322 switch ($formattedRow['barcode']['alignment']) {
339 'vpadding' => 'auto',
340 'fgcolor' => [0, 0, 0],
345 $this->pdf
->write2DBarcode($data['current_value'], 'QRCODE,H', $xAlign, $y +
$this->pdf
->height
- 26, 30,
352 * Helper function to print images.
362 public function printImage($img, $x = '', $y = '', $w = NULL, $h = NULL) {
364 $x = $this->pdf
->GetAbsX();
368 $y = $this->pdf
->GetY();
374 [$w, $h] = self
::getImageProperties($img, $this->imgRes
, $w, $h);
375 $this->pdf
->Image($img, $x, $y, $w, $h, '', '', '', FALSE, 72, '', FALSE,
376 FALSE, $this->debug
, FALSE, FALSE, FALSE);
378 $this->pdf
->SetXY($x, $y);
389 public static function getImageProperties($img, $imgRes = 300, $w = NULL, $h = NULL) {
390 $imgsize = getimagesize($img);
392 $w = !empty($w) ?
$w : $imgsize[0] / $f;
393 $h = !empty($h) ?
$h : $imgsize[1] / $f;
398 * Build badges parameters before actually creating badges.
400 * @param array $params
401 * Associated array of submitted values.
402 * @param CRM_Core_Form $form
404 public static function buildBadges(&$params, &$form) {
405 // get name badge layout info
406 $layoutInfo = CRM_Badge_BAO_Layout
::buildLayout($params);
407 $tokenProcessor = new TokenProcessor(\Civi
::dispatcher(), ['schema' => ['participantId'], 'smarty' => FALSE]);
408 // split/get actual field names from token and individual contact image URLs
409 $returnProperties = $processorTokens = [];
410 if (!empty($layoutInfo['data']['token'])) {
411 foreach ($layoutInfo['data']['token'] as $index => $value) {
413 $token = CRM_Utils_Token
::getTokens($value);
414 if (strpos($value, '{event.') === 0) {
415 $element = $token['event'][0];
416 //FIX ME - we need to standardize event token names
417 if (substr($element, 0, 6) != 'event_') {
419 $element = 'event_' . $element;
420 $returnProperties[$element] = 1;
421 // add actual field name to row element
422 $layoutInfo['data']['rowElements'][$index] = $element;
426 $tokenName = str_replace(['}', '{contact.', '{participant.'], '', $value);
427 $tokenProcessor->addMessage($tokenName, $value, 'text/plain');
428 $processorTokens[] = $tokenName;
429 $layoutInfo['data']['rowElements'][$index] = $tokenName;
435 // add additional required fields for query execution
436 $additionalFields = ['participant_id', 'event_id', 'contact_id'];
437 foreach ($additionalFields as $field) {
438 $returnProperties[$field] = 1;
441 if ($form->_single
) {
445 $queryParams = $form->get('queryParams');
448 $query = new CRM_Contact_BAO_Query($queryParams, $returnProperties, NULL, FALSE, FALSE,
449 CRM_Contact_BAO_Query
::MODE_EVENT
452 [$select, $from, $where, $having] = $query->query();
454 $where = "WHERE {$form->_componentClause}";
457 $where .= " AND {$form->_componentClause}";
461 if ($form->get(CRM_Utils_Sort
::SORT_ORDER
)) {
462 $sortOrder = $form->get(CRM_Utils_Sort
::SORT_ORDER
);
463 if (!empty($sortOrder)) {
464 $sortOrder = " ORDER BY $sortOrder";
467 $queryString = "$select $from $where $having $sortOrder";
469 $dao = CRM_Core_DAO
::executeQuery($queryString);
472 while ($dao->fetch()) {
473 $tokenProcessor->addRow(['contactId' => $dao->contact_id
, 'participantId' => $dao->participant_id
]);
474 $rows[$dao->participant_id
] = [];
475 foreach ($returnProperties as $key => $dontCare) {
476 // we are now only resolving the 4 event tokens here.
477 $rows[$dao->participant_id
][$key] = $dao->$key ??
NULL;
480 $tokenProcessor->evaluate();
481 foreach ($tokenProcessor->getRows() as $row) {
482 foreach ($processorTokens as $processorToken) {
483 $rows[$row->context
['participantId']][$processorToken] = $row->render($processorToken);
487 $eventBadgeClass = new CRM_Badge_BAO_Badge();
488 $eventBadgeClass->createLabels($rows, $layoutInfo);