diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 5c3e806b2a..fe4b191c08 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -743,7 +743,9 @@ phutil_register_library_map(array( 'PhabricatorApplicationReleephConfigOptions' => 'applications/releeph/config/PhabricatorApplicationReleephConfigOptions.php', 'PhabricatorApplicationRepositories' => 'applications/repository/application/PhabricatorApplicationRepositories.php', 'PhabricatorApplicationSearch' => 'applications/search/application/PhabricatorApplicationSearch.php', + 'PhabricatorApplicationSearchController' => 'applications/search/controller/PhabricatorApplicationSearchController.php', 'PhabricatorApplicationSearchEngine' => 'applications/search/engine/PhabricatorApplicationSearchEngine.php', + 'PhabricatorApplicationSearchResultsControllerInterface' => 'applications/search/interface/PhabricatorApplicationSearchResultsControllerInterface.php', 'PhabricatorApplicationSettings' => 'applications/settings/application/PhabricatorApplicationSettings.php', 'PhabricatorApplicationSlowvote' => 'applications/slowvote/application/PhabricatorApplicationSlowvote.php', 'PhabricatorApplicationStatusView' => 'applications/meta/view/PhabricatorApplicationStatusView.php', @@ -1235,7 +1237,6 @@ phutil_register_library_map(array( 'PhabricatorPasteDAO' => 'applications/paste/storage/PhabricatorPasteDAO.php', 'PhabricatorPasteEditController' => 'applications/paste/controller/PhabricatorPasteEditController.php', 'PhabricatorPasteListController' => 'applications/paste/controller/PhabricatorPasteListController.php', - 'PhabricatorPasteQueriesController' => 'applications/paste/controller/PhabricatorPasteQueriesController.php', 'PhabricatorPasteQuery' => 'applications/paste/query/PhabricatorPasteQuery.php', 'PhabricatorPasteRemarkupRule' => 'applications/paste/remarkup/PhabricatorPasteRemarkupRule.php', 'PhabricatorPasteSearchEngine' => 'applications/paste/query/PhabricatorPasteSearchEngine.php', @@ -2530,6 +2531,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationReleephConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorApplicationRepositories' => 'PhabricatorApplication', 'PhabricatorApplicationSearch' => 'PhabricatorApplication', + 'PhabricatorApplicationSearchController' => 'PhabricatorSearchBaseController', 'PhabricatorApplicationSettings' => 'PhabricatorApplication', 'PhabricatorApplicationSlowvote' => 'PhabricatorApplication', 'PhabricatorApplicationStatusView' => 'AphrontView', @@ -3016,8 +3018,11 @@ phutil_register_library_map(array( 'PhabricatorPasteController' => 'PhabricatorController', 'PhabricatorPasteDAO' => 'PhabricatorLiskDAO', 'PhabricatorPasteEditController' => 'PhabricatorPasteController', - 'PhabricatorPasteListController' => 'PhabricatorPasteController', - 'PhabricatorPasteQueriesController' => 'PhabricatorPasteController', + 'PhabricatorPasteListController' => + array( + 0 => 'PhabricatorPasteController', + 1 => 'PhabricatorApplicationSearchResultsControllerInterface', + ), 'PhabricatorPasteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPasteRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'PhabricatorPasteSearchEngine' => 'PhabricatorApplicationSearchEngine', diff --git a/src/aphront/AphrontController.php b/src/aphront/AphrontController.php index 8f14270a67..6d84c46195 100644 --- a/src/aphront/AphrontController.php +++ b/src/aphront/AphrontController.php @@ -7,6 +7,18 @@ abstract class AphrontController extends Phobject { private $request; private $currentApplication; + private $delegatingController; + + + public function setDelegatingController( + AphrontController $delegating_controller) { + $this->delegatingController = $delegating_controller; + return $this; + } + + public function getDelegatingController() { + return $this->delegatingController; + } public function willBeginExecution() { return; @@ -31,6 +43,13 @@ abstract class AphrontController extends Phobject { } final public function delegateToController(AphrontController $controller) { + $controller->setDelegatingController($this); + + $application = $this->getCurrentApplication(); + if ($application) { + $controller->setCurrentApplication($application); + } + return $controller->processRequest(); } diff --git a/src/applications/paste/application/PhabricatorApplicationPaste.php b/src/applications/paste/application/PhabricatorApplicationPaste.php index 006114cfec..f09024da0c 100644 --- a/src/applications/paste/application/PhabricatorApplicationPaste.php +++ b/src/applications/paste/application/PhabricatorApplicationPaste.php @@ -32,12 +32,9 @@ final class PhabricatorApplicationPaste extends PhabricatorApplication { return array( '/P(?P[1-9]\d*)' => 'PhabricatorPasteViewController', '/paste/' => array( - '' => 'PhabricatorPasteListController', - 'create/' => 'PhabricatorPasteEditController', - 'edit/(?P[1-9]\d*)/' => 'PhabricatorPasteEditController', - 'filter/(?P\w+)/' => 'PhabricatorPasteListController', - 'query/(?P[^/]+)/'=> 'PhabricatorPasteListController', - 'savedqueries/' => 'PhabricatorPasteQueriesController', + '(query/(?P[^/]+)/)?' => 'PhabricatorPasteListController', + 'create/' => 'PhabricatorPasteEditController', + 'edit/(?P[1-9]\d*)/' => 'PhabricatorPasteEditController', ), ); } diff --git a/src/applications/paste/controller/PhabricatorPasteController.php b/src/applications/paste/controller/PhabricatorPasteController.php index 5271603005..5d4db78f8a 100644 --- a/src/applications/paste/controller/PhabricatorPasteController.php +++ b/src/applications/paste/controller/PhabricatorPasteController.php @@ -12,27 +12,9 @@ abstract class PhabricatorPasteController extends PhabricatorController { $nav->addFilter('create', pht('Create Paste')); } - $nav->addLabel(pht('Queries')); - - $engine = id(new PhabricatorPasteSearchEngine()) - ->setViewer($user); - - $named_queries = id(new PhabricatorNamedQueryQuery()) + id(new PhabricatorPasteSearchEngine()) ->setViewer($user) - ->withUserPHIDs(array($user->getPHID())) - ->withEngineClassNames(array(get_class($engine))) - ->execute(); - - $named_queries = $named_queries + $engine->getBuiltinQueries($user); - - foreach ($named_queries as $query) { - $nav->addFilter('query/'.$query->getQueryKey(), $query->getQueryName()); - } - - $nav->addFilter('savedqueries', pht('Edit Queries...')); - - $nav->addLabel(pht('Search')); - $nav->addFilter('query/advanced', pht('Advanced Search')); + ->addNavigationItems($nav); $nav->selectFilter(null); diff --git a/src/applications/paste/controller/PhabricatorPasteListController.php b/src/applications/paste/controller/PhabricatorPasteListController.php index 447fb492c5..385e0ecc8c 100644 --- a/src/applications/paste/controller/PhabricatorPasteListController.php +++ b/src/applications/paste/controller/PhabricatorPasteListController.php @@ -1,6 +1,7 @@ getRequest(); - $user = $request->getUser(); + $controller = id(new PhabricatorApplicationSearchController($request)) + ->setQueryKey($this->queryKey) + ->setSearchEngine(new PhabricatorPasteSearchEngine()) + ->setNavigation($this->buildSideNavView()); - $engine = id(new PhabricatorPasteSearchEngine()) - ->setViewer($user); - - if ($request->isFormPost()) { - return id(new AphrontRedirectResponse())->setURI( - $engine->getQueryResultsPageURI( - $engine->buildSavedQueryFromRequest($request)->getQueryKey())); - } - - $nav = $this->buildSideNavView(); - - $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); - } - - $filter = $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 = $this->buildPasteList($pastes); - $list->setPager($pager); - $list->setNoDataString(pht("No results found for this query.")); - - $nav->appendChild($list); - } - - $crumbs = $this - ->buildApplicationCrumbs($nav) - ->addCrumb( - id(new PhabricatorCrumbView()) - ->setName(pht("Pastes")) - ->setHref($this->getApplicationURI('filter/'.$filter.'/'))); - - $nav->setCrumbs($crumbs); - - return $this->buildApplicationPage( - $nav, - array( - 'title' => pht("Pastes"), - 'device' => true, - 'dust' => true, - )); + return $this->delegateToController($controller); } - private function buildPasteList(array $pastes) { + public function renderResultsList(array $pastes) { assert_instances_of($pastes, 'PhabricatorPaste'); $user = $this->getRequest()->getUser(); diff --git a/src/applications/paste/controller/PhabricatorPasteQueriesController.php b/src/applications/paste/controller/PhabricatorPasteQueriesController.php deleted file mode 100644 index 75530fe1d8..0000000000 --- a/src/applications/paste/controller/PhabricatorPasteQueriesController.php +++ /dev/null @@ -1,80 +0,0 @@ -getRequest(); - $user = $request->getUser(); - - $engine = id(new PhabricatorPasteSearchEngine()) - ->setViewer($user); - - $nav = $this->buildSideNavView(); - $nav->selectFilter('savedqueries'); - - $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 results found for this query.")); - - $nav->appendChild( - array( - $list, - )); - - $crumbs = $this - ->buildApplicationCrumbs($nav) - ->addCrumb( - id(new PhabricatorCrumbView()) - ->setName(pht("Saved Queries")) - ->setHref($this->getApplicationURI('/savedqueries/'))); - - $nav->setCrumbs($crumbs); - - return $this->buildApplicationPage( - $nav, - array( - 'title' => pht("Saved Queries"), - 'device' => true, - 'dust' => true, - )); - } - -} diff --git a/src/applications/paste/query/PhabricatorPasteSearchEngine.php b/src/applications/paste/query/PhabricatorPasteSearchEngine.php index 306fe8a573..737a65e7e6 100644 --- a/src/applications/paste/query/PhabricatorPasteSearchEngine.php +++ b/src/applications/paste/query/PhabricatorPasteSearchEngine.php @@ -70,12 +70,8 @@ final class PhabricatorPasteSearchEngine ->setValue($author_tokens)); } - public function getQueryResultsPageURI($query_key) { - return '/paste/query/'.$query_key.'/'; - } - - public function getQueryManagementURI() { - return '/paste/savedqueries/'; + protected function getURI($path) { + return '/paste/'.$path; } public function getBuiltinQueryNames() { diff --git a/src/applications/search/controller/PhabricatorApplicationSearchController.php b/src/applications/search/controller/PhabricatorApplicationSearchController.php new file mode 100644 index 0000000000..f8f29bb1a7 --- /dev/null +++ b/src/applications/search/controller/PhabricatorApplicationSearchController.php @@ -0,0 +1,272 @@ +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, + )); + } +} diff --git a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php index 6ca93a121e..67b518e587 100644 --- a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php +++ b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php @@ -63,7 +63,9 @@ abstract class PhabricatorApplicationSearchEngine { * @return string URI where the query can be executed. * @task uri */ - abstract public function getQueryResultsPageURI($query_key); + public function getQueryResultsPageURI($query_key) { + return $this->getURI('query/'.$query_key.'/'); + } /** @@ -73,7 +75,19 @@ abstract class PhabricatorApplicationSearchEngine { * @return string URI where queries can be managed. * @task uri */ - abstract public function getQueryManagementURI(); + public function getQueryManagementURI() { + return $this->getURI('query/edit/'); + } + + + /** + * Return the URI to a path within the application. Used to construct default + * URIs for management and results. + * + * @return string URI to path. + * @task uri + */ + abstract protected function getURI($path); public function newSavedQuery() { @@ -82,6 +96,36 @@ abstract class PhabricatorApplicationSearchEngine { } + public function addNavigationItems(AphrontSideNavFilterView $nav) { + $viewer = $this->requireViewer(); + + $nav->addLabel(pht('Queries')); + + $named_queries = id(new PhabricatorNamedQueryQuery()) + ->setViewer($viewer) + ->withUserPHIDs(array($viewer->getPHID())) + ->withEngineClassNames(array(get_class($this))) + ->execute(); + + $named_queries = $named_queries + $this->getBuiltinQueries($viewer); + + foreach ($named_queries as $query) { + $key = $query->getQueryKey(); + $uri = $this->getQueryResultsPageURI($key); + $nav->addFilter('query/'.$key, $query->getQueryName(), $uri); + } + + $manage_uri = $this->getQueryManagementURI(); + $nav->addFilter('query/edit', pht('Edit Queries...'), $manage_uri); + + $nav->addLabel(pht('Search')); + $advanced_uri = $this->getQueryResultsPageURI('advanced'); + $nav->addFilter('query/advanced', pht('Advanced Search'), $advanced_uri); + + return $this; + } + + /* -( Builtin Queries )---------------------------------------------------- */ diff --git a/src/applications/search/interface/PhabricatorApplicationSearchResultsControllerInterface.php b/src/applications/search/interface/PhabricatorApplicationSearchResultsControllerInterface.php new file mode 100644 index 0000000000..378a308353 --- /dev/null +++ b/src/applications/search/interface/PhabricatorApplicationSearchResultsControllerInterface.php @@ -0,0 +1,7 @@ +