_styleLabels = $styleLabels;
$this->_styleIndent = $styleIndent;
}
function setSortOrder($sortOrder) {
switch ($sortOrder) {
case 'ASC':
case 'DESC':
if ($sortOrder != self::$_sortOrder) {
self::$_sortOrder = $sortOrder;
$this->rewind();
}
break;
default:
// spit out some error, someday
}
}
function getSortOrder() {
return self::$_sortOrder;
}
function getCurrentNestingLevel() {
return count($this->_parentStack);
}
/**
* Go back to the first element in the group nesting graph,
* which is the first group (according to _sortOrder) that
* has no parent groups
*/
function rewind() {
$this->_parentStack = array();
// calling _getNextParentlessGroup w/ no arguments
// makes it return the first parentless group
$firstGroup = $this->_getNextParentlessGroup();
$this->_current = $firstGroup;
$this->_lastParentlessGroup = $firstGroup;
$this->_alreadyStyled = FALSE;
}
function current() {
if ($this->_styleLabels &&
$this->valid() &&
!$this->_alreadyStyled
) {
$styledGroup = clone($this->_current);
$nestingLevel = $this->getCurrentNestingLevel();
$indent = '';
while ($nestingLevel--) {
$indent .= $this->_styleIndent;
}
$styledGroup->title = $indent . $styledGroup->title;
$this->_current = &$styledGroup;
$this->_alreadyStyled = TRUE;
}
return $this->_current;
}
function key() {
$group = &$this->_current;
$ids = array();
foreach ($this->_parentStack as $parentGroup) {
$ids[] = $parentGroup->id;
}
$key = implode('-', $ids);
if (strlen($key) > 0) {
$key .= '-';
}
$key .= $group->id;
return $key;
}
function next() {
$currentGroup = &$this->_current;
$childGroup = $this->_getNextChildGroup($currentGroup);
if ($childGroup) {
$nextGroup = &$childGroup;
$this->_parentStack[] = &$this->_current;
}
else {
$nextGroup = $this->_getNextSiblingGroup($currentGroup);
if (!$nextGroup) {
// no sibling, find an ancestor w/ a sibling
for (;; ) {
// since we pop this array everytime, we should be
// reasonably safe from infinite loops, I think :)
$ancestor = array_pop($this->_parentStack);
$this->_current = &$ancestor;
if ($ancestor == NULL) {
break;
}
$nextGroup = $this->_getNextSiblingGroup($ancestor);
if ($nextGroup) {
break;
}
}
}
}
$this->_current = &$nextGroup;
$this->_alreadyStyled = FALSE;
return $nextGroup;
}
function valid() {
if ($this->_current) {
return TRUE;
}
else {
return FALSE;
}
}
function _getNextParentlessGroup(&$group = NULL) {
$lastParentlessGroup = $this->_lastParentlessGroup;
$nextGroup = new CRM_Contact_BAO_Group();
$nextGroup->order_by = 'title ' . self::$_sortOrder;
$nextGroup->find();
if ($group == NULL) {
$sawLast = TRUE;
}
else {
$sawLast = FALSE;
}
while ($nextGroup->fetch()) {
if (!self::hasParentGroups($nextGroup->id) && $sawLast) {
return $nextGroup;
}
elseif ($lastParentlessGroup->id == $nextGroup->id) {
$sawLast = TRUE;
}
}
return NULL;
}
function _getNextChildGroup(&$parentGroup, &$group = NULL) {
$children = self::getChildGroupIds($parentGroup->id);
if (count($children) > 0) {
// we have child groups, so get the first one based on _sortOrder
$childGroup = new CRM_Contact_BAO_Group();
$cgQuery = "SELECT * FROM civicrm_group WHERE id IN (" . implode(',', $children) . ") ORDER BY title " . self::$_sortOrder;
$childGroup->query($cgQuery);
$currentGroup = &$this->_current;
if ($group == NULL) {
$sawLast = TRUE;
}
else {
$sawLast = FALSE;
}
while ($childGroup->fetch()) {
if ($sawLast) {
return $childGroup;
}
elseif ($currentGroup->id === $childGroup->id) {
$sawLast = TRUE;
}
}
}
return NULL;
}
function _getNextSiblingGroup(&$group) {
$parentGroup = end($this->_parentStack);
if ($parentGroup) {
$nextGroup = $this->_getNextChildGroup($parentGroup, $group);
return $nextGroup;
}
else {
/* if we get here, it could be because we're out of siblings
* (in which case we return null) or because we're at the
* top level groups which do not have parents but may still
* have siblings, so check for that first.
*/
$nextGroup = $this->_getNextParentlessGroup($group);
if ($nextGroup) {
$this->_lastParentlessGroup = $nextGroup;
return $nextGroup;
}
return NULL;
}
}
/**
* Adds a new child group identified by $childGroupId to the group
* identified by $groupId
*
* @param $groupId The id of the group to add the child to
* @param $childGroupId The id of the new child group
*
* @return void
*
* @access public
*/
static function add($parentID, $childID) {
// TODO: Add checks here to make sure invalid nests can't be created
$dao = new CRM_Contact_DAO_GroupNesting();
$query = "REPLACE INTO civicrm_group_nesting (child_group_id, parent_group_id) VALUES ($childID,$parentID);";
$dao->query($query);
}
/**
* Removes a child group identified by $childGroupId from the group
* identified by $groupId; does not delete child group, just the
* association between the two
*
* @param $parentID The id of the group to remove the child from
* @param $childID The id of the child group being removed
*
* @return void
*
* @access public
*/
static function remove($parentID, $childID) {
$dao = new CRM_Contact_DAO_GroupNesting();
$query = "DELETE FROM civicrm_group_nesting WHERE child_group_id = $childID AND parent_group_id = $parentID";
$dao->query($query);
}
/**
* Removes associations where a child group is identified by $childGroupId from the group
* identified by $groupId; does not delete child group, just the
* association between the two
*
* @param $parentID The id of the group to remove the child from
* @param $childID The id of the child group being removed
*
* @return void
*
* @access public
*/
static function removeAllParentForChild($childID) {
$dao = new CRM_Contact_DAO_GroupNesting();
$query = "DELETE FROM civicrm_group_nesting WHERE child_group_id = $childID";
$dao->query($query);
}
/**
* Returns true if the association between parent and child is present,
* false otherwise.
*
* @param $parentID The parent id of the association
* @param $childID The child id of the association
*
* @return boolean True if association is found, false otherwise.
*
* @access public
*/
static function isParentChild($parentID, $childID) {
$dao = new CRM_Contact_DAO_GroupNesting();
$query = "SELECT id FROM civicrm_group_nesting WHERE child_group_id = $childID AND parent_group_id = $parentID";
$dao->query($query);
if ($dao->fetch()) {
return TRUE;
}
return FALSE;
}
/**
* Returns true if if the given groupId has 1 or more child groups,
* false otherwise.
*
* @param $groupId The id of the group to check for child groups
*
* @return boolean True if 1 or more child groups are found, false otherwise.
*
* @access public
*/
static function hasChildGroups($groupId) {
$dao = new CRM_Contact_DAO_GroupNesting();
$query = "SELECT child_group_id FROM civicrm_group_nesting WHERE parent_group_id = $groupId LIMIT 1";
//print $query . "\n
";
$dao->query($query);
if ($dao->fetch()) {
return TRUE;
}
return FALSE;
}
/**
* Returns true if the given groupId has 1 or more parent groups,
* false otherwise.
*
* @param $groupId The id of the group to check for parent groups
*
* @return boolean True if 1 or more parent groups are found, false otherwise.
*
* @access public
*/
static function hasParentGroups($groupId) {
$dao = new CRM_Contact_DAO_GroupNesting();
$query = "SELECT parent_group_id FROM civicrm_group_nesting WHERE child_group_id = $groupId LIMIT 1";
$dao->query($query);
if ($dao->fetch()) {
return TRUE;
}
return FALSE;
}
/**
* Returns true if checkGroupId is a parent of one of the groups in
* groupIds, false otherwise.
*
* @param $groupIds Array of group ids (or one group id) to serve as the starting point
* @param $checkGroupId The group id to check if it is a parent of the $groupIds group(s)
*
* @return boolean True if $checkGroupId points to a group that is a parent of one of the $groupIds groups, false otherwise.
*
* @access public
*/
static function isParentGroup($groupIds, $checkGroupId) {
if (!is_array($groupIds)) {
$groupIds = array($groupIds);
}
$dao = new CRM_Contact_DAO_GroupNesting();
$query = "SELECT parent_group_id FROM civicrm_group_nesting WHERE child_group_id IN (" . implode(',', $groupIds) . ")";
$dao->query($query);
while ($dao->fetch()) {
$parentGroupId = $dao->parent_group_id;
if ($parentGroupId == $checkGroupId) {
/* print "One of these:
"; print_r($groupIds); print "has groupId $checkGroupId as an ancestor.
"; print_r($groupIds); print "has groupId $checkGroupId as a descendent.
"; print_r($groupIds); print "has groupId $checkGroupId as an ancestor.
"; print_r($groupIds); print "has groupId $checkGroupId as a descendent.