Skip to content
Snippets Groups Projects
Commit 59d645a7 authored by Jared Hancock's avatar Jared Hancock
Browse files

queue: Improve queries necessary for rendering

This removes a significant number of queries used to render the drop-down
menu for the queues.

Each queue displayed on the page previously required a database query to
determine its children. This patch changes the strategy to fetch all the
queues and organize them as a tree. The tree can then be walked as the menu
is rendered and does not require any further queries.

On my test system, it reduces the number of queries for the ticket listing
page from 56 to 46.
parent c12fb23c
No related branches found
No related tags found
No related merge requests found
......@@ -1265,6 +1265,44 @@ class CustomQueue extends VerySimpleModel {
&& $this->sorts->saveAll();
}
/**
* Fetch a tree-organized listing of the queues. Each queue is listed in
* the tree exactly once, and every visible queue is represented. The
* returned structure is an array where the items are two-item arrays
* where the first item is a CustomQueue object an the second is a list
* of the children using the same pattern (two-item arrays of a CustomQueue
* and its children). Visually:
*
* [ [ $queue, [ [ $child, [] ], [ $child, [] ] ], [ $queue, ... ] ]
*
* Parameters:
* $staff - <Staff> staff object which should be used to determine
* visible queues.
* $pid - <int> parent_id of root queue. Default is zero (top-level)
*/
static function getHierarchicalQueues(Staff $staff, $pid=0) {
$all = static::objects()
->filter(Q::any(array(
'flags__hasbit' => self::FLAG_PUBLIC,
'flags__hasbit' => static::FLAG_QUEUE,
'staff_id' => $staff->getId(),
)))
->exclude(['flags__hasbit' => self::FLAG_DISABLED])
->asArray();
// Find all the queues with a given parent
$for_parent = function($pid) use ($all, &$for_parent) {
$results = [];
foreach (new \ArrayIterator($all) as $q) {
if ($q->parent_id == $pid)
$results[] = [ $q, $for_parent($q->getId()) ];
}
return $results;
};
return $for_parent($pid);
}
static function getOrmPath($name, $query=null) {
// Special case for custom data `__answers!id__value`. Only add the
// join and constraint on the query the first pass, when the query
......
......@@ -4,6 +4,7 @@
// $q - <CustomQueue> object for this navigation entry
// $selected - <bool> true if this queue is currently active
// $child_selected - <bool> true if the selected queue is a descendent
$childs = $children;
$this_queue = $q;
$selected = (!isset($_REQUEST['a']) && $_REQUEST['queue'] == $this_queue->getId());
?>
......@@ -28,8 +29,21 @@ $selected = (!isset($_REQUEST['a']) && $_REQUEST['queue'] == $this_queue->getId
</li>
<!-- Start Dropdown and child queues -->
<?php foreach ($this_queue->getPublicChildren() as $q) {
include 'queue-subnavigation.tmpl.php';
<?php foreach ($childs as $_) {
list($q, $children) = $_;
if (!$q->isPrivate())
include 'queue-subnavigation.tmpl.php';
}
$first_child = true;
foreach ($childs as $_) {
list($q, $children) = $_;
if (!$q->isPrivate())
continue;
if ($first_child) {
$first_child = false;
echo '<li class="personalQ"></li>';
}
include 'queue-subnavigation.tmpl.php';
} ?>
<!-- Personal Queues -->
<?php
......
<?php
// Calling conventions
// $q - <CustomQueue> object for this navigation entry
// $children - <Array<CustomQueue>> all direct children of this queue
$queue = $q;
$children = !$queue instanceof SavedSearch ? $queue->getPublicChildren() : array();
$subq_searches = !$queue instanceof SavedSearch ? $queue->getMyChildren() : array();
$hasChildren = count($children) + count($subq_searches) > 0;
$hasChildren = count($children) > 0;
$selected = $_REQUEST['queue'] == $q->getId();
global $thisstaff;
?>
......@@ -27,24 +26,30 @@ global $thisstaff;
</a>
<?php
$closure_include = function($q) use ($thisstaff, $ost, $cfg) {
$closure_include = function($q, $children) {
global $thisstaff, $ost, $cfg;
include __FILE__;
};
if ($hasChildren) { ?>
<ul class="subMenuQ">
<?php
foreach ($children as $q)
$closure_include($q);
foreach ($children as $_) {
list($q, $childs) = $_;
if (!$q->isPrivate())
$closure_include($q, $childs);
}
// Include personal sub-queues
$first_child = true;
foreach ($subq_searches as $q) {
if ($first_child) {
foreach ($children as $_) {
list($q, $childs) = $_;
if ($q->isPrivate()) {
if ($first_child) {
$first_child = false;
echo '<li class="personalQ"></li>';
}
$closure_include($q, $childs);
}
$closure_include($q);
} ?>
</ul>
<?php
......
......@@ -445,19 +445,14 @@ $nav->setTabActive('tickets');
$nav->addSubNavInfo('jb-overflowmenu', 'customQ_nav');
// Fetch ticket queues organized by root and sub-queues
$queues = SavedQueue::queues()
->filter(Q::any(array(
'flags__hasbit' => CustomQueue::FLAG_PUBLIC,
'staff_id' => $thisstaff->getId(),
)))
->exclude(['flags__hasbit' => CustomQueue::FLAG_DISABLED])
->getIterator();
$queues = CustomQueue::getHierarchicalQueues($thisstaff);
// Start with all the top-level (container) queues
foreach ($queues->findAll(array('parent_id' => 0))
as $q) {
$nav->addSubMenu(function() use ($q, $queue) {
$selected = false;
foreach ($queues as $_) {
list($q, $children) = $_;
if ($q->isPrivate())
continue;
$nav->addSubMenu(function() use ($q, $queue, $children) {
// A queue is selected if it is the one being displayed. It is
// "child" selected if its ID is in the path of the one selected
$child_selected = $queue
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment