pino-8.x-1.2-no-core/modules/member_import/src/Form/ImportMembersForm.php
modules/member_import/src/Form/ImportMembersForm.php
<?php namespace Drupal\member_import\Form; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use PhpOffice\PhpSpreadsheet\IOFactory; /** * Form for importing new members. */ class ImportMembersForm extends FormBase { protected $step = 1; protected $data = []; protected $file = []; /** * {@inheritdoc} */ public function getFormId() { return 'import_members_form'; } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { // For step 2, display the data selection form. if ($this->step == 2) { // Populate the field options for Member entity. $entityManager = \Drupal::service('entity_field.manager'); $fields = $entityManager->getFieldDefinitions('member', 'member'); // Remove fields which are commonly not used. unset($fields['id'], $fields['uuid'], $fields['vid'], $fields['langcode'], $fields['revision_created'], $fields['revision_user'], $fields['revision_log_message'], $fields['user_id'], $fields['changed'], $fields['revision_translation_affected'], $fields['default_langcode'], $fields['revision_default']); $field_options = []; foreach ($fields as $key => $field) { $field_options[$key] = $field->getLabel(); } // Get the real path to the uploaded file. $file_path = \Drupal::service('file_system')->realpath($this->file->getFileUri()); // Load the file as a spreadsheet. $spreadsheet = IOFactory::load($file_path); $worksheet = $spreadsheet->getActiveSheet(); // Is the header row included. $header_included = $form_state->getValue('header_included'); if ($header_included) { $start_row = 2; } else { $start_row = 1; } // Loop through the columns. $lastColumn = $worksheet->getHighestColumn(); for ($column = 'A'; $column <= $lastColumn; $column++) { $form['column_' . $column]['header'] = [ '#markup' => '<h4 class="title is-4">' . t('Column %column', ['%column' => $column]) . ($header_included ? ' (' . $worksheet->getCell($column . '1') . ')' : '') . '</h4>', ]; $example_values = $worksheet->rangeToArray($column . $start_row . ':' . $column . ($start_row + 2)); $form['column_' . $column]['examples'] = [ '#markup' => '<div class="columns"><div class="column is-one-third"><p class="content"><strong>' . t('Example values:') . '</strong><br/>' . implode("<br/>", [ $example_values[0][0], $example_values[1][0], $example_values[2][0], ]) . '</p></div>', ]; $form['column_' . $column]['field_' . $column] = [ '#type' => 'select', '#options' => $field_options, '#empty_option' => t('- Not used -'), '#prefix' => '<div class="column">', '#suffix' => '</div></div>', ]; // Try to guess the field based on header. if ($header_included) { $form['column_' . $column]['field_' . $column]['#default_value'] = $this->guessField($worksheet->getCell($column . '1')->getValue(), $field_options); } } $form['submit'] = [ '#type' => 'submit', '#value' => t('Import'), ]; } else { $form['file'] = [ '#type' => 'file', '#title' => t('File upload'), '#upload_validators' => [ 'file_validate_extensions' => ['csv xls xlsx ods'], 'file_validate_size' => [file_upload_max_size()], ], '#description' => t('Allowed file extensions') . ': csv, xls, xlsx, ods', ]; $form['header_included'] = [ '#type' => 'checkbox', '#title' => t('First row of file is headers'), ]; $form['submit'] = [ '#type' => 'submit', '#value' => t('Import'), ]; $form['instructions'] = [ '#markup' => '<h4 class="title is-4">' . t('Instructions') . '</h4> <div class="content"><p>' . t('Upload a spreadsheet file containing the member data.') . '</p> <p>' . t('In the next step you can choose field relations between the spreadsheet data and Pino database.') . '</p> <p>' . t('Here are some tips for correct data handling:') . '</p> <ul> <li>' . t("Dates (like Join date) will be parsed using PHP's strtotime function, so no specific format is necessary") . '</li> <li>' . t('Booleans (like Is Active field) are handled as that empty fields are negative, and any data found is positive') . '</li> <li>' . t('Entity references (like Position field) have to be comma-separated text values. If only one value is present, commas are not required') . '</li> </ul></div>', ]; } return $form; } /** * {@inheritdoc} */ public function validateForm(array &$form, FormStateInterface $form_state) { // Step 2 requires no validation. if ($this->step == 2) { return; } $this->file = file_save_upload('file', $form['file']['#upload_validators'], FALSE, 0); if (!$this->file) { $form_state->setErrorByName('file', $this->t('File could not be uploaded.')); } $uploaded_files = $this->getRequest()->files->get('files', []); $form_state->setValue('file', $uploaded_files['file']->getRealPath()); $form_state->setValue('file_extension', $uploaded_files['file']->getClientOriginalExtension()); } /** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { // In step 1, rebuild the form, save the values and set the step to 2. if ($this->step == 1) { $form_state->setRebuild(); $this->step = 2; $this->data = $form_state->getValues(); return; } /* This is step 2, create a batch for rows * Get the real path to the uploaded file */ $file_path = \Drupal::service('file_system')->realpath($this->file->getFileUri()); // Load the file as a spreadsheet. $spreadsheet = IOFactory::load($file_path); $worksheet = $spreadsheet->getActiveSheet(); // Create relations between the Drupal field and spreadsheet column. $field_relations = []; $lastColumn = $worksheet->getHighestColumn(); $a = 0; for ($i = 'A'; $i <= $lastColumn; $i++) { $field_relations[$a] = $form_state->getValue('field_' . $i); $a++; } $rows = $worksheet->toArray(); // Skip the header row if necessary. if ($this->data['header_included']) { array_shift($rows); } $operations = []; foreach ($rows as $row) { $operations[] = ['member_import_batch_import', [$row, $field_relations]]; } $batch = [ 'title' => t('Importing new members'), 'operations' => $operations, 'finished' => 'member_import_batch_import_finished', 'init_message' => t('Starting to import new members.'), 'progress_message' => t('Processed @current out of @total. Estimated time: @estimate.'), 'error_message' => t('The importing process has encountered an error.'), 'file' => drupal_get_path('module', 'member_import') . '/member_import.batch.inc', ]; batch_set($batch); } /** * Guess the Drupal field from spreadsheet header field. */ private function guessField($field, $field_options) { // Header is named the same as the Drupal field. if (array_key_exists($field, $field_options)) { return $field; } $correct_field = ""; // Some common field names. switch (mb_strtolower($field)) { case 'full name': return 'name'; case 'email': case 'email address': return 'field_email_address'; case 'active': return 'field_is_active'; case 'join date': case 'joined': return 'field_join_date'; case 'description': case 'additional information': case 'notes': return 'field_notes'; case 'resignation': case 'resignation date': return 'field_resignation_date'; case 'title': case 'position': return 'field_position'; } return ''; } }