3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
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-2014
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');
105 static function checkCyclicGraph(&$tree) {
106 // lets keep this simple, we should probably use a graph algoritm here at some stage
108 // foreach group that has a parent or a child, ensure that
109 // the ancestors and descendants dont intersect
110 foreach ($tree as $id => $dontCare) {
111 if (self
::isCyclic($tree, $id)) {
125 static function isCyclic(&$tree, $id) {
126 $parents = $children = array();
127 self
::getAll($parent, $tree, $id, 'parents');
128 self
::getAll($child, $tree, $id, 'children');
130 $one = array_intersect($parents, $children);
131 $two = array_intersect($children, $parents);
135 CRM_Core_Error
::debug($id, $tree);
136 CRM_Core_Error
::debug($id, $one);
137 CRM_Core_Error
::debug($id, $two);
149 static function getPotentialCandidates($id, &$groups) {
150 $tree = CRM_Core_BAO_Cache
::getItem('contact groups', 'nestable tree hierarchy');
152 if ($tree === NULL) {
154 $tree = CRM_Core_BAO_Cache
::getItem('contact groups', 'nestable tree hierarchy');
157 $potential = $groups;
159 // remove all descendants
160 self
::invalidate($potential, $tree, $id, 'children');
162 // remove all ancestors
163 self
::invalidate($potential, $tree, $id, 'parents');
165 return array_keys($potential);
174 static function invalidate(&$potential, &$tree, $id, $token) {
175 unset($potential[$id]);
177 if (!isset($tree[$id]) ||
178 empty($tree[$id][$token])
183 foreach ($tree[$id][$token] as $tokenID) {
184 self
::invalidate($potential, $tree, $tokenID, $token);
194 static function getAll(&$all, &$tree, $id, $token) {
195 // if seen before, dont do anything
196 if (isset($all[$id])) {
201 if (!isset($tree[$id]) ||
202 empty($tree[$id][$token])
207 foreach ($tree[$id][$token] as $tokenID) {
208 self
::getAll($all, $tree, $tokenID, $token);
215 static function json() {
216 $tree = CRM_Core_BAO_Cache
::getItem('contact groups', 'nestable tree hierarchy');
218 if ($tree === NULL) {
220 $tree = CRM_Core_BAO_Cache
::getItem('contact groups', 'nestable tree hierarchy');
223 // get all the groups
224 $groups = CRM_Core_PseudoConstant
::group();
226 foreach ($groups as $id => $name) {
227 $string = "id:'$id', name:'$name'";
228 if (isset($tree[$id])) {
230 if (!empty($tree[$id]['children'])) {
231 foreach ($tree[$id]['children'] as $child) {
232 $children[] = "{_reference:'$child'}";
234 $children = implode(',', $children);
235 $string .= ", children:[$children]";
236 if (empty($tree[$id]['parents'])) {
237 $string .= ", type:'rootGroup'";
240 $string .= ", type:'middleGroup'";
244 $string .= ", type:'leafGroup'";
248 $string .= ", children:[], type:'rootGroup'";
250 $values[] = "{ $string }";
253 $items = implode(",\n", $values);