On uninstall, og does not remove the fields it created, leading to errors on re-installation/activation.

To reproduce (I did this with the current github version on RC2 of core):

1. On a new D7 install, downlad and activate the og module.
2. Deactivate the og module.
3. Go to the "uninstall" tab and uninstall the module.
4. Activate the og module and behold:

"FieldException: Attempt to create field name group_audience which already exists, although it is inactive. in field_create_field() (line 277 of /Users/slauer/Sites/drupal7/modules/field/field.crud.inc)."

Similar things happen with some of the other submodules.

I am happy to roll a patch to fix this, but wanted to get feedback first: What I would do is remove the fields in the uninstall hook. Is this correct? Or is there a field API way to do this automatically? (I have quite some experience with D6, but am just getting started with the new parts of the D7 API ...

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

sven.lauer’s picture

Related core issue: #366152: field_modules_uninstalled still exists, despite being an empty foreach loop.

It seems that, at some point, the idea was to auto-delete fields on uninstall of the module that owns it, but this was never implemented. The discussion in the issue referenced above suggests that this may never happen.

In any case, even if this gets implemented at some point, the question is what og should do in the mean time. As deleting the fields in the uninstall hook does not create any problems even if the auto-deletion gets implemented in the future, I think the best thing to do is for og modules to take care of the field deletion by themselves (for now).

Any thoughts?

amitaibu’s picture

> I am happy to roll a patch to fix this
...
> Any thoughts?

Nice catch, Would be great if you indeed could roll a patch.

sven.lauer’s picture

Looking into this some more, I find that og_create_field actually does check if the field exists before attempting to create it, which should make the existence of an old field a non-issue.

   $field = field_info_field($field_name);
    if (empty($field)) {
      $field = field_create_field($group_field['field']);
    }

The problem is that field_info_field does only return an array if the field in question is 'active'. However, when uninstalling og, the fields that it owns are automatically marked 'inactive' in the database. This means that the above code will always do the wrong thing if $field_name is the name of an inactive field.

(The API doc for field_info_field does not specify that only active fields will be returned. I will file an issue for this in a second. field_info_field uses _field_info_collate_fields, which in turn calls field_read_fields without 'include_inactive' => TRUE in the second argument.)

Two possible solutions: (a) change the test in og_create_field so as to test the right thing, or (b) as suggested above, have the uninstall hook remove the fields owned by the module. The latter seems to be the right thing to me, but maybe I am overlooking something.

amitaibu’s picture

OG code was already doing (a), but I've decided to change it, since it's not a pattern core does. So I think we should go with (b).

sven.lauer’s picture

Okay, I'll probably have a patch ready by tomorrow.

sven.lauer’s picture

Status: Active » Needs review
FileSize
2 KB

Here is a patch. That does not work. But it should.

It will work as soon as #943772: field_delete_field() and others fail for inactive fields is fixed. Until this happens, there is hardly any way in which a module can clean up after itself in terms of fields it creates. (I still have to review the detail of the final patch there, but in conjunction with the attached patch, it works very well.)

The helper function og_delete_fields I define should be in core, or at least in a utility module, but for now, I guess it it okay where it is.

Note that even before the core bug gets fixed, og does not behave worse WITH the attached patch than without: Without the patch, re-enabling after uninstall will result in an error because an existing field is attempted to be created. With the patch, this does not happen, but until the core bug is fixed, re-enabling og.module will result in an error because re-creating the field attempts to create a database table that exists because it has not been properly cleaned up.

Which is to say: The patch does not make matters worse (it makes things slightly better: things break a little later ;). At the same time, as soon as the core bug is fixed, everything will work fine with the patch. So I advocate for committing it, even though it does not solve the problem right now.

amitaibu’s picture

We have og_fields_info() that get all the fields related to OG, and it also has the module info. So og_delete_fields() can take care for all OG modules by implementing hook_modules_uninstalled() and deleting the fields for them.

sven.lauer’s picture

I had thought of using og_fields_info(), but the problem is that at modules_uninstalled time, the module will be disabled (and partially uninstalled)---and module_implements(), module_invoke() etc. only work on installed, enabled modules. The only way this could be made to work if we change og_fields_info() into an install hook (i.e. one that lives in the .install files) and than use module_load_install() to get at that hook. Which would still be fairly costly (as we would have to do this on every module uninstall, just to figure out whether the module implements og_fields_info() ... or am I missing something?

amitaibu’s picture

Priority: Major » Normal
Status: Needs review » Needs work

> but the problem is that at modules_uninstalled time

You are right.

+++ b/og.install
@@ -29,6 +29,7 @@ function og_uninstall() {
+  og_delete_fields('og');

Please patch against HEAD.

+++ b/og_language/og_language.install
@@ -7,6 +7,13 @@
 /**
+  * Implements hook_uninstall().
+  */
+function og_uninstall() {
+  og_delete_fields('og_language');
+}

Something is wrong here, og_uninstall already exists. Please patch against HEAD.

Also when you patch use git diff --no-prefix.

Powered by Dreditor.

sven.lauer’s picture

I am confused ... have I been pulling from the wrong repository? I have been using git://github.com/amitaibu/og.git and your commits came through there ... but https://github.com/amitaibu/og/blob/master/og_language/og_language.install does not have an implementation of og_uninstall(). So I must be doing something wrong. Can you give me a pointer?

sven.lauer’s picture

Of course you are right, though, that I forgot the --no-prefix. Here is a version of the patch that is identical with the prior one, except that it is generated with --no-prefix ...

sven.lauer’s picture

Status: Needs work » Needs review
FileSize
3.39 KB

And NOW I realize how stupid I am: I misnamed the hook implementations. Sorry about that.

This one should do the right thing.

amitaibu’s picture

Status: Needs review » Needs work
+++ og.test
@@ -568,4 +568,32 @@ class OgGroupudienceField extends DrupalWebTestCase {
+* Test (un)installing and re-installing.

Maybe better "Test re-installation of module." ?

+++ og.test
@@ -568,4 +568,32 @@ class OgGroupudienceField extends DrupalWebTestCase {
+      'group' => 'Organic groups-Sven',

OG-Sven ;)

+++ og.test
@@ -568,4 +568,32 @@ class OgGroupudienceField extends DrupalWebTestCase {
+      drupal_uninstall_modules(array('og'),FALSE);

Missing space.

+++ og.test
@@ -568,4 +568,32 @@ class OgGroupudienceField extends DrupalWebTestCase {
+      $this->assertTrue(empty($og_fields), 'Uninstalling og module removes all fields owned by the module.');

You can use assertFalse here.

+++ og_ui/og_ui.install
@@ -0,0 +1,14 @@
+/**
+  * Implements hook_uninstall().
+  */
+function og_ui_uninstall() {
+  og_delete_fields('og_ui');
+}

og-ui doesn't declare any field, so this isn't needed.

Powered by Dreditor.

amitaibu’s picture

> You can use assertFalse here.

Sorry, this is not correct, you did it right.

sven.lauer’s picture

Status: Needs work » Needs review
FileSize
3.39 KB

> Maybe better "Test re-installation of module." ?

Done.

> OG-Sven ;)

Ups. Fixed.

> Missing space.

Fixed.

> > You can use assertFalse here.

> Sorry, this is not correct, you did it right.

I did, at that point. But the assertion after that really should be assertFalse():

+ $this->assertTrue(!empty($modules['og']), 'Enabling og module after uninstall is sucessful.');

Fixed.

> og-ui doesn't declare any field, so this isn't needed.

What about

function og_ui_field_settings_submit($form, &$form_state) {
  $bundle = preg_replace('/^.*__/i', '', $form_state['values']['bundles']);
  $entity_type = str_replace('__' . $bundle, '', $form_state['values']['bundles']);
  $field_name = $form_state['values']['fields'];

  og_create_field($field_name, $entity_type, $bundle);

?

(There were like, three more mistakes wrt to function signatures in the test case as well. Also fixed.)

amitaibu’s picture

Status: Needs review » Needs work

> function og_ui_field_settings_submit($form, &$form_state) {

OG-ui is only a UI to allow users to add all teh different OG fields to bundles. It doesn't declare a field of its own.

However, you should add the uninstall to og_node_link and og_views -- as they declare their own fields.

sven.lauer’s picture

Uh-oh. This is even more tricky. I was supposing (without much thinking) that the module that creates the field owns it. Which is not true, the module that defines the FIELD TYPE owns it. Which actually means that fields like "og_views" will be neither owned by og_ui (even if created through it), nor doe og_views (which defines the field in the og_field_info hook), but by the "list" module.

Which means that the current og_delete_fields() function will only really work on the audience field. Which is just as well, as even the fields created in, e.g. og_theme's install hook will simply remain active and undeleted if og_theme is deactivated or de-installed. Which means that the test in og_create_field() will
do the right thing, and upon re-installation, there will be no attempt on re-creating the field.

Which means the only issue really is the audience field---so, maybe, we should just remove this one with a simple field_delete_field() call in og_uninstall and leave it at that.

It would be more clean, of course, to also remove the other fields, but in order to be able to do that, we would have to either have og_create_field() create a record somewhere or find a way to make hook_og_field_info() visible at uninstall time.

Since what is really breaking things right now is the audience field, I'd suggest we go with the conservative approach and just delete that field on uninstall, allowing the possibility of ghost fields for the other modules (they will not really be ghost fields ... just og-specific fields that don't do their magic anymore).

sven.lauer’s picture

Status: Needs work » Needs review
FileSize
1.8 KB

This patch employs the 'conservative' approach mentioned above. It fixes the issue in that uninstall removes all fields of type "group", which are what really made things break.

Fields created by og modules that are of other types will remain undeleted and active, but there does not seem to be a sane way to fix this right now. Also, because they stay active, the tests for existence in og_create_group do the right thing on re-install, so nothing breaks.

The remarks with respect to #943772: field_delete_field() and others fail for inactive fields still apply: The current patch will only work once that issue is fixed, but it does not make matters worse. Sadly, the referenced issue is not moving forward, even though there is a working patch ...

amitaibu’s picture

Status: Needs review » Needs work
FileSize
0 bytes

I have changed a bit the text and fixed coding standards (attached). Biggest problem is that the test fails :/

DatabaseSchemaObjectExistsException: Table <em class="placeholder">field_data_group_audience</em> already exists. in DatabaseSchema->createTable() (line 623 of /var/www/d7_dev/includes/database/schema.inc).
amitaibu’s picture

sven.lauer’s picture

Yes, but the test fails because of #943772: field_delete_field() and others fail for inactive fields --- and it does fails two lines later than before the patch ;).

But I am stupid---we can just mark the field data and instances to be deleted by hand.

A working patch is attached, with a rather lengthy inline comment explaining why we do the work of field_delete_field().

sven.lauer’s picture

Status: Needs work » Needs review
amitaibu’s picture

Status: Needs review » Reviewed & tested by the community

great. If I miss #943772: field_delete_field() and others fail for inactive fields please ping me, so we can remove the workaround. Simpletest is great! Fixed on github.

amitaibu’s picture

Status: Reviewed & tested by the community » Fixed

Fixed on CVS

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

BrightBold’s picture

Status: Closed (fixed) » Active

Did this fix make it into the release version (looks like it should have, based on the dates) or is it only in dev? I am having this problem with 7.x-1.0.

amitaibu’s picture

Status: Active » Fixed

Please don't open a closed issue. If you have a problem in 7.x-1.0 it means that the fix is probably on the -dev...

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

digitopo’s picture

Status: Closed (fixed) » Active

I have installed OG 7.x-1.x-dev and am trying to create a sub-group but am running into this error:

I created a content type for the group and set it to "Group Type" on the edit form. When I also select the radio button for "Group content type" I get the following error after submit:

FieldException: Attempt to create field name group_audience which already exists, although it is inactive. in field_create_field() (line 81 of .../d7/modules/field/field.crud.inc).

I am following the directions from this page http://drupal.org/node/1114890 on how to make a sub-group.

Click on Group Tab and set "Group" raido selector to "Group Type". "Group Content" radio selector should remain "Not a Group content type" unless you want the Group to be able to be a sub group of another group

Can anyone help resolve this issue? I tried applying the patch in this thread but it seems that it's already been committed to the dev release.

JamFar’s picture

Inside the Organic group fields settings, I am getting the following error:

Notice: Undefined index: label in og_ui_field_settings() (line 667 of /home/myuser/public_html/sites/all/modules/og/og_ui/og_ui.admin.inc).

I have the most current 7.x-1.x-dev

bjlewis2’s picture

I also get this inside the Organic group field settings using the July 7th dev version:
Error message
Notice: Undefined index: label in og_ui_field_settings() (line 667 of C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\website\d7\sites\all\modules\og\og_ui\og_ui.admin.inc).

Is this related, or should it be in its own issue queue?

amitaibu’s picture

> Is this related, or should it be in its own issue queue?

new issue.

BrightBold’s picture

@digitopo — If you had previously installed and then uninstalled OG, you might be having the same problem I was. The steps I used to resolve it are detailed in #1182966: Cannot fully uninstall or reinstall OG and involve manually deleting things form the database.

  • 56c303f committed on 8.x-1.x
    #997714 by sven.lauer: Fixed OG does not clean up after itself on...
  • amitaibu committed 698dfc9 on 8.x-1.x
    #997714 by sven.lauer: Fixed OG does not clean up after itself on...