I am building two modules: one that provides a field type, and one that provides an entity type that automatically creates an instance of that field on the entity during hook_enable(). In hook_uninstall of the entity's module, I'm calling field_delete_instance() and field_delete_field() to mark the field and instance as "deleted" so it can be cleaned up on the next cron run.
When I uninstall the entity module, it successfully marks the field and instance as "deleted." When I run cron, however, the field is deleted from the {field_config} table, but the instance is NOT deleted from the {field_config_instance} table.
After a little digging, I think it is impossible for this to work as expected, based on the code in field.crud.inc. Here's why...
field_purge_batch() is responsible for cleaning up fields and field instances that have been marked as "deleted" in the database. The first thing it does is loads up all the "deleted" instances:
// Retrieve all deleted field instances. We cannot use field_info_instances()
// because that function does not return deleted instances.
$instances = field_read_instances(array('deleted' => 1), array('include_deleted' => 1));
field_read_instances() is used to look up the field instances that are marked as "deleted". However, the function filters out any instances for entity types that don't exist, so they are not returned back to the field_purge_batch() function, and are never deleted.
Here is the code in field_read_instances() that filters out disabled entities:
...
$instances = array();
$results = $query->execute();
foreach ($results as $record) {
// Filter out instances on unknown entity types (for instance because the
// module exposing them was disabled).
$entity_info = entity_get_info($record['entity_type']);
if ($include_inactive || $entity_info) {
$instance = unserialize($record['data']);
$instance['id'] = $record['id'];
$instance['field_id'] = $record['field_id'];
$instance['field_name'] = $record['field_name'];
$instance['entity_type'] = $record['entity_type'];
$instance['bundle'] = $record['bundle'];
$instance['deleted'] = $record['deleted'];
module_invoke_all('field_read_instance', $instance);
$instances[] = $instance;
}
}
return $instances;
I will be happy to put together a patch to fix this, but I'm not entirely sure what the best approach is.
Why is field_read_instances() filtering out the disabled instances in the first place?
Comment | File | Size | Author |
---|---|---|---|
#17 | field_purge_inactive-1340390-17.patch | 757 bytes | greenSkin |
Comments
Comment #1
NimbyDagda CreditAttribution: NimbyDagda commentedNot quite sure why nobody else has responded to this, but we have just come across the exact same problem, and since it functionally means you can't properly clean up on your modules uninstallation I would have though more people would be worried about this.
As a temporary measure we have written our own version of field_purge_batch to be used, but I think its worth having the discussion about how this should be resolved properly. I am not entirely sure why field_purge_batch doesn't pass the include_inactive flag, I can't think of any reason why you would have a field marked as deleted that shouldn't be purged just because the entity is inactive.
Comment #2
fravemel CreditAttribution: fravemel commentedSame Issue in drupal 7.12.
I agree with you, fields instances from table field_config_instance are marked as deleted but never removed. Although you run cron, execute field_purge_batch() or empty cache.
when you get this situation instances will nerver be removed becouse in field_read_instances() it joins field_config_instance with field_config tables and as field config has been removed ¿?¿?
but why are removed config before instances¿? if my code does it the oposite.
the code to remove field is
Any clue?
Comment #3
marcoka CreditAttribution: marcoka commentedconfirmed, using field_collection
Comment #4
m.stentaI haven't tested this recently, but the version should be 7.x-dev. Not 7.12... otherwise it will get swept under the rug.
Comment #5
ghalenir CreditAttribution: ghalenir commentedI also have the same problem and I don't know if I should fix myself or Drupal core team will fix this problem because we are not supposed to modify any Drupal core files.
Comment #6
nicorac CreditAttribution: nicorac commentedSame here, field_config row already deleted while field_config_instance not, so the join prevents any further deletion.
I'm developing a custom module and this lead me to a lot of orphaned rows into field_config_instance table (after some module install/uninstall).
Is anybody working on this?
Comment #7
michfuer CreditAttribution: michfuer commentedI ran into the same issue, and as well it's not clear to me why field_read_instances() filters out field instances on unknown entity types.
The workaround I used was to put all of the field/entity type creation hooks into one module, and all of the field base/instance creation (and removal) into another module. Then make the latter module dependent on the former. This ensures the entity type is available when uninstalling your module set.
Comment #8
DannyPfeiffer CreditAttribution: DannyPfeiffer commentedStill appears to be a bug as of Drupal 7.35 :-(
Comment #9
kris-o3 CreditAttribution: kris-o3 commenteddrush updatedb
Comment #10
liquidcms CreditAttribution: liquidcms commentedyes, 7.38 and this bug still remains.
i have numerous field_config and field_config_instance records marked as deleted as well as field_deleted_data_ tables which are never removed regardless of how many times i run cron or field_purge_batch().
Comment #11
jamesalvarez CreditAttribution: jamesalvarez as a volunteer commentedI'm getting a similar issue, I am trying to delete fields on uninstall, but the instances are not getting removed.
For my problem, I've traced the problem here:
field_delete_field calls, field_info_instance, which calls FieldInfo->getBundleInstance() which calls field_red_instances, which then calls entity_get_info.
The problem is that entity_get_info is calling hook_entity_info, and this hook isn't called on the module that's uninstalling, since it has been disabled already. Presumably, because it can't find the entity's info, it causes field_read_instances to return an empty array, and now cannot delete.
Way around:
In .install file create a function return array of instance arrays (e.g. with field_name, entity_type, bundle etc), which is access by book hook_install and hook_uninstall.
For the uninstall call field_delete_instance in each of the instance arrays, before deleting the field) - so basically delete them manually e.g.:
Install:
$instances = my_default_field_instances();
foreach ($instances as $instance) {
field_create_instance($instance);
}
Uninstall:
$instances = my_default_field_instances();
foreach ($instances as $instance) {
field_delete_instance($instance, TRUE);
}
Comment #12
donquixote CreditAttribution: donquixote as a volunteer commentedI have entries in field_config with deleted = 1 and active = 0.
These are never deleted on cron.
Comment #13
donquixote CreditAttribution: donquixote as a volunteer commentedI don't know if "uninstalled entities" is the only use case. So I rename the issue title.
The problem occurs whenever fields are marked as inactive but disabled.
I think this is a follow-up to #943772: field_delete_field() and others fail for inactive fields (which was 5 years ago)
Comment #14
donquixote CreditAttribution: donquixote as a volunteer commentedBtw,
"Dynamic" return type, yeah!
Comment #15
donquixote CreditAttribution: donquixote as a volunteer commentedAnd one can ask why this is called with 1 instead of TRUE.
It does not make a difference in behavior, it is just weird.
Comment #16
donquixote CreditAttribution: donquixote as a volunteer commentedFrom #998048: field_info_field only works for active fields - document that comment #11 (yched):
From #2826320: Inactive fields cause "This module has been deleted from the file system":
Comment #17
greenSkin CreditAttribution: greenSkin commentedRan into this issue when looking at purging instances created by our custom module when the custom module is uninstalled.
The field_purge_batch() currently has an issue where a field can be purged when inactive and end up leaving rows of instances within the {field_config_instance} table that are otherwise marked for deletion. The field_read_instances() filters out instances belonging to inactive fields resulting in field_purge_batch() not being able to purge instances of inactive fields but can still purge the field despite it. Once the field has been deleted, the query in field_read_instances() function will never return instances that don't have a field to join with.
This patch simply allows the field_purge_batch() function to purge inactive instances when loading instances marked to be deleted.
Comment #18
Darren OhPatch looks good. It allows inactive instances to be deleted, but we still need the patch in #2337139: Fields with instances attached to unknown entities are deleted on cron run if the batch size is smaller than the number of instances that need to be deleted.
Comment #19
JParkinson1991 CreditAttribution: JParkinson1991 commentedPatch throws FatalErrors when run in the context of the entity that was using the instance being removed from the system.
Essentially, provide a fieldable entity via a module, install it, add a bundle and fields to that bundle, add entities of that bundle, uninstall the module.
Options are either, don't use this patch and accept orphan data in
field_config_instance
and all usedfield_data_FIELD_NAME
andfield_revision_FIELD_NAME
or manually clear out this data in the uninstallation hook.Comment #20
poker10 CreditAttribution: poker10 at ActivIT s.r.o. commentedTested the patch and I can confirm fatal error as mentioned in #19.