diff --git a/phpBB/adm/style/acp_search_index.html b/phpBB/adm/style/acp_search_index.html index 61ffb68d1d..fa09cb7991 100644 --- a/phpBB/adm/style/acp_search_index.html +++ b/phpBB/adm/style/acp_search_index.html @@ -2,20 +2,6 @@ - -

{{ lang('ACP_SEARCH_INDEX') }}

{{ lang('ACP_SEARCH_INDEX_EXPLAIN') }}

@@ -65,10 +51,10 @@

{% if backend.S_INDEXED %} - + {% else %} - + {% endif %}

{{ S_FORM_TOKEN }} diff --git a/phpBB/adm/style/acp_search_index_inprogress.html b/phpBB/adm/style/acp_search_index_inprogress.html index 3d9111192a..3f8f51f378 100644 --- a/phpBB/adm/style/acp_search_index_inprogress.html +++ b/phpBB/adm/style/acp_search_index_inprogress.html @@ -2,29 +2,38 @@ - +

+ {% if S_ACTION == 'create' %} + {{ lang('CONTINUE_INDEXING') }} + {% else %} + {{ lang('CONTINUE_DELETING_INDEX') }} + {% endif %} +

-

{{ lang('CONTINUE') }}

- -

{{ lang('CONTINUE_EXPLAIN') }}

+

+ {% if S_ACTION == 'create' %} + {{ lang('CONTINUE_INDEXING_EXPLAIN') }} + {% else %} + {{ lang('CONTINUE_DELETING_INDEX_EXPLAIN') }} + {% endif %} +

- {{ lang('ACP_SUBMIT_CHANGES') }} + {{ lang('CONTINUE_INDEXING') }} + {% if CONTINUE_PROGRESS %} +
+
+
+ {{ CONTINUE_PROGRESS.PERCENTAGE|number_format(2) ~ ' %' }}
+ {{ lang('SEARCH_INDEX_PROGRESS', CONTINUE_PROGRESS.VALUE, CONTINUE_PROGRESS.REMAINING, CONTINUE_PROGRESS.TOTAL) }} +
+ {% endif %}

-   +  

{{ S_FORM_TOKEN }} diff --git a/phpBB/adm/style/acp_search_index_progress.html b/phpBB/adm/style/acp_search_index_progress.html new file mode 100644 index 0000000000..6c41105bab --- /dev/null +++ b/phpBB/adm/style/acp_search_index_progress.html @@ -0,0 +1,23 @@ +{% include 'overall_header.html' %} + + + +
+

{{ INDEXING_TITLE }}

+

+ {{ INDEXING_EXPLAIN }} + {% if INDEXING_PROGRESS %}
{{ INDEXING_PROGRESS }}{% endif %} + {% if INDEXING_RATE %}
{{ INDEXING_RATE }}{% endif %} + {% if INDEXING_PROGRESS_BAR %} +
+
+ {{ INDEXING_PROGRESS_BAR.PERCENTAGE|number_format(2) ~ ' %' }}
+ {{ lang('SEARCH_INDEX_PROGRESS', INDEXING_PROGRESS_BAR.VALUE, INDEXING_PROGRESS_BAR.REMAINING, INDEXING_PROGRESS_BAR.TOTAL) }} + {% endif %} +

