Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2895273
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
13 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/applications/conpherence/query/ConpherenceThreadSearchEngine.php b/src/applications/conpherence/query/ConpherenceThreadSearchEngine.php
index e6c6855ca3..2a23d6c073 100644
--- a/src/applications/conpherence/query/ConpherenceThreadSearchEngine.php
+++ b/src/applications/conpherence/query/ConpherenceThreadSearchEngine.php
@@ -1,465 +1,464 @@
<?php
final class ConpherenceThreadSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Threads');
}
public function getApplicationClassName() {
return 'PhabricatorConpherenceApplication';
}
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter(
'participantPHIDs',
$this->readUsersFromRequest($request, 'participants'));
$saved->setParameter('fulltext', $request->getStr('fulltext'));
$saved->setParameter(
'threadType',
$request->getStr('threadType'));
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new ConpherenceThreadQuery())
->needParticipantCache(true);
$participant_phids = $saved->getParameter('participantPHIDs', array());
if ($participant_phids && is_array($participant_phids)) {
$query->withParticipantPHIDs($participant_phids);
}
$fulltext = $saved->getParameter('fulltext');
if (strlen($fulltext)) {
$query->withFulltext($fulltext);
}
$thread_type = $saved->getParameter('threadType');
if (idx($this->getTypeOptions(), $thread_type)) {
switch ($thread_type) {
case 'rooms':
$query->withIsRoom(true);
break;
case 'messages':
$query->withIsRoom(false);
break;
case 'both':
$query->withIsRoom(null);
break;
}
}
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved) {
$participant_phids = $saved->getParameter('participantPHIDs', array());
$fulltext = $saved->getParameter('fulltext');
$form
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorPeopleDatasource())
->setName('participants')
->setLabel(pht('Participants'))
->setValue($participant_phids))
->appendControl(
id(new AphrontFormTextControl())
->setName('fulltext')
->setLabel(pht('Contains Words'))
->setValue($fulltext))
->appendControl(
id(new AphrontFormSelectControl())
->setLabel(pht('Type'))
->setName('threadType')
->setOptions($this->getTypeOptions())
->setValue($saved->getParameter('threadType')));
}
protected function getURI($path) {
return '/conpherence/search/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array();
$names = array(
'all' => pht('All Rooms'),
);
if ($this->requireViewer()->isLoggedIn()) {
$names['participant'] = pht('Joined Rooms');
$names['messages'] = pht('All Messages');
}
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
$query->setParameter('threadType', 'rooms');
return $query;
case 'participant':
$query->setParameter('threadType', 'rooms');
return $query->setParameter(
'participantPHIDs',
array($this->requireViewer()->getPHID()));
case 'messages':
$query->setParameter('threadType', 'messages');
return $query->setParameter(
'participantPHIDs',
array($this->requireViewer()->getPHID()));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function getRequiredHandlePHIDsForResultList(
array $conpherences,
PhabricatorSavedQuery $query) {
$recent = mpull($conpherences, 'getRecentParticipantPHIDs');
return array_unique(array_mergev($recent));
}
protected function renderResultList(
array $conpherences,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($conpherences, 'ConpherenceThread');
$viewer = $this->requireViewer();
$policy_objects = ConpherenceThread::loadPolicyObjects(
$viewer,
$conpherences);
$fulltext = $query->getParameter('fulltext');
if (strlen($fulltext) && $conpherences) {
$context = $this->loadContextMessages($conpherences, $fulltext);
$author_phids = array();
foreach ($context as $messages) {
foreach ($messages as $group) {
foreach ($group as $message) {
$xaction = $message['xaction'];
if ($xaction) {
$author_phids[] = $xaction->getAuthorPHID();
}
}
}
}
$handles = $viewer->loadHandles($author_phids);
} else {
$context = array();
}
$list = new PHUIObjectItemListView();
$list->setUser($viewer);
foreach ($conpherences as $conpherence) {
$created = phabricator_date($conpherence->getDateCreated(), $viewer);
- $data = $conpherence->getDisplayData($viewer);
- $title = $data['title'];
+ $title = $conpherence->getDisplayTitle($viewer);
if ($conpherence->getIsRoom()) {
$icon_name = $conpherence->getPolicyIconName($policy_objects);
} else {
$icon_name = 'fa-envelope-o';
}
$icon = id(new PHUIIconView())
->setIconFont($icon_name);
$item = id(new PHUIObjectItemView())
->setObjectName($conpherence->getMonogram())
->setHeader($title)
->setHref('/conpherence/'.$conpherence->getID().'/')
->setObject($conpherence)
->addIcon('none', $created)
->addIcon(
'none',
pht('Messages: %d', $conpherence->getMessageCount()))
->addAttribute(
array(
$icon,
' ',
pht(
'Last updated %s',
phabricator_datetime($conpherence->getDateModified(), $viewer)),
));
$messages = idx($context, $conpherence->getPHID());
if ($messages) {
// TODO: This is egregiously under-designed.
foreach ($messages as $group) {
$rows = array();
$rowc = array();
foreach ($group as $message) {
$xaction = $message['xaction'];
if (!$xaction) {
continue;
}
$rowc[] = ($message['match'] ? 'highlighted' : null);
$rows[] = array(
$handles->renderHandle($xaction->getAuthorPHID()),
$xaction->getComment()->getContent(),
phabricator_datetime($xaction->getDateCreated(), $viewer),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(
array(
pht('User'),
pht('Message'),
pht('At'),
))
->setRowClasses($rowc)
->setColumnClasses(
array(
'',
'wide',
));
$box = id(new PHUIBoxView())
->appendChild($table)
->addMargin(PHUI::MARGIN_SMALL);
$item->appendChild($box);
}
}
$list->addItem($item);
}
return $list;
}
private function getTypeOptions() {
return array(
'rooms' => pht('Rooms'),
'messages' => pht('Messages'),
'both' => pht('Both'),
);
}
private function loadContextMessages(array $threads, $fulltext) {
$phids = mpull($threads, 'getPHID');
// We want to load a few messages for each thread in the result list, to
// show some of the actual content hits to help the user find what they
// are looking for.
// This method is trying to batch this lookup in most cases, so we do
// between one and "a handful" of queries instead of one per thread in
// most cases. To do this:
//
// - Load a big block of results for all of the threads.
// - If we didn't get a full block back, we have everything that matches
// the query. Sort it out and exit.
// - Otherwise, some threads had a ton of hits, so we might not be
// getting everything we want (we could be getting back 1,000 hits for
// the first thread). Remove any threads which we have enough results
// for and try again.
// - Repeat until we have everything or every thread has enough results.
//
// In the worst case, we could end up degrading to one query per thread,
// but this is incredibly unlikely on real data.
// Size of the result blocks we're going to load.
$limit = 1000;
// Number of messages we want for each thread.
$want = 3;
$need = $phids;
$hits = array();
while ($need) {
$rows = id(new ConpherenceFulltextQuery())
->withThreadPHIDs($need)
->withFulltext($fulltext)
->setLimit($limit)
->execute();
foreach ($rows as $row) {
$hits[$row['threadPHID']][] = $row;
}
if (count($rows) < $limit) {
break;
}
foreach ($need as $key => $phid) {
if (count($hits[$phid]) >= $want) {
unset($need[$key]);
}
}
}
// Now that we have all the fulltext matches, throw away any extras that we
// aren't going to render so we don't need to do lookups on them.
foreach ($hits as $phid => $rows) {
if (count($rows) > $want) {
$hits[$phid] = array_slice($rows, 0, $want);
}
}
// For each fulltext match, we want to render a message before and after
// the match to give it some context. We already know the transactions
// before each match because the rows have a "previousTransactionPHID",
// but we need to do one more query to figure out the transactions after
// each match.
// Collect the transactions we want to find the next transactions for.
$after = array();
foreach ($hits as $phid => $rows) {
foreach ($rows as $row) {
$after[] = $row['transactionPHID'];
}
}
// Look up the next transactions.
if ($after) {
$after_rows = id(new ConpherenceFulltextQuery())
->withPreviousTransactionPHIDs($after)
->execute();
} else {
$after_rows = array();
}
// Build maps from PHIDs to the previous and next PHIDs.
$prev_map = array();
$next_map = array();
foreach ($after_rows as $row) {
$next_map[$row['previousTransactionPHID']] = $row['transactionPHID'];
}
foreach ($hits as $phid => $rows) {
foreach ($rows as $row) {
$prev = $row['previousTransactionPHID'];
if ($prev) {
$prev_map[$row['transactionPHID']] = $prev;
$next_map[$prev] = $row['transactionPHID'];
}
}
}
// Now we're going to collect the actual transaction PHIDs, in order, that
// we want to show for each thread.
$groups = array();
foreach ($hits as $thread_phid => $rows) {
$rows = ipull($rows, null, 'transactionPHID');
foreach ($rows as $phid => $row) {
unset($rows[$phid]);
$group = array();
// Walk backward, finding all the previous results. We can just keep
// going until we run out of results because we've only loaded things
// that we want to show.
$prev = $phid;
while (true) {
if (!isset($prev_map[$prev])) {
// No previous transaction, so we're done.
break;
}
$prev = $prev_map[$prev];
if (isset($rows[$prev])) {
$match = true;
unset($rows[$prev]);
} else {
$match = false;
}
$group[] = array(
'phid' => $prev,
'match' => $match,
);
}
if (count($group) > 1) {
$group = array_reverse($group);
}
$group[] = array(
'phid' => $phid,
'match' => true,
);
$next = $phid;
while (true) {
if (!isset($next_map[$next])) {
break;
}
$next = $next_map[$next];
if (isset($rows[$next])) {
$match = true;
unset($rows[$next]);
} else {
$match = false;
}
$group[] = array(
'phid' => $next,
'match' => $match,
);
}
$groups[$thread_phid][] = $group;
}
}
// Load all the actual transactions we need.
$xaction_phids = array();
foreach ($groups as $thread_phid => $group) {
foreach ($group as $list) {
foreach ($list as $item) {
$xaction_phids[] = $item['phid'];
}
}
}
if ($xaction_phids) {
$xactions = id(new ConpherenceTransactionQuery())
->setViewer($this->requireViewer())
->withPHIDs($xaction_phids)
->needComments(true)
->execute();
$xactions = mpull($xactions, null, 'getPHID');
} else {
$xactions = array();
}
foreach ($groups as $thread_phid => $group) {
foreach ($group as $key => $list) {
foreach ($list as $lkey => $item) {
$xaction = idx($xactions, $item['phid']);
$groups[$thread_phid][$key][$lkey]['xaction'] = $xaction;
}
}
}
// TODO: Sort the groups chronologically?
return $groups;
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Jan 19 2025, 21:11 (6 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1128810
Default Alt Text
(13 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment