You are here

public function RendererBase::renderDomNode in Forena Reports 8

Recursive report renderer Walks the nodes rendering the report.

1 call to RendererBase::renderDomNode()
RendererBase::renderChildren in src/FrxPlugin/Renderer/RendererBase.php

File

src/FrxPlugin/Renderer/RendererBase.php, line 103
FrxRenderer.php Base class for FrxAPI custom Renderer @author davidmetzler

Class

RendererBase
Crosstab Renderer

Namespace

Drupal\forena\FrxPlugin\Renderer

Code

public function renderDomNode(DOMNode $dom_node, &$o) {

  // Write out buffer if we've gotten too big
  $continue = TRUE;
  $is_data_block = FALSE;

  //$o = '';
  $node_type = $dom_node->nodeType;
  $settings = $this->settings;
  $context = $this
    ->currentDataContextArray();

  // Shortcut process a text node
  if ($node_type == XML_TEXT_NODE || $node_type == XML_ENTITY_REF_NODE || $node_type == XML_ENTITY_NODE) {
    $text = $dom_node->textContent;
    if (!empty($settings['stripWhiteSpace'])) {
      $this
        ->write(trim($this->report
        ->replace(htmlspecialchars($text, ENT_NOQUOTES))));
    }
    else {
      $this
        ->write($this->report
        ->replace(htmlspecialchars($text, ENT_NOQUOTES)));
    }
    return NULL;
  }

  //Handle comment nodes
  if ($node_type == XML_COMMENT_NODE) {
    if (!empty($dom_node->length) && !empty($dom_node->data)) {
      $text = $dom_node->data;

      // strip empty comments if configured to
      if (!empty($settings['stripEmptyComments'])) {
        $comment_text = trim($this->report
          ->replace($text));
        if ($comment_text === '') {
          return '';
        }
      }

      // comment markup is stripped so need to add it back in
      $cmt = '<!--' . $this->report
        ->replace($text) . '-->';
      $this
        ->write($cmt);
      return NULL;
    }
    else {
      return NULL;
    }
  }

  // Continue processing non text nodes
  $node = simplexml_import_dom($dom_node);

  // Special catch to make sure we don't process bad nodes
  if (!is_object($node)) {
    return NULL;
  }
  $frx = $node
    ->attributes(Report::FRX_NS);
  $include_root = !isset($frx['skip_root']) || !$frx['skip_root'];
  $elements = $dom_node->childNodes->length;

  // Check for invalid link processing.
  if (@(string) $frx['invalid_link']) {
    $old_link_mode = $this->link_mode;
    $this->report->link_mode = (string) $frx['invalid_link'];
  }

  // Test to see if we have any nodes that contain data url
  $attrs = $node
    ->attributes();
  $id = (string) $attrs['id'];
  $tag = $node
    ->getName();
  $has_children = TRUE;

  // Preprocessing for detecting blank nodes
  if (@$settings['stripEmptyElements']) {
    $has_children = count($node
      ->children()) > 0;
    $has_attributes = FALSE;
    foreach ($attrs as $attr) {
      if (trim($this->report
        ->replace((string) $attr))) {
        $has_attributes = TRUE;
      }
    }
    if (!$has_children && !$has_attributes) {
      $has_text = trim($this->report
        ->replace((string) $dom_node->textContent)) !== '';
      if (!$has_text) {
        return NULL;
      }
      else {
        $has_children = TRUE;
      }
    }
  }
  else {
    $has_children = count($node
      ->children()) > 0 || trim($dom_node->textContent) !== '';
  }
  if ((string) $frx['block']) {

    // Determine the context
    $this->blockName = (string) $frx['block'];
    $this->blockParms = $context;

    // Now get the block
    $is_data_block = TRUE;
    $xml = $this->report
      ->getData((string) $frx['block'], (string) $frx['parameters']);
    if ($xml) {
      $this
        ->pushData($xml, $id);
    }
    else {
      if ($id) {
        $this
          ->setDataContext($id, $xml);
      }
      return NULL;
    }
  }

  //Implment if then logic
  if ((string) $frx['if']) {
    $cond = (string) $frx['if'];
    if (!$this->report
      ->test($cond)) {
      return NULL;
    }
  }

  // Preserve plain attributes
  $attr_text = '';
  $tmp_attrs = array();
  if ($attrs) {
    foreach ($attrs as $key => $value) {
      $attr_text .= ' ' . $key . '="' . (string) $value . '"';
      $tmp_attrs[$key] = (string) $value;
    }
  }

  // Preserve other namespaced attributes
  $ns_attrs = '';
  foreach ($node
    ->getNamespaces() as $ns_key => $ns_uri) {
    if ($ns_key && $ns_key != 'frx') {
      foreach ($node
        ->attributes($ns_uri) as $key => $value) {
        $ns_attrs .= ' ' . $ns_key . ':' . $key . '="' . (string) $value . '"';
      }
    }
  }

  // Check for include syntax
  $include_file = (string) $frx['include'];
  if ($include_file) {
    $parms = $this->dmSvc->dataSvc
      ->currentContextArray();
    forena_report_include($include_file, $parms);
    return NULL;
  }

  // Determine if we have a custom renderer
  $renderer = (string) $frx['renderer'];

  // if we have a foreach in this node, we need to iterate the children
  if ((string) $frx['foreach']) {

    // Get proper XML for current data context.
    $path = $this->report
      ->replace((string) $frx['foreach'], TRUE);
    if ($path && strpos($path, '.')) {
      @(list($context, $path) = explode('.', $path, 2));
      $data = $this
        ->getDataContext($context);
    }
    else {
      $data = $this
        ->currentDataContext();
    }
    if (is_object($data) || $path != '*') {
      if (method_exists($data, 'xpath') || is_array($data)) {
        if (is_array($data)) {
          $data = DataContext::arrayToXml($data);
        }
        $nodes = $data
          ->xpath($path);
      }
      else {
        $nodes = $data;
      }
    }
    else {
      $nodes = (array) $data;
    }

    // Sort values
    $sort = @(string) $frx['sort'];
    if ($sort) {
      $compare_type = @(string) $frx['compare'];
      $this->report
        ->sort($data, $sort, $compare_type);
    }

    //  values
    $group = @(string) $frx['group'];
    if ($group) {
      $opt = $this
        ->mergedAttributes($node);
      $sums = (array) @$opt['sum'];
      $nodes = $this->report
        ->group($nodes, $group, $sums);
    }
    $i = 0;

    //$tmp_attrs = (array)$attrs;
    if ($nodes) {
      foreach ($nodes as $x) {
        if ($group) {
          $this
            ->setDataContext('group', $x[0]);
        }
        $this
          ->pushData($x, $id);
        $i++;
        $odd = $i & 1;
        $row_class = $odd ? 'odd' : 'even';
        $r_attr_text = '';
        if (trim($id)) {
          if (strpos($attrs['id'], '{') !== FALSE) {
            $id_attr = $this->report
              ->replace($attrs['id']);
          }
          else {
            if (!empty($settings['numericFrxForeachID'])) {
              $id_attr = $i;
            }
            else {
              $id_attr = $attrs['id'] . '-' . $i;
            }
          }
          $tmp_attrs['id'] = $id_attr;
        }
        if (@(!$settings['noHelperClasses'])) {
          $tmp_attrs['class'] = trim($attrs['class'] . ' ' . $row_class);
        }
        foreach ($tmp_attrs as $key => $value) {
          $r_attr_text .= ' ' . $key . '="' . (string) $value . '"';
        }
        if ($include_root) {
          $this
            ->write($this->report
            ->replace('<' . $tag . $r_attr_text . $ns_attrs . '>', TRUE));
        }
        foreach ($dom_node->childNodes as $child) {
          $this
            ->renderDomNode($child, $o);
        }
        if ($include_root) {
          $close_tag = '</' . $tag . '>';
          $this
            ->write($close_tag);
        }
        $this
          ->popData();
      }
    }
  }
  elseif ($continue) {
    if ($renderer) {

      // Implement custom renderer.

      /** @var \Drupal\forena\FrxPlugin\Renderer\RendererInterface $co */
      $co = $this->report
        ->getRenderer($renderer);
      if ($co) {
        $co
          ->initReportNode($dom_node);
        $output = $co
          ->render();
        $this
          ->write($output);
      }
    }
    else {
      if ($has_children) {
        if ($include_root) {
          $this
            ->write($this->report
            ->replace('<' . $tag . $attr_text . $ns_attrs . '>', TRUE));
        }

        // None found, so render children
        foreach ($dom_node->childNodes as $child) {
          $this
            ->renderDomNode($child, $o);
        }
        if ($include_root) {
          $this
            ->write('</' . $tag . '>');
        }
      }
      else {
        $this
          ->write($this->report
          ->replace('<' . $tag . $attr_text . $ns_attrs . '/>', TRUE));
      }
    }
  }
  if ($is_data_block && $continue) {
    $this
      ->popData();
  }

  // Restore link processing.
  if (@(string) $frx['invalid_link']) {
    $this->report->link_mode = $old_link_mode;
  }
  return NULL;
}