views_streaming_data-8.x-1.x-dev/src/Plugin/views/style/StreamingCsvSerializer.php

src/Plugin/views/style/StreamingCsvSerializer.php
<?php

namespace Drupal\views_streaming_data\Plugin\views\style;

use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\csv_serialization\Encoder\CsvEncoder;
use Drupal\views\Plugin\views\style\StylePluginBase;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\ViewExecutable;

/**
 * The style plugin for serialized output formats.
 *
 * @ingroup views_style_plugins
 *
 * @ViewsStyle(
 *   id = "csv_streaming_data",
 *   title = @Translation("CSV streaming Serializer"),
 *   help = @Translation("Serializes views row data to CSV."),
 *   display_types = {"streaming_data"}
 * )
 */
class StreamingCsvSerializer extends StylePluginBase implements CacheableDependencyInterface {

  /**
   * {@inheritdoc}
   */
  protected $usesRowPlugin = TRUE;

  /**
   * {@inheritdoc}
   */
  protected $usesGrouping = FALSE;

  /**
   * Indicates the character used to delimit fields. Defaults to ",".
   *
   * @var string
   */
  protected $delimiter = ',';

  /**
   * Indicates the character used for field enclosure. Defaults to '"'.
   *
   * @var string
   */
  protected $enclosure = '"';

  /**
   * Indicates the character used for escaping. Defaults to "\".
   *
   * @var string
   */
  protected $escapeChar = "\\";

  /**
   * Whether to strip tags from values or not. Defaults to TRUE.
   *
   * @var bool
   */
  protected $stripTags = TRUE;

  /**
   * Whether to trim values or not. Defaults to TRUE.
   *
   * @var bool
   */
  protected $trimValues = TRUE;

  /**
   * The display object this plugin is for.
   *
   * @var \Drupal\views_streaming_data\Plugin\views\display\StreamingDisplayInterface
   */
  public $displayHandler;

  /**
   * Overrides \Drupal\views\Plugin\views\PluginBase::init().
   *
   * The style options might come externally as the style can be sourced from at
   * least two locations. If it's not included, look on the display.
   */
  public function init(ViewExecutable $view, DisplayPluginBase $display, ?array &$options = NULL) {
    parent::init($view, $display, $options);
    $delimiter = $this->options['delimiter'];
    $ext = 'csv';
    $mime_type = 'text/csv';
    if ($delimiter === '|') {
      $ext = 'txt';
      $mime_type = 'text/plain';
    }
    elseif ($delimiter === "\t") {
      // @see https://www.iana.org/assignments/media-types/text/tab-separated-values
      $ext = 'tsv';
      $mime_type = 'text/tab-separated-values';
    }
    $this->displayHandler->setMimeType($mime_type);
    $this->displayHandler->setFileExtension($ext);
  }

  /**
   * {@inheritdoc}
   */
  protected function defineOptions() {
    $options = parent::defineOptions();

    $options['delimiter'] = ['default' => $this->delimiter];
    $options['strip_tags'] = ['default' => $this->stripTags];
    $options['trim'] = ['default' => $this->trimValues];

    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    parent::buildOptionsForm($form, $form_state);

    $form['delimiter'] = [
      '#type' => 'select',
      '#title' => $this->t('Delimiter'),
      '#description' => $this->t('Delimiter for the generated file.'),
      '#options' => $this->getDelimiterOptions(),
      '#default_value' => $this->options['delimiter'],
    ];
    $form['strip_tags'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Strip tags'),
      '#description' => $this->t('Strip HTML tags in each value.'),
      '#default_value' => $this->options['strip_tags'],
    ];
    $form['trim'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Trim whitespace'),
      '#description' => $this->t('Trim leading and trailing whitespace for each value.'),
      '#default_value' => $this->options['trim'],
    ];
  }

  /**
   * Returns an array of format options.
   *
   * @return string[]
   *   An array of format options. Both key and value are the same.
   */
  protected function getDelimiterOptions() {
    return [
      ',' => $this->t('Comma ,'),
      '|' => $this->t('Pipe |'),
      "\t" => $this->t('Tab \t'),
    ];
  }

  /**
   * For non-CSV, replace any delimiters in the value.
   *
   * @param resource $stream
   *   The open stream to write.
   * @param array $row
   *   The current row of data.
   * @param string $delimiter
   *   The delimiter.
   */
  protected function outputWithDelimiter($stream, array $row, $delimiter) {
    if ($delimiter === ',') {
      fputcsv($stream, $row);
      return;
    }
    // For other delimiters replace them in the row if present.
    if ($delimiter === '|') {
      $replacement = ';';
    }
    else {
      $replacement = '  ';
    }
    foreach ($row as $k => $v) {
      $row[$k] = str_replace($delimiter, $replacement, $v);
    }
    fwrite($stream, implode($delimiter, $row) . "\n");
  }

  /**
   * Extracts the headers using the first row of values.
   *
   * Copied from \Drupal\csv_serialization\Encoder\CsvEncoder::extractHeaders().
   *
   * We must make the assumption that each row shares the same set of headers
   * will all other rows. This is inherent in the structure of a CSV.
   *
   * @param array $first_row
   *   The first row of of data to be converted to a CSV.
   *
   * @return array
   *   An array of CSV headers.
   */
  protected function extractHeaders(array $first_row) {
    $headers = [];

    $allowed_headers = array_keys($first_row);
    $fields = (array) $this->displayHandler->getOption('fields');

    foreach ($allowed_headers as $allowed_header) {
      $headers[] = !empty($fields[$allowed_header]['label']) ? $fields[$allowed_header]['label'] : $allowed_header;
    }

    return $headers;
  }

  /**
   * {@inheritdoc}
   */
  public function render() {
    $delimiter = $this->options['delimiter'];
    $stream = $this->displayHandler->getOutputStream();
    // Only the $strip_tags and $trim parameters matter for ::formatRow().
    $encoder = new CsvEncoder(",", '"', "\\", (bool) $this->options['strip_tags'], (bool) $this->options['trim']);
    // If the Data Entity row plugin is used, this will be an array of entities
    // which will pass through Serializer to one of the registered Normalizers,
    // which will transform it to arrays/scalars. If the Data field row plugin
    // is used, $rows will not contain objects and will pass directly to the
    // Encoder.
    $headers = NULL;

    // We expect to be able to traverse the view, but sanity check here.
    if ($this->view instanceof \Traversable) {
      $traversable = $this->view;
    }
    else {
      $traversable = $this->view->result;
    }
    foreach ($traversable as $row_index => $row) {
      $data = $this->view->rowPlugin->render($row);
      if (!isset($headers)) {
        $headers = $this->extractHeaders((array) $data);
        $this->outputWithDelimiter($stream, $headers, $delimiter);
      }
      $row = $encoder->formatRow($data);
      $this->outputWithDelimiter($stream, $row, $delimiter);
    }

    return '';
  }

  /**
   * Gets the available format that can be requested.
   *
   * @return string
   *   An format.
   */
  public function getFormat() {
    return 'csv';
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheMaxAge() {
    return 0;
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheContexts() {
    return ['request_format'];
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheTags() {
    return [];
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc