You are here

class GroupMembershipController in Group 7

Controller for group membership entities.

Hierarchy

Expanded class hierarchy of GroupMembershipController

1 string reference to 'GroupMembershipController'
group_entity_info in ./group.entity.inc
Implements hook_entity_info().

File

classes/group_membership.controller.inc, line 10
Defines the Entity API CRUD class for group memberships.

View source
class GroupMembershipController extends EntityAPIController {

  /**
   * Add group roles to group memberships upon loading.
   *
   * This will load the memberships' roles before it is passed onto any hooks
   * that act upon entity loading.
   */
  protected function attachLoad(&$queried_entities, $revision_id = FALSE) {
    if ($queried_entities) {

      // Gather all loaded memberships' role data.
      $query = db_select('group_membership_role', 'gmr')
        ->fields('gmr', array(
        'mid',
        'role',
      ))
        ->condition('mid', array_keys($queried_entities), 'IN');

      // Gather the roles per group membership id.
      foreach ($query
        ->execute() as $record) {
        $roles[$record->mid][] = $record->role;
      }

      // Add the group roles onto the memberships.
      foreach ($queried_entities as $mid => $group_membership) {
        $group_membership->roles = isset($roles[$mid]) ? $roles[$mid] : array();
      }
    }

    // Invoke the other attachLoad functionality.
    parent::attachLoad($queried_entities, $revision_id);
  }

  /**
   * Overridden to take care of saving membership roles.
   *
   * If this functionality were placed in GroupMembershipController::save(),
   * we'd find ourselves in a catch-22:
   * - On the one hand we need a membership id to save the roles to
   *   {group_membership_role}, requiring us to first save new
   *   GroupMembership entities before saving their roles.
   * - On the other hand, saving an entity causes the insert or update hooks
   *   to be invoked, leaving room for buggy behavior should one try to load
   *   the recently saved entity again (it gets removed from the cache upon
   *   being saved to the database).
   *
   * To solve this without overriding EntityAPIController::save() and without
   * having to fiddle with either module or hook weight, we place the code here
   * because GroupMembershipController::invoke() is called right after the
   * actual insert or update and we are sure to have a membership id already.
   *
   * @see EntityAPIController::save()
   * @see GroupMembershipController::save()
   */
  public function invoke($hook, $group_membership) {
    if ($hook == 'update' || $hook == 'insert') {

      // Below we take care of the 'roles' property that was set on the
      // GroupMembership; saving new roles to and removing revoked roles from
      // the database. For new GroupMembership entities, we can simply grant
      // all of the roles. For existing ones, we need to run some integrity
      // checks.
      if (!empty($group_membership->is_new)) {
        $grant = $group_membership->roles;
      }
      else {

        // Load the original entity to detect changes.
        $original = entity_load_unchanged('group_membership', $group_membership->mid);

        // Flag new roles for granting.
        $grant = array_diff($group_membership->roles, $original->roles);

        // Flag old roles for revoking.
        $revoke = array_diff($original->roles, $group_membership->roles);

        // Inform update hooks if any roles have changed. This is merely a
        // helper property so update hooks don't have to check again.
        $group_membership->roles_changed = $grant || $revoke;
      }

      // Grant the roles by inserting them into {group_membership_role}.
      if (!empty($grant)) {
        $query = db_insert('group_membership_role')
          ->fields(array(
          'mid',
          'role',
        ));
        foreach ($grant as $role) {
          $query
            ->values(array(
            'mid' => $group_membership->mid,
            'role' => $role,
          ));
        }
        $query
          ->execute();
      }

      // Revoke the roles by deleting them from {group_membership_role}.
      if (!empty($revoke)) {
        $query = db_delete('group_membership_role')
          ->condition('mid', $group_membership->mid);
        $query
          ->condition('role', $revoke, 'IN');
        $query
          ->execute();
      }
    }

    // Continue running the actual invoke logic.
    parent::invoke($hook, $group_membership);
  }

  /**
   * Delete a group membership.
   */
  public function delete($ids, DatabaseTransaction $transaction = NULL) {
    if (!empty($ids)) {

      // Delete all associated group membership roles.
      db_delete('group_membership_role')
        ->condition('mid', $ids, 'IN')
        ->execute();
    }
    parent::delete($ids, $transaction);
  }

