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 '';
}
}
