cforge-2.0.x-dev/modules/cforge_import/src/ImportForm.php

modules/cforge_import/src/ImportForm.php
<?php

namespace Drupal\cforge_import;

// This is for the validation of large sets.
ini_set('max_execution_time', 200);

use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\cforge_import\CsvImportManager;

/**
 * Form builder for selecting and importing from a csv.
 */
class ImportForm extends FormBase {

  private $csvImportManager;
  private $plugin;

  /**
   * Constructor.
   */
  public function __construct(CsvImportManager $csv_import_manager) {
    $this->csvImporter = $csv_import_manager;
  }

  /**
   * {@inheritDoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('cforge.csv_importer')
    );
  }

  /**
   * {@inheritDoc}
   */
  public function getFormId() {
    return 'cforge_import_csv_form';
  }

  /**
   * {@inheritDoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['format'] = [
      '#title' => $this->t('Csv source'),
      '#type' => 'radios',
      '#options' => [
        'file' => $this->t('Upload file'),
        'paste' => $this->t('Paste csv text'),
        'url' => $this->t('Absolute url'),
      ],
      '#default_value' => isset($_SESSION['import']) ? $_SESSION['import']['format'] : '',
    ];
    $form['import_type'] = [
      '#title' => $this->t('Data type'),
      '#descriptions' => $this->t('Importable types'),
      '#type' => 'radios',
      '#weight' => 1,
    ];

    $options = [];
    foreach ($this->getImportPluginDefs() as $id => $def) {
      $form['import_type']['#options'][$id] = $def['label'];
      $this->setPlugin($id);
      $col_names = array_keys($this->plugin->columns());
      $description = $this->t(
        'Csv columns: @columns',
        ['@columns' => implode(', ', $col_names)]
      );
      if ($this->plugin->ready()) {
        $form[$id . '_info'] = [
          '#type' => 'item',
          '#markup' => $this->t('Field descriptions') . '<br />',
          '#states' => [
            'visible' => [
              ':input[name="import_type"]' => ['value' => "$id"],
            ],
          ],
          '#weight' => 4,
        ];
        foreach ($this->plugin->columns() as $field => $info) {
          $form[$id . '_info']['#markup'] .= '<strong>' . $field . '</strong>' . ': ' . $info . '<br />';
        }
        $form[$id . '_file'] = [
          '#type' => 'file',
          '#title' => $def['label'],
          '#weight' => 5,
          '#states' => [
            'visible' => [
              ':input[name="import_type"]' => ['value' => "$id"],
              ':input[name="format"]' => ['value' => "file"],
            ],
          ],
        ];
        $form[$id . '_paste'] = [
          '#title' => $this->t('Paste your csv file here'),
          '#type' => 'textarea',
          '#placeholder' => '"'.implode('","', $col_names).'"',
          '#weight' => 6,
          '#states' => [
            'visible' => [
              ':input[name="import_type"]' => ['value' => "$id"],
              ':input[name="format"]' => ['value' => "paste"],
            ],
          ],
        ];
        $form[$id . '_url'] = [
          '#title' => $this->t('Url of csv file'),
          '#placeholder' => 'http://',
          '#type' => 'textfield',
          '#weight' => 6,
          '#states' => [
            'visible' => [
              ':input[name="import_type"]' => ['value' => "$id"],
              ':input[name="format"]' => ['value' => "url"],
            ],
          ],
        ];
      }
      else {
        $form['import_type'][$id]['#disabled'] = TRUE;
      }
    }
    $form['delete'] = array(
      '#title' => t('Delete existing'),
      '#type' => 'checkbox',
      '#default_value' => FALSE,
      '#weight' => 9,
    );
    $form['save'] = array(
      '#title' => t('Save entities after validation'),
      '#type' => 'checkbox',
      '#default_value' => FALSE,
      '#weight' => 9,
    );
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => 'import',
      '#weight' => 10,
    );
    return $form;
  }

  /**
   * {@inheritDoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    if ($form_state->getValue('format') == 'file') {
      $element_name = $form_state->getValue('import_type') . '_file';
      // Check for a new uploaded file.
      $file = file_save_upload($element_name, ['file_validate_extensions' => ['csv']], FALSE, 0);
      if (isset($file)) {
        // File upload was attempted.
        if ($file) {
          // Put the temporary file in form_values so we can save it on submit.
          $form_state->setValue($element_name, $file);
        }
        else {
          // File upload failed.
          $form_state->setErrorByName($element_name, $this->t('The csv could not be uploaded.'));
        }
      }
    }
    $type = $form_state->getValue('import_type');
    $this->setPlugin($type);
    if ($form_state->getValue('format') == 'file') {
      $file_entity  = $form_state->getValue($type . '_file');
      $csv_str = file_get_contents($file_entity->getFileUri());
    }
    elseif ($form_state->getValue('format') == 'url') {
      $url = $form_state->getValue($type . '_url');
      $csv_str = \Drupal::httpClient()->get($url)->getBody()->getContents();
    }
    else {
      $csv_str = $form_state->getValue($type . '_paste');
    }
    $form_state->set('csv', $this->parseCsv($csv_str));
  }

  /**
   * Load the given plugin.
   */
  public function setPlugin(string $id) {
    $this->plugin = $this->csvImporter->createInstance($id);
  }

