From ee2680794f75bdc2e0dfbf8a759982e5efdef980 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 3 Jan 2014 12:24:21 -0800 Subject: [PATCH] Recognize "#project" as a formal object name Summary: Ref T4264. Ref T4262. Ref T2628. Ref T3190. To write Herald object rules which bind to a project, I want to take the low budget approach and have the user just type `#project` into a text field. Formally recognize `#project` as an object name, by moving all the existing stuff from the remarkup rule to the PHID type declaration. Test Plan: Typed `#project` into jump nav and `phid.lookup` in Conduit. Typed `#project` into Remarkup. Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T3190, T4264, T2628, T4262 Differential Revision: https://secure.phabricator.com/D7882 --- .../PhabricatorProjectPHIDTypeProject.php | 54 +++++++++++++++++-- .../project/remarkup/ProjectRemarkupRule.php | 46 ++++++---------- 2 files changed, 66 insertions(+), 34 deletions(-) diff --git a/src/applications/project/phid/PhabricatorProjectPHIDTypeProject.php b/src/applications/project/phid/PhabricatorProjectPHIDTypeProject.php index 97a81b1d0c..56165dd3cf 100644 --- a/src/applications/project/phid/PhabricatorProjectPHIDTypeProject.php +++ b/src/applications/project/phid/PhabricatorProjectPHIDTypeProject.php @@ -41,9 +41,57 @@ final class PhabricatorProjectPHIDTypeProject extends PhabricatorPHIDType { } } - public function canLoadNamedObject($name) { - // TODO: We should be able to load named projects by hashtag, e.g. "#yolo". - return false; + public static function getProjectMonogramPatternFragment() { + // NOTE: This explicitly does not match strings which contain only + // digits, because digit strings like "#123" are used to reference tasks at + // Facebook and are somewhat conventional in general. + return '[^\s.!,:;]*[^\s\d.!,:;]+[^\s.!,:;]*'; } + public function canLoadNamedObject($name) { + $fragment = self::getProjectMonogramPatternFragment(); + return preg_match('/^#'.$fragment.'$/i', $name); + } + + public function loadNamedObjects( + PhabricatorObjectQuery $query, + array $names) { + + // If the user types "#YoloSwag", we still want to match "#yoloswag", so + // we normalize, query, and then map back to the original inputs. + + $map = array(); + foreach ($names as $key => $slug) { + $map[$this->normalizeSlug(substr($slug, 1))][] = $slug; + } + + $projects = id(new PhabricatorProjectQuery()) + ->setViewer($query->getViewer()) + ->withPhrictionSlugs(array_keys($map)) + ->execute(); + + $result = array(); + foreach ($projects as $project) { + $slugs = array($project->getPhrictionSlug()); + foreach ($slugs as $slug) { + foreach ($map[$slug] as $original) { + $result[$original] = $project; + } + } + } + + return $result; + } + + private function normalizeSlug($slug) { + // NOTE: We're using phutil_utf8_strtolower() (and not PhabricatorSlug's + // normalize() method) because this normalization should be only somewhat + // liberal. We want "#YOLO" to match against "#yolo", but "#\\yo!!lo" + // should not. normalize() strips out most punctuation and leads to + // excessively aggressive matches. + + return phutil_utf8_strtolower($slug).'/'; + } + + } diff --git a/src/applications/project/remarkup/ProjectRemarkupRule.php b/src/applications/project/remarkup/ProjectRemarkupRule.php index 9acd489dd6..637f0ea505 100644 --- a/src/applications/project/remarkup/ProjectRemarkupRule.php +++ b/src/applications/project/remarkup/ProjectRemarkupRule.php @@ -11,50 +11,34 @@ final class ProjectRemarkupRule } protected function getObjectIDPattern() { - // NOTE: This explicitly does not match strings which contain only - // digits, because digit strings like "#123" are used to reference tasks at - // Facebook and are somewhat conventional in general. - return '[^\s.!,:;]*[^\s\d.!,:;]+[^\s.!,:;]*'; + return + PhabricatorProjectPHIDTypeProject::getProjectMonogramPatternFragment(); } protected function loadObjects(array $ids) { $viewer = $this->getEngine()->getConfig('viewer'); - // If the user types "#YoloSwag", we still want to match "#yoloswag", so - // we normalize, query, and then map back to the original inputs. - - $map = array(); - foreach ($ids as $key => $slug) { - $map[$this->normalizeSlug($slug)][] = $slug; + // Put the "#" back on the front of these IDs. + $names = array(); + foreach ($ids as $id) { + $names[] = '#'.$id; } - $projects = id(new PhabricatorProjectQuery()) + // Issue a query by object name. + $query = id(new PhabricatorObjectQuery()) ->setViewer($viewer) - ->withPhrictionSlugs(array_keys($map)) - ->execute(); + ->withNames($names); + $query->execute(); + $projects = $query->getNamedResults(); + + // Slice the "#" off again. $result = array(); - foreach ($projects as $project) { - $slugs = array($project->getPhrictionSlug()); - foreach ($slugs as $slug) { - foreach ($map[$slug] as $original) { - $result[$original] = $project; - } - } + foreach ($projects as $name => $project) { + $result[substr($name, 1)] = $project; } - return $result; } - private function normalizeSlug($slug) { - // NOTE: We're using phutil_utf8_strtolower() (and not PhabricatorSlug's - // normalize() method) because this normalization should be only somewhat - // liberal. We want "#YOLO" to match against "#yolo", but "#\\yo!!lo" - // should not. normalize() strips out most punctuation and leads to - // excessively aggressive matches. - - return phutil_utf8_strtolower($slug).'/'; - } - }