class MetatagImport in Metatag Import Export CSV 8
Class for batch process for metatag import.
Hierarchy
- class \Drupal\metatag_import_export_csv\MetatagImport
Expanded class hierarchy of MetatagImport
1 file declares its use of MetatagImport
- MetatagImportTest.php in tests/
src/ Kernel/ MetatagImportTest.php
File
- src/
MetatagImport.php, line 11
Namespace
Drupal\metatag_import_export_csvView source
class MetatagImport {
/**
* Validate the CSV header row.
*
* Helper for validate_csv_header().
*
* @param \Drupal\file\FileInterface $file
* The uploaded file.
*
* @return array
* An array of errors.
*/
public static function validateCsvHeader(FileInterface $file) {
$url = $file
->getFileUri();
$filepath = file_create_url($url);
$handle = fopen($filepath, 'r');
$headers = fgetcsv($handle);
// Close the CSV file, as the batch setup needs to open it from the top.
fclose($handle);
$errors = [];
if (!in_array('path_alias', $headers)) {
if (!in_array('entity_type', $headers)) {
$errors[] = t("The CSV must have an 'entity_type' column if it does not have a 'path_alias' column.");
}
if (!in_array('entity_id', $headers)) {
$errors[] = t("The CSV must have an 'entity_id' column if it does not have a 'path_alias' column.");
}
}
return $errors;
}
/**
* Batch callback for parsing the CSV.
*
* @param array $headers
* The header row of the CSV file. This must contain an 'entity_type' and
* 'entity_id' column.
* @param array $filepath
* The filepath to the uploaded CSV file.
* @param array $context
* The batch context.
*/
public static function importCsvBatchOperation($headers, $filepath, &$context = []) {
// Initial setup on the first operation.
if (empty($context['sandbox'])) {
$context['sandbox']['handle'] = NULL;
$context['sandbox']['pointer_position'] = 0;
$context['sandbox']['csv_line'] = 0;
$context['results']['success'] = [];
$context['results']['error'] = [];
}
if (!is_resource($context['sandbox']['handle'])) {
$context['sandbox']['handle'] = fopen($filepath, 'r');
}
// If we've reached the end of the file, we're done.
if (feof($context['sandbox']['handle'])) {
$context['finished'] = 1;
return;
}
if ($context['sandbox']['pointer_position'] == 0) {
// On the first operation, discard the CSV header row.
fgetcsv($context['sandbox']['handle']);
$context['sandbox']['csv_line']++;
}
else {
// On subsequent operations, move the pointer to where it was for the last
// operation.
fseek($context['sandbox']['handle'], $context['sandbox']['pointer_position']);
}
// Get the data, and update our stored pointer.
$data = fgetcsv($context['sandbox']['handle']);
$context['sandbox']['csv_line']++;
$context['sandbox']['pointer_position'] = ftell($context['sandbox']['handle']);
try {
$entity = static::importCsvRow($headers, $data);
$context['results']['success'][$entity
->getEntityTypeId()][] = $entity
->id();
} catch (\Exception $e) {
$context['results']['error'][] = t("Unable to import line @line of the CSV. Error was: '@message'.", [
'@line' => $context['sandbox']['csv_line'],
'@message' => $e
->getMessage(),
]);
}
// We're not finished until we reach the end of the CSV file.
$context['finished'] = 0;
}
/**
* Imports a single row of data from the CSV.
*
* @param array $headers
* The header row of the CSV file.
* @param array $data
* A data row of the CSV file.
*
* @return
* The entity which has been updated by the CSV row.
*
* @throws \Exception
* Throws an exception if there was a problem finding or saving the entity.
*/
public static function importCsvRow($headers, $data) {
$entity_type_index = array_search('entity_type', $headers);
$entity_id_index = array_search('entity_id', $headers);
$language_index = array_search('language', $headers);
$path_alias_index = array_search('path_alias', $headers);
$entity = [];
if ($entity_type_index !== FALSE && $entity_id_index !== FALSE) {
$entity_type = trim($data[$entity_type_index]);
$entity_id = trim($data[$entity_id_index]);
}
if ($path_alias_index !== FALSE) {
$path_alias = trim($data[$path_alias_index]);
}
if (!(!empty($entity_type) && !empty($entity_id) || !empty($path_alias))) {
throw new \Exception(t("Either both of entity_id and entity_type or path_alias must be specified."));
}
if ($language_index !== FALSE) {
$langcode = trim($data[$language_index]);
}
// Resolve the path alias if that is being used.
if (!empty($path_alias)) {
$path = \Drupal::service('path_alias.manager')
->getPathByAlias($path_alias, $langcode ?? NULL);
$route_parameters = Url::fromUri("internal:" . $path)
->getRouteParameters();
$entity_type = key($route_parameters);
if (!\Drupal::service('entity_type.manager')
->hasDefinition($entity_type)) {
throw new \Exception(t("The path alias '@alias' does not correspond to an entity route.", [
'@alias' => $path_alias,
]));
}
$entity_id = $route_parameters[$entity_type];
}
if (!\Drupal::service('entity_type.manager')
->hasDefinition($entity_type)) {
throw new \Exception(t("The '@entity-type' entity type does not exist.", [
'@entity-type' => $entity_type,
]));
}
// Load the entity.
$entity = \Drupal::service('entity_type.manager')
->getStorage($entity_type)
->load($entity_id);
if (!$entity) {
throw new \Exception(t("No @entity-type with ID @entity-id was found.", [
'@entity-type' => $entity_type,
'@entity-id' => $entity_id,
]));
}
// Get the translation if the language is specified in the CSV data.
if (!empty($langcode)) {
if (!$entity
->hasTranslation($langcode)) {
throw new \Exception(t("The @entity-type with ID @entity-id has no @language translation.", [
'@entity-type' => $entity_type,
'@entity-id' => $entity_id,
'@language' => $langcode,
]));
}
$entity = $entity
->getTranslation($langcode);
}
$tags = [];
foreach ($headers as $keys => $values) {
if (trim($data[$keys]) == '_blank') {
$tags[$values] = "";
}
else {
$tags[$values] = $data[$keys];
}
}
// Remove non meta tags fields.
$metatag_machine_name = $tags['field_machine_name'];
unset($tags['entity_id'], $tags['entity_title'], $tags['entity_type'], $tags['alias'], $tags['field_machine_name']);
try {
$entity
->set($metatag_machine_name, serialize($tags));
$entity
->save();
} catch (\Exception $e) {
throw new \Exception(t("Error saving entity @entity-type @entity-id: '@message'.", [
'@entity-type' => $entity_type,
'@entity-id' => $entity_id,
'@message' => $e
->getMessage(),
]));
}
return $entity;
}
/**
* Batch finished callback for import.
*/
public static function importFinish($success, $results, $operations) {
$messenger = \Drupal::messenger();
if ($success) {
$message_entity_summary = [];
foreach ($results['success'] as $entity_type => $entity_ids) {
$entity_type_definition = \Drupal::service('entity_type.manager')
->getDefinition($entity_type);
$message_entity_summary[] = \Drupal::service('string_translation')
->formatPlural(count($entity_ids), '1 ' . $entity_type_definition
->getSingularLabel(), '@count ' . $entity_type_definition
->getPluralLabel());
}
if ($message_entity_summary) {
$messenger
->addMessage(t('Successfully updated entities: @summary.', [
'@summary' => implode(', ', $message_entity_summary),
]));
}
foreach ($results['error'] as $error_message) {
$messenger
->addError($error_message);
}
}
else {
$error_operation = reset($operations);
$messenger
->addMessage(t('An error occurred while processing @operation with arguments : @args', [
'@operation' => $error_operation[0],
'@args' => print_r($error_operation[0], TRUE),
]), 'error');
}
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
MetatagImport:: |
public static | function | Batch callback for parsing the CSV. | |
MetatagImport:: |
public static | function | Imports a single row of data from the CSV. | |
MetatagImport:: |
public static | function | Batch finished callback for import. | |
MetatagImport:: |
public static | function | Validate the CSV header row. |