@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+367 -237
+8 -3
src/__phutil_library_map__.php
··· 743 743 'PhabricatorApplicationReleephConfigOptions' => 'applications/releeph/config/PhabricatorApplicationReleephConfigOptions.php', 744 744 'PhabricatorApplicationRepositories' => 'applications/repository/application/PhabricatorApplicationRepositories.php', 745 745 'PhabricatorApplicationSearch' => 'applications/search/application/PhabricatorApplicationSearch.php', 746 + 'PhabricatorApplicationSearchController' => 'applications/search/controller/PhabricatorApplicationSearchController.php', 746 747 'PhabricatorApplicationSearchEngine' => 'applications/search/engine/PhabricatorApplicationSearchEngine.php', 748 + 'PhabricatorApplicationSearchResultsControllerInterface' => 'applications/search/interface/PhabricatorApplicationSearchResultsControllerInterface.php', 747 749 'PhabricatorApplicationSettings' => 'applications/settings/application/PhabricatorApplicationSettings.php', 748 750 'PhabricatorApplicationSlowvote' => 'applications/slowvote/application/PhabricatorApplicationSlowvote.php', 749 751 'PhabricatorApplicationStatusView' => 'applications/meta/view/PhabricatorApplicationStatusView.php', ··· 1235 1237 'PhabricatorPasteDAO' => 'applications/paste/storage/PhabricatorPasteDAO.php', 1236 1238 'PhabricatorPasteEditController' => 'applications/paste/controller/PhabricatorPasteEditController.php', 1237 1239 'PhabricatorPasteListController' => 'applications/paste/controller/PhabricatorPasteListController.php', 1238 - 'PhabricatorPasteQueriesController' => 'applications/paste/controller/PhabricatorPasteQueriesController.php', 1239 1240 'PhabricatorPasteQuery' => 'applications/paste/query/PhabricatorPasteQuery.php', 1240 1241 'PhabricatorPasteRemarkupRule' => 'applications/paste/remarkup/PhabricatorPasteRemarkupRule.php', 1241 1242 'PhabricatorPasteSearchEngine' => 'applications/paste/query/PhabricatorPasteSearchEngine.php', ··· 2530 2531 'PhabricatorApplicationReleephConfigOptions' => 'PhabricatorApplicationConfigOptions', 2531 2532 'PhabricatorApplicationRepositories' => 'PhabricatorApplication', 2532 2533 'PhabricatorApplicationSearch' => 'PhabricatorApplication', 2534 + 'PhabricatorApplicationSearchController' => 'PhabricatorSearchBaseController', 2533 2535 'PhabricatorApplicationSettings' => 'PhabricatorApplication', 2534 2536 'PhabricatorApplicationSlowvote' => 'PhabricatorApplication', 2535 2537 'PhabricatorApplicationStatusView' => 'AphrontView', ··· 3016 3018 'PhabricatorPasteController' => 'PhabricatorController', 3017 3019 'PhabricatorPasteDAO' => 'PhabricatorLiskDAO', 3018 3020 'PhabricatorPasteEditController' => 'PhabricatorPasteController', 3019 - 'PhabricatorPasteListController' => 'PhabricatorPasteController', 3020 - 'PhabricatorPasteQueriesController' => 'PhabricatorPasteController', 3021 + 'PhabricatorPasteListController' => 3022 + array( 3023 + 0 => 'PhabricatorPasteController', 3024 + 1 => 'PhabricatorApplicationSearchResultsControllerInterface', 3025 + ), 3021 3026 'PhabricatorPasteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 3022 3027 'PhabricatorPasteRemarkupRule' => 'PhabricatorRemarkupRuleObject', 3023 3028 'PhabricatorPasteSearchEngine' => 'PhabricatorApplicationSearchEngine',
+19
src/aphront/AphrontController.php
··· 7 7 8 8 private $request; 9 9 private $currentApplication; 10 + private $delegatingController; 11 + 12 + 13 + public function setDelegatingController( 14 + AphrontController $delegating_controller) { 15 + $this->delegatingController = $delegating_controller; 16 + return $this; 17 + } 18 + 19 + public function getDelegatingController() { 20 + return $this->delegatingController; 21 + } 10 22 11 23 public function willBeginExecution() { 12 24 return; ··· 31 43 } 32 44 33 45 final public function delegateToController(AphrontController $controller) { 46 + $controller->setDelegatingController($this); 47 + 48 + $application = $this->getCurrentApplication(); 49 + if ($application) { 50 + $controller->setCurrentApplication($application); 51 + } 52 + 34 53 return $controller->processRequest(); 35 54 } 36 55
+3 -6
src/applications/paste/application/PhabricatorApplicationPaste.php
··· 32 32 return array( 33 33 '/P(?P<id>[1-9]\d*)' => 'PhabricatorPasteViewController', 34 34 '/paste/' => array( 35 - '' => 'PhabricatorPasteListController', 36 - 'create/' => 'PhabricatorPasteEditController', 37 - 'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorPasteEditController', 38 - 'filter/(?P<filter>\w+)/' => 'PhabricatorPasteListController', 39 - 'query/(?P<queryKey>[^/]+)/'=> 'PhabricatorPasteListController', 40 - 'savedqueries/' => 'PhabricatorPasteQueriesController', 35 + '(query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorPasteListController', 36 + 'create/' => 'PhabricatorPasteEditController', 37 + 'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorPasteEditController', 41 38 ), 42 39 ); 43 40 }
+2 -20
src/applications/paste/controller/PhabricatorPasteController.php
··· 12 12 $nav->addFilter('create', pht('Create Paste')); 13 13 } 14 14 15 - $nav->addLabel(pht('Queries')); 16 - 17 - $engine = id(new PhabricatorPasteSearchEngine()) 18 - ->setViewer($user); 19 - 20 - $named_queries = id(new PhabricatorNamedQueryQuery()) 15 + id(new PhabricatorPasteSearchEngine()) 21 16 ->setViewer($user) 22 - ->withUserPHIDs(array($user->getPHID())) 23 - ->withEngineClassNames(array(get_class($engine))) 24 - ->execute(); 25 - 26 - $named_queries = $named_queries + $engine->getBuiltinQueries($user); 27 - 28 - foreach ($named_queries as $query) { 29 - $nav->addFilter('query/'.$query->getQueryKey(), $query->getQueryName()); 30 - } 31 - 32 - $nav->addFilter('savedqueries', pht('Edit Queries...')); 33 - 34 - $nav->addLabel(pht('Search')); 35 - $nav->addFilter('query/advanced', pht('Advanced Search')); 17 + ->addNavigationItems($nav); 36 18 37 19 $nav->selectFilter(null); 38 20
+8 -120
src/applications/paste/controller/PhabricatorPasteListController.php
··· 1 1 <?php 2 2 3 - final class PhabricatorPasteListController extends PhabricatorPasteController { 3 + final class PhabricatorPasteListController extends PhabricatorPasteController 4 + implements PhabricatorApplicationSearchResultsControllerInterface { 4 5 5 6 private $queryKey; 6 7 ··· 14 15 15 16 public function processRequest() { 16 17 $request = $this->getRequest(); 17 - $user = $request->getUser(); 18 - 19 - $engine = id(new PhabricatorPasteSearchEngine()) 20 - ->setViewer($user); 21 - 22 - if ($request->isFormPost()) { 23 - return id(new AphrontRedirectResponse())->setURI( 24 - $engine->getQueryResultsPageURI( 25 - $engine->buildSavedQueryFromRequest($request)->getQueryKey())); 26 - } 27 - 28 - $nav = $this->buildSideNavView(); 29 - 30 - $named_query = null; 31 - $run_query = true; 32 - $query_key = $this->queryKey; 33 - if ($this->queryKey == 'advanced') { 34 - $run_query = false; 35 - $query_key = $request->getStr('query'); 36 - } 37 - 38 - if ($engine->isBuiltinQuery($query_key)) { 39 - $saved_query = $engine->buildSavedQueryFromBuiltin($query_key); 40 - $named_query = $engine->getBuiltinQuery($query_key); 41 - } else if ($query_key) { 42 - $saved_query = id(new PhabricatorSavedQueryQuery()) 43 - ->setViewer($user) 44 - ->withQueryKeys(array($query_key)) 45 - ->executeOne(); 46 - 47 - if (!$saved_query) { 48 - return new Aphront404Response(); 49 - } 50 - 51 - $named_query = id(new PhabricatorNamedQueryQuery()) 52 - ->setViewer($user) 53 - ->withQueryKeys(array($saved_query->getQueryKey())) 54 - ->withEngineClassNames(array(get_class($engine))) 55 - ->withUserPHIDs(array($user->getPHID())) 56 - ->executeOne(); 57 - } else { 58 - $saved_query = $engine->buildSavedQueryFromRequest($request); 59 - } 60 - 61 - $filter = $nav->selectFilter( 62 - 'query/'.$saved_query->getQueryKey(), 63 - 'query/advanced'); 64 - 65 - $form = id(new AphrontFormView()) 66 - ->setNoShading(true) 67 - ->setUser($user); 68 - 69 - $engine->buildSearchForm($form, $saved_query); 70 - 71 - $submit = id(new AphrontFormSubmitControl()) 72 - ->setValue(pht('Execute Query')); 73 - 74 - if ($run_query && !$named_query) { 75 - $submit->addCancelButton( 76 - '/search/edit/'.$saved_query->getQueryKey().'/', 77 - pht('Save Custom Query...')); 78 - } 79 - 80 - $form->appendChild($submit); 81 - $filter_view = id(new AphrontListFilterView())->appendChild($form); 82 - 83 - if ($run_query && $named_query) { 84 - if ($named_query->getIsBuiltin()) { 85 - $description = pht( 86 - 'Showing results for query "%s".', 87 - $named_query->getQueryName()); 88 - } else { 89 - $description = pht( 90 - 'Showing results for saved query "%s".', 91 - $named_query->getQueryName()); 92 - } 93 - 94 - $filter_view->setCollapsed( 95 - pht('Edit Query...'), 96 - pht('Hide Query'), 97 - $description, 98 - $this->getApplicationURI('query/advanced/?query='.$query_key)); 99 - } 100 - 101 - $nav->appendChild($filter_view); 102 - 103 - if ($run_query) { 104 - $query = id(new PhabricatorPasteSearchEngine()) 105 - ->buildQueryFromSavedQuery($saved_query); 106 - 107 - $pager = new AphrontCursorPagerView(); 108 - $pager->readFromRequest($request); 109 - $pastes = $query->setViewer($request->getUser()) 110 - ->needContent(true) 111 - ->executeWithCursorPager($pager); 112 - 113 - $list = $this->buildPasteList($pastes); 114 - $list->setPager($pager); 115 - $list->setNoDataString(pht("No results found for this query.")); 116 - 117 - $nav->appendChild($list); 118 - } 119 - 120 - $crumbs = $this 121 - ->buildApplicationCrumbs($nav) 122 - ->addCrumb( 123 - id(new PhabricatorCrumbView()) 124 - ->setName(pht("Pastes")) 125 - ->setHref($this->getApplicationURI('filter/'.$filter.'/'))); 126 - 127 - $nav->setCrumbs($crumbs); 18 + $controller = id(new PhabricatorApplicationSearchController($request)) 19 + ->setQueryKey($this->queryKey) 20 + ->setSearchEngine(new PhabricatorPasteSearchEngine()) 21 + ->setNavigation($this->buildSideNavView()); 128 22 129 - return $this->buildApplicationPage( 130 - $nav, 131 - array( 132 - 'title' => pht("Pastes"), 133 - 'device' => true, 134 - 'dust' => true, 135 - )); 23 + return $this->delegateToController($controller); 136 24 } 137 25 138 - private function buildPasteList(array $pastes) { 26 + public function renderResultsList(array $pastes) { 139 27 assert_instances_of($pastes, 'PhabricatorPaste'); 140 28 141 29 $user = $this->getRequest()->getUser();
-80
src/applications/paste/controller/PhabricatorPasteQueriesController.php
··· 1 - <?php 2 - 3 - final class PhabricatorPasteQueriesController 4 - extends PhabricatorPasteController { 5 - 6 - public function processRequest() { 7 - $request = $this->getRequest(); 8 - $user = $request->getUser(); 9 - 10 - $engine = id(new PhabricatorPasteSearchEngine()) 11 - ->setViewer($user); 12 - 13 - $nav = $this->buildSideNavView(); 14 - $nav->selectFilter('savedqueries'); 15 - 16 - $named_queries = id(new PhabricatorNamedQueryQuery()) 17 - ->setViewer($user) 18 - ->withUserPHIDs(array($user->getPHID())) 19 - ->withEngineClassNames(array(get_class($engine))) 20 - ->execute(); 21 - 22 - $named_queries += $engine->getBuiltinQueries(); 23 - 24 - $list = new PhabricatorObjectItemListView(); 25 - $list->setUser($user); 26 - 27 - foreach ($named_queries as $named_query) { 28 - $date_created = phabricator_datetime( 29 - $named_query->getDateCreated(), 30 - $user); 31 - 32 - $item = id(new PhabricatorObjectItemView()) 33 - ->setHeader($named_query->getQueryName()) 34 - ->setHref($engine->getQueryResultsPageURI($named_query->getQueryKey())); 35 - 36 - if ($named_query->getIsBuiltin()) { 37 - $item->addIcon('lock-grey', pht('Builtin')); 38 - $item->setBarColor('grey'); 39 - } else { 40 - $item->addIcon('none', $date_created); 41 - $item->addAction( 42 - id(new PhabricatorMenuItemView()) 43 - ->setIcon('delete') 44 - ->setHref('/search/delete/'.$named_query->getQueryKey().'/') 45 - ->setWorkflow(true)); 46 - $item->addAction( 47 - id(new PhabricatorMenuItemView()) 48 - ->setIcon('edit') 49 - ->setHref('/search/edit/'.$named_query->getQueryKey().'/')); 50 - } 51 - 52 - $list->addItem($item); 53 - } 54 - 55 - $list->setNoDataString(pht("No results found for this query.")); 56 - 57 - $nav->appendChild( 58 - array( 59 - $list, 60 - )); 61 - 62 - $crumbs = $this 63 - ->buildApplicationCrumbs($nav) 64 - ->addCrumb( 65 - id(new PhabricatorCrumbView()) 66 - ->setName(pht("Saved Queries")) 67 - ->setHref($this->getApplicationURI('/savedqueries/'))); 68 - 69 - $nav->setCrumbs($crumbs); 70 - 71 - return $this->buildApplicationPage( 72 - $nav, 73 - array( 74 - 'title' => pht("Saved Queries"), 75 - 'device' => true, 76 - 'dust' => true, 77 - )); 78 - } 79 - 80 - }
+2 -6
src/applications/paste/query/PhabricatorPasteSearchEngine.php
··· 70 70 ->setValue($author_tokens)); 71 71 } 72 72 73 - public function getQueryResultsPageURI($query_key) { 74 - return '/paste/query/'.$query_key.'/'; 75 - } 76 - 77 - public function getQueryManagementURI() { 78 - return '/paste/savedqueries/'; 73 + protected function getURI($path) { 74 + return '/paste/'.$path; 79 75 } 80 76 81 77 public function getBuiltinQueryNames() {
+272
src/applications/search/controller/PhabricatorApplicationSearchController.php
··· 1 + <?php 2 + 3 + final class PhabricatorApplicationSearchController 4 + extends PhabricatorSearchBaseController { 5 + 6 + private $searchEngine; 7 + private $navigation; 8 + private $queryKey; 9 + 10 + public function setQueryKey($query_key) { 11 + $this->queryKey = $query_key; 12 + return $this; 13 + } 14 + 15 + protected function getQueryKey() { 16 + return $this->queryKey; 17 + } 18 + 19 + public function setNavigation(AphrontSideNavFilterView $navigation) { 20 + $this->navigation = $navigation; 21 + return $this; 22 + } 23 + 24 + protected function getNavigation() { 25 + return $this->navigation; 26 + } 27 + 28 + public function setSearchEngine( 29 + PhabricatorApplicationSearchEngine $search_engine) { 30 + $this->searchEngine = $search_engine; 31 + return $this; 32 + } 33 + 34 + protected function getSearchEngine() { 35 + return $this->searchEngine; 36 + } 37 + 38 + protected function validateDelegatingController() { 39 + $parent = $this->getDelegatingController(); 40 + 41 + if (!$parent) { 42 + throw new Exception( 43 + "You must delegate to this controller, not invoke it directly."); 44 + } 45 + 46 + $engine = $this->getSearchEngine(); 47 + if (!$engine) { 48 + throw new Exception( 49 + "Call setEngine() before delegating to this controller!"); 50 + } 51 + 52 + $nav = $this->getNavigation(); 53 + if (!$nav) { 54 + throw new Exception( 55 + "Call setNavigation() before delegating to this controller!"); 56 + } 57 + 58 + $engine->setViewer($this->getRequest()->getUser()); 59 + 60 + $parent = $this->getDelegatingController(); 61 + $interface = 'PhabricatorApplicationSearchResultsControllerInterface'; 62 + if (!$parent instanceof $interface) { 63 + throw new Exception( 64 + "Delegating controller must implement '{$interface}'."); 65 + } 66 + } 67 + 68 + public function processRequest() { 69 + $this->validateDelegatingController(); 70 + 71 + $key = $this->getQueryKey(); 72 + if ($key == 'edit') { 73 + return $this->processEditRequest(); 74 + } else { 75 + return $this->processSearchRequest(); 76 + } 77 + } 78 + 79 + private function processSearchRequest() { 80 + $parent = $this->getDelegatingController(); 81 + $request = $this->getRequest(); 82 + $user = $request->getUser(); 83 + $engine = $this->getSearchEngine(); 84 + $nav = $this->getNavigation(); 85 + 86 + if ($request->isFormPost()) { 87 + return id(new AphrontRedirectResponse())->setURI( 88 + $engine->getQueryResultsPageURI( 89 + $engine->buildSavedQueryFromRequest($request)->getQueryKey())); 90 + } 91 + 92 + $named_query = null; 93 + $run_query = true; 94 + $query_key = $this->queryKey; 95 + if ($this->queryKey == 'advanced') { 96 + $run_query = false; 97 + $query_key = $request->getStr('query'); 98 + } 99 + 100 + if ($engine->isBuiltinQuery($query_key)) { 101 + $saved_query = $engine->buildSavedQueryFromBuiltin($query_key); 102 + $named_query = $engine->getBuiltinQuery($query_key); 103 + } else if ($query_key) { 104 + $saved_query = id(new PhabricatorSavedQueryQuery()) 105 + ->setViewer($user) 106 + ->withQueryKeys(array($query_key)) 107 + ->executeOne(); 108 + 109 + if (!$saved_query) { 110 + return new Aphront404Response(); 111 + } 112 + 113 + $named_query = id(new PhabricatorNamedQueryQuery()) 114 + ->setViewer($user) 115 + ->withQueryKeys(array($saved_query->getQueryKey())) 116 + ->withEngineClassNames(array(get_class($engine))) 117 + ->withUserPHIDs(array($user->getPHID())) 118 + ->executeOne(); 119 + } else { 120 + $saved_query = $engine->buildSavedQueryFromRequest($request); 121 + } 122 + 123 + $nav->selectFilter( 124 + 'query/'.$saved_query->getQueryKey(), 125 + 'query/advanced'); 126 + 127 + $form = id(new AphrontFormView()) 128 + ->setNoShading(true) 129 + ->setUser($user); 130 + 131 + $engine->buildSearchForm($form, $saved_query); 132 + 133 + $submit = id(new AphrontFormSubmitControl()) 134 + ->setValue(pht('Execute Query')); 135 + 136 + if ($run_query && !$named_query) { 137 + $submit->addCancelButton( 138 + '/search/edit/'.$saved_query->getQueryKey().'/', 139 + pht('Save Custom Query...')); 140 + } 141 + 142 + $form->appendChild($submit); 143 + $filter_view = id(new AphrontListFilterView())->appendChild($form); 144 + 145 + if ($run_query && $named_query) { 146 + if ($named_query->getIsBuiltin()) { 147 + $description = pht( 148 + 'Showing results for query "%s".', 149 + $named_query->getQueryName()); 150 + } else { 151 + $description = pht( 152 + 'Showing results for saved query "%s".', 153 + $named_query->getQueryName()); 154 + } 155 + 156 + $filter_view->setCollapsed( 157 + pht('Edit Query...'), 158 + pht('Hide Query'), 159 + $description, 160 + $this->getApplicationURI('query/advanced/?query='.$query_key)); 161 + } 162 + 163 + $nav->appendChild($filter_view); 164 + 165 + if ($run_query) { 166 + $query = id(new PhabricatorPasteSearchEngine()) 167 + ->buildQueryFromSavedQuery($saved_query); 168 + 169 + $pager = new AphrontCursorPagerView(); 170 + $pager->readFromRequest($request); 171 + $pastes = $query->setViewer($request->getUser()) 172 + ->needContent(true) 173 + ->executeWithCursorPager($pager); 174 + 175 + $list = $parent->renderResultsList($pastes); 176 + $list->setPager($pager); 177 + $list->setNoDataString(pht("No results found for this query.")); 178 + 179 + $nav->appendChild($list); 180 + } 181 + 182 + if ($named_query) { 183 + $title = pht('Query: %s', $named_query->getQueryName()); 184 + } else { 185 + $title = pht('Advanced Search'); 186 + } 187 + 188 + $crumbs = $parent 189 + ->buildApplicationCrumbs() 190 + ->addCrumb( 191 + id(new PhabricatorCrumbView()) 192 + ->setName(pht("Search"))); 193 + 194 + $nav->setCrumbs($crumbs); 195 + 196 + return $this->buildApplicationPage( 197 + $nav, 198 + array( 199 + 'title' => $title, 200 + 'device' => true, 201 + 'dust' => true, 202 + )); 203 + } 204 + 205 + private function processEditRequest() { 206 + $parent = $this->getDelegatingController(); 207 + $request = $this->getRequest(); 208 + $user = $request->getUser(); 209 + $engine = $this->getSearchEngine(); 210 + $nav = $this->getNavigation(); 211 + 212 + $named_queries = id(new PhabricatorNamedQueryQuery()) 213 + ->setViewer($user) 214 + ->withUserPHIDs(array($user->getPHID())) 215 + ->withEngineClassNames(array(get_class($engine))) 216 + ->execute(); 217 + 218 + $named_queries += $engine->getBuiltinQueries(); 219 + 220 + $list = new PhabricatorObjectItemListView(); 221 + $list->setUser($user); 222 + 223 + foreach ($named_queries as $named_query) { 224 + $date_created = phabricator_datetime( 225 + $named_query->getDateCreated(), 226 + $user); 227 + 228 + $item = id(new PhabricatorObjectItemView()) 229 + ->setHeader($named_query->getQueryName()) 230 + ->setHref($engine->getQueryResultsPageURI($named_query->getQueryKey())); 231 + 232 + if ($named_query->getIsBuiltin()) { 233 + $item->addIcon('lock-grey', pht('Builtin')); 234 + $item->setBarColor('grey'); 235 + } else { 236 + $item->addIcon('none', $date_created); 237 + $item->addAction( 238 + id(new PhabricatorMenuItemView()) 239 + ->setIcon('delete') 240 + ->setHref('/search/delete/'.$named_query->getQueryKey().'/') 241 + ->setWorkflow(true)); 242 + $item->addAction( 243 + id(new PhabricatorMenuItemView()) 244 + ->setIcon('edit') 245 + ->setHref('/search/edit/'.$named_query->getQueryKey().'/')); 246 + } 247 + 248 + $list->addItem($item); 249 + } 250 + 251 + $list->setNoDataString(pht('No saved queries.')); 252 + 253 + $crumbs = $parent 254 + ->buildApplicationCrumbs() 255 + ->addCrumb( 256 + id(new PhabricatorCrumbView()) 257 + ->setName(pht("Saved Queries")) 258 + ->setHref($engine->getQueryManagementURI())); 259 + 260 + $nav->selectFilter('query/edit'); 261 + $nav->setCrumbs($crumbs); 262 + $nav->appendChild($list); 263 + 264 + return $parent->buildApplicationPage( 265 + $nav, 266 + array( 267 + 'title' => pht("Saved Queries"), 268 + 'device' => true, 269 + 'dust' => true, 270 + )); 271 + } 272 + }
+46 -2
src/applications/search/engine/PhabricatorApplicationSearchEngine.php
··· 63 63 * @return string URI where the query can be executed. 64 64 * @task uri 65 65 */ 66 - abstract public function getQueryResultsPageURI($query_key); 66 + public function getQueryResultsPageURI($query_key) { 67 + return $this->getURI('query/'.$query_key.'/'); 68 + } 67 69 68 70 69 71 /** ··· 73 75 * @return string URI where queries can be managed. 74 76 * @task uri 75 77 */ 76 - abstract public function getQueryManagementURI(); 78 + public function getQueryManagementURI() { 79 + return $this->getURI('query/edit/'); 80 + } 81 + 82 + 83 + /** 84 + * Return the URI to a path within the application. Used to construct default 85 + * URIs for management and results. 86 + * 87 + * @return string URI to path. 88 + * @task uri 89 + */ 90 + abstract protected function getURI($path); 77 91 78 92 79 93 public function newSavedQuery() { 80 94 return id(new PhabricatorSavedQuery()) 81 95 ->setEngineClassName(get_class($this)); 96 + } 97 + 98 + 99 + public function addNavigationItems(AphrontSideNavFilterView $nav) { 100 + $viewer = $this->requireViewer(); 101 + 102 + $nav->addLabel(pht('Queries')); 103 + 104 + $named_queries = id(new PhabricatorNamedQueryQuery()) 105 + ->setViewer($viewer) 106 + ->withUserPHIDs(array($viewer->getPHID())) 107 + ->withEngineClassNames(array(get_class($this))) 108 + ->execute(); 109 + 110 + $named_queries = $named_queries + $this->getBuiltinQueries($viewer); 111 + 112 + foreach ($named_queries as $query) { 113 + $key = $query->getQueryKey(); 114 + $uri = $this->getQueryResultsPageURI($key); 115 + $nav->addFilter('query/'.$key, $query->getQueryName(), $uri); 116 + } 117 + 118 + $manage_uri = $this->getQueryManagementURI(); 119 + $nav->addFilter('query/edit', pht('Edit Queries...'), $manage_uri); 120 + 121 + $nav->addLabel(pht('Search')); 122 + $advanced_uri = $this->getQueryResultsPageURI('advanced'); 123 + $nav->addFilter('query/advanced', pht('Advanced Search'), $advanced_uri); 124 + 125 + return $this; 82 126 } 83 127 84 128
+7
src/applications/search/interface/PhabricatorApplicationSearchResultsControllerInterface.php
··· 1 + <?php 2 + 3 + interface PhabricatorApplicationSearchResultsControllerInterface { 4 + 5 + public function renderResultsList(array $items); 6 + 7 + }