Created
November 23, 2017 00:07
-
-
Save swichers/d0141a3ab14d93835d09943684480ee0 to your computer and use it in GitHub Desktop.
drush 8 command to rebuild Drupal 8 field mappings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @file | |
* Drush command implementation for rebuild-field-map. | |
* | |
* This will allow rebuilding the field mapping stored in the key value store | |
* for a given entity type. This is helpful when trying to repair a corrupted | |
* field map store without having to add and remove fields. | |
*/ | |
/** | |
* Implements HOOK_drush_command(). | |
*/ | |
function rebuild_field_map_drush_command() { | |
$items = []; | |
$items['rebuild-field-map'] = [ | |
'description' => dt('Rebuilds the bundle field maps inside the key value store.'), | |
'arguments' => [ | |
'type' => dt('The entity type to rebuild field maps for.'), | |
], | |
'options' => [ | |
'force' => dt('Force rebuilding even if no additions or removals were detected.'), | |
], | |
'examples' => [ | |
'drush rfm node --force' => dt('Rebuild the field mappings for nodes and ignore if no changes were detected.'), | |
'drush rfm paragraph' => dt('Rebuild the field mappings for paragraphs'), | |
], | |
'aliases' => ['rfm'], | |
'command-hook' => 'rebuild', | |
'required-arguments' => TRUE, | |
'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL, | |
]; | |
return $items; | |
} | |
/** | |
* Process the rebuild command from the user. | |
* | |
* @param string $entity_type | |
* The type of entity to rebuild mappings for. | |
* | |
* @return bool | |
* TRUE on success, FALSE otherwise. | |
*/ | |
function drush_rebuild_field_map_rebuild($entity_type) { | |
$bundle_key_value = \Drupal::service('keyvalue') | |
->get('entity.definitions.bundle_field_map'); | |
$new_mapping = rebuild_field_map_get_bundle_map_by_entity_type($entity_type); | |
$existing_map = $bundle_key_value->get($entity_type); | |
$to_be_added = array_diff_key($new_mapping, $existing_map); | |
$to_be_removed = array_diff_key($existing_map, $new_mapping); | |
$has_changes = !empty($to_be_added) || !empty($to_be_removed); | |
drush_print(dt('Rebuilding stored field mapping values for @entity_type.', ['@entity_type' => $entity_type])); | |
if ($has_changes) { | |
$rows = [ | |
[ | |
dt('Field'), | |
NULL, | |
dt('Change'), | |
], | |
]; | |
$rows = array_merge( | |
$rows, | |
rebuild_field_map_list_to_table_row($to_be_added, dt('Add')), | |
rebuild_field_map_list_to_table_row($to_be_removed, dt('Remove')) | |
); | |
drush_print_table($rows, TRUE); | |
if (!empty($to_be_added)) { | |
drush_print(\Drupal::translation() | |
->formatPlural(count($to_be_added), | |
'@count item will be added.', | |
'@count items will be added.'), 2); | |
} | |
if (!empty($to_be_removed)) { | |
drush_print(\Drupal::translation() | |
->formatPlural(count($to_be_removed), | |
'@count item will be removed.', | |
'@count items will be removed.'), 2); | |
} | |
} | |
else { | |
drush_log(dt('There are no changes to be made. The stored field mapping matches the generated one.'), 'ok'); | |
} | |
if ($has_changes || drush_get_option('force', FALSE)) { | |
if (drush_confirm(dt('Rebuild the field map? This action cannot be undone.'))) { | |
$bundle_key_value->set($entity_type, $new_mapping); | |
drupal_flush_all_caches(); | |
drush_log(dt('The field mapping has been rebuilt.'), 'success'); | |
} | |
else { | |
return drush_user_abort(); | |
} | |
} | |
return TRUE; | |
} | |
/** | |
* Convert a field mapping array into a drush table value. | |
* | |
* @param array $map | |
* The field mapping array keyed by the field name. | |
* @param string $action | |
* The action being taken on this set of mappings (Add, Remove). | |
* | |
* @return array | |
* A multivalued array that combines the action with the mapping. | |
*/ | |
function rebuild_field_map_list_to_table_row(array $map, $action) { | |
return drush_key_value_to_array_table( | |
array_combine( | |
array_keys($map), | |
array_pad([], count($map), $action) | |
) | |
); | |
} | |
/** | |
* Gets the field mappings for the given entity type. | |
* | |
* @param string $entity_type | |
* The type of the entity to generate field mappings for. | |
* | |
* @return array | |
* An array of field mappings ready to store in the key value store. | |
*/ | |
function rebuild_field_map_get_bundle_map_by_entity_type($entity_type) { | |
$bundle_field_map = []; | |
$entity_manager = \Drupal::service('entity_field.manager'); | |
$bundle_info = \Drupal::service('entity_type.bundle.info') | |
->getBundleInfo($entity_type); | |
foreach ($bundle_info as $bundle => $info) { | |
$definitions = $entity_manager->getFieldDefinitions($entity_type, $bundle); | |
if (empty($definitions)) { | |
continue; | |
} | |
// Filter out the definitions that are not of the target type. | |
// @todo This filter was based on what was in the current field mapping vs | |
// what was being returned by getFieldDefinitions(). Is there a way to get | |
// the list already filtered to this point? | |
$definitions = array_filter($definitions, function ($definition) { | |
return $definition instanceof \Drupal\Field\Entity\FieldConfig; | |
}); | |
if (!empty($definitions)) { | |
foreach ($definitions as $field_definition) { | |
// Mimicking Drupal core behavior by pulling bundle and name from the | |
// definition instead of using the existing bundle and name variables. | |
$field_bundle = $field_definition->getTargetBundle(); | |
$field_name = $field_definition->getName(); | |
if (!isset($bundle_field_map[$field_name])) { | |
// This field did not exist yet, initialize it with the type and empty | |
// bundle list. | |
$bundle_field_map[$field_name] = [ | |
'type' => $field_definition->getType(), | |
'bundles' => [], | |
]; | |
} | |
$bundle_field_map[$field_name]['bundles'][$field_bundle] = $field_bundle; | |
} | |
} | |
} | |
return $bundle_field_map; | |
} |
Ok thank you, but this did not remove my bug :/
Table mapping contains invalid field langcode. dans Drupal\Core\Entity\Sql\SqlContentEntityStorage->mapToStorageRecord()
Do you have any idea please ?
Thank you
You can add it to a custom module. You would need to name it "rebuild_field_map". Here's an example https://github.com/rakeshjames/custom_drush_command
That set, this was written 2 years ago. Drush has made many changes since then. Those instructions are for Drush 8 when Drush 9 is the current version. This code will not work for Drush 9.
Wanted to let you know this works perfectly for me at Drush 10 + Drupal 8, so thank you!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You can add it to a custom module. You would need to name it "rebuild_field_map". Here's an example https://github.com/rakeshjames/custom_drush_command
That set, this was written 2 years ago. Drush has made many changes since then. Those instructions are for Drush 8 when Drush 9 is the current version. This code will not work for Drush 9.