I have a custom entity being a group content type.
When deleting entities of this type, the og_membership table is not cleaned.

Digging a bit, it seems that Entity API is calling field_attach_delete (which calls OgBehaviorHandler::delete) before invoking og_entity_delete. The result is that the delete_og_membership flag is not set when we look for it in OgBehaviorHandler::delete.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

DuaelFr’s picture

Assigned: DuaelFr » Unassigned
Status: Active » Needs review
FileSize
866 bytes

Here is a patch fixing this case.

This patch is part of the #1day1patch initiative.

VasilyKraev’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community

Same problem with stable 2.3 version. I apply this patch, and problem is gone.

RoySegall’s picture

I used the Entity Example from the examples module. I set here as the a group content type, added her to a group and then delete the entity and the OG membership was cleaned.

I think you have a problem in your Entity class.

DuaelFr’s picture

Here is my Entity class. As you can see, nothing can really be issuing this.
Plus, in the summary, I was talking about Entity API which is not used by entity_example.
Maybe it is an Entity API issue but their approach, cleaning fields before deleting the entities, seems legit.

/**
 * Main class for tracking_item entities.
 */
class TrackingItemEntity extends Entity {

  /**
   * Class constructor.
   */
  public function __construct(array $values = array(), $entityType = NULL) {
    parent::__construct($values, 'tracking_item');
  }

  /**
   * Specifies the default label, which is picked up by label() by default.
   */
  protected function defaultLabel() {
    $info = $this->entityInfo();
    $type = $info['bundles'][$this->bundle()]['label'];
    $label = $type . ' - ' . $this->identifier();

    switch ($this->bundle()) {
      case 'denunciation':
        $label = $this->wrapper()->field_gender->raw() . ' ' . $this->wrapper()->field_firstname->raw() . ' ' . $this->wrapper()->field_lastname->raw() . ' (' . $this->wrapper()->field_zipcode->raw() . ')';
        break;
    }

    return $label;
  }

  /**
   * Specifies the default uri, which is picked up by uri() by default.
   */
  protected function defaultURI() {
    return array('path' => 'tracking/' . $this->bundle() . '/' . $this->identifier());
  }
}
RoySegall’s picture

Can you supply you hook_schema and hook_entity_info? I would like to check this on my local machine.

DuaelFr’s picture

Sure

/**
 * Implements hook_entity_info().
 */
function mymodule_entity_info() {
  $entities = array();

  $entities['tracking_item'] = array(
    'label' => t('Tracking item'),
    'plural label' => t('Tracking items'),
    'description' => t('Tracking item for XXX'),
    'module' => 'mymodule',

    'controller class' => 'EntityAPIController',
    'views controller class' => 'EntityDefaultViewsController',
    'entity class' => 'TrackingItemEntity',

    'base table' => 'tracking_item',
    'revision table' => 'tracking_item_revision',

    'fieldable' => TRUE,
    'exportable' => FALSE,

    'label callback' => 'entity_class_label',
    'uri callback' => 'entity_class_uri',

    'entity keys' => array(
      'id' => 'trid',
      'revision' => 'vid',
      'bundle' => 'type',
    ),

    'bundles' => array(
      'bundle1' => array(
        'label' => t('Bundle 1'),
      ),
      'bundle2' => array(
        'label' => t('Bundle 2'),
      ),
    ),

    'view modes' => array(
      'default' => array(
        'label' => t('Default'),
        'custom settings' => FALSE,
      ),
    ),

    'admin ui' => array(
      'path' => 'admin/content/tracking',
      'file' => 'mymodule.admin.inc',
      'controller class' => 'EntityDefaultUIController',
      'menu wildcard' => '%tracking_item',
    ),
  );

  foreach ($entities['tracking_item']['bundles'] as $name => $bundle) {
    $entities['tracking_item']['bundles'][$name]['admin'] = array(
      'path' => 'admin/structure/tracking/manage/%tracking_type',
      'real path' => 'admin/structure/tracking/manage/' . str_replace('_', '-', $name),
      'bundle argument' => 4,
      'access arguments' => array('administer tracking'),
    );
  }

  return $entities;
}

