Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions app/Controller/AppController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1401,12 +1401,7 @@ function menuContent() {
false);

// Pull the list of COUs and their names. Primarily intended for CO Service portal.
$args = array();
$args['conditions']['Cou.co_id'] = $this->cur_co['Co']['id'];
$args['fields'] = array('Cou.id', 'Cou.name');
$args['contain'] = false;

$menu['cous'] = $this->Co->Cou->find('list', $args);
$menu['cous'] = $this->Co->Cou->allCous($this->cur_co['Co']['id'], 'hash');

// Gather the available Enrollment Flows available to the current user.
// This will be used on the user panel.
Expand Down
17 changes: 14 additions & 3 deletions app/Controller/CoPeopleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,17 @@ public function beforeRender() {

// Calculate COU node path from root in case the role COU has a parent id.
if(!empty($this->viewVars["co_people"][0]["CoPersonRole"])) {
$couPathCache = array();

foreach($this->viewVars["co_people"][0]["CoPersonRole"] as $idx => $prole) {
if(isset($prole['Cou']['id'])) {
// Add the path to parent node under the COU record
$this->viewVars["co_people"][0]["CoPersonRole"][$idx]["Cou"]["path"] = $this->constructTreeParentPath($prole['Cou']['id']);
$couId = (int)$prole['Cou']['id'];

if(!isset($couPathCache[$couId])) {
$couPathCache[$couId] = $this->constructTreeParentPath($couId);
}

$this->viewVars["co_people"][0]["CoPersonRole"][$idx]["Cou"]["path"] = $couPathCache[$couId];
}
}
}
Expand Down Expand Up @@ -552,7 +559,11 @@ public function constructTreeParentPath($nodeId) {
return "";
}

$parents = $this->CoPerson->CoPersonRole->Cou->getPath($nodeId);
// Prefer Cou::cachedPath() over TreeBehavior::getPath() to avoid repeated nested-set queries.
// Scope to the current CO if available so the underlying tree cache stays small.
$coId = !empty($this->cur_co['Co']['id']) ? (int)$this->cur_co['Co']['id'] : null;

$parents = $this->CoPerson->CoPersonRole->Cou->cachedPath($nodeId, $coId);

if(empty($parents)) return "";

Expand Down
85 changes: 50 additions & 35 deletions app/Controller/Component/RoleComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,27 @@ public function approverForByOrgIdentities($orgIdentityIds) {

return $ret;
}

/**
* Cached COU path lookup (request scoped).
*
* TreeBehavior::getPath() can be expensive and is often called repeatedly for
* the same COU ID during authorization and view rendering.
*
* Delegates to the Cou model's request-scoped cache so the cache is shared
* across the request (eg: between models and components) via ClassRegistry.
*
* @since COmanage Registry v4.6.1
* @param int $couId
* @return array Path results as returned by Cou::getPath()
*/
protected function cachedCouPath($couId) {
$Cou = ClassRegistry::init('Cou');

$path = $Cou->cachedPath((int)$couId);

return (!empty($path) ? $path : array());
}

/**
* Cached CO ID lookup.
Expand Down Expand Up @@ -689,47 +710,47 @@ public function canRequestVerificationOfEmailAddress($coPersonId, $emailAddressI
* @return Array List COU IDs and Names
* @throws InvalidArgumentException
*/

public function couAdminFor($coPersonId) {
global $group_sep;

$couNames = array();
$childCous = array();

if(!$coPersonId) {
return array();
}

try {
$coId = $this->cachedCoIdLookup($coPersonId);
}
catch(InvalidArgumentException $e) {
throw new InvalidArgumentException($e->getMessage());
}

// First pull the COUs $coPersonId is explicitly an admin for

$couGroups = $this->cachedGroupGet($coPersonId, "", "", null, false, GroupEnum::Admins, true);

// What we actually have are the groups associated with each COU for which
// coPersonId is an admin.

$Cou = ClassRegistry::init('Cou');


if(empty($couGroups)) {
return array();
}

// Extract unique root COU IDs from the groups
$rootIds = array();
foreach($couGroups as $couGroup) {
if(!empty($couGroup['CoGroup']['cou_id'])) {
// Pull the COU and its children (if any)

try {
$childCous = array_unique($childCous + $Cou->childCousById($couGroup['CoGroup']['cou_id'], true, true));
}
catch(InvalidArgumentException $e) {
throw new InvalidArgumentException($e->getMessage());
}
// Use the array as a set to de-duplicate COU IDs while iterating $couGroups.
// If the person is in multiple admin groups that point at the same cou_id,
// we only want each root once.
$rootIds[(int)$couGroup['CoGroup']['cou_id']] = true;
}
}

return $childCous;
$rootIds = array_keys($rootIds);

if(empty($rootIds)) {
return array();
}

$Cou = ClassRegistry::init('Cou');

// Expand via cached tree (request-scoped) only; no legacy fallback.
// includeParents=true, includeHierarchy=true to match prior behavior
return $Cou->childCousByIds($rootIds, true, true, $coId);
}

/**
Expand Down Expand Up @@ -1413,11 +1434,8 @@ public function isCouAdmin($coPersonId, $couId=null) {
global $group_sep;

if($couId) {
$Cou = ClassRegistry::init('Cou');

// Get a listing of this COU and its parents.

$cous = $Cou->getPath($couId);
// Get a listing of this COU and its parents (cached per request).
$cous = $this->cachedCouPath($couId);

if(!empty($cous)) {
// This will be in order from the top of the tree down to $couId, but
Expand Down Expand Up @@ -1460,11 +1478,8 @@ public function isCouApprover($coPersonId, $couId=null) {
global $group_sep;

if($couId) {
$Cou = ClassRegistry::init('Cou');

// Get a listing of this COU and its parents.

$cous = $Cou->getPath($couId);
// Get a listing of this COU and its parents (cached per request).
$cous = $this->cachedCouPath($couId);

if(!empty($cous)) {
// This will be in order from the top of the tree down to $couId, but
Expand Down
Loading