/**
 * Control access to memberships.
 *
 * @param string $op
 *   The membership operation.
 * @param MembershipEntity $membership
 *   The membership object. NULL if $op is 'join'.
 * @param object $account
 *   The loaded user account object. Defaults to logged in user.
 *
 * @return bool
 *   TRUE if $account as permission for $op.
 */
function hook_membership_entity_access($op, $membership = NULL, $account = NULL)
{
    $user = isset($account) ? $account : $GLOBALS['user'];
    // Join page access.
    if ($op == 'join') {
        $type = str_replace('-', '_', $membership);
        // Check if a membership already exists for this user.
        $exists = (bool) db_query('SELECT mid FROM {membership_entity} WHERE uid = :uid AND uid <> 0 AND type = :type', array(':uid' => $user->uid, ':type' => $type))->rowCount();
        if (!$exists && user_access("{$type} join", $user)) {
            return TRUE;
        }
        return FALSE;
    }
    if (isset($membership) && ($type_name = $membership->type)) {
        if (user_access("{$type_name} {$op} any membership", $user)) {
            return TRUE;
        }
        if (user_access("{$type_name} {$op} own membership", $user) && $membership->uid == $user->uid) {
            return TRUE;
        }
        // Secondary member access.
        $results = db_query('SELECT mid FROM {membership_entity_secondary_member} WHERE uid = :uid', array(':uid' => $user->uid))->fetchAllAssoc('mid');
        if (!empty($results) && in_array($membership->mid, array_keys($results))) {
            // Can secondary members edit the membership?
            $bundle_settings = membership_entity_get_bundle_settings($type_name);
            if ($op == 'edit' && $bundle_settings['all_edit'] && user_access("{$type} edit own membership", $user)) {
                return TRUE;
            }
            // Can secondary members view the membership?
            if ($op == 'view' && user_access("{$type} view own membership", $user)) {
                return TRUE;
            }
        }
    }
}
/**
 * Alter a membership term start date before it is saved.
 *
 * Membership term start dates default to when the term is created. This hook
 * allows you to apply special rules when calculating the start date.
 *
 * @param DateObject $start
 *   The start date. Timezone is UTC. Defaults to now.
 * @param MembershipEntityTerm $term
 *   The full membership term object.
 */
function hook_membership_entity_term_start_date_alter(&$start, $term)
{
    // Determine the renewal start date.
    if (!empty($term->is_renewal)) {
        $membership = membership_entity_load($term->mid);
        $bundle_settings = membership_entity_get_bundle_settings($membership->type);
        $latest_term = end($membership->terms);
        if (!empty($latest_term)) {
            $grace = new DateObject($latest_term->end, 'UTC');
            // Check for grace period.
            if (preg_match(MEMBERSHIP_ENTITY_TERM_LENGTH_REGEX, $bundle_settings['grace_period'])) {
                $grace = _membership_entity_term_modify_date($grace, $bundle_settings['grace_period']);
            }
            // If the renewal is within the grace period there is no lapse in
            // membership terms. The new term starts when the old term ended.
            if ($grace > $start) {
                $start = new DateObject($latest_term->end, 'UTC');
            }
        }
    }
}