  /**
   * Save a group membership.
   *
   * The saving of roles takes place in GroupMembershipController::invoke().
   *
   * @see GroupMembershipController::invoke()
   *
   * @todo Validation of added roles.
   */
  public function save($group_membership, DatabaseTransaction $transaction = NULL) {
    if (!isset($group_membership->uid) || $group_membership->uid == 0) {
      throw new EntityMalformedException(t("Group memberships cannot be created for anonymous users."));
    }

    // Clean up the 'roles' property to avoid duplicates.
    $group_membership->roles = array_unique($group_membership->roles);
    return parent::save($group_membership, $transaction);
  }

  /**
   * Create a group membership.
   *
   * We first set up the values that are specific to the group schema
   * but then also run the EntityAPIController counterpart.
   *
   * @param array $values
   *   An array of values to set, keyed by property name.
   *
   * @return GroupMembership
   *   A new GroupMembership instance.
   */
  public function create(array $values = array()) {

    // Provide defaults that are needed for the db.
    $values += array(
      'roles' => array(),
      'status' => 'active',
    );
    return parent::create($values);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DrupalDefaultEntityController::$cache protected property Whether this entity type should use the static cache.
DrupalDefaultEntityController::$entityCache protected property Static cache of entities, keyed by entity ID.
DrupalDefaultEntityController::$entityInfo protected property Array of information about the entity.
DrupalDefaultEntityController::$entityType protected property Entity type for this controller instance.
DrupalDefaultEntityController::$hookLoadArguments protected property Additional arguments to pass to hook_TYPE_load().
DrupalDefaultEntityController::$idKey protected property Name of the entity's ID field in the entity database table.
DrupalDefaultEntityController::$revisionKey protected property Name of entity's revision database table field, if it supports revisions.
DrupalDefaultEntityController::$revisionTable protected property The table that stores revisions, if the entity supports revisions.
DrupalDefaultEntityController::cacheGet protected function Gets entities from the static cache. 1
DrupalDefaultEntityController::cacheSet protected function Stores entities in the static entity cache.
DrupalDefaultEntityController::cleanIds protected function Ensures integer entity IDs are valid.
DrupalDefaultEntityController::filterId protected function Callback for array_filter that removes non-integer IDs.
EntityAPIController::$bundleKey protected property
EntityAPIController::$cacheComplete protected property
EntityAPIController::$defaultRevisionKey protected property
EntityAPIController::buildContent public function Implements EntityAPIControllerInterface. Overrides EntityAPIControllerInterface::buildContent
EntityAPIController::buildQuery protected function Overrides DrupalDefaultEntityController::buildQuery(). Overrides DrupalDefaultEntityController::buildQuery 1
EntityAPIController::deleteRevision public function Implements EntityAPIControllerRevisionableInterface::deleteRevision(). Overrides EntityAPIControllerRevisionableInterface::deleteRevision
EntityAPIController::export public function Implements EntityAPIControllerInterface. Overrides EntityAPIControllerInterface::export 1
EntityAPIController::import public function Implements EntityAPIControllerInterface. Overrides EntityAPIControllerInterface::import
EntityAPIController::load public function Overridden. Overrides DrupalDefaultEntityController::load 1
EntityAPIController::query public function Builds and executes the query for loading.
EntityAPIController::renderEntityProperty protected function Renders a single entity property.
EntityAPIController::resetCache public function Overrides DrupalDefaultEntityController::resetCache(). Overrides DrupalDefaultEntityController::resetCache 1
EntityAPIController::saveRevision protected function Saves an entity revision.
EntityAPIController::view public function Implements EntityAPIControllerInterface. Overrides EntityAPIControllerInterface::view 1
EntityAPIController::__construct public function Overridden. Overrides DrupalDefaultEntityController::__construct 1
GroupMembershipController::attachLoad protected function Add group roles to group memberships upon loading. Overrides DrupalDefaultEntityController::attachLoad
GroupMembershipController::create public function Create a group membership. Overrides EntityAPIController::create
GroupMembershipController::delete public function Delete a group membership. Overrides EntityAPIController::delete
GroupMembershipController::invoke public function Overridden to take care of saving membership roles. Overrides EntityAPIController::invoke
GroupMembershipController::save public function Save a group membership. Overrides EntityAPIController::save