diff --git a/phpBB/config/default/container/services_console.yml b/phpBB/config/default/container/services_console.yml index a7e3f7b136..ff29a83e22 100644 --- a/phpBB/config/default/container/services_console.yml +++ b/phpBB/config/default/container/services_console.yml @@ -264,6 +264,7 @@ services: - '@log' - '@post.helper' - '@search.backend_factory' + - '@search.state_helper' - '@user' tags: - { name: console.command } @@ -276,6 +277,7 @@ services: - '@log' - '@post.helper' - '@search.backend_factory' + - '@search.state_helper' - '@user' tags: - { name: console.command } diff --git a/phpBB/config/default/container/services_search.yml b/phpBB/config/default/container/services_search.yml index 1dba3732be..dc29617bf8 100644 --- a/phpBB/config/default/container/services_search.yml +++ b/phpBB/config/default/container/services_search.yml @@ -1,5 +1,11 @@ services: + search.state_helper: + class: phpbb\search\state_helper + arguments: + - '@config' + - '@search.backend_collection' + # Search backends search.fulltext.mysql: class: phpbb\search\backend\fulltext_mysql diff --git a/phpBB/includes/acp/acp_search.php b/phpBB/includes/acp/acp_search.php index e2cbea4956..667e74baaa 100644 --- a/phpBB/includes/acp/acp_search.php +++ b/phpBB/includes/acp/acp_search.php @@ -21,6 +21,7 @@ use phpbb\language\language; use phpbb\log\log; use phpbb\request\request; use phpbb\search\search_backend_factory; +use phpbb\search\state_helper; use phpbb\template\template; use phpbb\user; @@ -35,10 +36,6 @@ class acp_search public $tpl_name; public $page_title; - protected const STATE_SEARCH_TYPE = 0; - protected const STATE_ACTION = 1; - protected const STATE_POST_COUNTER = 2; - /** @var config */ protected $config; @@ -57,6 +54,9 @@ class acp_search /** @var search_backend_factory */ protected $search_backend_factory; + /** @var state_helper */ + protected $search_state_helper; + /** @var template */ protected $template; @@ -79,6 +79,7 @@ class acp_search $this->request = $request; $this->search_backend_collection = $phpbb_container->get('search.backend_collection'); $this->search_backend_factory = $phpbb_container->get('search.backend_factory'); + $this->search_state_helper = $phpbb_container->get('search.state_helper'); $this->template = $template; $this->user = $user; $this->phpbb_admin_path = $phpbb_admin_path; @@ -272,7 +273,6 @@ class acp_search public function index(string $id, string $mode): void { $action = $this->request->variable('action', ''); - $state = !empty($this->config['search_indexing_state']) ? explode(',', $this->config['search_indexing_state']) : []; if ($action && !$this->request->is_set_post('cancel')) { @@ -284,7 +284,7 @@ class acp_search case 'create': case 'delete': - $this->index_action($id, $mode, $action, $state); + $this->index_action($id, $mode, $action); break; default: @@ -296,13 +296,12 @@ class acp_search // If clicked to cancel the indexing progress (acp_search_index_inprogress form) if ($this->request->is_set_post('cancel')) { - $state = []; - $this->save_state($state); + $this->search_state_helper->clear_state(); } - if (!empty($state)) + if ($this->search_state_helper->is_action_in_progress()) { - $this->index_inprogress($id, $mode, $state[self::STATE_ACTION]); + $this->index_inprogress($id, $mode); } else { @@ -368,9 +367,8 @@ class acp_search * @param string $id * @param string $mode * @param string $action - * @param array $state */ - private function index_action(string $id, string $mode, string $action, array $state): void + private function index_action(string $id, string $mode, string $action): void { // For some this may be of help... @ini_set('memory_limit', '128M'); @@ -381,29 +379,23 @@ class acp_search } // Entering here for the first time - if (empty($state)) + if (!$this->search_state_helper->is_action_in_progress()) { if ($this->request->is_set_post('search_type', '')) { - $state = [ - self::STATE_SEARCH_TYPE => $this->request->variable('search_type', ''), - self::STATE_ACTION => $action, - self::STATE_POST_COUNTER => 0 - ]; + $this->search_state_helper->init($this->request->variable('search_type', ''), $action); } else { trigger_error($this->language->lang('FORM_INVALID') . adm_back_link($this->u_action), E_USER_WARNING); } - - $this->save_state($state); // Create new state in the database } - $type = $state[self::STATE_SEARCH_TYPE]; - $action = $state[self::STATE_ACTION]; - $post_counter = &$state[self::STATE_POST_COUNTER]; - // Execute create/delete + $type = $this->search_state_helper->type(); + $action = $this->search_state_helper->action(); + $post_counter = $this->search_state_helper->counter(); + $search = $this->search_backend_factory->get($type); try @@ -411,7 +403,7 @@ class acp_search $status = ($action == 'create') ? $search->create_index($post_counter) : $search->delete_index($post_counter); if ($status) // Status is not null, so action is in progress.... { - $this->save_state($state); // update $post_counter in $state in the database + $this->search_state_helper->update_counter($status['post_counter']); $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); @@ -423,13 +415,13 @@ class acp_search } catch (Exception $e) { - $this->save_state([]); // Unexpected error, cancel action + $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); } $search->tidy(); - $this->save_state([]); // finished operation, cancel action + $this->search_state_helper->clear_state(); // finished operation, cancel action $log_operation = ($action == 'create') ? 'LOG_SEARCH_INDEX_CREATED' : 'LOG_SEARCH_INDEX_REMOVED'; $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, $log_operation, false, [$search->get_name()]); @@ -473,14 +465,4 @@ class acp_search "// ]]>\n" . "\n"; } - - /** - * @param array $state - */ - private function save_state(array $state = []): void - { - ksort($state); - - $this->config->set('search_indexing_state', implode(',', $state), true); - } } diff --git a/phpBB/phpbb/console/command/searchindex/create.php b/phpBB/phpbb/console/command/searchindex/create.php index 9985373d20..2ee2c0f35a 100644 --- a/phpBB/phpbb/console/command/searchindex/create.php +++ b/phpBB/phpbb/console/command/searchindex/create.php @@ -21,6 +21,7 @@ use phpbb\post\post_helper; use phpbb\search\exception\index_created_exception; use phpbb\search\exception\no_search_backend_found_exception; use phpbb\search\search_backend_factory; +use phpbb\search\state_helper; use phpbb\user; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -29,10 +30,6 @@ use Symfony\Component\Console\Style\SymfonyStyle; class create extends command { - protected const STATE_SEARCH_TYPE = 0; - protected const STATE_ACTION = 1; - protected const STATE_POST_COUNTER = 2; - /** @var config */ protected $config; @@ -48,23 +45,28 @@ class create extends command /** @var search_backend_factory */ protected $search_backend_factory; + /** @var state_helper */ + protected $state_helper; + /** * Construct method * - * @param config $config - * @param language $language - * @param log $log - * @param post_helper $post_helper - * @param search_backend_factory $search_backend_factory - * @param user $user + * @param config $config + * @param language $language + * @param log $log + * @param post_helper $post_helper + * @param search_backend_factory $search_backend_factory + * @param state_helper $state_helper + * @param user $user */ - public function __construct(config $config, language $language, log $log, post_helper $post_helper, search_backend_factory $search_backend_factory, user $user) + public function __construct(config $config, language $language, log $log, post_helper $post_helper, search_backend_factory $search_backend_factory, state_helper $state_helper, user $user) { $this->config = $config; $this->language = $language; $this->log = $log; $this->post_helper = $post_helper; $this->search_backend_factory = $search_backend_factory; + $this->state_helper = $state_helper; parent::__construct($user); } @@ -116,9 +118,8 @@ class create extends command return command::FAILURE; } - if (!empty($this->config['search_indexing_state'])) + if ($this->state_helper->is_action_in_progress()) { - var_dump($this->config['search_indexing_state']); $io->error($this->language->lang('CLI_SEARCHINDEX_ACTION_IN_PROGRESS', $search_backend)); return command::FAILURE; } @@ -129,17 +130,12 @@ class create extends command $progress->setMessage(''); $progress->start(); - $state = [ - self::STATE_SEARCH_TYPE => $search->get_type(), - self::STATE_ACTION => 'create', - self::STATE_POST_COUNTER => 0 - ]; - $this->save_state($state); + $this->state_helper->init($search->get_type(), 'create'); - $counter = &$state[self::STATE_POST_COUNTER]; + $counter = 0; while (($status = $search->create_index($counter)) !== null) { - $this->save_state($state); + $this->state_helper->update_counter($status['post_counter']); $progress->setMaxSteps($status['max_post_id']); $progress->setProgress($status['post_counter']); @@ -152,7 +148,7 @@ class create extends command } catch(index_created_exception $e) { - $this->save_state([]); + $this->state_helper->clear_state(); $io->error($this->language->lang('CLI_SEARCHINDEX_ALREADY_CREATED', $name)); return command::FAILURE; } @@ -164,21 +160,11 @@ class create extends command $search->tidy(); - $this->save_state([]); + $this->state_helper->clear_state(); $this->log->add('admin', ANONYMOUS, '', 'LOG_SEARCH_INDEX_CREATED', false, array($name)); $io->success($this->language->lang('CLI_SEARCHINDEX_CREATE_SUCCESS', $name)); return command::SUCCESS; } - - /** - * @param array $state - */ - private function save_state(array $state = []): void - { - ksort($state); - - $this->config->set('search_indexing_state', implode(',', $state), true); - } } diff --git a/phpBB/phpbb/console/command/searchindex/delete.php b/phpBB/phpbb/console/command/searchindex/delete.php index ec101ac084..c2ba8f0476 100644 --- a/phpBB/phpbb/console/command/searchindex/delete.php +++ b/phpBB/phpbb/console/command/searchindex/delete.php @@ -21,6 +21,7 @@ use phpbb\post\post_helper; use phpbb\search\exception\index_empty_exception; use phpbb\search\exception\no_search_backend_found_exception; use phpbb\search\search_backend_factory; +use phpbb\search\state_helper; use phpbb\user; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -29,10 +30,6 @@ use Symfony\Component\Console\Style\SymfonyStyle; class delete extends command { - protected const STATE_SEARCH_TYPE = 0; - protected const STATE_ACTION = 1; - protected const STATE_POST_COUNTER = 2; - /** @var config */ protected $config; @@ -48,23 +45,28 @@ class delete extends command /** @var search_backend_factory */ protected $search_backend_factory; + /** @var state_helper */ + protected $state_helper; + /** * Construct method * - * @param config $config - * @param language $language - * @param log $log - * @param post_helper $post_helper - * @param search_backend_factory $search_backend_factory - * @param user $user + * @param config $config + * @param language $language + * @param log $log + * @param post_helper $post_helper + * @param search_backend_factory $search_backend_factory + * @param state_helper $state_helper + * @param user $user */ - public function __construct(config $config, language $language, log $log, post_helper $post_helper, search_backend_factory $search_backend_factory, user $user) + public function __construct(config $config, language $language, log $log, post_helper $post_helper, search_backend_factory $search_backend_factory, state_helper $state_helper, user $user) { $this->config = $config; $this->language = $language; $this->log = $log; $this->post_helper = $post_helper; $this->search_backend_factory = $search_backend_factory; + $this->state_helper = $state_helper; parent::__construct($user); } @@ -116,7 +118,7 @@ class delete extends command return command::FAILURE; } - if (!empty($this->config['search_indexing_state'])) + if ($this->state_helper->is_action_in_progress()) { $io->error($this->language->lang('CLI_SEARCHINDEX_ACTION_IN_PROGRESS', $search_backend)); return command::FAILURE; @@ -128,17 +130,12 @@ class delete extends command $progress->setMessage(''); $progress->start(); - $state = [ - self::STATE_SEARCH_TYPE => $search->get_type(), - self::STATE_ACTION => 'delete', - self::STATE_POST_COUNTER => 0 - ]; - $this->save_state($state); + $this->state_helper->init($search->get_type(), 'delete'); - $counter = &$state[self::STATE_POST_COUNTER]; + $counter = 0; while (($status = $search->delete_index($counter)) !== null) { - $this->save_state($state); + $this->state_helper->update_counter($status['post_counter']); $progress->setMaxSteps($status['max_post_id']); $progress->setProgress($status['post_counter']); @@ -151,7 +148,7 @@ class delete extends command } catch(index_empty_exception $e) { - $this->save_state([]); + $this->state_helper->clear_state(); $io->error($this->language->lang('CLI_SEARCHINDEX_NO_CREATED', $name)); return command::FAILURE; } @@ -163,21 +160,11 @@ class delete extends command $search->tidy(); - $this->save_state([]); + $this->state_helper->clear_state(); $this->log->add('admin', ANONYMOUS, '', 'LOG_SEARCH_INDEX_REMOVED', false, array($name)); $io->success($this->language->lang('CLI_SEARCHINDEX_DELETE_SUCCESS', $name)); return command::SUCCESS; } - - /** - * @param array $state - */ - private function save_state(array $state = []): void - { - ksort($state); - - $this->config->set('search_indexing_state', implode(',', $state), true); - } } diff --git a/phpBB/phpbb/search/exception/action_in_progress_exception.php b/phpBB/phpbb/search/exception/action_in_progress_exception.php new file mode 100644 index 0000000000..183c00f512 --- /dev/null +++ b/phpBB/phpbb/search/exception/action_in_progress_exception.php @@ -0,0 +1,20 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\search\exception; + + +class action_in_progress_exception extends search_exception +{ + +} diff --git a/phpBB/phpbb/search/exception/no_action_in_progress_exception.php b/phpBB/phpbb/search/exception/no_action_in_progress_exception.php new file mode 100644 index 0000000000..4c04b8c720 --- /dev/null +++ b/phpBB/phpbb/search/exception/no_action_in_progress_exception.php @@ -0,0 +1,20 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\search\exception; + + +class no_action_in_progress_exception extends search_exception +{ + +} diff --git a/phpBB/phpbb/search/state_helper.php b/phpBB/phpbb/search/state_helper.php new file mode 100644 index 0000000000..b3e5dd0aea --- /dev/null +++ b/phpBB/phpbb/search/state_helper.php @@ -0,0 +1,170 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\search; + +use phpbb\config\config; +use phpbb\search\exception\action_in_progress_exception; +use phpbb\search\exception\no_action_in_progress_exception; + +class state_helper +{ + protected const STATE_SEARCH_TYPE = 0; + protected const STATE_ACTION = 1; + protected const STATE_POST_COUNTER = 2; + + /** @var config */ + protected $config; + + /** @var search_backend_factory */ + protected $search_backend_factory; + + /** + * Constructor. + * + * @param \phpbb\config\config $config + * @param \phpbb\search\search_backend_factory $search_backend_factory + */ + public function __construct(config $config, search_backend_factory $search_backend_factory) + { + $this->config = $config; + $this->search_backend_factory = $search_backend_factory; + } + + /** + * Returns if there is an action in progress + * + * @return bool + */ + public function is_action_in_progress(): bool + { + return !empty($this->config['search_indexing_state']); + } + + /** + * @return string + * + * @throws no_action_in_progress_exception If there is no action in progress + */ + public function type(): string + { + $state = $this->load_state(); + + return $state[self::STATE_SEARCH_TYPE]; + } + + /** + * @return string + * + * @throws no_action_in_progress_exception If there is no action in progress + */ + public function action(): string + { + $state = $this->load_state(); + + return $state[self::STATE_ACTION]; + } + + /** + * @return int + * + * @throws no_action_in_progress_exception If there is no action in progress + */ + public function counter(): int + { + $state = $this->load_state(); + + return $state[self::STATE_POST_COUNTER]; + } + + /** + * @param string $search_type + * @param string $action + * + * @throws action_in_progress_exception If there is an action in progress + * @throws no_search_backend_found_exception If search backend don't exist + */ + public function init(string $search_type, string $action): void + { + // Is not possible to start a new process when there is one already running + if ($this->is_action_in_progress()) + { + throw new action_in_progress_exception(); + } + + // Make sure the search type exist (if not, the next line launch an exception) + $this->search_backend_factory->get($search_type); + + // Make sure the action is correct (just in case) + if (!in_array($action, ['create', 'delete'])) + { + throw new \RuntimeException('Invalid action'); + } + + $state = [ + self::STATE_SEARCH_TYPE => $search_type, + self::STATE_ACTION => $action, + self::STATE_POST_COUNTER => 0 + ]; + + $this->save_state($state); + } + + /** + * @param int $counter + * + * @throws \phpbb\search\exception\no_action_in_progress_exception If there is no action in progress + */ + public function update_counter(int $counter): void + { + $state = $this->load_state(); + + $state[self::STATE_POST_COUNTER] = $counter; + + $this->save_state($state); + } + + /** + * Clear the state + */ + public function clear_state(): void + { + $this->save_state([]); + } + + /** + * @return array + * + * @throws no_action_in_progress_exception If there is no action in progress + */ + private function load_state(): array + { + // Is not possible to execute an action over state if is empty + if (!$this->is_action_in_progress()) + { + throw new no_action_in_progress_exception(); + } + + return explode(',', $this->config['search_indexing_state']); + } + + /** + * @param array $state + */ + private function save_state(array $state = []): void + { + ksort($state); + + $this->config->set('search_indexing_state', implode(',', $state), true); + } +}