3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.4 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2013
35 class CRM_Contact_BAO_GroupNestingCache
{
36 static public function update() {
37 // lets build the tree in memory first
40 SELECT n.child_group_id as child ,
41 n.parent_group_id as parent
42 FROM civicrm_group_nesting n,
45 WHERE n.child_group_id = gc.id
46 AND n.parent_group_id = gp.id
49 $dao = CRM_Core_DAO
::executeQuery($sql);
52 while ($dao->fetch()) {
53 if (!array_key_exists($dao->child
, $tree)) {
54 $tree[$dao->child
] = array('children' => array(),
59 if (!array_key_exists($dao->parent
, $tree)) {
60 $tree[$dao->parent
] = array('children' => array(),
65 $tree[$dao->child
]['parents'][] = $dao->parent
;
66 $tree[$dao->parent
]['children'][] = $dao->child
;
69 if (self
::checkCyclicGraph($tree)) {
70 CRM_Core_Error
::fatal(ts('We detected a cycle which we cant handle. aborting'));
73 // first reset the current cache entries
79 CRM_Core_DAO
::executeQuery($sql);
82 foreach (array_keys($tree) as $id) {
83 $parents = implode(',', $tree[$id]['parents']);
84 $children = implode(',', $tree[$id]['children']);
85 $parents = $parents == NULL ?
'null' : "'$parents'";
86 $children = $children == NULL ?
'null' : "'$children'";
89 SET parents = $parents ,
93 CRM_Core_DAO
::executeQuery($sql);
96 // this tree stuff is quite useful, so lets store it in the cache
97 CRM_Core_BAO_Cache
::setItem($tree, 'contact groups', 'nestable tree hierarchy');
100 static function checkCyclicGraph(&$tree) {
101 // lets keep this simple, we should probably use a graph algoritm here at some stage
103 // foreach group that has a parent or a child, ensure that
104 // the ancestors and descendants dont intersect
105 foreach ($tree as $id => $dontCare) {
106 if (self
::isCyclic($tree, $id)) {
114 static function isCyclic(&$tree, $id) {
115 $parents = $children = array();
116 self
::getAll($parent, $tree, $id, 'parents');
117 self
::getAll($child, $tree, $id, 'children');
119 $one = array_intersect($parents, $children);
120 $two = array_intersect($children, $parents);
124 CRM_Core_Error
::debug($id, $tree);
125 CRM_Core_Error
::debug($id, $one);
126 CRM_Core_Error
::debug($id, $two);
132 static function getPotentialCandidates($id, &$groups) {
133 $tree = CRM_Core_BAO_Cache
::getItem('contact groups', 'nestable tree hierarchy');
135 if ($tree === NULL) {
137 $tree = CRM_Core_BAO_Cache
::getItem('contact groups', 'nestable tree hierarchy');
140 $potential = $groups;
142 // remove all descendants
143 self
::invalidate($potential, $tree, $id, 'children');
145 // remove all ancestors
146 self
::invalidate($potential, $tree, $id, 'parents');
148 return array_keys($potential);
151 static function invalidate(&$potential, &$tree, $id, $token) {
152 unset($potential[$id]);
154 if (!isset($tree[$id]) ||
155 empty($tree[$id][$token])
160 foreach ($tree[$id][$token] as $tokenID) {
161 self
::invalidate($potential, $tree, $tokenID, $token);
165 static function getAll(&$all, &$tree, $id, $token) {
166 // if seen before, dont do anything
167 if (isset($all[$id])) {
172 if (!isset($tree[$id]) ||
173 empty($tree[$id][$token])
178 foreach ($tree[$id][$token] as $tokenID) {
179 self
::getAll($all, $tree, $tokenID, $token);
183 static function json() {
184 $tree = CRM_Core_BAO_Cache
::getItem('contact groups', 'nestable tree hierarchy');
186 if ($tree === NULL) {
188 $tree = CRM_Core_BAO_Cache
::getItem('contact groups', 'nestable tree hierarchy');
191 // get all the groups
192 $groups = CRM_Core_PseudoConstant
::group();
194 foreach ($groups as $id => $name) {
195 $string = "id:'$id', name:'$name'";
196 if (isset($tree[$id])) {
198 if (!empty($tree[$id]['children'])) {
199 foreach ($tree[$id]['children'] as $child) {
200 $children[] = "{_reference:'$child'}";
202 $children = implode(',', $children);
203 $string .= ", children:[$children]";
204 if (empty($tree[$id]['parents'])) {
205 $string .= ", type:'rootGroup'";
208 $string .= ", type:'middleGroup'";
212 $string .= ", type:'leafGroup'";
216 $string .= ", children:[], type:'rootGroup'";
218 $values[] = "{ $string }";
221 $items = implode(",\n", $values);