diff --git a/src/applications/pholio/query/PholioMockQuery.php b/src/applications/pholio/query/PholioMockQuery.php index 2f6edd313f..f431ec07a1 100644 --- a/src/applications/pholio/query/PholioMockQuery.php +++ b/src/applications/pholio/query/PholioMockQuery.php @@ -1,181 +1,189 @@ ids = $ids; return $this; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } public function withAuthorPHIDs(array $author_phids) { $this->authorPHIDs = $author_phids; return $this; } public function withStatuses(array $statuses) { $this->statuses = $statuses; return $this; } public function needCoverFiles($need_cover_files) { $this->needCoverFiles = $need_cover_files; return $this; } public function needImages($need_images) { $this->needImages = $need_images; return $this; } public function needInlineComments($need_inline_comments) { $this->needInlineComments = $need_inline_comments; return $this; } public function needTokenCounts($need) { $this->needTokenCounts = $need; return $this; } protected function loadPage() { $table = new PholioMock(); $conn_r = $table->establishConnection('r'); $data = queryfx_all( $conn_r, - 'SELECT * FROM %T %Q %Q %Q', + '%Q FROM %T mock %Q %Q %Q %Q %Q %Q', + $this->buildSelectClause($conn_r), $table->getTableName(), + $this->buildJoinClause($conn_r), $this->buildWhereClause($conn_r), + $this->buildGroupClause($conn_r), $this->buildOrderClause($conn_r), + $this->buildHavingClause($conn_r), $this->buildLimitClause($conn_r)); $mocks = $table->loadAllFromArray($data); if ($mocks && $this->needImages) { self::loadImages($this->getViewer(), $mocks, $this->needInlineComments); } if ($mocks && $this->needCoverFiles) { $this->loadCoverFiles($mocks); } if ($mocks && $this->needTokenCounts) { $this->loadTokenCounts($mocks); } return $mocks; } protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { $where = array(); - $where[] = $this->buildPagingClause($conn_r); + $where[] = $this->buildWhereClauseParts($conn_r); - if ($this->ids) { + if ($this->ids !== null) { $where[] = qsprintf( $conn_r, - 'id IN (%Ld)', + 'mock.id IN (%Ld)', $this->ids); } - if ($this->phids) { + if ($this->phids !== null) { $where[] = qsprintf( $conn_r, - 'phid IN (%Ls)', + 'mock.phid IN (%Ls)', $this->phids); } - if ($this->authorPHIDs) { + if ($this->authorPHIDs !== null) { $where[] = qsprintf( $conn_r, - 'authorPHID in (%Ls)', + 'mock.authorPHID in (%Ls)', $this->authorPHIDs); } - if ($this->statuses) { + if ($this->statuses !== null) { $where[] = qsprintf( $conn_r, - 'status IN (%Ls)', + 'mock.status IN (%Ls)', $this->statuses); } return $this->formatWhereClause($where); } public static function loadImages( PhabricatorUser $viewer, array $mocks, $need_inline_comments) { assert_instances_of($mocks, 'PholioMock'); $mock_map = mpull($mocks, null, 'getID'); $all_images = id(new PholioImageQuery()) ->setViewer($viewer) ->setMockCache($mock_map) ->withMockIDs(array_keys($mock_map)) ->needInlineComments($need_inline_comments) ->execute(); $image_groups = mgroup($all_images, 'getMockID'); foreach ($mocks as $mock) { $mock_images = idx($image_groups, $mock->getID(), array()); $mock->attachAllImages($mock_images); $active_images = mfilter($mock_images, 'getIsObsolete', true); $mock->attachImages(msort($active_images, 'getSequence')); } } private function loadCoverFiles(array $mocks) { assert_instances_of($mocks, 'PholioMock'); $cover_file_phids = mpull($mocks, 'getCoverPHID'); $cover_files = id(new PhabricatorFileQuery()) ->setViewer($this->getViewer()) ->withPHIDs($cover_file_phids) ->execute(); $cover_files = mpull($cover_files, null, 'getPHID'); foreach ($mocks as $mock) { $file = idx($cover_files, $mock->getCoverPHID()); if (!$file) { $file = PhabricatorFile::loadBuiltin($this->getViewer(), 'missing.png'); } $mock->attachCoverFile($file); } } private function loadTokenCounts(array $mocks) { assert_instances_of($mocks, 'PholioMock'); $phids = mpull($mocks, 'getPHID'); $counts = id(new PhabricatorTokenCountQuery()) ->withObjectPHIDs($phids) ->execute(); foreach ($mocks as $mock) { $mock->attachTokenCount(idx($counts, $mock->getPHID(), 0)); } } public function getQueryApplicationClass() { return 'PhabricatorPholioApplication'; } + public function getPrimaryTableAlias() { + return 'mock'; + } + } diff --git a/src/applications/pholio/query/PholioMockSearchEngine.php b/src/applications/pholio/query/PholioMockSearchEngine.php index 91bc61f323..c04ece1da0 100644 --- a/src/applications/pholio/query/PholioMockSearchEngine.php +++ b/src/applications/pholio/query/PholioMockSearchEngine.php @@ -1,143 +1,170 @@ setParameter( 'authorPHIDs', $this->readUsersFromRequest($request, 'authors')); + + $saved->setParameter( + 'projects', + $this->readProjectsFromRequest($request, 'projects')); + $saved->setParameter( 'statuses', $request->getStrList('status')); return $saved; } public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { $query = id(new PholioMockQuery()) ->needCoverFiles(true) ->needImages(true) - ->needTokenCounts(true) - ->withAuthorPHIDs($saved->getParameter('authorPHIDs', array())) - ->withStatuses($saved->getParameter('statuses', array())); + ->needTokenCounts(true); + + $datasource = id(new PhabricatorTypeaheadUserParameterizedDatasource()) + ->setViewer($this->requireViewer()); + + $author_phids = $saved->getParameter('authorPHIDs', array()); + $author_phids = $datasource->evaluateTokens($author_phids); + if ($author_phids) { + $query->withAuthorPHIDs($author_phids); + } + + $statuses = $saved->getParameter('statuses', array()); + if ($statuses) { + $query->withStatuses($statuses); + } + + $this->setQueryProjects($query, $saved); return $query; } public function buildSearchForm( AphrontFormView $form, PhabricatorSavedQuery $saved_query) { $author_phids = $saved_query->getParameter('authorPHIDs', array()); + $projects = $saved_query->getParameter('projects', array()); $statuses = array( '' => pht('Any Status'), 'closed' => pht('Closed'), 'open' => pht('Open'), ); $status = $saved_query->getParameter('statuses', array()); $status = head($status); $form ->appendControl( id(new AphrontFormTokenizerControl()) - ->setDatasource(new PhabricatorPeopleDatasource()) + ->setDatasource(new PhabricatorTypeaheadUserParameterizedDatasource()) ->setName('authors') ->setLabel(pht('Authors')) ->setValue($author_phids)) + ->appendControl( + id(new AphrontFormTokenizerControl()) + ->setDatasource(new PhabricatorProjectLogicalDatasource()) + ->setName('projects') + ->setLabel(pht('Projects')) + ->setValue($projects)) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Status')) ->setName('status') ->setOptions($statuses) ->setValue($status)); } protected function getURI($path) { return '/pholio/'.$path; } protected function getBuiltinQueryNames() { $names = array( 'open' => pht('Open Mocks'), 'all' => pht('All Mocks'), ); if ($this->requireViewer()->isLoggedIn()) { $names['authored'] = pht('Authored'); } return $names; } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { case 'open': return $query->setParameter( 'statuses', array('open')); case 'all': return $query; case 'authored': return $query->setParameter( 'authorPHIDs', array($this->requireViewer()->getPHID())); } return parent::buildSavedQueryFromBuiltin($query_key); } protected function getRequiredHandlePHIDsForResultList( array $mocks, PhabricatorSavedQuery $query) { return mpull($mocks, 'getAuthorPHID'); } protected function renderResultList( array $mocks, PhabricatorSavedQuery $query, array $handles) { assert_instances_of($mocks, 'PholioMock'); $viewer = $this->requireViewer(); $board = new PHUIPinboardView(); foreach ($mocks as $mock) { $header = 'M'.$mock->getID().' '.$mock->getName(); $item = id(new PHUIPinboardItemView()) ->setHeader($header) ->setURI('/M'.$mock->getID()) ->setImageURI($mock->getCoverFile()->getThumb280x210URI()) ->setImageSize(280, 210) ->setDisabled($mock->isClosed()) ->addIconCount('fa-picture-o', count($mock->getImages())) ->addIconCount('fa-trophy', $mock->getTokenCount()); if ($mock->getAuthorPHID()) { $author_handle = $handles[$mock->getAuthorPHID()]; $datetime = phabricator_date($mock->getDateCreated(), $viewer); $item->appendChild( pht('By %s on %s', $author_handle->renderLink(), $datetime)); } $board->addItem($item); } return $board; } }