copyValues($params); if ($group->find(TRUE)) { CRM_Core_DAO::storeValues($group, $defaults); return $group; } return NULL; } /** * Function to delete the group and all the object that connect to * this group. Incredibly destructive * * @param int $id group id * * @return null * @access public * @static * */ static function discard($id) { CRM_Utils_Hook::pre('delete', 'Group', $id, CRM_Core_DAO::$_nullArray); $transaction = new CRM_Core_Transaction(); // added for CRM-1631 and CRM-1794 // delete all subscribed mails with the selected group id $subscribe = new CRM_Mailing_Event_DAO_Subscribe(); $subscribe->group_id = $id; $subscribe->delete(); // delete all Subscription records with the selected group id $subHistory = new CRM_Contact_DAO_SubscriptionHistory(); $subHistory->group_id = $id; $subHistory->delete(); // delete all crm_group_contact records with the selected group id $groupContact = new CRM_Contact_DAO_GroupContact(); $groupContact->group_id = $id; $groupContact->delete(); // make all the 'add_to_group_id' field of 'civicrm_uf_group table', pointing to this group, as null $params = array(1 => array($id, 'Integer')); $query = "UPDATE civicrm_uf_group SET `add_to_group_id`= NULL WHERE `add_to_group_id` = %1"; CRM_Core_DAO::executeQuery($query, $params); $query = "UPDATE civicrm_uf_group SET `limit_listings_group_id`= NULL WHERE `limit_listings_group_id` = %1"; CRM_Core_DAO::executeQuery($query, $params); // make sure u delete all the entries from civicrm_mailing_group and civicrm_campaign_group // CRM-6186 $query = "DELETE FROM civicrm_mailing_group where entity_table = 'civicrm_group' AND entity_id = %1"; CRM_Core_DAO::executeQuery($query, $params); $query = "DELETE FROM civicrm_campaign_group where entity_table = 'civicrm_group' AND entity_id = %1"; CRM_Core_DAO::executeQuery($query, $params); $query = "DELETE FROM civicrm_acl_entity_role where entity_table = 'civicrm_group' AND entity_id = %1"; CRM_Core_DAO::executeQuery($query, $params); if (CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME, 'is_enabled' )) { // clear any descendant groups cache if exists $finalGroups = CRM_Core_BAO_Cache::deleteGroup('descendant groups for an org'); } // delete from group table $group = new CRM_Contact_DAO_Group(); $group->id = $id; $group->delete(); $transaction->commit(); CRM_Utils_Hook::post('delete', 'Group', $id, $group); // delete the recently created Group $groupRecent = array( 'id' => $id, 'type' => 'Group', ); CRM_Utils_Recent::del($groupRecent); } /** * Returns an array of the contacts in the given group. * */ static function getGroupContacts($id) { $params = array(array('group', 'IN', array($id => 1), 0, 0)); list($contacts, $_) = CRM_Contact_BAO_Query::apiQuery($params, array('contact_id')); return $contacts; } /** * Get the count of a members in a group with the specific status * * @param int $id group id * @param enum $status status of members in group * * @return int count of members in the group with above status * @access public */ static function memberCount($id, $status = 'Added', $countChildGroups = FALSE) { $groupContact = new CRM_Contact_DAO_GroupContact(); $groupIds = array($id); if ($countChildGroups) { $groupIds = CRM_Contact_BAO_GroupNesting::getDescendentGroupIds($groupIds); } $count = 0; $contacts = self::getGroupContacts($id); foreach ($groupIds as $groupId) { $groupContacts = self::getGroupContacts($groupId); foreach ($groupContacts as $gcontact) { if ($groupId != $id) { // Loop through main group's contacts // and subtract from the count for each contact which // matches one in the present group, if it is not the // main group foreach ($contacts as $contact) { if ($contact['contact_id'] == $gcontact['contact_id']) { $count--; } } } } $groupContact->group_id = $groupId; if (isset($status)) { $groupContact->status = $status; } $groupContact->_query['condition'] = 'WHERE contact_id NOT IN (SELECT id FROM civicrm_contact WHERE is_deleted = 1)'; $count += $groupContact->count(); } return $count; } /** * Get the list of member for a group id * * @param int $lngGroupId this is group id * * @return array $aMembers this arrray contains the list of members for this group id * @access public * @static */ static function &getMember($groupID, $useCache = TRUE) { $params = array(array('group', 'IN', array($groupID => 1), 0, 0)); $returnProperties = array('contact_id'); list($contacts, $_) = CRM_Contact_BAO_Query::apiQuery($params, $returnProperties, NULL, NULL, 0, 0, $useCache); $aMembers = array(); foreach ($contacts as $contact) { $aMembers[$contact['contact_id']] = 1; } return $aMembers; } /** * Returns array of group object(s) matching a set of one or Group properties. * * @param array $param Array of one or more valid property_name=>value pairs. * Limits the set of groups returned. * @param array $returnProperties Which properties should be included in the returned group objects. * (member_count should be last element.) * * @return An array of group objects. * * @access public * * @todo other BAO functions that use returnProperties (e.g. Query Objects) receive the array flipped & filled with 1s and * add in essential fields (e.g. id). This should follow a regular pattern like the others */ static function getGroups( $params = NULL, $returnProperties = NULL, $sort = NULL, $offset = NULL, $rowCount = NULL ) { $dao = new CRM_Contact_DAO_Group(); if (!isset($params['is_active'])) { $dao->is_active = 1; } if ($params) { foreach ($params as $k => $v) { if ($k == 'name' || $k == 'title') { $dao->whereAdd($k . ' LIKE "' . CRM_Core_DAO::escapeString($v) . '"'); } elseif ($k == 'group_type') { foreach ((array) $v as $type) { $dao->whereAdd($k . " LIKE '%" . CRM_Core_DAO::VALUE_SEPARATOR . (int) $type . CRM_Core_DAO::VALUE_SEPARATOR . "%'"); } } elseif (is_array($v)) { foreach ($v as &$num) { $num = (int) $num; } $dao->whereAdd($k . ' IN (' . implode(',', $v) . ')'); } else { $dao->$k = $v; } } } if ($offset || $rowCount) { $offset = ($offset > 0) ? $offset : 0; $rowCount = ($rowCount > 0) ? $rowCount : 25; $dao->limit($offset, $rowCount); } if ($sort) { $dao->orderBy($sort); } // return only specific fields if returnproperties are sent if (!empty($returnProperties)) { $dao->selectAdd(); $dao->selectAdd(implode(',', $returnProperties)); } $dao->find(); $flag = $returnProperties && in_array('member_count', $returnProperties) ? 1 : 0; $groups = array(); while ($dao->fetch()) { $group = new CRM_Contact_DAO_Group(); if ($flag) { $dao->member_count = CRM_Contact_BAO_Group::memberCount($dao->id); } $groups[] = clone($dao); } return $groups; } /** * make sure that the user has permission to access this group * * @param int $id the id of the object * * @return string the permission that the user has (or null) * @access public * @static */ static function checkPermission($id) { $allGroups = CRM_Core_PseudoConstant::allGroup(); $permissions = NULL; if (CRM_Core_Permission::check('edit all contacts') || CRM_ACL_API::groupPermission(CRM_ACL_API::EDIT, $id, NULL, 'civicrm_saved_search', $allGroups ) ) { $permissions[] = CRM_Core_Permission::EDIT; } if (CRM_Core_Permission::check('view all contacts') || CRM_ACL_API::groupPermission(CRM_ACL_API::VIEW, $id, NULL, 'civicrm_saved_search', $allGroups ) ) { $permissions[] = CRM_Core_Permission::VIEW; } if (!empty($permissions) && CRM_Core_Permission::check('delete contacts')) { // Note: using !empty() in if condition, restricts the scope of delete // permission to groups/contacts that are editable/viewable. // We can remove this !empty condition once we have ACL support for delete functionality. $permissions[] = CRM_Core_Permission::DELETE; } return $permissions; } /** * Create a new group * * @param array $params Associative array of parameters * * @return object|null The new group BAO (if created) * @access public * @static */ public static function &create(&$params) { if (CRM_Utils_Array::value('id', $params)) { CRM_Utils_Hook::pre('edit', 'Group', $params['id'], $params); } else { CRM_Utils_Hook::pre('create', 'Group', NULL, $params); } // form the name only if missing: CRM-627 if (!CRM_Utils_Array::value('name', $params) && !CRM_Utils_Array::value('id', $params) ) { $params['name'] = CRM_Utils_String::titleToVar($params['title']); } // convert params if array type if (isset($params['group_type'])) { if (is_array($params['group_type'])) { $params['group_type'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, array_keys($params['group_type']) ) . CRM_Core_DAO::VALUE_SEPARATOR; } } else { $params['group_type'] = ''; } $session = CRM_Core_Session::singleton( ); $cid = $session->get('userID'); // this action is add if ($cid && empty($params['id'])) { $params['created_id'] = $cid; } // this action is update if ($cid && !empty($params['id'])) { $params['modified_id'] = $cid; } $group = new CRM_Contact_BAO_Group(); $group->copyValues($params); //@todo very hacky fix for the fact this function wants to receive 'parents' as an array further down but // needs it as a separated string for the DB. Preferred approaches are having the copyParams or save fn // use metadata to translate the array to the appropriate DB type or altering the param in the api layer, // or at least altering the param in same section as 'group_type' rather than repeating here. However, further down // we need the $params one to be in it's original form & we are not sure what test coverage we have on that if(isset($group->parents) && is_array($group->parents)) { $group->parents = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, array_keys($group->parents) ) . CRM_Core_DAO::VALUE_SEPARATOR; } if (!CRM_Utils_Array::value('id', $params)) { $group->name .= "_tmp"; } $group->save(); if (!$group->id) { return NULL; } if (!CRM_Utils_Array::value('id', $params)) { $group->name = substr($group->name, 0, -4) . "_{$group->id}"; } $group->buildClause(); $group->save(); // add custom field values if (CRM_Utils_Array::value('custom', $params)) { CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_group', $group->id); } // make the group, child of domain/site group by default. $domainGroupID = CRM_Core_BAO_Domain::getGroupId(); if (CRM_Utils_Array::value('no_parent', $params) !== 1) { if (empty($params['parents']) && $domainGroupID != $group->id && CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MULTISITE_PREFERENCES_NAME, 'is_enabled' ) && !CRM_Contact_BAO_GroupNesting::hasParentGroups($group->id) ) { // if no parent present and the group doesn't already have any parents, // make sure site group goes as parent $params['parents'] = array($domainGroupID => 1); } elseif (array_key_exists('parents', $params) && !is_array($params['parents'])) { $params['parents'] = array($params['parents'] => 1); } if (!empty($params['parents'])) { foreach ($params['parents'] as $parentId => $dnc) { if ($parentId && !CRM_Contact_BAO_GroupNesting::isParentChild($parentId, $group->id)) { CRM_Contact_BAO_GroupNesting::add($parentId, $group->id); } } } // clear any descendant groups cache if exists $finalGroups = CRM_Core_BAO_Cache::deleteGroup('descendant groups for an org'); // this is always required, since we don't know when a // parent group is removed CRM_Contact_BAO_GroupNestingCache::update(); // update group contact cache for all parent groups $parentIds = CRM_Contact_BAO_GroupNesting::getParentGroupIds($group->id); foreach ($parentIds as $parentId) { CRM_Contact_BAO_GroupContactCache::add($parentId); } } if (CRM_Utils_Array::value('organization_id', $params)) { $groupOrg = array(); $groupOrg = $params; $groupOrg['group_id'] = $group->id; CRM_Contact_BAO_GroupOrganization::add($groupOrg); } CRM_Contact_BAO_GroupContactCache::add($group->id); if (CRM_Utils_Array::value('id', $params)) { CRM_Utils_Hook::post('edit', 'Group', $group->id, $group); } else { CRM_Utils_Hook::post('create', 'Group', $group->id, $group); } $recentOther = array(); if (CRM_Core_Permission::check('edit groups')) { $recentOther['editUrl'] = CRM_Utils_System::url('civicrm/group', 'reset=1&action=update&id=' . $group->id); // currently same permission we are using for delete a group $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/group', 'reset=1&action=delete&id=' . $group->id); } // add the recently added group (unless hidden: CRM-6432) if (!$group->is_hidden) { CRM_Utils_Recent::add($group->title, CRM_Utils_System::url('civicrm/group/search', 'reset=1&force=1&context=smog&gid=' . $group->id), $group->id, 'Group', NULL, NULL, $recentOther ); } return $group; } /** * given a saved search compute the clause and the tables * and store it for future use */ function buildClause() { $params = array(array('group', 'IN', array($this->id => 1), 0, 0)); if (!empty($params)) { $tables = $whereTables = array(); $this->where_clause = CRM_Contact_BAO_Query::getWhereClause($params, NULL, $tables, $whereTables); if (!empty($tables)) { $this->select_tables = serialize($tables); } if (!empty($whereTables)) { $this->where_tables = serialize($whereTables); } } return; } /** * Defines a new smart group * * @param array $params Associative array of parameters * * @return object|null The new group BAO (if created) * @access public * @static */ public static function createSmartGroup(&$params) { if (CRM_Utils_Array::value('formValues', $params)) { $ssParams = $params; unset($ssParams['id']); if (isset($ssParams['saved_search_id'])) { $ssParams['id'] = $ssParams['saved_search_id']; } $savedSearch = CRM_Contact_BAO_SavedSearch::create($params); $params['saved_search_id'] = $savedSearch->id; } else { return NULL; } return self::create($params); } /** * update the is_active flag in the db * * @param int $id id of the database record * @param boolean $isActive value we want to set the is_active field * * @return Object DAO object on sucess, null otherwise * @static */ static function setIsActive($id, $isActive) { return CRM_Core_DAO::setFieldValue('CRM_Contact_DAO_Group', $id, 'is_active', $isActive); } /** * build the condition to retrieve groups. * * @param string $groupType type of group(Access/Mailing) OR the key of the group * @param boolen $excludeHidden exclude hidden groups. * * @return string $condition * @static */ static function groupTypeCondition($groupType = NULL, $excludeHidden = TRUE) { $value = NULL; if ($groupType == 'Mailing') { $value = CRM_Core_DAO::VALUE_SEPARATOR . '2' . CRM_Core_DAO::VALUE_SEPARATOR; } elseif ($groupType == 'Access') { $value = CRM_Core_DAO::VALUE_SEPARATOR . '1' . CRM_Core_DAO::VALUE_SEPARATOR; } elseif (!empty($groupType)){ // ie we have been given the group key $value = CRM_Core_DAO::VALUE_SEPARATOR . $groupType . CRM_Core_DAO::VALUE_SEPARATOR; } $condition = NULL; if ($excludeHidden) { $condition = "is_hidden = 0"; } if ($value) { if ($condition) { $condition .= " AND group_type LIKE '%$value%'"; } else { $condition = "group_type LIKE '%$value%'"; } } return $condition; } public function __toString() { return $this->title; } /** * This function create the hidden smart group when user perform * contact seach and want to send mailing to search contacts. * * @param array $params ( reference ) an assoc array of name/value pairs * * @return array ( smartGroupId, ssId ) smart group id and saved search id * @access public * @static */ static function createHiddenSmartGroup($params) { $ssId = CRM_Utils_Array::value('saved_search_id', $params); //add mapping record only for search builder saved search $mappingId = NULL; if ($params['search_context'] == 'builder') { //save the mapping for search builder if (!$ssId) { //save record in mapping table $temp = array(); $mappingParams = array('mapping_type' => 'Search Builder'); $mapping = CRM_Core_BAO_Mapping::add($mappingParams, $temp); $mappingId = $mapping->id; } else { //get the mapping id from saved search $savedSearch = new CRM_Contact_BAO_SavedSearch(); $savedSearch->id = $ssId; $savedSearch->find(TRUE); $mappingId = $savedSearch->mapping_id; } //save mapping fields CRM_Core_BAO_Mapping::saveMappingFields($params['form_values'], $mappingId); } //create/update saved search record. $savedSearch = new CRM_Contact_BAO_SavedSearch(); $savedSearch->id = $ssId; $savedSearch->form_values = serialize($params['form_values']); $savedSearch->mapping_id = $mappingId; $savedSearch->search_custom_id = CRM_Utils_Array::value('search_custom_id', $params); $savedSearch->save(); $ssId = $savedSearch->id; if (!$ssId) { return NULL; } $smartGroupId = NULL; if (CRM_Utils_Array::value('saved_search_id', $params)) { $smartGroupId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Group', $ssId, 'id', 'saved_search_id'); } else { //create group only when new saved search. $groupParams = array( 'title' => "Hidden Smart Group {$ssId}", 'is_active' => CRM_Utils_Array::value('is_active', $params, 1), 'is_hidden' => CRM_Utils_Array::value('is_hidden', $params, 1), 'group_type' => CRM_Utils_Array::value('group_type', $params), 'visibility' => CRM_Utils_Array::value('visibility', $params), 'saved_search_id' => $ssId, ); $smartGroup = self::create($groupParams); $smartGroupId = $smartGroup->id; } return array($smartGroupId, $ssId); } /** * This function is a wrapper for ajax group selector * * @param array $params associated array for params record id. * * @return array $groupList associated array of group list * @access public */ public function getGroupListSelector(&$params) { // format the params $params['offset'] = ($params['page'] - 1) * $params['rp']; $params['rowCount'] = $params['rp']; $params['sort'] = CRM_Utils_Array::value('sortBy', $params); // get groups $groups = CRM_Contact_BAO_Group::getGroupList($params); //skip total if we are making call to show only children if ( !CRM_Utils_Array::value('parent_id', $params) ) { // add total $params['total'] = CRM_Contact_BAO_Group::getGroupCount($params); // get all the groups $allGroups = CRM_Core_PseudoConstant::allGroup(); } // format params and add links $groupList = array(); if (!empty($groups)) { foreach ($groups as $id => $value) { $groupList[$id]['group_id'] = $value['id']; $groupList[$id]['group_name'] = $value['title']; $groupList[$id]['class'] = implode(' ', $value['class']); // append parent names if in search mode if ( !CRM_Utils_Array::value('parent_id', $params) && CRM_Utils_Array::value( 'parents', $value ) ) { $groupIds = explode(',', $value['parents']); $title = array(); foreach($groupIds as $gId) { $title[] = $allGroups[$gId]; } $groupList[$id]['group_name'] .= '