/**
 * Implements hook_schema().
 */
function mymodule_schema() {

  $schema['tracking_item'] = array(
    'description' => 'A saved search that will be periodically executed.',
    'fields' => array(
      'trid' => array(
        'description' => 'The primary identifier for a tracking item.',
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      // Defaults to NULL in order to avoid a brief period of potential
      // deadlocks on the index.
      'vid' => array(
        'description' => 'The current {tracking_item_revision}.vid version identifier.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => FALSE,
        'default' => NULL,
      ),
      'type' => array(
        'description' => 'The bundle of this tracking item.',
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
      ),
      'uid' => array(
        'description' => 'The {users}.uid that owns this tracking item; initially, this is the user that created it.',
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ),
      'status' => array(
        'description' => 'Boolean indicating whether the tracking item is active.',
        'type' => 'int',
        'not null' => TRUE,
        'default' => 1,
      ),
      'created' => array(
        'description' => 'The Unix timestamp when the tracking item was created.',
        'type' => 'int',
        'not null' => TRUE,
      ),
      'changed' => array(
        'description' => 'The Unix timestamp when the tracking item was changed.',
        'type' => 'int',
        'not null' => TRUE,
      ),
    ),
    'indexes' => array(
      'tracking_changed' => array('changed'),
      'tracking_created' => array('created'),
      'tracking_type'    => array(array('type', 4)),
      'uid'              => array('uid'),
    ),
    'foreign keys' => array(
      'tracking_revision' => array(
        'table' => 'tracking_item_revision',
        'columns' => array('vid' => 'vid'),
      ),
      'tracking_author' => array(
        'table' => 'users',
        'columns' => array('uid' => 'uid'),
      ),
    ),
    'primary key' => array('trid'),
  );

  $schema['tracking_item_revision'] = array(
    'description' => 'Stores information about each saved version of a {tracking_item}.',
    'fields' => array(
      'trid' => array(
        'description' => 'The {tracking_item} this version belongs to.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
      'vid' => array(
        'description' => 'The primary identifier for this version.',
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'uid' => array(
        'description' => 'The {users}.uid that created this version.',
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ),
      'log' => array(
        'description' => 'The log entry explaining the changes in this version.',
        'type' => 'text',
        'not null' => TRUE,
        'size' => 'big',
      ),
      'timestamp' => array(
        'description' => 'A Unix timestamp indicating when this version was created.',
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ),
      'status' => array(
        'description' => 'Boolean indicating whether the tracking item (at the time of this revision) is active.',
        'type' => 'int',
        'not null' => TRUE,
        'default' => 1,
      ),
    ),
    'indexes' => array(
      'trid' => array('trid'),
      'uid' => array('uid'),
    ),
    'primary key' => array('vid'),
    'foreign keys' => array(
      'versioned_tracking_item' => array(
        'table' => 'tracking_item',
        'columns' => array('trid' => 'trid'),
      ),
      'version_author' => array(
        'table' => 'users',
        'columns' => array('uid' => 'uid'),
      ),
    ),
  );

  return $schema;
}

/**
 * Implements hook_permission().
 */
function mymodule_permission() {
  $perms = array();

  $perms['administer tracking'] = array(
    'title' => t('Administer Tracking fields'),
    'restrict access' => TRUE,
  );

  return $perms;
}

RoySegall’s picture

10x, i'll try to have a look.

amitaibu’s picture

Can you confirm your entity pass through og_entity_delete() when it's deleted?

hctom’s picture

I am having the exact same issue. I tracked it down a little bit, and in my case OgBehaviorHandler::delete() is called before og_entity_delete where $entity->delete_og_membership is set... but OgBehaviorHandler::delete() relies only on this flag and so nothing gets deleted, because the flag is not set at the moment, the EntityReference handler delete() callback is called.

amitaibu’s picture

Status: Reviewed & tested by the community » Needs work

This will need a simpleTest

rudiedirkx’s picture

Same problem for files being members in group nodes. Still in 2.7.

Patch works like a charm. The disadvantage of tests: after years, it's still a bug, although FIXED, because it there are no tests.