Use delegation to generalize application search controllers
Summary: Ref T2625. Lifts almost all of the search logic out of Paste controllers and into Search. This uses controller delegation for generalization. We use this in a few places, but don't use it very much yet. I think it's pretty reasonable as-is, but I might be able to make even more stuff free. There are some slightly rough edges around routes, still, but I want to hit Phame and Differential (which both have multiple application search engines) before trying to generalize that. Test Plan: Executed, browsed and managed Paste searches. Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T2625 Differential Revision: https://secure.phabricator.com/D6073
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
<?php
|
||||
|
||||
final class PhabricatorApplicationSearchController
|
||||
extends PhabricatorSearchBaseController {
|
||||
|
||||
private $searchEngine;
|
||||
private $navigation;
|
||||
private $queryKey;
|
||||
|
||||
public function setQueryKey($query_key) {
|
||||
$this->queryKey = $query_key;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getQueryKey() {
|
||||
return $this->queryKey;
|
||||
}
|
||||
|
||||
public function setNavigation(AphrontSideNavFilterView $navigation) {
|
||||
$this->navigation = $navigation;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getNavigation() {
|
||||
return $this->navigation;
|
||||
}
|
||||
|
||||
public function setSearchEngine(
|
||||
PhabricatorApplicationSearchEngine $search_engine) {
|
||||
$this->searchEngine = $search_engine;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getSearchEngine() {
|
||||
return $this->searchEngine;
|
||||
}
|
||||
|
||||
protected function validateDelegatingController() {
|
||||
$parent = $this->getDelegatingController();
|
||||
|
||||
if (!$parent) {
|
||||
throw new Exception(
|
||||
"You must delegate to this controller, not invoke it directly.");
|
||||
}
|
||||
|
||||
$engine = $this->getSearchEngine();
|
||||
if (!$engine) {
|
||||
throw new Exception(
|
||||
"Call setEngine() before delegating to this controller!");
|
||||
}
|
||||
|
||||
$nav = $this->getNavigation();
|
||||
if (!$nav) {
|
||||
throw new Exception(
|
||||
"Call setNavigation() before delegating to this controller!");
|
||||
}
|
||||
|
||||
$engine->setViewer($this->getRequest()->getUser());
|
||||
|
||||
$parent = $this->getDelegatingController();
|
||||
$interface = 'PhabricatorApplicationSearchResultsControllerInterface';
|
||||
if (!$parent instanceof $interface) {
|
||||
throw new Exception(
|
||||
"Delegating controller must implement '{$interface}'.");
|
||||
}
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$this->validateDelegatingController();
|
||||
|
||||
$key = $this->getQueryKey();
|
||||
if ($key == 'edit') {
|
||||
return $this->processEditRequest();
|
||||
} else {
|
||||
return $this->processSearchRequest();
|
||||
}
|
||||
}
|
||||
|
||||
private function processSearchRequest() {
|
||||
$parent = $this->getDelegatingController();
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$engine = $this->getSearchEngine();
|
||||
$nav = $this->getNavigation();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
return id(new AphrontRedirectResponse())->setURI(
|
||||
$engine->getQueryResultsPageURI(
|
||||
$engine->buildSavedQueryFromRequest($request)->getQueryKey()));
|
||||
}
|
||||
|
||||
$named_query = null;
|
||||
$run_query = true;
|
||||
$query_key = $this->queryKey;
|
||||
if ($this->queryKey == 'advanced') {
|
||||
$run_query = false;
|
||||
$query_key = $request->getStr('query');
|
||||
}
|
||||
|
||||
if ($engine->isBuiltinQuery($query_key)) {
|
||||
$saved_query = $engine->buildSavedQueryFromBuiltin($query_key);
|
||||
$named_query = $engine->getBuiltinQuery($query_key);
|
||||
} else if ($query_key) {
|
||||
$saved_query = id(new PhabricatorSavedQueryQuery())
|
||||
->setViewer($user)
|
||||
->withQueryKeys(array($query_key))
|
||||
->executeOne();
|
||||
|
||||
if (!$saved_query) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$named_query = id(new PhabricatorNamedQueryQuery())
|
||||
->setViewer($user)
|
||||
->withQueryKeys(array($saved_query->getQueryKey()))
|
||||
->withEngineClassNames(array(get_class($engine)))
|
||||
->withUserPHIDs(array($user->getPHID()))
|
||||
->executeOne();
|
||||
} else {
|
||||
$saved_query = $engine->buildSavedQueryFromRequest($request);
|
||||
}
|
||||
|
||||
$nav->selectFilter(
|
||||
'query/'.$saved_query->getQueryKey(),
|
||||
'query/advanced');
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setNoShading(true)
|
||||
->setUser($user);
|
||||
|
||||
$engine->buildSearchForm($form, $saved_query);
|
||||
|
||||
$submit = id(new AphrontFormSubmitControl())
|
||||
->setValue(pht('Execute Query'));
|
||||
|
||||
if ($run_query && !$named_query) {
|
||||
$submit->addCancelButton(
|
||||
'/search/edit/'.$saved_query->getQueryKey().'/',
|
||||
pht('Save Custom Query...'));
|
||||
}
|
||||
|
||||
$form->appendChild($submit);
|
||||
$filter_view = id(new AphrontListFilterView())->appendChild($form);
|
||||
|
||||
if ($run_query && $named_query) {
|
||||
if ($named_query->getIsBuiltin()) {
|
||||
$description = pht(
|
||||
'Showing results for query "%s".',
|
||||
$named_query->getQueryName());
|
||||
} else {
|
||||
$description = pht(
|
||||
'Showing results for saved query "%s".',
|
||||
$named_query->getQueryName());
|
||||
}
|
||||
|
||||
$filter_view->setCollapsed(
|
||||
pht('Edit Query...'),
|
||||
pht('Hide Query'),
|
||||
$description,
|
||||
$this->getApplicationURI('query/advanced/?query='.$query_key));
|
||||
}
|
||||
|
||||
$nav->appendChild($filter_view);
|
||||
|
||||
if ($run_query) {
|
||||
$query = id(new PhabricatorPasteSearchEngine())
|
||||
->buildQueryFromSavedQuery($saved_query);
|
||||
|
||||
$pager = new AphrontCursorPagerView();
|
||||
$pager->readFromRequest($request);
|
||||
$pastes = $query->setViewer($request->getUser())
|
||||
->needContent(true)
|
||||
->executeWithCursorPager($pager);
|
||||
|
||||
$list = $parent->renderResultsList($pastes);
|
||||
$list->setPager($pager);
|
||||
$list->setNoDataString(pht("No results found for this query."));
|
||||
|
||||
$nav->appendChild($list);
|
||||
}
|
||||
|
||||
if ($named_query) {
|
||||
$title = pht('Query: %s', $named_query->getQueryName());
|
||||
} else {
|
||||
$title = pht('Advanced Search');
|
||||
}
|
||||
|
||||
$crumbs = $parent
|
||||
->buildApplicationCrumbs()
|
||||
->addCrumb(
|
||||
id(new PhabricatorCrumbView())
|
||||
->setName(pht("Search")));
|
||||
|
||||
$nav->setCrumbs($crumbs);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
$nav,
|
||||
array(
|
||||
'title' => $title,
|
||||
'device' => true,
|
||||
'dust' => true,
|
||||
));
|
||||
}
|
||||
|
||||
private function processEditRequest() {
|
||||
$parent = $this->getDelegatingController();
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
$engine = $this->getSearchEngine();
|
||||
$nav = $this->getNavigation();
|
||||
|
||||
$named_queries = id(new PhabricatorNamedQueryQuery())
|
||||
->setViewer($user)
|
||||
->withUserPHIDs(array($user->getPHID()))
|
||||
->withEngineClassNames(array(get_class($engine)))
|
||||
->execute();
|
||||
|
||||
$named_queries += $engine->getBuiltinQueries();
|
||||
|
||||
$list = new PhabricatorObjectItemListView();
|
||||
$list->setUser($user);
|
||||
|
||||
foreach ($named_queries as $named_query) {
|
||||
$date_created = phabricator_datetime(
|
||||
$named_query->getDateCreated(),
|
||||
$user);
|
||||
|
||||
$item = id(new PhabricatorObjectItemView())
|
||||
->setHeader($named_query->getQueryName())
|
||||
->setHref($engine->getQueryResultsPageURI($named_query->getQueryKey()));
|
||||
|
||||
if ($named_query->getIsBuiltin()) {
|
||||
$item->addIcon('lock-grey', pht('Builtin'));
|
||||
$item->setBarColor('grey');
|
||||
} else {
|
||||
$item->addIcon('none', $date_created);
|
||||
$item->addAction(
|
||||
id(new PhabricatorMenuItemView())
|
||||
->setIcon('delete')
|
||||
->setHref('/search/delete/'.$named_query->getQueryKey().'/')
|
||||
->setWorkflow(true));
|
||||
$item->addAction(
|
||||
id(new PhabricatorMenuItemView())
|
||||
->setIcon('edit')
|
||||
->setHref('/search/edit/'.$named_query->getQueryKey().'/'));
|
||||
}
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
||||
$list->setNoDataString(pht('No saved queries.'));
|
||||
|
||||
$crumbs = $parent
|
||||
->buildApplicationCrumbs()
|
||||
->addCrumb(
|
||||
id(new PhabricatorCrumbView())
|
||||
->setName(pht("Saved Queries"))
|
||||
->setHref($engine->getQueryManagementURI()));
|
||||
|
||||
$nav->selectFilter('query/edit');
|
||||
$nav->setCrumbs($crumbs);
|
||||
$nav->appendChild($list);
|
||||
|
||||
return $parent->buildApplicationPage(
|
||||
$nav,
|
||||
array(
|
||||
'title' => pht("Saved Queries"),
|
||||
'device' => true,
|
||||
'dust' => true,
|
||||
));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user