+
+ +{% include 'overall_footer.html' %} diff --git a/phpBB/includes/acp/acp_search.php b/phpBB/includes/acp/acp_search.php index f13b9c8dea..cd45e527d0 100644 --- a/phpBB/includes/acp/acp_search.php +++ b/phpBB/includes/acp/acp_search.php @@ -16,6 +16,7 @@ */ use phpbb\config\config; +use phpbb\db\driver\driver_interface; use phpbb\di\service_collection; use phpbb\language\language; use phpbb\log\log; @@ -39,6 +40,9 @@ class acp_search /** @var config */ protected $config; + /** @var driver_interface */ + protected $db; + /** @var language */ protected $language; @@ -71,9 +75,10 @@ class acp_search public function __construct($p_master) { - global $config, $phpbb_container, $language, $phpbb_log, $request, $template, $user, $phpbb_admin_path, $phpEx; + global $config, $db, $phpbb_container, $language, $phpbb_log, $request, $template, $user, $phpbb_admin_path, $phpEx; $this->config = $config; + $this->db = $db; $this->language = $language; $this->log = $phpbb_log; $this->request = $request; @@ -278,10 +283,6 @@ class acp_search { switch ($action) { - case 'progress_bar': - $this->display_progress_bar(); - break; - case 'create': case 'delete': $this->index_action($id, $mode, $action); @@ -352,12 +353,11 @@ class acp_search $this->page_title = 'ACP_SEARCH_INDEX'; $action = $this->search_state_helper->action(); + $post_counter = $this->search_state_helper->counter(); $this->template->assign_vars([ 'U_ACTION' => $this->u_action . '&action=' . $action . '&hash=' . generate_link_hash('acp_search'), - 'UA_PROGRESS_BAR' => addslashes($this->u_action . '&action=progress_bar'), - 'L_CONTINUE' => ($action === 'create') ? $this->language->lang('CONTINUE_INDEXING') : $this->language->lang('CONTINUE_DELETING_INDEX'), - 'L_CONTINUE_EXPLAIN' => ($action === 'create') ? $this->language->lang('CONTINUE_INDEXING_EXPLAIN') : $this->language->lang('CONTINUE_DELETING_INDEX_EXPLAIN'), + 'CONTINUE_PROGRESS' => $this->get_post_index_progress($post_counter), 'S_ACTION' => $action, ]); } @@ -392,6 +392,13 @@ class acp_search } } + // Start displaying progress on first submit + if ($this->request->is_set_post('submit')) + { + $this->display_progress_bar($id, $mode); + return; + } + // Execute create/delete $type = $this->search_state_helper->type(); $action = $this->search_state_helper->action(); @@ -409,15 +416,36 @@ class acp_search $u_action = append_sid($this->phpbb_admin_path . "index." . $this->php_ex, "i=$id&mode=$mode&action=$action&hash=" . generate_link_hash('acp_search'), false); meta_refresh(1, $u_action); - $message_redirect = $this->language->lang(($action == 'create') ? 'SEARCH_INDEX_CREATE_REDIRECT' : 'SEARCH_INDEX_DELETE_REDIRECT', (int) $status['row_count'], $status['post_counter']); - $message_rate = $this->language->lang(($action == 'create') ? 'SEARCH_INDEX_CREATE_REDIRECT_RATE' : 'SEARCH_INDEX_DELETE_REDIRECT_RATE', $status['rows_per_second']); - trigger_error($message_redirect . $message_rate); + $message_progress = $this->language->lang(($action === 'create') ? 'INDEXING_IN_PROGRESS' : 'DELETING_INDEX_IN_PROGRESS'); + $message_progress_explain = $this->language->lang(($action == 'create') ? 'INDEXING_IN_PROGRESS_EXPLAIN' : 'DELETING_INDEX_IN_PROGRESS_EXPLAIN'); + $message_redirect = $this->language->lang( + ($action === 'create') ? 'SEARCH_INDEX_CREATE_REDIRECT' : 'SEARCH_INDEX_DELETE_REDIRECT', + (int) $status['row_count'], + $status['post_counter'] + ); + $message_redirect_rate = $this->language->lang( + ($action === 'create') ? 'SEARCH_INDEX_CREATE_REDIRECT_RATE' : 'SEARCH_INDEX_DELETE_REDIRECT_RATE', + $status['rows_per_second'] + ); + + $this->template->assign_vars([ + 'INDEXING_TITLE' => $this->language->lang($message_progress), + 'INDEXING_EXPLAIN' => $this->language->lang($message_progress_explain), + 'INDEXING_PROGRESS' => $message_redirect, + 'INDEXING_RATE' => $message_redirect_rate, + 'INDEXING_PROGRESS_BAR' => $this->get_post_index_progress($post_counter), + ]); + + $this->tpl_name = 'acp_search_index_progress'; + $this->page_title = 'ACP_SEARCH_INDEX'; + + return; } } catch (Exception $e) { $this->search_state_helper->clear_state(); // Unexpected error, cancel action - trigger_error($e->getMessage() . adm_back_link($this->u_action) . $this->close_popup_js(), E_USER_WARNING); + trigger_error($e->getMessage() . adm_back_link($this->u_action), E_USER_WARNING); } $search->tidy(); @@ -428,42 +456,73 @@ class acp_search $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, $log_operation, false, [$search->get_name()]); $message = $this->language->lang(($action == 'create') ? 'SEARCH_INDEX_CREATED' : 'SEARCH_INDEX_REMOVED'); - trigger_error($message . adm_back_link($this->u_action) . $this->close_popup_js()); + trigger_error($message . adm_back_link($this->u_action)); } /** - * Popup window + * Display progress bar for search after first submit + * + * @param string $id ACP module id + * @param string $mode ACP module mode */ - private function display_progress_bar(): void + private function display_progress_bar(string $id, string $mode): void { - $type = $this->request->variable('type', ''); - $l_type = ($type === 'create') ? 'INDEXING_IN_PROGRESS' : 'DELETING_INDEX_IN_PROGRESS'; + $action = $this->search_state_helper->action(); + $post_counter = $this->search_state_helper->counter(); - adm_page_header($this->language->lang($l_type)); + $message_progress = $this->language->lang(($action === 'create') ? 'INDEXING_IN_PROGRESS' : 'DELETING_INDEX_IN_PROGRESS'); + $message_progress_explain = $this->language->lang(($action == 'create') ? 'INDEXING_IN_PROGRESS_EXPLAIN' : 'DELETING_INDEX_IN_PROGRESS_EXPLAIN'); + + $u_action = append_sid($this->phpbb_admin_path . "index." . $this->php_ex, "i=$id&mode=$mode&action=$action&hash=" . generate_link_hash('acp_search'), false); + meta_refresh(1, $u_action); + + adm_page_header($this->language->lang($message_progress)); $this->template->set_filenames([ - 'body' => 'progress_bar.html' + 'body' => 'acp_search_index_progress.html' ]); $this->template->assign_vars([ - 'L_PROGRESS' => $this->language->lang($l_type), - 'L_PROGRESS_EXPLAIN' => $this->language->lang($l_type . '_EXPLAIN'), + 'INDEXING_TITLE' => $this->language->lang($message_progress), + 'INDEXING_EXPLAIN' => $this->language->lang($message_progress_explain), + 'INDEXING_PROGRESS_BAR' => $this->get_post_index_progress($post_counter), ]); adm_page_footer(); } /** - * Javascript code for closing the waiting screen (is attached to the trigger_errors) + * Get progress stats of search index with HTML progress bar. * - * @return string + * @param int $post_counter Post ID of last post indexed. + * @return array Returns array with progress bar data. */ - private function close_popup_js(): string + protected function get_post_index_progress(int $post_counter): array { - return "\n"; + global $db; + + $sql = 'SELECT COUNT(post_id) as done_count + FROM ' . POSTS_TABLE . ' + WHERE post_id <= ' . $post_counter; + $result = $db->sql_query($sql); + $done_count = (int) $db->sql_fetchfield('done_count'); + $db->sql_freeresult($result); + + $sql = 'SELECT COUNT(post_id) as remain_count + FROM ' . POSTS_TABLE . ' + WHERE post_id > ' . $post_counter; + $result = $db->sql_query($sql); + $remain_count = (int) $db->sql_fetchfield('remain_count'); + $db->sql_freeresult($result); + + $total_count = $done_count + $remain_count; + $percent = ($done_count / $total_count) * 100; + + return [ + 'VALUE' => $done_count, + 'TOTAL' => $total_count, + 'PERCENTAGE' => $percent, + 'REMAINING' => $remain_count, + ]; } } diff --git a/phpBB/language/en/acp/search.php b/phpBB/language/en/acp/search.php index 183ccf0d7b..da9bd89105 100644 --- a/phpBB/language/en/acp/search.php +++ b/phpBB/language/en/acp/search.php @@ -52,7 +52,7 @@ $lang = array_merge($lang, array( 'DEFAULT_SEARCH_RETURN_CHARS' => 'Default number of returned characters', 'DEFAULT_SEARCH_RETURN_CHARS_EXPLAIN' => 'The default number of characters that will be returned while searching. A value of 0 will return the entire post.', 'DELETE_INDEX' => 'Delete index', - 'DELETING_INDEX_IN_PROGRESS' => 'Deleting the index in progress', + 'DELETING_INDEX_IN_PROGRESS' => 'Deletion of index is in progress…', 'DELETING_INDEX_IN_PROGRESS_EXPLAIN' => 'The search backend is currently cleaning its index. This can take a few minutes.', 'FULLTEXT_MYSQL_INCOMPATIBLE_DATABASE' => 'The MySQL fulltext backend can only be used with MySQL4 and above.', @@ -94,7 +94,7 @@ $lang = array_merge($lang, array( 'INVALID_ACTION' => 'Invalid action', 'INDEX_STATS' => 'Index statistics', - 'INDEXING_IN_PROGRESS' => 'Indexing in progress', + 'INDEXING_IN_PROGRESS' => 'Indexing in progress…', 'INDEXING_IN_PROGRESS_EXPLAIN' => 'The search backend is currently indexing all posts on the board. This can take from a few minutes to a few hours depending on your board’s size.', 'LIMIT_SEARCH_LOAD' => 'Search page system load limit', @@ -114,18 +114,19 @@ $lang = array_merge($lang, array( 'SEARCH_GUEST_INTERVAL' => 'Guest search flood interval', 'SEARCH_GUEST_INTERVAL_EXPLAIN' => 'Number of seconds guests must wait between searches. If one guest searches all others have to wait until the time interval passed.', 'SEARCH_INDEX_CREATE_REDIRECT' => array( - 2 => 'All posts up to post id %2$d have now been indexed, of which %1$d posts were within this step.
', + 2 => 'All posts up to post id %2$d have now been indexed, of which %1$d posts were within this step.', ), 'SEARCH_INDEX_CREATE_REDIRECT_RATE' => array( - 2 => 'The current rate of indexing is approximately %1$.1f posts per second.
Indexing in progress…', + 2 => 'The current rate of indexing is approximately %1$.1f posts per second.', ), 'SEARCH_INDEX_DELETE_REDIRECT' => array( - 2 => 'All posts up to post id %2$d have been removed from the search index, of which %1$d posts were within this step.
', + 2 => 'All posts up to post id %2$d have been removed from the search index, of which %1$d posts were within this step.', ), 'SEARCH_INDEX_DELETE_REDIRECT_RATE' => array( - 2 => 'The current rate of deleting is approximately %1$.1f posts per second.
Deleting in progress…', + 2 => 'The current rate of deleting is approximately %1$.1f posts per second.', ), 'SEARCH_INDEX_CREATED' => 'Successfully indexed all posts in the board database.', + 'SEARCH_INDEX_PROGRESS' => 'Done: %1$d | Pending: %2$d | Total: %3$d', 'SEARCH_INDEX_REMOVED' => 'Successfully deleted the search index for this backend.', 'SEARCH_INTERVAL' => 'User search flood interval', 'SEARCH_INTERVAL_EXPLAIN' => 'Number of seconds users must wait between searches. This interval is checked independently for each user.', diff --git a/tests/functional/search/base.php b/tests/functional/search/base.php index d5f6980a3a..b66bb5c7a2 100644 --- a/tests/functional/search/base.php +++ b/tests/functional/search/base.php @@ -210,6 +210,21 @@ abstract class phpbb_functional_search_base extends phpbb_functional_test_case ); $form->setValues($form_values); $crawler = self::submit($form); + + $meta_refresh = $crawler->filter('meta[http-equiv="refresh"]'); + + if ($meta_refresh->count() > 0) + { + // Wait for posts to be fully indexed + while ($meta_refresh->count() > 0) + { + preg_match('#url=.+/(adm+.+)#', $meta_refresh->attr('content'), $match); + $url = $match[1]; + $crawler = self::request('POST', $url); + $meta_refresh = $crawler->filter('meta[http-equiv="refresh"]'); + } + } + $this->assertContainsLang('SEARCH_INDEX_CREATED', $crawler->text()); // Ensure search index has been actually created @@ -232,6 +247,21 @@ abstract class phpbb_functional_search_base extends phpbb_functional_test_case ); $form->setValues($form_values); $crawler = self::submit($form); + + $meta_refresh = $crawler->filter('meta[http-equiv="refresh"]'); + + if ($meta_refresh->count() > 0) + { + // Wait for index to be fully deleted + while ($meta_refresh->count() > 0) + { + preg_match('#url=.+/(adm+.+)#', $meta_refresh->attr('content'), $match); + $url = $match[1]; + $crawler = self::request('POST', $url); + $meta_refresh = $crawler->filter('meta[http-equiv="refresh"]'); + } + } + $this->assertContainsLang('SEARCH_INDEX_REMOVED', $crawler->text()); // Ensure search index has been actually removed