You are here

function tablefield_field_formatter_view in TableField 7.3

Same name and namespace in other branches
  1. 7 tablefield.module \tablefield_field_formatter_view()
  2. 7.2 tablefield.module \tablefield_field_formatter_view()

Implements hook_field_formatter_view().

File

./tablefield.module, line 869
Provides a set of fields that can be used to store tabular data with a node.

Code

function tablefield_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  $settings = $display['settings'];
  $formatter = $display['type'];
  if (!empty($items)) {
    switch ($display['type']) {
      case 'format_raw':
        $values = array();
        foreach ($items as $delta => $table) {
          $value = unserialize($table['value']);

          // Swap rows and columns if the header is vertical (first column).
          if ($settings['vertheader']) {
            $transposed = tablefield_transpose($value['tabledata']);
            unset($value['tabledata']);
            array_pop($transposed);

            // Swap column and row key names.
            foreach ($transposed as $colk => $colv) {
              foreach ($colv as $rowk => $rowv) {
                $value['tabledata'][str_replace('col_', 'row_', $colk)][str_replace('row_', 'col_', $rowk)] = $rowv;
              }

              // Add a 'weight' although the value is not relevant.
              $value['tabledata'][str_replace('col_', 'row_', $colk)]['weight'] = 0;
            }
          }

          // Remove unneeded data.
          unset($value['rebuild']);
          unset($value['import']);
          unset($value['paste']);

          // DEVELOPERS! Extra future data should be captured and unset below.
          $caption = $value['caption'];
          unset($value['caption']);
          if ($settings['usearraykeys'] === 'Header' || $settings['usearraykeys'] === 'Both') {

            // Keep first row values (header) to use for array keys later.
            $keys = $value['tabledata']['row_0'];

            // Remove linebreaks from array keys.
            array_walk_recursive($keys, function (&$key) {
              $key = str_replace(array(
                "\r",
                "\n",
                "<br />",
              ), '', $key);
            });

            // If a header value is empty use the column key (col_#).
            foreach ($keys as $key => $content) {
              if (empty($content)) {
                $keys[$key] = $key;
              }
            }

            // Warning about columns with duplicate names being suppressed.
            $unique = array_unique($keys);
            $duplicates = array_diff_assoc($keys, $unique);
            foreach ($duplicates as $duplicate) {
              drupal_set_message(t('The column header "%key" appears multiple times in a table. In the JSON output only the last column with this key is used to avoid duplicate names.', array(
                '%key' => $duplicate,
              )), 'warning', FALSE);
            }
            unset($keys['weight']);

            // Remove the first row (header).
            unset($value['tabledata']['row_0']);
            if ($settings['usearraykeys'] === 'Both') {

              // Remove the first column from the keys.
              unset($keys['col_0']);

              // Make number of elements same as $row for array_combine later.
              unset($keys['weight']);
            }
          }
          foreach ($value['tabledata'] as $key => $row) {
            unset($row['weight']);
            if ($settings['usearraykeys'] === 'Header' || $settings['usearraykeys'] === 'Both') {
              if ($settings['usearraykeys'] === 'Both') {
                $row_ident = $row['col_0'];

                // Clean up unneeded data.
                unset($value['tabledata'][$key]);
                unset($row['col_0']);
                $row = array_combine($keys, $row);

                // If the first column value is empty use the row key (row_#).
                $row_id = empty($row_ident) ? $key : $row_ident;
                $row_id = str_replace(array(
                  "\r",
                  "\n",
                  "<br />",
                ), '', $row_id);

                // Warning about rows with duplicate names being suppressed.
                if (isset($value['tabledata'][$row_id])) {
                  drupal_set_message(t('The row header "%row_id" appears multiple times in a table. In the JSON output only the last row with this key is used to avoid duplicate names.', array(
                    '%row_id' => $row_id,
                  )), 'warning', FALSE);
                }
                $value['tabledata'][$row_id] = $row;

                // Remove the old key from the data set if it was replaced.
                if (!empty($row_ident)) {
                  unset($value['tabledata'][$key]);
                }
              }
              $unique = array_unique($keys);
              $row = array_combine($unique, $row);
            }
            if ($settings['usearraykeys'] != 'Both') {
              $value['tabledata'][$key] = $row;
            }
          }

          // For a row identifier key to be retained we need to insert a
          // numeric index key for each row.
          if ($settings['usearraykeys'] === 'Both' || $settings['rowkey']) {
            $i = 0;
            foreach ($value as $key => $val) {
              $value[$i][$key] = $val;

              // Remove original key. We'll get it back with array_values().
              unset($value[$key]);
              $i++;
            }
          }
          if ($settings['tabledataonly']) {
            $value = reset($value);
          }
          else {

            // DEVELOPERS! Extra future data should be unset below (e.g. title).
            $value['caption'] = $caption;
          }

          // Use the set wrapper for the table data.
          if (isset($value[0]['tabledata']) && $settings['tabledatakey'] !== 'tabledata') {
            $value[0][$settings['tabledatakey']] = $value[0]['tabledata'];
            unset($value[0]['tabledata']);
          }
          elseif (isset($value['tabledata']) && $settings['tabledatakey'] !== 'tabledata') {
            $value[$settings['tabledatakey']] = $value['tabledata'];
            unset($value['tabledata']);
          }

          // Add the table to the final output.
          if ($settings['tabledataonly']) {
            array_push($values, array_values($value));
          }
          else {
            $value[$settings['tabledatakey']] = $settings['usearraykeys'] === 'Both' || $settings['rowkey'] ? $value[0][$settings['tabledatakey']] : array_values($value[$settings['tabledatakey']]);
            unset($value[0]);
            krsort($value);
            array_push($values, $value);
          }

          // If the field is not plain text and a text area then remove
          // linebreaks.
          $format = isset($items[$delta]['format']) ? $items[$delta]['format'] : 'plain_text';
          array_walk_recursive($values, function (&$value) use ($format, $settings) {
            if ($format !== 'plain_text') {
              if ($settings['xml']) {
                switch ($settings['xml_safe']) {
                  case 'htmlspecialchars':
                    $value = str_replace(array(
                      "\r",
                      "\n",
                    ), '', htmlspecialchars($value));
                    break;
                  case 'cdata':
                    if (preg_match('/[&"\'<>]/', $value)) {
                      $value = str_replace(array(
                        "\r",
                        "\n",
                      ), '', '<![CDATA[' . str_replace(']]>', '', $value) . ']]>');
                    }
                    else {
                      $value = str_replace(array(
                        "\r",
                        "\n",
                      ), '', $value);
                    }
                    break;
                  default:
                    $value = str_replace(array(
                      "\r",
                      "\n",
                    ), '', '<![CDATA[' . str_replace(']]>', '', $value) . ']]>');
                    break;
                }
              }
              else {
                $value = str_replace(array(
                  "\r",
                  "\n",
                ), '', $value);
              }
            }
          });
        }

        // Serve pretty print with a fixed-width font and preserve spaces and
        // line breaks.
        // Show pretty print on node pages and raw on other pages.
        $prettyprint = menu_get_object() && arg(2) !== 'themeless' ? JSON_PRETTY_PRINT : FALSE;
        if ($prettyprint) {
          $element['#prefix'] = '<pre>';
          $element['#suffix'] = '</pre>';
        }
        $numeric_check = $settings['numeric_check'] ? JSON_NUMERIC_CHECK : FALSE;

        // Avoid a wrapping array if we have a single table (not multi-value).
        if (!(count($values) - 1)) {
          $values = array_shift($values);
        }

        // Render multiple values as one to ensure valid JSON (e.g. seperator)
        // or XML.
        if ($settings['xml']) {

          // Creating object of SimpleXMLElement.
          $xml_data = new SimpleXMLElement('<?xml version="1.0"?><' . $settings['tabledatakey'] . '></' . $settings['tabledatakey'] . '>');

          // Flatten the array if we only have one element.
          if (count($values) === 1) {
            $values = current($values);
          }

          // Function call to convert array to xml.
          array_to_xml($values, $xml_data);
          if ($prettyprint) {
            $dom = dom_import_simplexml($xml_data)->ownerDocument;
            $dom->formatOutput = TRUE;
            $output = $dom
              ->saveXML();
            $markup = '<xmp>' . $output . '</xmp>';

            // Let other modules change the output.
            $context = array(
              'entity_type' => $entity_type,
              'entity' => $entity,
              'field' => $field,
              'instance' => $instance,
              'language' => $langcode,
              'items' => $items,
              'display' => $display,
              'table_field_output_type' => 'xml_pretty_print',
            );
            drupal_alter('tablefield_output', $markup, $context);
            $element[0] = array(
              '#markup' => $markup,
            );
          }
          else {
            $output = $xml_data
              ->asXML();
            $markup = str_replace('<?xml version="1.0"?>', '', $output);

            // Let other modules change the output.
            $context = array(
              'entity_type' => $entity_type,
              'entity' => $entity,
              'field' => $field,
              'instance' => $instance,
              'language' => $langcode,
              'items' => $items,
              'display' => $display,
              'table_field_output_type' => 'xml_raw',
            );
            drupal_alter('tablefield_output', $markup, $context);
            $element[0] = array(
              '#markup' => $markup,
            );
          }
        }
        else {
          $markup = json_encode($values, $prettyprint | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | $numeric_check);

          // Let other modules change the output.
          $context = array(
            'entity_type' => $entity_type,
            'entity' => $entity,
            'field' => $field,
            'instance' => $instance,
            'language' => $langcode,
            'items' => $items,
            'display' => $display,
            'table_field_output_type' => $prettyprint ? 'json_pretty_print' : 'json_raw',
          );
          drupal_alter('tablefield_output', $markup, $context);
          $element[0] = array(
            // See http://php.net/manual/en/json.constants.php#119565.
            '#markup' => check_plain($markup),
          );
        }
        break;
      default:
        foreach ($items as $delta => $table) {

          // Check for table caption.
          $raw = unserialize($table['value']);
          $caption = isset($raw['caption']) ? check_plain($raw['caption']) : '';

          // Rationalize the stored data.
          if (!empty($table['tablefield'])) {
            $tabledata = $table['tablefield'];
          }
          elseif (!empty($table['value'])) {
            $tabledata = unserialize($table['value']);
          }

          // Run the table through input filters.
          if (isset($tabledata['tabledata'])) {
            if (!empty($tabledata['tabledata'])) {
              if ($settings['trim_trailing_rows']) {
                $tabledata['tabledata'] = tablefield_trim($tabledata['tabledata']);
              }
              if ($settings['trim_trailing_cols']) {
                $tabledata['tabledata'] = tablefield_rtrim_cols($tabledata['tabledata']);
              }
              if ($settings['hide_empty_rows']) {
                $tabledata['tabledata'] = tablefield_hide_rows($tabledata['tabledata']);
              }
              if ($settings['hide_empty_cols']) {
                $tabledata['tabledata'] = tablefield_hide_cols($tabledata['tabledata']);
              }
              if ($settings['hide_cols_skip_head']) {
                $tabledata['tabledata'] = tablefield_hide_cols($tabledata['tabledata'], TRUE);
              }
              foreach ($tabledata['tabledata'] as $row_key => $row) {
                foreach ($row as $col_key => $cell) {
                  if (!empty($table['format']) && $col_key !== 'weight') {
                    $tabledata[$row_key][$col_key] = array(
                      'data' => check_markup($cell, $table['format']),
                      'class' => array(
                        $row_key,
                        $col_key,
                      ),
                    );
                  }
                  elseif ($col_key !== 'weight') {
                    $tabledata[$row_key][$col_key] = array(
                      'data' => check_plain($cell),
                      'class' => array(
                        $row_key,
                        $col_key,
                      ),
                    );
                  }
                }
              }
            }

            // Grab the header orientation.
            $header_orientation = !empty($tabledata['rebuild']['header_orientation']) ? $tabledata['rebuild']['header_orientation'] : (isset($instance['default_value'][0]['tablefield']['rebuild']['header_orientation']) ? $instance['default_value'][0]['tablefield']['rebuild']['header_orientation'] : 'Horizontal');

            // Pull the header for theming.
            unset($tabledata['caption']);
            unset($tabledata['tabledata']);
            unset($tabledata['rebuild']);
            unset($tabledata['import']);
            unset($tabledata['paste']);
            $header_data = isset($tabledata['row_0']) ? $tabledata['row_0'] : NULL;

            // Check for an empty header, if so we don't want to theme it.
            $noheader = TRUE;
            if (empty($settings['hide_header']) && $header_data) {
              foreach ($header_data as $cell) {
                if (strlen($cell['data']) > 0) {
                  $noheader = FALSE;
                  break;
                }
              }
            }
            $header = $noheader ? [] : $header_data;
            $entity_info = entity_get_info($entity_type);
            $entity_id = !empty($entity_info['entity keys']['id']) ? $entity->{$entity_info['entity keys']['id']} : NULL;

            // Remove the first row from the tabledata.
            if (empty($settings['hide_header']) && $header_data || $settings['hide_header']) {
              array_shift($tabledata);
            }

            // Theme the table for display, but only if we have printable
            // table data.
            if (!$settings['hide_cols_skip_head'] || $tabledata || $header) {
              $element[$delta] = array(
                '#theme' => 'tablefield_view',
                '#caption' => $caption,
                '#header_orientation' => $header_orientation,
                '#sticky' => isset($settings['sticky_header']) ? $settings['sticky_header'] : NULL,
                '#striping' => isset($settings['striping']) ? $settings['striping'] : NULL,
                '#sortable' => isset($settings['sortable']) ? $settings['sortable'] : NULL,
                '#header' => $header,
                '#rows' => $tabledata,
                '#delta' => $delta,
                '#table_custom_class_attributes' => !trim($settings['table_custom_class_attributes']) == FALSE ? $settings['table_custom_class_attributes'] : NULL,
                '#export' => isset($settings['export_csv']) ? $settings['export_csv'] : NULL,
                '#entity_type' => $entity_type,
                '#entity_id' => $entity_id,
                '#field_name' => $field['field_name'],
                '#langcode' => $langcode,
                '#formatter' => $formatter,
              );
            }
          }
        }
    }
  }
  return $element;
}