Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/people/query/PhabricatorPeopleQuery.php b/src/applications/people/query/PhabricatorPeopleQuery.php
index f79957dfa2..73a951bd3a 100644
--- a/src/applications/people/query/PhabricatorPeopleQuery.php
+++ b/src/applications/people/query/PhabricatorPeopleQuery.php
@@ -1,299 +1,350 @@
<?php
final class PhabricatorPeopleQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $usernames;
private $realnames;
private $emails;
private $phids;
private $ids;
private $dateCreatedAfter;
private $dateCreatedBefore;
private $isAdmin;
private $isSystemAgent;
private $isDisabled;
private $isApproved;
private $nameLike;
+ private $nameTokens;
private $needPrimaryEmail;
private $needProfile;
private $needProfileImage;
private $needStatus;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withEmails(array $emails) {
$this->emails = $emails;
return $this;
}
public function withRealnames(array $realnames) {
$this->realnames = $realnames;
return $this;
}
public function withUsernames(array $usernames) {
$this->usernames = $usernames;
return $this;
}
public function withDateCreatedBefore($date_created_before) {
$this->dateCreatedBefore = $date_created_before;
return $this;
}
public function withDateCreatedAfter($date_created_after) {
$this->dateCreatedAfter = $date_created_after;
return $this;
}
public function withIsAdmin($admin) {
$this->isAdmin = $admin;
return $this;
}
public function withIsSystemAgent($system_agent) {
$this->isSystemAgent = $system_agent;
return $this;
}
public function withIsDisabled($disabled) {
$this->isDisabled = $disabled;
return $this;
}
public function withIsApproved($approved) {
$this->isApproved = $approved;
return $this;
}
public function withNameLike($like) {
$this->nameLike = $like;
return $this;
}
+ public function withNameTokens(array $tokens) {
+ $this->nameTokens = array_values($tokens);
+ return $this;
+ }
+
public function needPrimaryEmail($need) {
$this->needPrimaryEmail = $need;
return $this;
}
public function needProfile($need) {
$this->needProfile = $need;
return $this;
}
public function needProfileImage($need) {
$this->needProfileImage = $need;
return $this;
}
public function needStatus($need) {
$this->needStatus = $need;
return $this;
}
protected function loadPage() {
$table = new PhabricatorUser();
$conn_r = $table->establishConnection('r');
$data = queryfx_all(
$conn_r,
'SELECT * FROM %T user %Q %Q %Q %Q %Q',
$table->getTableName(),
$this->buildJoinsClause($conn_r),
$this->buildWhereClause($conn_r),
- $this->buildApplicationSearchGroupClause($conn_r),
+ $this->buildGroupClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
if ($this->needPrimaryEmail) {
$table->putInSet(new LiskDAOSet());
}
return $table->loadAllFromArray($data);
}
protected function didFilterPage(array $users) {
if ($this->needProfile) {
$user_list = mpull($users, null, 'getPHID');
$profiles = new PhabricatorUserProfile();
$profiles = $profiles->loadAllWhere('userPHID IN (%Ls)',
array_keys($user_list));
$profiles = mpull($profiles, null, 'getUserPHID');
foreach ($user_list as $user_phid => $user) {
$profile = idx($profiles, $user_phid);
if (!$profile) {
$profile = new PhabricatorUserProfile();
$profile->setUserPHID($user_phid);
}
$user->attachUserProfile($profile);
}
}
if ($this->needProfileImage) {
$user_profile_file_phids = mpull($users, 'getProfileImagePHID');
$user_profile_file_phids = array_filter($user_profile_file_phids);
if ($user_profile_file_phids) {
$files = id(new PhabricatorFileQuery())
->setParentQuery($this)
->setViewer($this->getViewer())
->withPHIDs($user_profile_file_phids)
->execute();
$files = mpull($files, null, 'getPHID');
} else {
$files = array();
}
foreach ($users as $user) {
$image_phid = $user->getProfileImagePHID();
if (isset($files[$image_phid])) {
$profile_image_uri = $files[$image_phid]->getBestURI();
} else {
$profile_image_uri = PhabricatorUser::getDefaultProfileImageURI();
}
$user->attachProfileImageURI($profile_image_uri);
}
}
if ($this->needStatus) {
$user_list = mpull($users, null, 'getPHID');
$statuses = id(new PhabricatorCalendarEvent())->loadCurrentStatuses(
array_keys($user_list));
foreach ($user_list as $phid => $user) {
$status = idx($statuses, $phid);
if ($status) {
$user->attachStatus($status);
}
}
}
return $users;
}
+ private function buildGroupClause(AphrontDatabaseConnection $conn) {
+ if ($this->nameTokens) {
+ return qsprintf(
+ $conn,
+ 'GROUP BY user.id');
+ } else {
+ return $this->buildApplicationSearchGroupClause($conn);
+ }
+ }
+
private function buildJoinsClause($conn_r) {
$joins = array();
if ($this->emails) {
$email_table = new PhabricatorUserEmail();
$joins[] = qsprintf(
$conn_r,
'JOIN %T email ON email.userPHID = user.PHID',
$email_table->getTableName());
}
+ if ($this->nameTokens) {
+ foreach ($this->nameTokens as $key => $token) {
+ $token_table = 'token_'.$key;
+ $joins[] = qsprintf(
+ $conn_r,
+ 'JOIN %T %T ON %T.userID = user.id AND %T.token LIKE %>',
+ PhabricatorUser::NAMETOKEN_TABLE,
+ $token_table,
+ $token_table,
+ $token_table,
+ $token);
+ }
+ }
+
$joins[] = $this->buildApplicationSearchJoinClause($conn_r);
$joins = implode(' ', $joins);
return $joins;
}
private function buildWhereClause($conn_r) {
$where = array();
if ($this->usernames !== null) {
$where[] = qsprintf(
$conn_r,
'user.userName IN (%Ls)',
$this->usernames);
}
if ($this->emails !== null) {
$where[] = qsprintf(
$conn_r,
'email.address IN (%Ls)',
$this->emails);
}
if ($this->realnames !== null) {
$where[] = qsprintf(
$conn_r,
'user.realName IN (%Ls)',
$this->realnames);
}
if ($this->phids !== null) {
$where[] = qsprintf(
$conn_r,
'user.phid IN (%Ls)',
$this->phids);
}
if ($this->ids !== null) {
$where[] = qsprintf(
$conn_r,
'user.id IN (%Ld)',
$this->ids);
}
if ($this->dateCreatedAfter) {
$where[] = qsprintf(
$conn_r,
'user.dateCreated >= %d',
$this->dateCreatedAfter);
}
if ($this->dateCreatedBefore) {
$where[] = qsprintf(
$conn_r,
'user.dateCreated <= %d',
$this->dateCreatedBefore);
}
if ($this->isAdmin) {
$where[] = qsprintf(
$conn_r,
'user.isAdmin = 1');
}
if ($this->isDisabled !== null) {
$where[] = qsprintf(
$conn_r,
'user.isDisabled = %d',
(int)$this->isDisabled);
}
if ($this->isApproved !== null) {
$where[] = qsprintf(
$conn_r,
'user.isApproved = %d',
(int)$this->isApproved);
}
if ($this->isSystemAgent) {
$where[] = qsprintf(
$conn_r,
'user.isSystemAgent = 1');
}
if (strlen($this->nameLike)) {
$where[] = qsprintf(
$conn_r,
'user.username LIKE %~ OR user.realname LIKE %~',
$this->nameLike,
$this->nameLike);
}
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);
}
protected function getPrimaryTableAlias() {
return 'user';
}
public function getQueryApplicationClass() {
return 'PhabricatorPeopleApplication';
}
+ public function getOrderableColumns() {
+ return parent::getOrderableColumns() + array(
+ 'username' => array(
+ 'table' => 'user',
+ 'column' => 'username',
+ 'type' => 'string',
+ 'reverse' => true,
+ 'unique' => true,
+ ),
+ );
+ }
+
+ public function getPagingValueMap($cursor, array $keys) {
+ $user = $this->loadCursorObject($cursor);
+ return array(
+ 'id' => $user->getID(),
+ 'username' => $user->getUsername(),
+ );
+ }
+
+
}
diff --git a/src/applications/people/typeahead/PhabricatorPeopleDatasource.php b/src/applications/people/typeahead/PhabricatorPeopleDatasource.php
index c9e8381c35..a2df2750ad 100644
--- a/src/applications/people/typeahead/PhabricatorPeopleDatasource.php
+++ b/src/applications/people/typeahead/PhabricatorPeopleDatasource.php
@@ -1,125 +1,79 @@
<?php
final class PhabricatorPeopleDatasource
extends PhabricatorTypeaheadDatasource {
private $enrichResults;
/**
* Controls enriched rendering, for global search. This is a bit hacky and
* should probably be handled in a more general way, but is fairly reasonable
* for now.
*/
public function setEnrichResults($enrich) {
$this->enrichResults = $enrich;
return $this;
}
public function getPlaceholderText() {
return pht('Type a username...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorPeopleApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
- $raw_query = $this->getRawQuery();
+ $tokens = $this->getTokens();
- $results = array();
-
- $users = array();
- if (strlen($raw_query)) {
- // This is an arbitrary limit which is just larger than any limit we
- // actually use in the application.
-
- // TODO: The datasource should pass this in the query.
- $limit = 15;
-
- $user_table = new PhabricatorUser();
- $conn_r = $user_table->establishConnection('r');
- $ids = queryfx_all(
- $conn_r,
- 'SELECT id FROM %T WHERE username LIKE %>
- ORDER BY username ASC LIMIT %d',
- $user_table->getTableName(),
- $raw_query,
- $limit);
- $ids = ipull($ids, 'id');
-
- if (count($ids) < $limit) {
- // If we didn't find enough username hits, look for real name hits.
- // We need to pull the entire pagesize so that we end up with the
- // right number of items if this query returns many duplicate IDs
- // that we've already selected.
-
- $realname_ids = queryfx_all(
- $conn_r,
- 'SELECT DISTINCT userID FROM %T WHERE token LIKE %>
- ORDER BY token ASC LIMIT %d',
- PhabricatorUser::NAMETOKEN_TABLE,
- $raw_query,
- $limit);
- $realname_ids = ipull($realname_ids, 'userID');
- $ids = array_merge($ids, $realname_ids);
-
- $ids = array_unique($ids);
- $ids = array_slice($ids, 0, $limit);
- }
-
- // Always add the logged-in user because some tokenizers autosort them
- // first. They'll be filtered out on the client side if they don't
- // match the query.
- if ($viewer->getID()) {
- $ids[] = $viewer->getID();
- }
+ $query = id(new PhabricatorPeopleQuery())
+ ->setOrderVector(array('username'));
- if ($ids) {
- $users = id(new PhabricatorPeopleQuery())
- ->setViewer($viewer)
- ->withIDs($ids)
- ->execute();
- }
+ if ($tokens) {
+ $query->withNameTokens($tokens);
}
+ $users = $this->executeQuery($query);
+
if ($this->enrichResults && $users) {
$phids = mpull($users, 'getPHID');
$handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->withPHIDs($phids)
->execute();
}
+ $results = array();
foreach ($users as $user) {
$closed = null;
if ($user->getIsDisabled()) {
$closed = pht('Disabled');
} else if ($user->getIsSystemAgent()) {
$closed = pht('Bot/Script');
}
$result = id(new PhabricatorTypeaheadResult())
->setName($user->getFullName())
->setURI('/p/'.$user->getUsername())
->setPHID($user->getPHID())
->setPriorityString($user->getUsername())
->setPriorityType('user')
->setClosed($closed);
if ($this->enrichResults) {
$display_type = 'User';
if ($user->getIsAdmin()) {
$display_type = 'Administrator';
}
$result->setDisplayType($display_type);
$result->setImageURI($handles[$user->getPHID()]->getImageURI());
}
$results[] = $result;
}
return $results;
}
}
diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
index 8990460505..b1f55190c9 100644
--- a/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
+++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
@@ -1,66 +1,68 @@
<?php
abstract class PhabricatorTypeaheadCompositeDatasource
extends PhabricatorTypeaheadDatasource {
abstract public function getComponentDatasources();
public function getDatasourceApplicationClass() {
return null;
}
public function loadResults() {
$offset = $this->getOffset();
$limit = $this->getLimit();
$results = array();
foreach ($this->getUsableDatasources() as $source) {
$source
->setRawQuery($this->getRawQuery())
->setQuery($this->getQuery())
->setViewer($this->getViewer());
if ($limit) {
$source->setLimit($offset + $limit);
}
$results[] = $source->loadResults();
}
$results = array_mergev($results);
- $results = msort($results, 'getName');
+ $results = msort($results, 'getSortKey');
+ $count = count($results);
if ($offset || $limit) {
if (!$limit) {
$limit = count($results);
}
+
$results = array_slice($results, $offset, $limit, $preserve_keys = true);
}
return $results;
}
private function getUsableDatasources() {
$sources = $this->getComponentDatasources();
$usable = array();
foreach ($sources as $source) {
$application_class = $source->getDatasourceApplicationClass();
if ($application_class) {
$result = id(new PhabricatorApplicationQuery())
->setViewer($this->getViewer())
->withClasses(array($application_class))
->execute();
if (!$result) {
continue;
}
}
$usable[] = $source;
}
return $usable;
}
}
diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
index ac29954fff..3d6d2b75f2 100644
--- a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
+++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
@@ -1,91 +1,105 @@
<?php
abstract class PhabricatorTypeaheadDatasource extends Phobject {
private $viewer;
private $query;
private $rawQuery;
private $offset;
private $limit;
private $parameters = array();
public function setLimit($limit) {
$this->limit = $limit;
return $this;
}
public function getLimit() {
return $this->limit;
}
public function setOffset($offset) {
$this->offset = $offset;
return $this;
}
public function getOffset() {
return $this->offset;
}
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
public function getViewer() {
return $this->viewer;
}
public function setRawQuery($raw_query) {
$this->rawQuery = $raw_query;
return $this;
}
public function getRawQuery() {
return $this->rawQuery;
}
public function setQuery($query) {
$this->query = $query;
return $this;
}
public function getQuery() {
return $this->query;
}
public function setParameters(array $params) {
$this->parameters = $params;
return $this;
}
public function getParameters() {
return $this->parameters;
}
public function getParameter($name, $default = null) {
return idx($this->parameters, $name, $default);
}
public function getDatasourceURI() {
$uri = new PhutilURI('/typeahead/class/'.get_class($this).'/');
$uri->setQueryParams($this->parameters);
return (string)$uri;
}
abstract public function getPlaceholderText();
abstract public function getDatasourceApplicationClass();
abstract public function loadResults();
public static function tokenizeString($string) {
$string = phutil_utf8_strtolower($string);
$string = trim($string);
if (!strlen($string)) {
return array();
}
$tokens = preg_split('/\s+|[-\[\]]/', $string);
return array_unique($tokens);
}
+ public function getTokens() {
+ return self::tokenizeString($this->getRawQuery());
+ }
+
+ protected function executeQuery(
+ PhabricatorCursorPagedPolicyAwareQuery $query) {
+
+ return $query
+ ->setViewer($this->getViewer())
+ ->setOffset($this->getOffset())
+ ->setLimit($this->getLimit())
+ ->execute();
+ }
+
}
diff --git a/src/applications/typeahead/storage/PhabricatorTypeaheadResult.php b/src/applications/typeahead/storage/PhabricatorTypeaheadResult.php
index 134bebbf90..22a1f21b18 100644
--- a/src/applications/typeahead/storage/PhabricatorTypeaheadResult.php
+++ b/src/applications/typeahead/storage/PhabricatorTypeaheadResult.php
@@ -1,136 +1,140 @@
<?php
final class PhabricatorTypeaheadResult {
private $name;
private $uri;
private $phid;
private $priorityString;
private $displayName;
private $displayType;
private $imageURI;
private $priorityType;
private $imageSprite;
private $icon;
private $closed;
public function setIcon($icon) {
$this->icon = $icon;
return $this;
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function setURI($uri) {
$this->uri = $uri;
return $this;
}
public function setPHID($phid) {
$this->phid = $phid;
return $this;
}
public function setPriorityString($priority_string) {
$this->priorityString = $priority_string;
return $this;
}
public function setDisplayName($display_name) {
$this->displayName = $display_name;
return $this;
}
public function setDisplayType($display_type) {
$this->displayType = $display_type;
return $this;
}
public function setImageURI($image_uri) {
$this->imageURI = $image_uri;
return $this;
}
public function setPriorityType($priority_type) {
$this->priorityType = $priority_type;
return $this;
}
public function setImageSprite($image_sprite) {
$this->imageSprite = $image_sprite;
return $this;
}
public function setClosed($closed) {
$this->closed = $closed;
return $this;
}
public function getName() {
return $this->name;
}
public function getDisplayName() {
return coalesce($this->displayName, $this->getName());
}
public function getIcon() {
return nonempty($this->icon, $this->getDefaultIcon());
}
public function getPHID() {
return $this->phid;
}
+ public function getSortKey() {
+ return phutil_utf8_strtolower($this->getName());
+ }
+
public function getWireFormat() {
$data = array(
$this->name,
$this->uri ? (string)$this->uri : null,
$this->phid,
$this->priorityString,
$this->displayName,
$this->displayType,
$this->imageURI ? (string)$this->imageURI : null,
$this->priorityType,
$this->getIcon(),
$this->closed,
$this->imageSprite ? (string)$this->imageSprite : null,
);
while (end($data) === null) {
array_pop($data);
}
return $data;
}
/**
* If the datasource did not specify an icon explicitly, try to select a
* default based on PHID type.
*/
private function getDefaultIcon() {
static $icon_map;
if ($icon_map === null) {
$types = PhabricatorPHIDType::getAllTypes();
$map = array();
foreach ($types as $type) {
$icon = $type->getTypeIcon();
if ($icon !== null) {
$map[$type->getTypeConstant()] = "{$icon} bluegrey";
}
}
$icon_map = $map;
}
$phid_type = phid_get_type($this->phid);
if (isset($icon_map[$phid_type])) {
return $icon_map[$phid_type];
}
return null;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 3, 8:07 PM (8 m, 13 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
166334
Default Alt Text
(21 KB)

Event Timeline