You are here

public function PdfTemplate::drawTable in Views PDF 7.3

Same name and namespace in other branches
  1. 6 views_pdf_template.php \PdfTemplate::drawTable()
  2. 7 views_pdf_template.php \PdfTemplate::drawTable()
  3. 7.2 views_pdf_template.php \PdfTemplate::drawTable()

This method draws a table on the PDF.

File

./views_pdf_template.php, line 672
PDF Class to generate PDFs with native PHP. This class based on FPDF and FPDI.

Class

PdfTemplate
The main class to generate the PDF.

Code

public function drawTable(&$view, $options) {
  $rows = $view->result;
  $columns = $view->field;
  $pageDim = $this
    ->getPageDimensions();
  $width = (double) $pageDim['wk'] - (double) $this->lMargin - (double) $this->rMargin;
  $sumWidth = 0;
  $numberOfColumnsWithoutWidth = 0;

  // Default header height is height of default font.
  $options['position']['header_style']['height'] = $this
    ->getCellHeight($this->defaultFontSize / $this->k);

  // Compute the row height as the max of default font size and explicit row height.
  $options['position']['body_style']['height'] = max($options['position']['row_height'], $options['position']['header_style']['height']);

  // Create a safety height padding, in current units.
  // Without this, FP rounding errors can result in the computed row height
  // being fractionally too small on occasional rows, making them invisible.
  $safety = 0.01 / $this->k;

  // Pre-process column info to determine layout parameters.
  $borderpad = array(
    'header_style' => $safety,
    'body_style' => $safety,
  );
  foreach ($columns as $id => $column) {

    // Check for hide-empty columns and scan results to check if they are empty.
    if (!empty($options['info'][$id]['empty']['hide_empty']) && ($row = reset($rows))) {
      do {
        $content = $view->field[$id]
          ->theme($row);
      } while (empty($content) && ($row = next($rows)));

      // If the loop got to the end of the rows, then they are all empty.
      if (!$row) {
        $column->options['exclude'] = TRUE;
      }
    }

    // Skip excluded fields and the page-break field.
    if (empty($column->options['exclude']) && $id != 'page_break') {

      // Options are merge of specific options and defaults.
      if (isset($options['info']['_default_'])) {
        if (!empty($options['info'][$id])) {

          // Merge column specifics with column defaults.
          $options['info'][$id] = array_replace_recursive($options['info']['_default_'], $options['info'][$id]);
        }
        else {
          $options['info'][$id] = $options['info']['_default_'];
        }
      }
      elseif (empty($options['info'][$id])) {
        $options['info'][$id] = array();
      }
      if (!empty($options['info'][$id]['position']['width'])) {
        $sumWidth += $options['info'][$id]['position']['width'];
      }
      else {
        $numberOfColumnsWithoutWidth++;
      }
      foreach (array(
        'header_style',
        'body_style',
      ) as $style) {
        $font_size = empty($options['info'][$id][$style]['text']['font_size']) ? $this->defaultFontSize : $options['info'][$id][$style]['text']['font_size'];
        $cell_height = $this
          ->getCellHeight($font_size / $this->k);

        // Add extra padding if specified.
        if (!empty($options['info'][$id][$style]['text']['vpad'])) {
          $cell_height += $options['info'][$id][$style]['text']['vpad'] * 2;
        }

        // Increase row height if column font size requires.
        $options['position'][$style]['height'] = max($options['position'][$style]['height'], $cell_height);

        // Get extra vertical padding required if borders are present.
        if (!empty($options['info'][$id][$style]['text']['border'])) {
          $this->cell_padding['T'] = $this->cell_padding['B'] = 0;
          $extra_paddings = $this
            ->adjustCellPadding($options['info'][$id][$style]['text']['border']);
          $borderpad[$style] = max($borderpad[$style], $extra_paddings['T'] + $extra_paddings['B']);
        }
      }
    }
  }
  $defaultColumnWidth = $numberOfColumnsWithoutWidth > 0 ? $defaultColumnWidth = ($width - $sumWidth) / $numberOfColumnsWithoutWidth : 0;

  // Increase heights to allow for borders.
  foreach (array(
    'header_style',
    'body_style',
  ) as $style) {
    $options['position'][$style]['height'] += $borderpad[$style];
  }

  // Get table header spacing, or set to 0 if not using header.
  // Note the value of $hspace is the distance from the top of the header to the first line,
  // but the option value in the settings UI is the space from the bottom of the header
  // to the first line.
  if (empty($options['position']['use_header'])) {
    $hspace = 0;
  }
  else {
    $hspace = $options['position']['header_style']['height'];
    if (is_numeric($options['position']['h'])) {
      $hspace += $options['position']['h'];
    }
  }

  // Increase the top margin by the table header spacing.
  $this->tMargin += $hspace;
  $y = (double) $this->tMargin;
  $x = (double) $this->lMargin;

  // Add default option values, and gather all the column header data into an array for use by the Header() function.
  $xh = $x;
  $yh = $y - $hspace;
  foreach ($columns as $id => $column) {

    // Skip excluded fields and the page-break field.
    if (empty($column->options['exclude']) && $id != 'page_break') {
      foreach (array(
        'header_style',
        'body_style',
      ) as $style) {
        $options['info'][$id][$style] += array(
          'position' => array(),
          'text' => array(),
          'render' => array(),
        );
        $options['info'][$id][$style]['position'] += array(
          'corner' => 'top_left',
          'x' => NULL,
          'y' => NULL,
          'object' => '',
          'width' => NULL,
          'height' => NULL,
        );
        $options['info'][$id][$style]['text'] += array(
          'font_family' => 'default',
          'font_style' => array(),
        );
        $options['info'][$id][$style]['render'] += array(
          'eval_before' => '',
          'eval_after' => '',
        );
      }
      if ($hspace) {
        $headerOptions = $options['info'][$id]['header_style'];
        $headerOptions['position']['width'] = !empty($options['info'][$id]['position']['width']) ? $options['info'][$id]['position']['width'] : $defaultColumnWidth;
        $headerOptions['position']['height'] = $options['position']['header_style']['height'];

        // Save the parameters for rendering the column headers for use by the Header() function.
        $this->tableHeader[] = array(
          $xh,
          $yh,
          $column->options['label'],
          $headerOptions,
          &$view,
          $id,
        );
        $xh += $headerOptions['position']['width'];
      }
    }
  }

  // Save default paddings for use in the header.
  $this->cellPaddings = $this->cell_padding;

  // Add the first page, this will print the header.
  $this
    ->addPage();
  $rowX = $x;
  $view->row_index = 0;
  $break = FALSE;
  foreach ($rows as $row) {
    $x = $rowX;

    // If last row forced a new page, or this row would overflow page, add a page.
    if ($break || $this->y + $this->bMargin + $options['position']['body_style']['height'] > $pageDim['hk']) {
      $break = FALSE;
      $this
        ->addPage();
    }
    $y = (double) $this->y;
    foreach ($columns as $id => $column) {

      // Always render the field in order to generate tokens for other fields.
      $content = $view->field[$id]
        ->theme($row);
      if (empty($column->options['exclude'])) {
        if ($id == 'page_break') {
          $break = !empty($content);
        }
        else {
          $bodyOptions = $options['info'][$id]['body_style'];
          $bodyOptions['position']['width'] = !empty($options['info'][$id]['position']['width']) ? $options['info'][$id]['position']['width'] : $defaultColumnWidth;
          $bodyOptions['position']['height'] = $options['position']['body_style']['height'];
          $this
            ->renderItem($x, $y, $content, $row, $bodyOptions, $view, $id, FALSE, TRUE);

          // Set x to start position of next cell
          $x += (double) $bodyOptions['position']['width'];
        }
      }
    }

    // Set y position to start of next row.
    $this
      ->SetY($y + (double) $options['position']['body_style']['height']);
    $view->row_index++;
  }

  // Empty the table header data so as not to print on a trailing template.
  $this->tableHeader = array();
}