Saturday 19 February 2011

field_delete_field ooops

I'm in the process of converting a D6 module to several D7 module.

The original required manual set up of a node type and attaching various CCK fields before being able to run - a perfectly OK scenario for Drupal 6. However for D7 I wanted the module to create the node and attach the fields automagically - a perfectly acceptable scenario for Drupal 7. (I've learned only too well recently that entities, though powerful, require a lot of effort so that conversion can wait.)

One thing I've done is extracted the specialist field I need into its own module - in a similar fashion to the various field modules (text, number and so on).

So I put it together and installed on a minimum D7 installation. All good. I uninstall and then reinstall - and en exception gets thrown because the DB tables for my new field have not been renamed. Drupal 7, for speed, renames discarded tables then deletes them at its leisure during hook_cron.

I know this process works because I've seen it in action - when I've been creating fields through the User Interface. But it was failing during hook_uninstall() - in other words field_delete_field() just fails completely but without reporting an error.

Turns out this is a known bug. And it's because when a module is disabled its fields are tagged as inactive and the routine that collects the file_info does not collect information about inactive fields.

The only solution is to use this function from the field.install file:


function _update_7000_field_delete_field($field_name) {
  $table_name = 'field_data_' . $field_name;
  if (db_select($table_name)->range(0, 1)->countQuery()->execute()->fetchField()) {
    $t = get_t();
    throw new Exception($t('This function can only be used to delete fields without data'));
  }
  // Delete all instances.
  db_delete('field_config_instance')
    ->condition('field_name', $field_name)
    ->execute();


  // Nuke field data and revision tables.
  db_drop_table($table_name);
  db_drop_table('field_revision_' . $field_name);


  // Delete the field.
  db_delete('field_config')
    ->condition('field_name', $field_name)
    ->execute();
}

There is a patch on the go for fixing but this will have to do until it arrives.

No comments: