@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

Implement ApplicationSearch in Files

Summary: Ref T2625. Ref T1163. A couple of small generalization nudges, but this is almost entirely straightforward.

Test Plan: Executed various File queries.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T1163, T2625

Differential Revision: https://secure.phabricator.com/D6091

+184 -78
+2
resources/sql/patches/20130531.filekeys.sql
··· 1 + ALTER TABLE {$NAMESPACE}_file.file 2 + ADD KEY `key_dateCreated` (dateCreated);
+7 -1
src/__phutil_library_map__.php
··· 1006 1006 'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php', 1007 1007 'PhabricatorFileListController' => 'applications/files/controller/PhabricatorFileListController.php', 1008 1008 'PhabricatorFileQuery' => 'applications/files/query/PhabricatorFileQuery.php', 1009 + 'PhabricatorFileSearchEngine' => 'applications/files/query/PhabricatorFileSearchEngine.php', 1009 1010 'PhabricatorFileShortcutController' => 'applications/files/controller/PhabricatorFileShortcutController.php', 1010 1011 'PhabricatorFileStorageBlob' => 'applications/files/storage/PhabricatorFileStorageBlob.php', 1011 1012 'PhabricatorFileStorageConfigurationException' => 'applications/files/exception/PhabricatorFileStorageConfigurationException.php', ··· 2812 2813 'PhabricatorFileInfoController' => 'PhabricatorFileController', 2813 2814 'PhabricatorFileLinkListView' => 'AphrontView', 2814 2815 'PhabricatorFileLinkView' => 'AphrontView', 2815 - 'PhabricatorFileListController' => 'PhabricatorFileController', 2816 + 'PhabricatorFileListController' => 2817 + array( 2818 + 0 => 'PhabricatorFileController', 2819 + 1 => 'PhabricatorApplicationSearchResultsControllerInterface', 2820 + ), 2816 2821 'PhabricatorFileQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 2822 + 'PhabricatorFileSearchEngine' => 'PhabricatorApplicationSearchEngine', 2817 2823 'PhabricatorFileShortcutController' => 'PhabricatorFileController', 2818 2824 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 2819 2825 'PhabricatorFileStorageConfigurationException' => 'Exception',
+1 -2
src/applications/files/application/PhabricatorApplicationFiles.php
··· 38 38 return array( 39 39 '/F(?P<id>[1-9]\d*)' => 'PhabricatorFileShortcutController', 40 40 '/file/' => array( 41 - '' => 'PhabricatorFileListController', 42 - 'filter/(?P<filter>\w+)/' => 'PhabricatorFileListController', 41 + '(query/(?P<key>[^/]+)/)?' => 'PhabricatorFileListController', 43 42 'upload/' => 'PhabricatorFileUploadController', 44 43 'dropupload/' => 'PhabricatorFileDropUploadController', 45 44 'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFileDeleteController',
+3 -7
src/applications/files/controller/PhabricatorFileController.php
··· 29 29 $menu->newLink(pht('Upload File'), $this->getApplicationURI('/upload/')); 30 30 } 31 31 32 - $menu->newLabel(pht('Filters')); 33 - 34 - $menu->newLink(pht('My Files'), $this->getApplicationURI('filter/my/')) 35 - ->setKey('my'); 36 - 37 - $menu->newLink(pht('All Files'), $this->getApplicationURI('filter/all/')) 38 - ->setKey('all'); 32 + id(new PhabricatorFileSearchEngine()) 33 + ->setViewer($this->getRequest()->getUser()) 34 + ->addNavigationItems($menu); 39 35 40 36 return $menu; 41 37 }
+19 -60
src/applications/files/controller/PhabricatorFileListController.php
··· 1 1 <?php 2 2 3 - final class PhabricatorFileListController extends PhabricatorFileController { 4 - 5 - private $filter; 3 + final class PhabricatorFileListController extends PhabricatorFileController 4 + implements PhabricatorApplicationSearchResultsControllerInterface { 6 5 7 - private function setFilter($filter) { 8 - $this->filter = $filter; 9 - return $this; 10 - } 6 + private $key; 11 7 12 - private function getFilter() { 13 - return $this->filter; 8 + public function shouldAllowPublic() { 9 + return true; 14 10 } 15 11 16 12 public function willProcessRequest(array $data) { 17 - $this->setFilter(idx($data, 'filter', 'my')); 13 + $this->key = idx($data, 'key', 'authored'); 18 14 } 19 15 20 16 public function processRequest() { 21 17 $request = $this->getRequest(); 22 - $user = $request->getUser(); 18 + $controller = id(new PhabricatorApplicationSearchController($request)) 19 + ->setQueryKey($this->key) 20 + ->setSearchEngine(new PhabricatorFileSearchEngine()) 21 + ->setNavigation($this->buildSideNavView()); 23 22 24 - $pager = id(new AphrontCursorPagerView()) 25 - ->readFromRequest($request); 23 + return $this->delegateToController($controller); 24 + } 26 25 27 - $query = id(new PhabricatorFileQuery()) 28 - ->setViewer($user); 26 + public function renderResultsList(array $files) { 27 + assert_instances_of($files, 'PhabricatorFile'); 29 28 30 - switch ($this->getFilter()) { 31 - case 'my': 32 - $query->withAuthorPHIDs(array($user->getPHID())); 33 - $query->showOnlyExplicitUploads(true); 34 - $header = pht('Files You Uploaded'); 35 - break; 36 - case 'all': 37 - default: 38 - $header = pht('All Files'); 39 - break; 40 - } 29 + $request = $this->getRequest(); 30 + $user = $request->getUser(); 41 31 42 - $files = $query->executeWithCursorPager($pager); 32 + $highlighted_ids = $request->getStrList('h'); 43 33 $this->loadHandles(mpull($files, 'getAuthorPHID')); 44 - 45 - $highlighted = $request->getStrList('h'); 46 - $file_list = $this->buildFileList($files, $highlighted); 47 - 48 - $side_nav = $this->buildSideNavView(); 49 - $side_nav->selectFilter($this->getFilter()); 50 - 51 - $side_nav->appendChild( 52 - array( 53 - $file_list, 54 - $pager, 55 - new PhabricatorGlobalUploadTargetView(), 56 - )); 57 - 58 - $side_nav->setCrumbs( 59 - $this 60 - ->buildApplicationCrumbs() 61 - ->addCrumb( 62 - id(new PhabricatorCrumbView()) 63 - ->setName($header) 64 - ->setHref($request->getRequestURI()))); 65 - 66 - return $this->buildApplicationPage( 67 - $side_nav, 68 - array( 69 - 'title' => 'Files', 70 - 'device' => true, 71 - 'dust' => true, 72 - )); 73 - } 74 - 75 - private function buildFileList(array $files, array $highlighted_ids) { 76 - assert_instances_of($files, 'PhabricatorFile'); 77 34 78 35 $request = $this->getRequest(); 79 36 $user = $request->getUser(); ··· 117 74 118 75 $list_view->addItem($item); 119 76 } 77 + 78 + $list_view->appendChild(new PhabricatorGlobalUploadTargetView()); 120 79 121 80 return $list_view; 122 81 }
+26
src/applications/files/query/PhabricatorFileQuery.php
··· 8 8 private $authorPHIDs; 9 9 private $explicitUploads; 10 10 private $transforms; 11 + private $dateCreatedAfter; 12 + private $dateCreatedBefore; 11 13 12 14 public function withIDs(array $ids) { 13 15 $this->ids = $ids; ··· 21 23 22 24 public function withAuthorPHIDs(array $phids) { 23 25 $this->authorPHIDs = $phids; 26 + return $this; 27 + } 28 + 29 + public function withDateCreatedBefore($date_created_before) { 30 + $this->dateCreatedBefore = $date_created_before; 31 + return $this; 32 + } 33 + 34 + public function withDateCreatedAfter($date_created_after) { 35 + $this->dateCreatedAfter = $date_created_after; 24 36 return $this; 25 37 } 26 38 ··· 154 166 } 155 167 } 156 168 $where[] = qsprintf($conn_r, '(%Q)', implode(') OR (', $clauses)); 169 + } 170 + 171 + if ($this->dateCreatedAfter) { 172 + $where[] = qsprintf( 173 + $conn_r, 174 + 'f.dateCreated >= %d', 175 + $this->dateCreatedAfter); 176 + } 177 + 178 + if ($this->dateCreatedBefore) { 179 + $where[] = qsprintf( 180 + $conn_r, 181 + 'f.dateCreated <= %d', 182 + $this->dateCreatedBefore); 157 183 } 158 184 159 185 return $this->formatWhereClause($where);
+113
src/applications/files/query/PhabricatorFileSearchEngine.php
··· 1 + <?php 2 + 3 + final class PhabricatorFileSearchEngine 4 + extends PhabricatorApplicationSearchEngine { 5 + 6 + public function buildSavedQueryFromRequest(AphrontRequest $request) { 7 + $saved = new PhabricatorSavedQuery(); 8 + $saved->setParameter( 9 + 'authorPHIDs', 10 + array_values($request->getArr('authors'))); 11 + 12 + $saved->setParameter('explicit', $request->getBool('explicit')); 13 + $saved->setParameter('createdStart', $request->getStr('createdStart')); 14 + $saved->setParameter('createdEnd', $request->getStr('createdEnd')); 15 + 16 + return $saved; 17 + } 18 + 19 + public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { 20 + $query = id(new PhabricatorFileQuery()) 21 + ->withAuthorPHIDs($saved->getParameter('authorPHIDs', array())); 22 + 23 + if ($saved->getParameter('explicit')) { 24 + $query->showOnlyExplicitUploads(true); 25 + } 26 + 27 + $start = $this->parseDateTime($saved->getParameter('createdStart')); 28 + $end = $this->parseDateTime($saved->getParameter('createdEnd')); 29 + 30 + if ($start) { 31 + $query->withDateCreatedAfter($start); 32 + } 33 + 34 + if ($end) { 35 + $query->withDateCreatedBefore($end); 36 + } 37 + 38 + return $query; 39 + } 40 + 41 + public function buildSearchForm( 42 + AphrontFormView $form, 43 + PhabricatorSavedQuery $saved_query) { 44 + 45 + $phids = $saved_query->getParameter('authorPHIDs', array()); 46 + $handles = id(new PhabricatorObjectHandleData($phids)) 47 + ->setViewer($this->requireViewer()) 48 + ->loadHandles(); 49 + $author_tokens = mpull($handles, 'getFullName', 'getPHID'); 50 + 51 + $explicit = $saved_query->getParameter('explicit'); 52 + 53 + $form 54 + ->appendChild( 55 + id(new AphrontFormTokenizerControl()) 56 + ->setDatasource('/typeahead/common/users/') 57 + ->setName('authors') 58 + ->setLabel(pht('Authors')) 59 + ->setValue($author_tokens)) 60 + ->appendChild( 61 + id(new AphrontFormCheckboxControl()) 62 + ->addCheckbox( 63 + 'explicit', 64 + 1, 65 + pht('Show only manually uploaded files.'), 66 + $explicit)); 67 + 68 + $this->buildDateRange( 69 + $form, 70 + $saved_query, 71 + 'createdStart', 72 + pht('Created After'), 73 + 'createdEnd', 74 + pht('Created Before')); 75 + } 76 + 77 + protected function getURI($path) { 78 + return '/file/'.$path; 79 + } 80 + 81 + public function getBuiltinQueryNames() { 82 + $names = array(); 83 + 84 + if ($this->requireViewer()->isLoggedIn()) { 85 + $names['authored'] = pht('Authored'); 86 + } 87 + 88 + $names += array( 89 + 'all' => pht('All'), 90 + ); 91 + 92 + return $names; 93 + } 94 + 95 + public function buildSavedQueryFromBuiltin($query_key) { 96 + 97 + $query = $this->newSavedQuery(); 98 + $query->setQueryKey($query_key); 99 + 100 + switch ($query_key) { 101 + case 'all': 102 + return $query; 103 + case 'authored': 104 + $author_phid = array($this->requireViewer()->getPHID()); 105 + return $query 106 + ->setParameter('authorPHIDs', $author_phid) 107 + ->setParameter('explicit', true); 108 + } 109 + 110 + return parent::buildSavedQueryFromBuiltin($query_key); 111 + } 112 + 113 + }
+1 -1
src/applications/macro/controller/PhabricatorMacroController.php
··· 16 16 17 17 id(new PhabricatorMacroSearchEngine()) 18 18 ->setViewer($this->getRequest()->getUser()) 19 - ->addNavigationItems($nav); 19 + ->addNavigationItems($nav->getMenu()); 20 20 21 21 return $nav; 22 22 }
+1 -1
src/applications/paste/controller/PhabricatorPasteController.php
··· 14 14 15 15 id(new PhabricatorPasteSearchEngine()) 16 16 ->setViewer($user) 17 - ->addNavigationItems($nav); 17 + ->addNavigationItems($nav->getMenu()); 18 18 19 19 $nav->selectFilter(null); 20 20
+6 -6
src/applications/search/engine/PhabricatorApplicationSearchEngine.php
··· 106 106 } 107 107 108 108 109 - public function addNavigationItems(AphrontSideNavFilterView $nav) { 109 + public function addNavigationItems(PhabricatorMenuView $menu) { 110 110 $viewer = $this->requireViewer(); 111 111 112 - $nav->addLabel(pht('Queries')); 112 + $menu->newLabel(pht('Queries')); 113 113 114 114 $named_queries = id(new PhabricatorNamedQueryQuery()) 115 115 ->setViewer($viewer) ··· 122 122 foreach ($named_queries as $query) { 123 123 $key = $query->getQueryKey(); 124 124 $uri = $this->getQueryResultsPageURI($key); 125 - $nav->addFilter('query/'.$key, $query->getQueryName(), $uri); 125 + $menu->newLink($query->getQueryName(), $uri, 'query/'.$key); 126 126 } 127 127 128 128 $manage_uri = $this->getQueryManagementURI(); 129 - $nav->addFilter('query/edit', pht('Edit Queries...'), $manage_uri); 129 + $menu->newLink(pht('Edit Queries...'), $manage_uri, 'query/edit'); 130 130 131 - $nav->addLabel(pht('Search')); 131 + $menu->newLabel(pht('Search')); 132 132 $advanced_uri = $this->getQueryResultsPageURI('advanced'); 133 - $nav->addFilter('query/advanced', pht('Advanced Search'), $advanced_uri); 133 + $menu->newLink(pht('Advanced Search'), $advanced_uri, 'query/advanced'); 134 134 135 135 return $this; 136 136 }
+4
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
··· 1338 1338 'type' => 'sql', 1339 1339 'name' => $this->getPatchPath('20130530.pastekeys.sql'), 1340 1340 ), 1341 + '20130531.filekeys.sql' => array( 1342 + 'type' => 'sql', 1343 + 'name' => $this->getPatchPath('20130531.filekeys.sql'), 1344 + ), 1341 1345 ); 1342 1346 } 1343 1347 }
+1
src/view/layout/PhabricatorObjectItemListView.php
··· 93 93 $header, 94 94 $items, 95 95 $pager, 96 + $this->renderChildren(), 96 97 )); 97 98 } 98 99