Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15416428
D12460.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
13 KB
Referenced Files
None
Subscribers
None
D12460.id.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2295,11 +2295,15 @@
'PhabricatorProjectIcon' => 'applications/project/icon/PhabricatorProjectIcon.php',
'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php',
'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php',
+ 'PhabricatorProjectLogicDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicDatasource.php',
+ 'PhabricatorProjectLogicalAndDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalAndDatasource.php',
+ 'PhabricatorProjectLogicalOrNotDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php',
'PhabricatorProjectMemberOfProjectEdgeType' => 'applications/project/edge/PhabricatorProjectMemberOfProjectEdgeType.php',
'PhabricatorProjectMembersDatasource' => 'applications/project/typeahead/PhabricatorProjectMembersDatasource.php',
'PhabricatorProjectMembersEditController' => 'applications/project/controller/PhabricatorProjectMembersEditController.php',
'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php',
'PhabricatorProjectMoveController' => 'applications/project/controller/PhabricatorProjectMoveController.php',
+ 'PhabricatorProjectNoProjectsDatasource' => 'applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php',
'PhabricatorProjectObjectHasProjectEdgeType' => 'applications/project/edge/PhabricatorProjectObjectHasProjectEdgeType.php',
'PhabricatorProjectOrUserDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserDatasource.php',
'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php',
@@ -5674,11 +5678,15 @@
'PhabricatorProjectFeedController' => 'PhabricatorProjectController',
'PhabricatorProjectIcon' => 'Phobject',
'PhabricatorProjectListController' => 'PhabricatorProjectController',
+ 'PhabricatorProjectLogicDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
+ 'PhabricatorProjectLogicalAndDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
+ 'PhabricatorProjectLogicalOrNotDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorProjectMemberOfProjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorProjectMembersDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorProjectMembersEditController' => 'PhabricatorProjectController',
'PhabricatorProjectMembersRemoveController' => 'PhabricatorProjectController',
'PhabricatorProjectMoveController' => 'PhabricatorProjectController',
+ 'PhabricatorProjectNoProjectsDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorProjectObjectHasProjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorProjectOrUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/typeahead/PhabricatorProjectLogicDatasource.php
@@ -0,0 +1,22 @@
+<?php
+
+final class PhabricatorProjectLogicDatasource
+ extends PhabricatorTypeaheadCompositeDatasource {
+
+ public function getPlaceholderText() {
+ return pht('Type a project name or selector...');
+ }
+
+ public function getDatasourceApplicationClass() {
+ return 'PhabricatorProjectApplication';
+ }
+
+ public function getComponentDatasources() {
+ return array(
+ new PhabricatorProjectNoProjectsDatasource(),
+ new PhabricatorProjectLogicalAndDatasource(),
+ new PhabricatorProjectLogicalOrNotDatasource(),
+ );
+ }
+
+}
diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalAndDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalAndDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/typeahead/PhabricatorProjectLogicalAndDatasource.php
@@ -0,0 +1,32 @@
+<?php
+
+final class PhabricatorProjectLogicalAndDatasource
+ extends PhabricatorTypeaheadCompositeDatasource {
+
+ public function getPlaceholderText() {
+ return pht('Type a project name...');
+ }
+
+ public function getDatasourceApplicationClass() {
+ return 'PhabricatorProjectApplication';
+ }
+
+ public function getComponentDatasources() {
+ return array(
+ new PhabricatorProjectDatasource(),
+ );
+ }
+
+ public function evaluateTokens(array $tokens) {
+ $results = parent::evaluateTokens($tokens);
+
+ foreach ($results as $key => $result) {
+ $results[$key] = new PhabricatorQueryConstraint(
+ PhabricatorQueryConstraint::OPERATOR_AND,
+ $result);
+ }
+
+ return $results;
+ }
+
+}
diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php
@@ -0,0 +1,115 @@
+<?php
+
+final class PhabricatorProjectLogicalOrNotDatasource
+ extends PhabricatorTypeaheadCompositeDatasource {
+
+ public function getPlaceholderText() {
+ return pht('Type any(<project>) or not(<project>)...');
+ }
+
+ public function getDatasourceApplicationClass() {
+ return 'PhabricatorProjectApplication';
+ }
+
+ public function getComponentDatasources() {
+ return array(
+ new PhabricatorProjectDatasource(),
+ );
+ }
+
+ public function getDatasourceFunctions() {
+ return array(
+ 'any' => array(
+ 'name' => pht('Find results in any of several projects.'),
+ ),
+ 'not' => array(
+ 'name' => pht('Find results not in specific projects.'),
+ ),
+ );
+ }
+
+ protected function didLoadResults(array $results) {
+ $function = $this->getCurrentFunction();
+ $return_any = ($function !== 'not');
+ $return_not = ($function !== 'any');
+
+ $return = array();
+ foreach ($results as $result) {
+ $result
+ ->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
+ ->setIcon('fa-asterisk');
+
+ if ($return_any) {
+ $return[] = id(clone $result)
+ ->setPHID('any('.$result->getPHID().')')
+ ->setDisplayName(pht('In Any: %s', $result->getDisplayName()))
+ ->setName($result->getName().' any');
+ }
+
+ if ($return_not) {
+ $return[] = id(clone $result)
+ ->setPHID('not('.$result->getPHID().')')
+ ->setDisplayName(pht('Not In: %s', $result->getDisplayName()))
+ ->setName($result->getName().' not');
+ }
+ }
+
+ return $return;
+ }
+
+ protected function evaluateFunction($function, array $argv_list) {
+ $phids = array();
+ foreach ($argv_list as $argv) {
+ $phids[] = head($argv);
+ }
+
+ $operator = array(
+ 'any' => PhabricatorQueryConstraint::OPERATOR_OR,
+ 'not' => PhabricatorQueryConstraint::OPERATOR_NOT,
+ );
+
+ $results = array();
+ foreach ($phids as $phid) {
+ $results[] = new PhabricatorQueryConstraint(
+ $operator[$function],
+ $phid);
+ }
+
+ return $phids;
+ }
+
+ public function renderFunctionTokens($function, array $argv_list) {
+ $phids = array();
+ foreach ($argv_list as $argv) {
+ $phids[] = head($argv);
+ }
+
+ $tokens = $this->renderTokens($phids);
+ foreach ($tokens as $token) {
+ if ($token->isInvalid()) {
+ if ($function == 'any') {
+ $token->setValue(pht('In Any: Invalid Project'));
+ } else {
+ $token->setValue(pht('Not In: Invalid Project'));
+ }
+ } else {
+ $token
+ ->setIcon('fa-asterisk')
+ ->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION);
+
+ if ($function == 'any') {
+ $token
+ ->setKey('any('.$token->getKey().')')
+ ->setValue(pht('In Any: %s', $token->getValue()));
+ } else {
+ $token
+ ->setKey('not('.$token->getKey().')')
+ ->setValue(pht('Not In: %s', $token->getValue()));
+ }
+ }
+ }
+
+ return $tokens;
+ }
+
+}
diff --git a/src/applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php b/src/applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php
@@ -0,0 +1,62 @@
+<?php
+
+final class PhabricatorProjectNoProjectsDatasource
+ extends PhabricatorTypeaheadDatasource {
+
+ public function getPlaceholderText() {
+ return pht('Type "not in any projects"...');
+ }
+
+ public function getDatasourceApplicationClass() {
+ return 'PhabricatorProjectApplication';
+ }
+
+ public function getDatasourceFunctions() {
+ return array(
+ 'null' => array(
+ 'name' => pht('Find results which are not in any projects.'),
+ ),
+ );
+ }
+
+ public function loadResults() {
+ $results = array(
+ $this->buildNullResult(),
+ );
+
+ return $this->filterResultsAgainstTokens($results);
+ }
+
+ protected function evaluateFunction($function, array $argv_list) {
+ $results = array();
+
+ foreach ($argv_list as $argv) {
+ $results[] = new PhabricatorQueryConstraint(
+ PhabricatorQueryConstraint::OPERATOR_NULL,
+ 'empty');
+ }
+
+ return $results;
+ }
+
+ public function renderFunctionTokens($function, array $argv_list) {
+ $results = array();
+ foreach ($argv_list as $argv) {
+ $results[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult(
+ $this->buildNullResult());
+ }
+ return $results;
+ }
+
+ private function buildNullResult() {
+ $name = pht('Not In Any Projects');
+
+ return $this->newFunctionResult()
+ ->setUnique(true)
+ ->setPHID('null()')
+ ->setIcon('fa-ban')
+ ->setName('null '.$name)
+ ->setDisplayName($name);
+ }
+
+}
diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
--- a/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
+++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
@@ -30,17 +30,39 @@
// query to child sources. This makes it easier to implement function
// sources in terms of real object sources.
$raw_query = $this->getRawQuery();
+
+ $is_function = false;
if (self::isFunctionToken($raw_query)) {
- $function = $this->parseFunction($raw_query, $allow_partial = true);
- if ($function) {
- $raw_query = head($function['argv']);
- }
+ $is_function = true;
}
+ $stack = $this->getFunctionStack();
+
$results = array();
foreach ($this->getUsableDatasources() as $source) {
+ $source_stack = $stack;
+
+ $source_query = $raw_query;
+ if ($is_function) {
+ // If this source can't handle the function, skip it.
+ $function = $source->parseFunction($raw_query, $allow_partial = true);
+ if (!$function) {
+ continue;
+ }
+
+ // If this source handles the function directly, strip the function.
+ // Otherwise, this is something like a composite source which has
+ // some internal source which can evaluate the function, but will
+ // perform stripping later.
+ if ($source->shouldStripFunction($function['name'])) {
+ $source_query = head($function['argv']);
+ $source_stack[] = $function['name'];
+ }
+ }
+
$source
- ->setRawQuery($raw_query)
+ ->setFunctionStack($source_stack)
+ ->setRawQuery($source_query)
->setQuery($this->getQuery())
->setViewer($this->getViewer());
@@ -106,7 +128,6 @@
return parent::canEvaluateFunction($function);
}
-
protected function evaluateFunction($function, array $argv) {
foreach ($this->getUsableDatasources() as $source) {
if ($source->canEvaluateFunction($function)) {
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
@@ -11,6 +11,7 @@
private $offset;
private $limit;
private $parameters = array();
+ private $functionStack = array();
public function setLimit($limit) {
$this->limit = $limit;
@@ -274,6 +275,14 @@
* @task functions
*/
protected function canEvaluateFunction($function) {
+ return $this->shouldStripFunction($function);
+ }
+
+
+ /**
+ * @task functions
+ */
+ protected function shouldStripFunction($function) {
$functions = $this->getDatasourceFunctions();
return isset($functions[$function]);
}
@@ -337,7 +346,7 @@
$matches = null;
if ($allow_partial) {
- $ok = preg_match('/^([^(]+)\((.*)$/', $token, $matches);
+ $ok = preg_match('/^([^(]+)\((.*?)\)?$/', $token, $matches);
} else {
$ok = preg_match('/^([^(]+)\((.*)\)$/', $token, $matches);
}
@@ -367,4 +376,28 @@
}
+ /**
+ * @task functions
+ */
+ public function setFunctionStack(array $function_stack) {
+ $this->functionStack = $function_stack;
+ return $this;
+ }
+
+
+ /**
+ * @task functions
+ */
+ public function getFunctionStack() {
+ return $this->functionStack;
+ }
+
+
+ /**
+ * @task functions
+ */
+ protected function getCurrentFunction() {
+ return nonempty(last($this->functionStack), null);
+ }
+
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Mar 21, 11:00 AM (2 w, 6 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7355254
Default Alt Text
D12460.id.diff (13 KB)
Attached To
Mode
D12460: Implement a project logic datasource
Attached
Detach File
Event Timeline
Log In to Comment