Implement a projects() datasource function
Summary: Ref T4100. This is like members(), but is implemented on top of the raw datasource. This is a lot simpler and involves way less code duplication. I'll go back and implement members() like this, too. Nothing actually uses this yet. Test Plan: - Used browse view to browse datasource. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T4100 Differential Revision: https://secure.phabricator.com/D12458
This commit is contained in:
		@@ -2664,6 +2664,7 @@ phutil_register_library_map(array(
 | 
			
		||||
    'PhabricatorUserPreferences' => 'applications/settings/storage/PhabricatorUserPreferences.php',
 | 
			
		||||
    'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php',
 | 
			
		||||
    'PhabricatorUserProfileEditor' => 'applications/people/editor/PhabricatorUserProfileEditor.php',
 | 
			
		||||
    'PhabricatorUserProjectsDatasource' => 'applications/people/typeahead/PhabricatorUserProjectsDatasource.php',
 | 
			
		||||
    'PhabricatorUserRealNameField' => 'applications/people/customfield/PhabricatorUserRealNameField.php',
 | 
			
		||||
    'PhabricatorUserRolesField' => 'applications/people/customfield/PhabricatorUserRolesField.php',
 | 
			
		||||
    'PhabricatorUserSchemaSpec' => 'applications/people/storage/PhabricatorUserSchemaSpec.php',
 | 
			
		||||
@@ -6083,6 +6084,7 @@ phutil_register_library_map(array(
 | 
			
		||||
    'PhabricatorUserPreferences' => 'PhabricatorUserDAO',
 | 
			
		||||
    'PhabricatorUserProfile' => 'PhabricatorUserDAO',
 | 
			
		||||
    'PhabricatorUserProfileEditor' => 'PhabricatorApplicationTransactionEditor',
 | 
			
		||||
    'PhabricatorUserProjectsDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
 | 
			
		||||
    'PhabricatorUserRealNameField' => 'PhabricatorUserCustomField',
 | 
			
		||||
    'PhabricatorUserRolesField' => 'PhabricatorUserCustomField',
 | 
			
		||||
    'PhabricatorUserSchemaSpec' => 'PhabricatorConfigSchemaSpec',
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,85 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
final class PhabricatorUserProjectsDatasource
 | 
			
		||||
  extends PhabricatorTypeaheadCompositeDatasource {
 | 
			
		||||
 | 
			
		||||
  public function getPlaceholderText() {
 | 
			
		||||
    return pht('Type projects(<user>)...');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getDatasourceApplicationClass() {
 | 
			
		||||
    return 'PhabricatorProjectApplication';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getComponentDatasources() {
 | 
			
		||||
    return array(
 | 
			
		||||
      new PhabricatorPeopleDatasource(),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getDatasourceFunctions() {
 | 
			
		||||
    return array(
 | 
			
		||||
      'projects' => array(
 | 
			
		||||
        'name' => pht("Find results in any of a user's projects."),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function didLoadResults(array $results) {
 | 
			
		||||
    foreach ($results as $result) {
 | 
			
		||||
      $result
 | 
			
		||||
        ->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
 | 
			
		||||
        ->setIcon('fa-briefcase')
 | 
			
		||||
        ->setPHID('projects('.$result->getPHID().')')
 | 
			
		||||
        ->setDisplayName(pht('Projects: %s', $result->getDisplayName()))
 | 
			
		||||
        ->setName($result->getName().' projects');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $results;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected function evaluateFunction($function, array $argv_list) {
 | 
			
		||||
    $phids = array();
 | 
			
		||||
    foreach ($argv_list as $argv) {
 | 
			
		||||
      $phids[] = head($argv);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $projects = id(new PhabricatorPeopleQuery())
 | 
			
		||||
      ->setViewer($this->getViewer())
 | 
			
		||||
      ->needMembers(true)
 | 
			
		||||
      ->withPHIDs($phids)
 | 
			
		||||
      ->execute();
 | 
			
		||||
 | 
			
		||||
    $results = array();
 | 
			
		||||
    foreach ($projects as $project) {
 | 
			
		||||
      foreach ($project->getMemberPHIDs() as $phid) {
 | 
			
		||||
        $results[$phid] = $phid;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return array_values($results);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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()) {
 | 
			
		||||
        $token
 | 
			
		||||
          ->setValue(pht('Projects: Invalid User'));
 | 
			
		||||
      } else {
 | 
			
		||||
        $token
 | 
			
		||||
          ->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
 | 
			
		||||
          ->setKey('projects('.$token->getKey().')')
 | 
			
		||||
          ->setValue(pht('Projects: %s', $token->getValue()));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $tokens;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -25,10 +25,22 @@ abstract class PhabricatorTypeaheadCompositeDatasource
 | 
			
		||||
    $offset = $this->getOffset();
 | 
			
		||||
    $limit = $this->getLimit();
 | 
			
		||||
 | 
			
		||||
    // If the input query is a function like `members(platy`, and we can
 | 
			
		||||
    // parse the function, we strip the function off and hand the stripped
 | 
			
		||||
    // query to child sources. This makes it easier to implement function
 | 
			
		||||
    // sources in terms of real object sources.
 | 
			
		||||
    $raw_query = $this->getRawQuery();
 | 
			
		||||
    if (self::isFunctionToken($raw_query)) {
 | 
			
		||||
      $function = $this->parseFunction($raw_query, $allow_partial = true);
 | 
			
		||||
      if ($function) {
 | 
			
		||||
        $raw_query = head($function['argv']);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $results = array();
 | 
			
		||||
    foreach ($this->getUsableDatasources() as $source) {
 | 
			
		||||
      $source
 | 
			
		||||
        ->setRawQuery($this->getRawQuery())
 | 
			
		||||
        ->setRawQuery($raw_query)
 | 
			
		||||
        ->setQuery($this->getQuery())
 | 
			
		||||
        ->setViewer($this->getViewer());
 | 
			
		||||
 | 
			
		||||
@@ -36,7 +48,9 @@ abstract class PhabricatorTypeaheadCompositeDatasource
 | 
			
		||||
        $source->setLimit($offset + $limit);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $results[] = $source->loadResults();
 | 
			
		||||
      $source_results = $source->loadResults();
 | 
			
		||||
      $source_results = $source->didLoadResults($source_results);
 | 
			
		||||
      $results[] = $source_results;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $results = array_mergev($results);
 | 
			
		||||
 
 | 
			
		||||
@@ -90,6 +90,10 @@ abstract class PhabricatorTypeaheadDatasource extends Phobject {
 | 
			
		||||
  abstract public function getDatasourceApplicationClass();
 | 
			
		||||
  abstract public function loadResults();
 | 
			
		||||
 | 
			
		||||
  protected function didLoadResults(array $results) {
 | 
			
		||||
    return $results;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static function tokenizeString($string) {
 | 
			
		||||
    $string = phutil_utf8_strtolower($string);
 | 
			
		||||
    $string = trim($string);
 | 
			
		||||
@@ -258,11 +262,20 @@ abstract class PhabricatorTypeaheadDatasource extends Phobject {
 | 
			
		||||
/* -(  Token Functions  )---------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @task functions
 | 
			
		||||
   */
 | 
			
		||||
  public function getDatasourceFunctions() {
 | 
			
		||||
    return array();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @task functions
 | 
			
		||||
   */
 | 
			
		||||
  protected function canEvaluateFunction($function) {
 | 
			
		||||
    return false;
 | 
			
		||||
    $functions = $this->getDatasourceFunctions();
 | 
			
		||||
    return isset($functions[$function]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,10 @@ final class PhabricatorTypeaheadTokenView
 | 
			
		||||
    return $token;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function isInvalid() {
 | 
			
		||||
    return ($this->getTokenType() == self::TYPE_INVALID);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function setKey($key) {
 | 
			
		||||
    $this->key = $key;
 | 
			
		||||
    return $this;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user