-
-
Save swichers/d0141a3ab14d93835d09943684480ee0 to your computer and use it in GitHub Desktop.
<?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; | |
} |
@criley Here's an attempt I made: drush 9 command to rebuild Drupal 8.4+ field mappings
How can I execute this script please ? Drush dose not recognise it :
The drush command 'rebuild-field-map' could not be found
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.
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!
Any chance of a Drush 9 version of this?