First commit
This commit is contained in:
commit
c6e2478c40
13918 changed files with 2303184 additions and 0 deletions
268
sites/all/modules/civicrm/CRM/Contact/BAO/GroupNestingCache.php
Normal file
268
sites/all/modules/civicrm/CRM/Contact/BAO/GroupNestingCache.php
Normal file
|
@ -0,0 +1,268 @@
|
|||
<?php
|
||||
/*
|
||||
+--------------------------------------------------------------------+
|
||||
| CiviCRM version 4.7 |
|
||||
+--------------------------------------------------------------------+
|
||||
| Copyright CiviCRM LLC (c) 2004-2017 |
|
||||
+--------------------------------------------------------------------+
|
||||
| This file is a part of CiviCRM. |
|
||||
| |
|
||||
| CiviCRM is free software; you can copy, modify, and distribute it |
|
||||
| under the terms of the GNU Affero General Public License |
|
||||
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
||||
| |
|
||||
| CiviCRM is distributed in the hope that it will be useful, but |
|
||||
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| See the GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| You should have received a copy of the GNU Affero General Public |
|
||||
| License and the CiviCRM Licensing Exception along |
|
||||
| with this program; if not, contact CiviCRM LLC |
|
||||
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
||||
| GNU Affero General Public License or the licensing of CiviCRM, |
|
||||
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
||||
+--------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @package CRM
|
||||
* @copyright CiviCRM LLC (c) 2004-2017
|
||||
*/
|
||||
class CRM_Contact_BAO_GroupNestingCache {
|
||||
|
||||
/**
|
||||
* Update cache.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
static public function update() {
|
||||
// lets build the tree in memory first
|
||||
|
||||
$sql = "
|
||||
SELECT n.child_group_id as child ,
|
||||
n.parent_group_id as parent
|
||||
FROM civicrm_group_nesting n,
|
||||
civicrm_group gc,
|
||||
civicrm_group gp
|
||||
WHERE n.child_group_id = gc.id
|
||||
AND n.parent_group_id = gp.id
|
||||
";
|
||||
|
||||
$dao = CRM_Core_DAO::executeQuery($sql);
|
||||
|
||||
$tree = array();
|
||||
while ($dao->fetch()) {
|
||||
if (!array_key_exists($dao->child, $tree)) {
|
||||
$tree[$dao->child] = array(
|
||||
'children' => array(),
|
||||
'parents' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
if (!array_key_exists($dao->parent, $tree)) {
|
||||
$tree[$dao->parent] = array(
|
||||
'children' => array(),
|
||||
'parents' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
$tree[$dao->child]['parents'][] = $dao->parent;
|
||||
$tree[$dao->parent]['children'][] = $dao->child;
|
||||
}
|
||||
|
||||
if (self::checkCyclicGraph($tree)) {
|
||||
CRM_Core_Error::fatal(ts("We detected a cycle which we can't handle. aborting"));
|
||||
}
|
||||
|
||||
// first reset the current cache entries
|
||||
$sql = "
|
||||
UPDATE civicrm_group
|
||||
SET parents = null,
|
||||
children = null
|
||||
";
|
||||
CRM_Core_DAO::executeQuery($sql);
|
||||
|
||||
$values = array();
|
||||
foreach (array_keys($tree) as $id) {
|
||||
$parents = implode(',', $tree[$id]['parents']);
|
||||
$children = implode(',', $tree[$id]['children']);
|
||||
$parents = $parents == NULL ? 'null' : "'$parents'";
|
||||
$children = $children == NULL ? 'null' : "'$children'";
|
||||
$sql = "
|
||||
UPDATE civicrm_group
|
||||
SET parents = $parents ,
|
||||
children = $children
|
||||
WHERE id = $id
|
||||
";
|
||||
CRM_Core_DAO::executeQuery($sql);
|
||||
}
|
||||
|
||||
// this tree stuff is quite useful, so lets store it in the cache
|
||||
CRM_Core_BAO_Cache::setItem($tree, 'contact groups', 'nestable tree hierarchy');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $tree
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function checkCyclicGraph(&$tree) {
|
||||
// lets keep this simple, we should probably use a graph algorithm here at some stage
|
||||
|
||||
// foreach group that has a parent or a child, ensure that
|
||||
// the ancestors and descendants dont intersect
|
||||
foreach ($tree as $id => $dontCare) {
|
||||
if (self::isCyclic($tree, $id)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $tree
|
||||
* @param int $id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isCyclic(&$tree, $id) {
|
||||
$parents = $children = array();
|
||||
self::getAll($parent, $tree, $id, 'parents');
|
||||
self::getAll($child, $tree, $id, 'children');
|
||||
|
||||
$one = array_intersect($parents, $children);
|
||||
$two = array_intersect($children, $parents);
|
||||
if (!empty($one) ||
|
||||
!empty($two)
|
||||
) {
|
||||
CRM_Core_Error::debug($id, $tree);
|
||||
CRM_Core_Error::debug($id, $one);
|
||||
CRM_Core_Error::debug($id, $two);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param $groups
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getPotentialCandidates($id, &$groups) {
|
||||
$tree = CRM_Core_BAO_Cache::getItem('contact groups', 'nestable tree hierarchy');
|
||||
|
||||
if ($tree === NULL) {
|
||||
self::update();
|
||||
$tree = CRM_Core_BAO_Cache::getItem('contact groups', 'nestable tree hierarchy');
|
||||
}
|
||||
|
||||
$potential = $groups;
|
||||
|
||||
// remove all descendants
|
||||
self::invalidate($potential, $tree, $id, 'children');
|
||||
|
||||
// remove all ancestors
|
||||
self::invalidate($potential, $tree, $id, 'parents');
|
||||
|
||||
return array_keys($potential);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $potential
|
||||
* @param $tree
|
||||
* @param int $id
|
||||
* @param $token
|
||||
*/
|
||||
public static function invalidate(&$potential, &$tree, $id, $token) {
|
||||
unset($potential[$id]);
|
||||
|
||||
if (!isset($tree[$id]) ||
|
||||
empty($tree[$id][$token])
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($tree[$id][$token] as $tokenID) {
|
||||
self::invalidate($potential, $tree, $tokenID, $token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $all
|
||||
* @param $tree
|
||||
* @param int $id
|
||||
* @param $token
|
||||
*/
|
||||
public static function getAll(&$all, &$tree, $id, $token) {
|
||||
// if seen before, dont do anything
|
||||
if (isset($all[$id])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$all[$id] = 1;
|
||||
if (!isset($tree[$id]) ||
|
||||
empty($tree[$id][$token])
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($tree[$id][$token] as $tokenID) {
|
||||
self::getAll($all, $tree, $tokenID, $token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function json() {
|
||||
$tree = CRM_Core_BAO_Cache::getItem('contact groups', 'nestable tree hierarchy');
|
||||
|
||||
if ($tree === NULL) {
|
||||
self::update();
|
||||
$tree = CRM_Core_BAO_Cache::getItem('contact groups', 'nestable tree hierarchy');
|
||||
}
|
||||
|
||||
// get all the groups
|
||||
$groups = CRM_Core_PseudoConstant::group();
|
||||
|
||||
foreach ($groups as $id => $name) {
|
||||
$string = "id:'$id', name:'$name'";
|
||||
if (isset($tree[$id])) {
|
||||
$children = array();
|
||||
if (!empty($tree[$id]['children'])) {
|
||||
foreach ($tree[$id]['children'] as $child) {
|
||||
$children[] = "{_reference:'$child'}";
|
||||
}
|
||||
$children = implode(',', $children);
|
||||
$string .= ", children:[$children]";
|
||||
if (empty($tree[$id]['parents'])) {
|
||||
$string .= ", type:'rootGroup'";
|
||||
}
|
||||
else {
|
||||
$string .= ", type:'middleGroup'";
|
||||
}
|
||||
}
|
||||
else {
|
||||
$string .= ", type:'leafGroup'";
|
||||
}
|
||||
}
|
||||
else {
|
||||
$string .= ", children:[], type:'rootGroup'";
|
||||
}
|
||||
$values[] = "{ $string }";
|
||||
}
|
||||
|
||||
$items = implode(",\n", $values);
|
||||
$json = "{
|
||||
identifier:'id',
|
||||
label:'name',
|
||||
items:[ $items ]
|
||||
}";
|
||||
return $json;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue