@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.

Modernize search engine selection

Summary: Remove the `PhabricatorDefaultSearchEngineSelector` class. This is quite similar to D12053.

Test Plan: Went to `/view/PhabricatorSearchApplication/` and saw the storage engine configuration. Set `search.elastic.host` and saw the highlighted storage engine change.

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: Korvin, epriestley

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

+263 -78
+4 -5
src/__phutil_library_map__.php
··· 1744 1744 'PhabricatorDatabaseSetupCheck' => 'applications/config/check/PhabricatorDatabaseSetupCheck.php', 1745 1745 'PhabricatorDateTimeSettingsPanel' => 'applications/settings/panel/PhabricatorDateTimeSettingsPanel.php', 1746 1746 'PhabricatorDebugController' => 'applications/system/controller/PhabricatorDebugController.php', 1747 - 'PhabricatorDefaultSearchEngineSelector' => 'applications/search/selector/PhabricatorDefaultSearchEngineSelector.php', 1748 1747 'PhabricatorDestructibleInterface' => 'applications/system/interface/PhabricatorDestructibleInterface.php', 1749 1748 'PhabricatorDestructionEngine' => 'applications/system/engine/PhabricatorDestructionEngine.php', 1750 1749 'PhabricatorDeveloperConfigOptions' => 'applications/config/option/PhabricatorDeveloperConfigOptions.php', ··· 1776 1775 'PhabricatorEdgeType' => 'infrastructure/edges/type/PhabricatorEdgeType.php', 1777 1776 'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php', 1778 1777 'PhabricatorElasticSearchEngine' => 'applications/search/engine/PhabricatorElasticSearchEngine.php', 1779 - 'PhabricatorElasticSetupCheck' => 'applications/config/check/PhabricatorElasticSetupCheck.php', 1778 + 'PhabricatorElasticSearchSetupCheck' => 'applications/config/check/PhabricatorElasticSearchSetupCheck.php', 1780 1779 'PhabricatorEmailAddressesSettingsPanel' => 'applications/settings/panel/PhabricatorEmailAddressesSettingsPanel.php', 1781 1780 'PhabricatorEmailFormatSettingsPanel' => 'applications/settings/panel/PhabricatorEmailFormatSettingsPanel.php', 1782 1781 'PhabricatorEmailLoginController' => 'applications/auth/controller/PhabricatorEmailLoginController.php', ··· 2501 2500 'PhabricatorSearchAbstractDocument' => 'applications/search/index/PhabricatorSearchAbstractDocument.php', 2502 2501 'PhabricatorSearchApplication' => 'applications/search/application/PhabricatorSearchApplication.php', 2503 2502 'PhabricatorSearchApplicationSearchEngine' => 'applications/search/query/PhabricatorSearchApplicationSearchEngine.php', 2503 + 'PhabricatorSearchApplicationStorageEnginePanel' => 'applications/search/applicationpanel/PhabricatorSearchApplicationStorageEnginePanel.php', 2504 2504 'PhabricatorSearchAttachController' => 'applications/search/controller/PhabricatorSearchAttachController.php', 2505 2505 'PhabricatorSearchBaseController' => 'applications/search/controller/PhabricatorSearchBaseController.php', 2506 2506 'PhabricatorSearchConfigOptions' => 'applications/search/config/PhabricatorSearchConfigOptions.php', ··· 2516 2516 'PhabricatorSearchDocumentTypeDatasource' => 'applications/search/typeahead/PhabricatorSearchDocumentTypeDatasource.php', 2517 2517 'PhabricatorSearchEditController' => 'applications/search/controller/PhabricatorSearchEditController.php', 2518 2518 'PhabricatorSearchEngine' => 'applications/search/engine/PhabricatorSearchEngine.php', 2519 - 'PhabricatorSearchEngineSelector' => 'applications/search/selector/PhabricatorSearchEngineSelector.php', 2520 2519 'PhabricatorSearchField' => 'applications/search/constants/PhabricatorSearchField.php', 2521 2520 'PhabricatorSearchHovercardController' => 'applications/search/controller/PhabricatorSearchHovercardController.php', 2522 2521 'PhabricatorSearchIndexer' => 'applications/search/index/PhabricatorSearchIndexer.php', ··· 5140 5139 'PhabricatorDatabaseSetupCheck' => 'PhabricatorSetupCheck', 5141 5140 'PhabricatorDateTimeSettingsPanel' => 'PhabricatorSettingsPanel', 5142 5141 'PhabricatorDebugController' => 'PhabricatorController', 5143 - 'PhabricatorDefaultSearchEngineSelector' => 'PhabricatorSearchEngineSelector', 5144 5142 'PhabricatorDestructionEngine' => 'Phobject', 5145 5143 'PhabricatorDeveloperConfigOptions' => 'PhabricatorApplicationConfigOptions', 5146 5144 'PhabricatorDeveloperPreferencesSettingsPanel' => 'PhabricatorSettingsPanel', ··· 5169 5167 'PhabricatorEdgeType' => 'Phobject', 5170 5168 'PhabricatorEditor' => 'Phobject', 5171 5169 'PhabricatorElasticSearchEngine' => 'PhabricatorSearchEngine', 5172 - 'PhabricatorElasticSetupCheck' => 'PhabricatorSetupCheck', 5170 + 'PhabricatorElasticSearchSetupCheck' => 'PhabricatorSetupCheck', 5173 5171 'PhabricatorEmailAddressesSettingsPanel' => 'PhabricatorSettingsPanel', 5174 5172 'PhabricatorEmailFormatSettingsPanel' => 'PhabricatorSettingsPanel', 5175 5173 'PhabricatorEmailLoginController' => 'PhabricatorAuthController', ··· 5973 5971 'PhabricatorScheduleTaskTriggerAction' => 'PhabricatorTriggerAction', 5974 5972 'PhabricatorSearchApplication' => 'PhabricatorApplication', 5975 5973 'PhabricatorSearchApplicationSearchEngine' => 'PhabricatorApplicationSearchEngine', 5974 + 'PhabricatorSearchApplicationStorageEnginePanel' => 'PhabricatorApplicationConfigurationPanel', 5976 5975 'PhabricatorSearchAttachController' => 'PhabricatorSearchBaseController', 5977 5976 'PhabricatorSearchBaseController' => 'PhabricatorController', 5978 5977 'PhabricatorSearchConfigOptions' => 'PhabricatorApplicationConfigOptions',
+10 -3
src/applications/config/check/PhabricatorElasticSetupCheck.php src/applications/config/check/PhabricatorElasticSearchSetupCheck.php
··· 1 1 <?php 2 2 3 - final class PhabricatorElasticSetupCheck extends PhabricatorSetupCheck { 3 + final class PhabricatorElasticSearchSetupCheck extends PhabricatorSetupCheck { 4 4 5 5 public function getDefaultGroup() { 6 6 return self::GROUP_OTHER; 7 7 } 8 8 9 9 protected function executeChecks() { 10 - if (PhabricatorDefaultSearchEngineSelector::shouldUseElasticSearch()) { 11 - $engine = PhabricatorSearchEngineSelector::newSelector()->newEngine(); 10 + if ($this->shouldUseElasticSearchEngine()) { 11 + $engine = new PhabricatorElasticSearchEngine(); 12 + 12 13 if (!$engine->indexExists()) { 13 14 $summary = pht( 14 15 'You enabled Elasticsearch but the index does not exist.'); ··· 40 41 } 41 42 } 42 43 } 44 + 45 + protected function shouldUseElasticSearchEngine() { 46 + $search_engine = PhabricatorSearchEngine::loadEngine(); 47 + return $search_engine instanceof PhabricatorElasticSearchEngine; 48 + } 49 + 43 50 }
+4
src/applications/config/check/PhabricatorExtraConfigSetupCheck.php
··· 252 252 253 253 'style.monospace' => $monospace_reason, 254 254 'style.monospace.windows' => $monospace_reason, 255 + 256 + 'search.engine-selector' => pht( 257 + 'Phabricator now automatically discovers available search engines '. 258 + 'at runtime.'), 255 259 ); 256 260 257 261 return $ancient_config;
+9 -4
src/applications/config/check/PhabricatorMySQLSetupCheck.php
··· 116 116 } 117 117 118 118 $stopword_file = self::loadRawConfigValue('ft_stopword_file'); 119 - if (!PhabricatorDefaultSearchEngineSelector::shouldUseElasticSearch()) { 119 + 120 + if ($this->shouldUseMySQLSearchEngine()) { 120 121 if ($stopword_file === null) { 121 122 $summary = pht( 122 123 'Your version of MySQL does not support configuration of a '. ··· 190 191 191 192 $min_len = self::loadRawConfigValue('ft_min_word_len'); 192 193 if ($min_len >= 4) { 193 - if (!PhabricatorDefaultSearchEngineSelector::shouldUseElasticSearch()) { 194 + if ($this->shouldUseMySQLSearchEngine()) { 194 195 $namespace = PhabricatorEnv::getEnvConfig('storage.default-namespace'); 195 196 196 197 $summary = pht( ··· 235 236 236 237 $bool_syntax = self::loadRawConfigValue('ft_boolean_syntax'); 237 238 if ($bool_syntax != ' |-><()~*:""&^') { 238 - if (!PhabricatorDefaultSearchEngineSelector::shouldUseElasticSearch()) { 239 - 239 + if ($this->shouldUseMySQLSearchEngine()) { 240 240 $summary = pht( 241 241 'MySQL is configured to search on fulltext indexes using "OR" by '. 242 242 'default. Using "AND" is usually the desired behaviour.'); ··· 338 338 ->setMessage($message); 339 339 } 340 340 341 + } 342 + 343 + protected function shouldUseMySQLSearchEngine() { 344 + $search_engine = PhabricatorSearchEngine::loadEngine(); 345 + return $search_engine instanceof PhabricatorMySQLSearchEngine; 341 346 } 342 347 343 348 }
-2
src/applications/files/applicationpanel/PhabricatorFilesApplicationStorageEnginePanel.php
··· 61 61 ); 62 62 } 63 63 64 - $table = 65 - 66 64 $table = id(new AphrontTableView($rows)) 67 65 ->setNoDataString(pht('No storage engines available.')) 68 66 ->setHeaders(
+1 -1
src/applications/maniphest/query/ManiphestTaskQuery.php
··· 563 563 $fulltext_query->setParameter('types', 564 564 array(ManiphestTaskPHIDType::TYPECONST)); 565 565 566 - $engine = PhabricatorSearchEngineSelector::newSelector()->newEngine(); 566 + $engine = PhabricatorSearchEngine::loadEngine(); 567 567 $fulltext_results = $engine->executeSearch($fulltext_query); 568 568 569 569 if (empty($fulltext_results)) {
+82
src/applications/search/applicationpanel/PhabricatorSearchApplicationStorageEnginePanel.php
··· 1 + <?php 2 + 3 + final class PhabricatorSearchApplicationStorageEnginePanel 4 + extends PhabricatorApplicationConfigurationPanel { 5 + 6 + public function getPanelKey() { 7 + return 'search'; 8 + } 9 + 10 + public function shouldShowForApplication( 11 + PhabricatorApplication $application) { 12 + return $application instanceof PhabricatorSearchApplication; 13 + } 14 + 15 + public function buildConfigurationPagePanel() { 16 + $viewer = $this->getViewer(); 17 + $application = $this->getApplication(); 18 + 19 + $active_engine = PhabricatorSearchEngine::loadEngine(); 20 + $engines = PhabricatorSearchEngine::loadAllEngines(); 21 + 22 + $rows = array(); 23 + $rowc = array(); 24 + 25 + foreach ($engines as $key => $engine) { 26 + try { 27 + $index_exists = $engine->indexExists() ? pht('Yes') : pht('No'); 28 + } catch (Exception $ex) { 29 + $index_exists = pht('N/A'); 30 + } 31 + 32 + try { 33 + $index_is_sane = $engine->indexIsSane() ? pht('Yes') : pht('No'); 34 + } catch (Exception $ex) { 35 + $index_is_sane = pht('N/A'); 36 + } 37 + 38 + if ($engine == $active_engine) { 39 + $rowc[] = 'highlighted'; 40 + } else { 41 + $rowc[] = null; 42 + } 43 + 44 + $rows[] = array( 45 + $key, 46 + get_class($engine), 47 + $index_exists, 48 + $index_is_sane, 49 + ); 50 + } 51 + 52 + $table = id(new AphrontTableView($rows)) 53 + ->setNoDataString(pht('No search engines available.')) 54 + ->setHeaders( 55 + array( 56 + pht('Key'), 57 + pht('Class'), 58 + pht('Index Exists'), 59 + pht('Index Is Sane'), 60 + )) 61 + ->setRowClasses($rowc) 62 + ->setColumnClasses( 63 + array( 64 + '', 65 + 'wide', 66 + '', 67 + )); 68 + 69 + $box = id(new PHUIObjectBoxView()) 70 + ->setHeaderText(pht('Search Engines')) 71 + ->appendChild($table); 72 + 73 + return $box; 74 + } 75 + 76 + public function handlePanelRequest( 77 + AphrontRequest $request, 78 + PhabricatorController $controller) { 79 + return new Aphront404Response(); 80 + } 81 + 82 + }
-15
src/applications/search/config/PhabricatorSearchConfigOptions.php
··· 21 21 22 22 public function getOptions() { 23 23 return array( 24 - $this->newOption( 25 - 'search.engine-selector', 26 - 'class', 27 - 'PhabricatorDefaultSearchEngineSelector') 28 - ->setBaseClass('PhabricatorSearchEngineSelector') 29 - ->setSummary(pht('Search engine selector.')) 30 - ->setDescription( 31 - pht( 32 - 'Phabricator uses a search engine selector to choose which '. 33 - 'search engine to use when indexing and reconstructing '. 34 - 'documents, and when executing queries. You can override the '. 35 - 'engine selector to provide a new selector class which can '. 36 - 'select some custom engine you implement, if you want to store '. 37 - 'your documents in some search engine which does not have '. 38 - 'default support.')), 39 24 $this->newOption('search.elastic.host', 'string', null) 40 25 ->setLocked(true) 41 26 ->setDescription(pht('Elastic Search host.'))
+28 -2
src/applications/search/engine/PhabricatorElasticSearchEngine.php
··· 1 1 <?php 2 2 3 3 final class PhabricatorElasticSearchEngine extends PhabricatorSearchEngine { 4 + 4 5 private $uri; 5 6 private $index; 6 7 private $timeout; 7 8 8 - public function __construct($uri, $index) { 9 + public function getEngineIdentifier() { 10 + return 'elasticsearch'; 11 + } 12 + 13 + public function getEnginePriority() { 14 + return 10; 15 + } 16 + 17 + public function isEnabled() { 18 + return (bool)PhabricatorEnv::getEnvConfig('search.elastic.host'); 19 + } 20 + 21 + public function setURI($uri) { 9 22 $this->uri = $uri; 23 + return $this; 24 + } 25 + 26 + public function setIndex($index) { 10 27 $this->index = $index; 28 + return $this; 11 29 } 12 30 13 31 public function setTimeout($timeout) { 14 32 $this->timeout = $timeout; 15 33 return $this; 34 + } 35 + 36 + public function getURI() { 37 + return $this->uri; 38 + } 39 + 40 + public function getIndex() { 41 + return $this->index; 16 42 } 17 43 18 44 public function getTimeout() { ··· 99 125 $spec[] = array( 100 126 'simple_query_string' => array( 101 127 'query' => $query->getParameter('query'), 102 - 'fields' => array( 'field.corpus' ), 128 + 'fields' => array('field.corpus'), 103 129 ), 104 130 ); 105 131
+17 -5
src/applications/search/engine/PhabricatorMySQLSearchEngine.php
··· 2 2 3 3 final class PhabricatorMySQLSearchEngine extends PhabricatorSearchEngine { 4 4 5 + public function getEngineIdentifier() { 6 + return 'mysql'; 7 + } 8 + 9 + public function getEnginePriority() { 10 + return 100; 11 + } 12 + 13 + public function isEnabled() { 14 + return true; 15 + } 16 + 5 17 public function reindexAbstractDocument( 6 18 PhabricatorSearchAbstractDocument $doc) { 7 19 8 20 $phid = $doc->getPHID(); 9 21 if (!$phid) { 10 - throw new Exception('Document has no PHID!'); 22 + throw new Exception(pht('Document has no PHID!')); 11 23 } 12 24 13 25 $store = new PhabricatorSearchDocument(); ··· 31 43 queryfx( 32 44 $conn_w, 33 45 'INSERT INTO %T (phid, phidType, field, auxPHID, corpus) '. 34 - ' VALUES (%s, %s, %s, %ns, %s)', 46 + 'VALUES (%s, %s, %s, %ns, %s)', 35 47 $field_dao->getTableName(), 36 48 $phid, 37 49 $doc->getDocumentType(), ··· 63 75 if ($sql) { 64 76 queryfx( 65 77 $conn_w, 66 - 'INSERT INTO %T'. 67 - ' (phid, relatedPHID, relation, relatedType, relatedTime) '. 68 - ' VALUES %Q', 78 + 'INSERT INTO %T '. 79 + '(phid, relatedPHID, relation, relatedType, relatedTime) '. 80 + 'VALUES %Q', 69 81 $rship_dao->getTableName(), 70 82 implode(', ', $sql)); 71 83 }
+105 -4
src/applications/search/engine/PhabricatorSearchEngine.php
··· 1 1 <?php 2 2 3 - 4 3 /** 5 4 * Base class for Phabricator search engine providers. Each engine must offer 6 5 * three capabilities: indexing, searching, and reconstruction (this can be ··· 8 7 */ 9 8 abstract class PhabricatorSearchEngine { 10 9 10 + /* -( Engine Metadata )---------------------------------------------------- */ 11 + 12 + /** 13 + * Return a unique, nonempty string which identifies this storage engine. 14 + * 15 + * @return string Unique string for this engine, max length 32. 16 + * @task meta 17 + */ 18 + abstract public function getEngineIdentifier(); 19 + 20 + /** 21 + * Prioritize this engine relative to other engines. 22 + * 23 + * Engines with a smaller priority number get an opportunity to write files 24 + * first. Generally, lower-latency filestores should have lower priority 25 + * numbers, and higher-latency filestores should have higher priority 26 + * numbers. Setting priority to approximately the number of milliseconds of 27 + * read latency will generally produce reasonable results. 28 + * 29 + * In conjunction with filesize limits, the goal is to store small files like 30 + * profile images, thumbnails, and text snippets in lower-latency engines, 31 + * and store large files in higher-capacity engines. 32 + * 33 + * @return float Engine priority. 34 + * @task meta 35 + */ 36 + abstract public function getEnginePriority(); 37 + 38 + /** 39 + * Return `true` if the engine is currently writable. 40 + * 41 + * Engines that are disabled or missing configuration should return `false` 42 + * to prevent new writes. If writes were made with this engine in the past, 43 + * the application may still try to perform reads. 44 + * 45 + * @return bool True if this engine can support new writes. 46 + * @task meta 47 + */ 48 + abstract public function isEnabled(); 49 + 50 + 51 + /* -( Managing Documents )------------------------------------------------- */ 52 + 11 53 /** 12 54 * Update the index for an abstract document. 13 55 * ··· 16 58 */ 17 59 abstract public function reindexAbstractDocument( 18 60 PhabricatorSearchAbstractDocument $document); 19 - 20 61 21 62 /** 22 63 * Reconstruct the document for a given PHID. This is used for debugging ··· 26 67 * @return PhabricatorSearchAbstractDocument Abstract document. 27 68 */ 28 69 abstract public function reconstructDocument($phid); 29 - 30 70 31 71 /** 32 72 * Execute a search query. ··· 53 93 } 54 94 55 95 /** 56 - * Do any sort of setup for the search index 96 + * Do any sort of setup for the search index. 57 97 * 58 98 * @return void 59 99 */ 60 100 public function initIndex() {} 101 + 102 + 103 + /* -( Loading Storage Engines )-------------------------------------------- */ 104 + 105 + /** 106 + * @task load 107 + */ 108 + public static function loadAllEngines() { 109 + static $engines; 110 + 111 + if ($engines === null) { 112 + $objects = id(new PhutilSymbolLoader()) 113 + ->setAncestorClass(__CLASS__) 114 + ->loadObjects(); 115 + 116 + $map = array(); 117 + foreach ($objects as $engine) { 118 + $key = $engine->getEngineIdentifier(); 119 + if (empty($map[$key])) { 120 + $map[$key] = $engine; 121 + } else { 122 + throw new Exception( 123 + pht( 124 + 'Search engines "%s" and "%s" have the same engine identifier '. 125 + '"%s". Each storage engine must have a unique identifier.', 126 + get_class($engine), 127 + get_class($map[$key]), 128 + $key)); 129 + } 130 + } 131 + 132 + $map = msort($map, 'getEnginePriority'); 133 + 134 + $engines = $map; 135 + } 136 + 137 + return $engines; 138 + } 139 + 140 + /** 141 + * @task load 142 + */ 143 + public static function loadActiveEngines() { 144 + $engines = self::loadAllEngines(); 145 + 146 + $active = array(); 147 + foreach ($engines as $key => $engine) { 148 + if (!$engine->isEnabled()) { 149 + continue; 150 + } 151 + 152 + $active[$key] = $engine; 153 + } 154 + 155 + return $active; 156 + } 157 + 158 + public static function loadEngine() { 159 + return head(self::loadActiveEngines()); 160 + } 161 + 61 162 }
+1 -1
src/applications/search/index/PhabricatorSearchDocumentIndexer.php
··· 69 69 $this->indexProjects($document, $object); 70 70 } 71 71 72 - $engine = PhabricatorSearchEngineSelector::newSelector()->newEngine(); 72 + $engine = PhabricatorSearchEngine::loadEngine(); 73 73 try { 74 74 $engine->reindexAbstractDocument($document); 75 75 } catch (Exception $ex) {
+1 -1
src/applications/search/management/PhabricatorSearchManagementInitWorkflow.php
··· 13 13 public function execute(PhutilArgumentParser $args) { 14 14 $console = PhutilConsole::getConsole(); 15 15 16 - $engine = PhabricatorSearchEngineSelector::newSelector()->newEngine(); 16 + $engine = PhabricatorSearchEngine::loadEngine(); 17 17 18 18 $work_done = false; 19 19 if (!$engine->indexExists()) {
+1 -1
src/applications/search/query/PhabricatorSearchDocumentQuery.php
··· 74 74 ->setParameter('offset', $this->getOffset()) 75 75 ->setParameter('limit', $this->getRawResultLimit()); 76 76 77 - $engine = PhabricatorSearchEngineSelector::newSelector()->newEngine(); 77 + $engine = PhabricatorSearchEngine::loadEngine(); 78 78 79 79 return $engine->executeSearch($query); 80 80 }
-19
src/applications/search/selector/PhabricatorDefaultSearchEngineSelector.php
··· 1 - <?php 2 - 3 - final class PhabricatorDefaultSearchEngineSelector 4 - extends PhabricatorSearchEngineSelector { 5 - 6 - public function newEngine() { 7 - if (self::shouldUseElasticSearch()) { 8 - $elastic_host = PhabricatorEnv::getEnvConfig('search.elastic.host'); 9 - $elastic_index = PhabricatorEnv::getEnvConfig('search.elastic.namespace'); 10 - return new PhabricatorElasticSearchEngine($elastic_host, $elastic_index); 11 - } 12 - return new PhabricatorMySQLSearchEngine(); 13 - } 14 - 15 - public static function shouldUseElasticSearch() { 16 - return (bool)PhabricatorEnv::getEnvConfig('search.elastic.host'); 17 - } 18 - 19 - }
-15
src/applications/search/selector/PhabricatorSearchEngineSelector.php
··· 1 - <?php 2 - 3 - abstract class PhabricatorSearchEngineSelector { 4 - 5 - final public function __construct() { 6 - // <empty> 7 - } 8 - 9 - abstract public function newEngine(); 10 - 11 - final public static function newSelector() { 12 - return PhabricatorEnv::newObjectFromConfig('search.engine-selector'); 13 - } 14 - 15 - }