diff --git a/include/class.orm.php b/include/class.orm.php index 44d292f664038f825478fc01bc6e2e848e78e4aa..9798d94819db755e51664e83e739b4ec4dfde6f6 100644 --- a/include/class.orm.php +++ b/include/class.orm.php @@ -1069,6 +1069,10 @@ class QuerySet implements IteratorAggregate, ArrayAccess, Serializable, Countabl return $this; } + function copy() { + return clone $this; + } + function all() { return $this->getIterator()->asArray(); } @@ -2233,10 +2237,13 @@ class MySqlCompiler extends SqlCompiler { $vals = array_map(array($this, 'input'), $b); $b = '('.implode(', ', $vals).')'; } + // MySQL is almost always faster with a join. Use one if possible // MySQL doesn't support LIMIT or OFFSET in subqueries. Instead, add // the query as a JOIN and add the join constraint into the WHERE // clause. - elseif ($b instanceof QuerySet && ($b->isWindowed() || $b->countSelectFields() > 1)) { + elseif ($b instanceof QuerySet + && ($b->isWindowed() || $b->countSelectFields() > 1 || $b->chain) + ) { $f1 = $b->values[0]; $view = $b->asView(); $alias = $this->pushJoin($view, $a, $view, array('constraint'=>array())); diff --git a/include/client/tickets.inc.php b/include/client/tickets.inc.php index 32ad5abf8fc8def44985e6b56214b5fad6b7d613..fef80c6008f3bae8555da341d00dd55a237e316e 100644 --- a/include/client/tickets.inc.php +++ b/include/client/tickets.inc.php @@ -32,23 +32,11 @@ else { $closedTickets = $thisclient->getNumClosedTickets($org_tickets); } -$tickets = TicketModel::objects(); +$tickets = Ticket::objects(); $qs = array(); $status=null; -if ($settings['status']) - $status = strtolower($settings['status']); - switch ($status) { - default: - $status = 'open'; - case 'open': - case 'closed': - $results_type = ($status == 'closed') ? __('Closed Tickets') : __('Open Tickets'); - $tickets->filter(array('status__state' => $status)); - break; -} - $sortOptions=array('id'=>'number', 'subject'=>'cdata__subject', 'status'=>'status__name', 'dept'=>'dept__name','date'=>'created'); $orderWays=array('DESC'=>'-','ASC'=>''); @@ -65,16 +53,40 @@ if($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])]) $x=$sort.'_sort'; $$x=' class="'.strtolower($_REQUEST['order'] ?: 'desc').'" '; -// Add visibility constraints -$visibility = Q::any(array( - 'user_id' => $thisclient->getId(), - 'thread__collaborators__user_id' => $thisclient->getId(), -)); +$basic_filter = Ticket::objects(); +if ($settings['topic_id']) { + $basic_filter = $basic_filter->filter(array('topic_id' => $settings['topic_id'])); +} + +if ($settings['status']) + $status = strtolower($settings['status']); + switch ($status) { + default: + $status = 'open'; + case 'open': + case 'closed': + $results_type = ($status == 'closed') ? __('Closed Tickets') : __('Open Tickets'); + $basic_filter->filter(array('status__state' => $status)); + break; +} -if ($thisclient->canSeeOrgTickets()) - $visibility->add(array('user__org_id' => $thisclient->getOrgId())); +// Add visibility constraints — use a union query to use multiple indexes, +// use UNION without "ALL" (false as second parameter to union()) to imply +// unique values +$visibility = $basic_filter->copy() + ->values_flat('ticket_id') + ->filter(array('user_id' => $thisclient->getId())) + ->union($basic_filter->copy() + ->values_flat('ticket_id') + ->filter(array('thread__collaborators__user_id' => $thisclient->getId())) + , false); -$tickets->filter($visibility); +if ($thisclient->canSeeOrgTickets()) { + $visibility = $visibility->union( + $basic_filter->copy()->values_flat('ticket_id') + ->filter(array('user__org_id' => $thisclient->getOrgId())) + , false); +} // Perform basic search if ($settings['keywords']) { @@ -83,14 +95,10 @@ if ($settings['keywords']) { $tickets->filter(array('number__startswith'=>$q)); } else { //Deep search! // Use the search engine to perform the search - $tickets = $ost->searcher->find($q, $tickets); + $tickets = $ost->searcher->find($q, $tickets)->distinct('ticket_id'); } } -if ($settings['topic_id']) { - $tickets = $tickets->filter(array('topic_id' => $settings['topic_id'])); -} - TicketForm::ensureDynamicDataView(); $total=$tickets->count(); @@ -99,6 +107,7 @@ $pageNav=new Pagenate($total, $page, PAGE_LIMIT); $qstr = '&'. Http::build_query($qs); $qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']); $pageNav->setURL('tickets.php', $qs); +$tickets->filter(array('ticket_id__in' => $visibility)); $pageNav->paginate($tickets); $showing =$total ? $pageNav->showing() : ""; @@ -112,7 +121,6 @@ if($search) $negorder=$order=='-'?'ASC':'DESC'; //Negate the sorting -$tickets->order_by($order.$order_by); $tickets->values( 'ticket_id', 'number', 'created', 'isanswered', 'source', 'status_id', 'status__state', 'status__name', 'cdata__subject', 'dept_id',