-
-
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?