  /**
   * get only the deepest subclass of plugins
   */
  private function getImportPluginDefs() {
    $all_defs = $this->csvImporter->getDefinitions();
    $defs = $all_defs;
    foreach ($all_defs as $def1) {
      foreach ($defs as $d2 => $def2) {
        if (is_subclass_of($def1['class'], $def2['class'])) {
          unset($defs[$d2]);
          break;
        }
      }
    }
    return $defs;
  }

  /**
   * {@inheritDoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    // Remember the form settings.
    // Tidy up.
    if ($form_state->getValue('format') == 'file') {
      $form_state->getValue($form_state->getValue('import_type') . '_file')->delete();
    }
    $_SESSION['import']['format'] = $form_state->getValue('format');
    $rows = $this->plugin->getCsvRows($form_state->get('csv'));
    if (!$rows) {
      \Drupal::messenger()->addError('Csv not parsed');
    }
    if (count($rows) > 100) {
      $batch = $this->plugin->makeBatch($rows, $form_state->getValue('delete'), $form_state->getValue('save'));
      batch_set($batch);
    }
    else {
      if ($form_state->getValue('delete')) {
        $this->plugin->deleteAll();
      }
      $this->plugin::saveEntities($this->plugin->getPluginId(), $rows, $form_state->getValue('save'));
    }
  }

  function parseCsv($str) {
    $str = str_replace('", "', '","', $str); // remove spaces between fields
    $str = str_replace(',,', ',"",', $str); // quote unquoted empty fields
    // Match all the non-quoted text and one series of quoted text (or the end of the string)
    // Each group of matches will be parsed with the callback, with $matches[1] containing all the non-quoted text,
    // nd $matches[3] containing everything inside the quotes
    $str = preg_replace_callback('/([^"]*)("((""|[^"])*)"|$)/s', [$this, 'parseCsvQuotes'], $str);
    //remove the very last newline to prevent a 0-field array for the last line
    $str = preg_replace('/\n$/', '', $str);
    //split on LF and parse each line with a callback
    return array_map([$this, 'parseCsvLine'], explode("\n", $str));
  }

  //replace all the csv-special characters inside double quotes with markers using an escape sequence
  function parseCsvQuotes(array $matches) {
    if (!isset($matches[3]))return $matches[1];
    //anything inside the quotes that might be used to split the string into lines and fields later,
    //needs to be quoted. The only character we can guarantee as safe to use, because it will never appear in the unquoted text, is a CR
    //So we're going to use CR as a marker to make escape sequences for CR, LF, Quotes, and Commas.
    $str = str_replace("\r", "\rR", $matches[3]);
    $str = str_replace("\n", "\rN", $str);
    $str = str_replace('""', "\rQ", $str);
    $str = str_replace(',', "\rC", $str);
    //The unquoted text is where commas and newlines are allowed, and where the splits will happen
    //We're going to remove all CRs from the unquoted text, by normalizing all line endings to just LF
    //This ensures us that the only place CR is used, is as the escape sequences for quoted text
    return preg_replace('/\r\n?/', "\n", $matches[1]) . $str;
  }

  //split on comma and parse each field with a callback
  function parseCsvLine($line) {
    return array_map([$this, 'parseCsvField'], explode(',', trim($line)));
  }

  //restore any csv-special characters that are part of the data
  function parseCsvField($field) {
      $field = str_replace("\rC", ',', $field);
      $field = str_replace("\rQ", '"', $field);
      $field = str_replace("\rN", "\n", $field);
      $field = str_replace("\rR", "\r", $field);
      return $field;
  }

}

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

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