Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15387622
D9896.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
D9896.id.diff
View Options
diff --git a/resources/sql/autopatches/20140711.pnames.1.sql b/resources/sql/autopatches/20140711.pnames.1.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20140711.pnames.1.sql
@@ -0,0 +1,7 @@
+CREATE TABLE {$NAMESPACE}_project.project_datasourcetoken (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ projectID INT UNSIGNED NOT NULL,
+ token VARCHAR(128) NOT NULL COLLATE utf8_general_ci,
+ UNIQUE KEY (token, projectID),
+ KEY (projectID)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
diff --git a/resources/sql/autopatches/20140711.pnames.2.php b/resources/sql/autopatches/20140711.pnames.2.php
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20140711.pnames.2.php
@@ -0,0 +1,11 @@
+<?php
+
+echo "Updating project datasource tokens...\n";
+
+foreach (new LiskMigrationIterator(new PhabricatorProject()) as $project) {
+ $name = $project->getName();
+ echo "Updating project '{$name}'...\n";
+ $project->updateDatasourceTokens();
+}
+
+echo "Done.\n";
diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php
--- a/src/applications/people/storage/PhabricatorUser.php
+++ b/src/applications/people/storage/PhabricatorUser.php
@@ -459,32 +459,18 @@
return $this;
}
- private static function tokenizeName($name) {
- if (function_exists('mb_strtolower')) {
- $name = mb_strtolower($name, 'UTF-8');
- } else {
- $name = strtolower($name);
- }
- $name = trim($name);
- if (!strlen($name)) {
- return array();
- }
- return preg_split('/\s+/', $name);
- }
-
/**
* Populate the nametoken table, which used to fetch typeahead results. When
* a user types "linc", we want to match "Abraham Lincoln" from on-demand
* typeahead sources. To do this, we need a separate table of name fragments.
*/
public function updateNameTokens() {
- $tokens = array_merge(
- self::tokenizeName($this->getRealName()),
- self::tokenizeName($this->getUserName()));
- $tokens = array_unique($tokens);
$table = self::NAMETOKEN_TABLE;
$conn_w = $this->establishConnection('w');
+ $tokens = PhabricatorTypeaheadDatasource::tokenizeString(
+ $this->getUserName().' '.$this->getRealName());
+
$sql = array();
foreach ($tokens as $token) {
$sql[] = qsprintf(
diff --git a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
--- a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
+++ b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
@@ -125,6 +125,8 @@
->setProjectPHID($object->getPHID())
->save();
+ $object->updateDatasourceTokens();
+
// TODO -- delete all of the below once we sever automagical project
// to phriction stuff
if ($xaction->getOldValue() === null) {
@@ -182,6 +184,9 @@
$rem_slug->delete();
}
}
+
+ $object->updateDatasourceTokens();
+
return;
case PhabricatorTransactions::TYPE_VIEW_POLICY:
case PhabricatorTransactions::TYPE_EDIT_POLICY:
diff --git a/src/applications/project/query/PhabricatorProjectQuery.php b/src/applications/project/query/PhabricatorProjectQuery.php
--- a/src/applications/project/query/PhabricatorProjectQuery.php
+++ b/src/applications/project/query/PhabricatorProjectQuery.php
@@ -9,6 +9,7 @@
private $slugs;
private $phrictionSlugs;
private $names;
+ private $datasourceQuery;
private $status = 'status-any';
const STATUS_ANY = 'status-any';
@@ -57,6 +58,11 @@
return $this;
}
+ public function withDatasourceQuery($string) {
+ $this->datasourceQuery = $string;
+ return $this;
+ }
+
public function needMembers($need_members) {
$this->needMembers = $need_members;
return $this;
@@ -286,7 +292,7 @@
}
private function buildGroupClause($conn_r) {
- if ($this->memberPHIDs) {
+ if ($this->memberPHIDs || $this->datasourceQuery) {
return 'GROUP BY p.id';
} else {
return $this->buildApplicationSearchGroupClause($conn_r);
@@ -296,7 +302,7 @@
private function buildJoinClause($conn_r) {
$joins = array();
- if (!$this->needMembers) {
+ if (!$this->needMembers !== null) {
$joins[] = qsprintf(
$conn_r,
'LEFT JOIN %T vm ON vm.src = p.phid AND vm.type = %d AND vm.dst = %s',
@@ -305,7 +311,7 @@
$this->getViewer()->getPHID());
}
- if ($this->memberPHIDs) {
+ if ($this->memberPHIDs !== null) {
$joins[] = qsprintf(
$conn_r,
'JOIN %T e ON e.src = p.phid AND e.type = %d',
@@ -313,13 +319,32 @@
PhabricatorEdgeConfig::TYPE_PROJ_MEMBER);
}
- if ($this->slugs) {
+ if ($this->slugs !== null) {
$joins[] = qsprintf(
$conn_r,
'JOIN %T slug on slug.projectPHID = p.phid',
id(new PhabricatorProjectSlug())->getTableName());
}
+ if ($this->datasourceQuery !== null) {
+ $tokens = PhabricatorTypeaheadDatasource::tokenizeString(
+ $this->datasourceQuery);
+ if (!$tokens) {
+ throw new PhabricatorEmptyQueryException();
+ }
+
+ $likes = array();
+ foreach ($tokens as $token) {
+ $likes[] = qsprintf($conn_r, 'token.token LIKE %>', $token);
+ }
+
+ $joins[] = qsprintf(
+ $conn_r,
+ 'JOIN %T token ON token.projectID = p.id AND (%Q)',
+ PhabricatorProject::TABLE_DATASOURCE_TOKEN,
+ '('.implode(') OR (', $likes).')');
+ }
+
$joins[] = $this->buildApplicationSearchJoinClause($conn_r);
return implode(' ', $joins);
diff --git a/src/applications/project/query/PhabricatorProjectSearchEngine.php b/src/applications/project/query/PhabricatorProjectSearchEngine.php
--- a/src/applications/project/query/PhabricatorProjectSearchEngine.php
+++ b/src/applications/project/query/PhabricatorProjectSearchEngine.php
@@ -21,7 +21,9 @@
$saved->setParameter(
'memberPHIDs',
$this->readUsersFromRequest($request, 'members'));
+
$saved->setParameter('status', $request->getStr('status'));
+ $saved->setParameter('name', $request->getStr('name'));
$this->readCustomFieldsFromRequest($request, $saved);
@@ -43,6 +45,11 @@
$query->withStatus($status);
}
+ $name = $saved->getParameter('name');
+ if (strlen($name)) {
+ $query->withDatasourceQuery($name);
+ }
+
$this->applyCustomFieldsToQuery($query, $saved);
return $query;
@@ -59,9 +66,15 @@
->execute();
$status = $saved->getParameter('status');
+ $name = $saved->getParameter('name');
$form
->appendChild(
+ id(new AphrontFormTextControl())
+ ->setName('name')
+ ->setLabel(pht('Name'))
+ ->setValue($name))
+ ->appendChild(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorPeopleDatasource())
->setName('members')
diff --git a/src/applications/project/storage/PhabricatorProject.php b/src/applications/project/storage/PhabricatorProject.php
--- a/src/applications/project/storage/PhabricatorProject.php
+++ b/src/applications/project/storage/PhabricatorProject.php
@@ -32,6 +32,8 @@
const DEFAULT_ICON = 'fa-briefcase';
const DEFAULT_COLOR = 'blue';
+ const TABLE_DATASOURCE_TOKEN = 'project_datasourcetoken';
+
public static function initializeNewProject(PhabricatorUser $actor) {
return id(new PhabricatorProject())
->setName('')
@@ -219,6 +221,53 @@
return $this->color;
}
+ public function save() {
+ $this->openTransaction();
+ $result = parent::save();
+ $this->updateDatasourceTokens();
+ $this->saveTransaction();
+
+ return $result;
+ }
+
+ public function updateDatasourceTokens() {
+ $table = self::TABLE_DATASOURCE_TOKEN;
+ $conn_w = $this->establishConnection('w');
+ $id = $this->getID();
+
+ $slugs = queryfx_all(
+ $conn_w,
+ 'SELECT * FROM %T WHERE projectPHID = %s',
+ id(new PhabricatorProjectSlug())->getTableName(),
+ $this->getPHID());
+
+ $all_strings = ipull($slugs, 'slug');
+ $all_strings[] = $this->getName();
+ $all_strings = implode(' ', $all_strings);
+
+ $tokens = PhabricatorTypeaheadDatasource::tokenizeString($all_strings);
+
+ $sql = array();
+ foreach ($tokens as $token) {
+ $sql[] = qsprintf($conn_w, '(%d, %s)', $id, $token);
+ }
+
+ $this->openTransaction();
+ queryfx(
+ $conn_w,
+ 'DELETE FROM %T WHERE projectID = %d',
+ $table,
+ $id);
+
+ foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) {
+ queryfx(
+ $conn_w,
+ 'INSERT INTO %T (projectID, token) VALUES %Q',
+ $table,
+ $chunk);
+ }
+ $this->saveTransaction();
+ }
/* -( PhabricatorSubscribableInterface )----------------------------------- */
diff --git a/src/applications/project/typeahead/PhabricatorProjectDatasource.php b/src/applications/project/typeahead/PhabricatorProjectDatasource.php
--- a/src/applications/project/typeahead/PhabricatorProjectDatasource.php
+++ b/src/applications/project/typeahead/PhabricatorProjectDatasource.php
@@ -13,22 +13,37 @@
public function loadResults() {
$viewer = $this->getViewer();
+
$raw_query = $this->getRawQuery();
- $results = array();
+ // Allow users to type "#qa" or "qa" to find "Quality Assurance".
+ $raw_query = ltrim($raw_query, '#');
+
+ if (!strlen($raw_query)) {
+ return array();
+ }
$projs = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->needImages(true)
+ ->needSlugs(true)
+ ->withDatasourceQuery($raw_query)
->execute();
+
+ $results = array();
foreach ($projs as $proj) {
$closed = null;
if ($proj->isArchived()) {
$closed = pht('Archived');
}
+ $all_strings = mpull($proj->getSlugs(), 'getSlug');
+ $all_strings[] = $proj->getName();
+ $all_strings = implode(' ', $all_strings);
+
$proj_result = id(new PhabricatorTypeaheadResult())
- ->setName($proj->getName())
+ ->setName($all_strings)
+ ->setDisplayName($proj->getName())
->setDisplayType('Project')
->setURI('/tag/'.$proj->getPrimarySlug().'/')
->setPHID($proj->getPHID())
diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
--- a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
+++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
@@ -51,4 +51,15 @@
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);
+ }
+
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Mar 16, 2:42 AM (6 d, 3 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7703769
Default Alt Text
D9896.id.diff (10 KB)
Attached To
Mode
D9896: Give projects a proper on-demand datasource
Attached
Detach File
Event Timeline
Log In to Comment