diff --git a/phpBB/config/default/container/services.yml b/phpBB/config/default/container/services.yml
index 73260f7a92..547053631b 100644
--- a/phpBB/config/default/container/services.yml
+++ b/phpBB/config/default/container/services.yml
@@ -23,6 +23,7 @@ imports:
- { resource: services_notification.yml }
- { resource: services_password.yml }
- { resource: services_php.yml }
+ - { resource: services_post.yml }
- { resource: services_profilefield.yml }
- { resource: services_report.yml }
- { resource: services_routing.yml }
diff --git a/phpBB/config/default/container/services_console.yml b/phpBB/config/default/container/services_console.yml
index 422a99992f..a7e3f7b136 100644
--- a/phpBB/config/default/container/services_console.yml
+++ b/phpBB/config/default/container/services_console.yml
@@ -262,6 +262,7 @@ services:
- '@config'
- '@language'
- '@log'
+ - '@post.helper'
- '@search.backend_factory'
- '@user'
tags:
@@ -273,6 +274,7 @@ services:
- '@config'
- '@language'
- '@log'
+ - '@post.helper'
- '@search.backend_factory'
- '@user'
tags:
diff --git a/phpBB/config/default/container/services_post.yml b/phpBB/config/default/container/services_post.yml
new file mode 100644
index 0000000000..f6ad5ba80f
--- /dev/null
+++ b/phpBB/config/default/container/services_post.yml
@@ -0,0 +1,5 @@
+services:
+ post.helper:
+ class: phpbb\post\post_helper
+ arguments:
+ - '@dbal.conn'
diff --git a/phpBB/language/en/cli.php b/phpBB/language/en/cli.php
index 168d7f36e1..82c1c3d62a 100644
--- a/phpBB/language/en/cli.php
+++ b/phpBB/language/en/cli.php
@@ -152,6 +152,10 @@ $lang = array_merge($lang, array(
'CLI_SEARCHINDEX_CREATE_FAILURE' => 'Error creating search index',
'CLI_SEARCHINDEX_DELETE_SUCCESS' => 'Search index deleted successfully',
'CLI_SEARCHINDEX_DELETE_FAILURE' => 'Error deleting search index',
+ 'CLI_SEARCHINDEX_ALREADY_CREATED' => 'Search index is already created, try removing it first',
+ 'CLI_SEARCHINDEX_NO_CREATED' => 'Search index is already empty, try creating it first',
+ 'CLI_SEARCHINDEX_ACTION_IN_PROGRESS' => 'There is an action currently in progress. CLI doesn\'t support incomplete index/delete actions, please solve it from the ACP',
+ 'CLI_SEARCHINDEX_ACTIVE_NOT_INDEXED' => 'Active search backend isn\'t indexed',
// In all the case %1$s is the logical name of the file and %2$s the real name on the filesystem
// eg: big_image.png (2_a51529ae7932008cf8454a95af84cacd) generated.
diff --git a/phpBB/phpbb/console/command/searchindex/create.php b/phpBB/phpbb/console/command/searchindex/create.php
index e77f833ffb..9985373d20 100644
--- a/phpBB/phpbb/console/command/searchindex/create.php
+++ b/phpBB/phpbb/console/command/searchindex/create.php
@@ -17,6 +17,8 @@ use phpbb\config\config;
use phpbb\console\command\command;
use phpbb\language\language;
use phpbb\log\log;
+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\user;
@@ -27,6 +29,10 @@ 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;
@@ -36,23 +42,28 @@ class create extends command
/** @var log */
protected $log;
+ /** @var post_helper */
+ protected $post_helper;
+
/** @var search_backend_factory */
protected $search_backend_factory;
/**
* Construct method
*
- * @param config $config
- * @param language $language
- * @param log $log
- * @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 user $user
*/
- public function __construct(config $config, language $language, log $log, 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, user $user)
{
$this->config = $config;
$this->language = $language;
$this->log = $log;
+ $this->post_helper = $post_helper;
$this->search_backend_factory = $search_backend_factory;
parent::__construct($user);
@@ -61,7 +72,7 @@ class create extends command
/**
* Sets the command name and description
*
- * @return null
+ * @return void
*/
protected function configure()
{
@@ -105,15 +116,31 @@ class create extends command
return command::FAILURE;
}
+ if (!empty($this->config['search_indexing_state']))
+ {
+ var_dump($this->config['search_indexing_state']);
+ $io->error($this->language->lang('CLI_SEARCHINDEX_ACTION_IN_PROGRESS', $search_backend));
+ return command::FAILURE;
+ }
+
try
{
- $progress = $this->create_progress_bar(1, $io, $output, true);
+ $progress = $this->create_progress_bar($this->post_helper->get_max_post_id(), $io, $output, true);
$progress->setMessage('');
$progress->start();
- $counter = 0;
+ $state = [
+ self::STATE_SEARCH_TYPE => $search->get_type(),
+ self::STATE_ACTION => 'create',
+ self::STATE_POST_COUNTER => 0
+ ];
+ $this->save_state($state);
+
+ $counter = &$state[self::STATE_POST_COUNTER];
while (($status = $search->create_index($counter)) !== null)
{
+ $this->save_state($state);
+
$progress->setMaxSteps($status['max_post_id']);
$progress->setProgress($status['post_counter']);
$progress->setMessage(round($status['rows_per_second'], 2) . ' rows/s');
@@ -123,15 +150,35 @@ class create extends command
$io->newLine(2);
}
+ catch(index_created_exception $e)
+ {
+ $this->save_state([]);
+ $io->error($this->language->lang('CLI_SEARCHINDEX_ALREADY_CREATED', $name));
+ return command::FAILURE;
+ }
catch (\Exception $e)
{
$io->error($this->language->lang('CLI_SEARCHINDEX_CREATE_FAILURE', $name));
return command::FAILURE;
}
+ $search->tidy();
+
+ $this->save_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 45176f785a..ec101ac084 100644
--- a/phpBB/phpbb/console/command/searchindex/delete.php
+++ b/phpBB/phpbb/console/command/searchindex/delete.php
@@ -17,6 +17,8 @@ use phpbb\config\config;
use phpbb\console\command\command;
use phpbb\language\language;
use phpbb\log\log;
+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\user;
@@ -27,6 +29,10 @@ 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;
@@ -36,23 +42,28 @@ class delete extends command
/** @var log */
protected $log;
+ /** @var post_helper */
+ protected $post_helper;
+
/** @var search_backend_factory */
protected $search_backend_factory;
/**
* Construct method
*
- * @param config $config
- * @param language $language
- * @param log $log
- * @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 user $user
*/
- public function __construct(config $config, language $language, log $log, 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, user $user)
{
$this->config = $config;
$this->language = $language;
$this->log = $log;
+ $this->post_helper = $post_helper;
$this->search_backend_factory = $search_backend_factory;
parent::__construct($user);
@@ -61,7 +72,7 @@ class delete extends command
/**
* Sets the command name and description
*
- * @return null
+ * @return void
*/
protected function configure()
{
@@ -105,16 +116,30 @@ class delete extends command
return command::FAILURE;
}
+ if (!empty($this->config['search_indexing_state']))
+ {
+ $io->error($this->language->lang('CLI_SEARCHINDEX_ACTION_IN_PROGRESS', $search_backend));
+ return command::FAILURE;
+ }
+
try
{
- // TODO: Read the max_post_id from db because the bucle is not always executed
- $progress = $this->create_progress_bar(1, $io, $output, true);
+ $progress = $this->create_progress_bar($this->post_helper->get_max_post_id(), $io, $output, true);
$progress->setMessage('');
$progress->start();
- $counter = 0;
+ $state = [
+ self::STATE_SEARCH_TYPE => $search->get_type(),
+ self::STATE_ACTION => 'delete',
+ self::STATE_POST_COUNTER => 0
+ ];
+ $this->save_state($state);
+
+ $counter = &$state[self::STATE_POST_COUNTER];
while (($status = $search->delete_index($counter)) !== null)
{
+ $this->save_state($state);
+
$progress->setMaxSteps($status['max_post_id']);
$progress->setProgress($status['post_counter']);
$progress->setMessage(round($status['rows_per_second'], 2) . ' rows/s');
@@ -124,15 +149,35 @@ class delete extends command
$io->newLine(2);
}
+ catch(index_empty_exception $e)
+ {
+ $this->save_state([]);
+ $io->error($this->language->lang('CLI_SEARCHINDEX_NO_CREATED', $name));
+ return command::FAILURE;
+ }
catch (\Exception $e)
{
$io->error($this->language->lang('CLI_SEARCHINDEX_DELETE_FAILURE', $name));
return command::FAILURE;
}
+ $search->tidy();
+
+ $this->save_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/console/command/searchindex/list_all.php b/phpBB/phpbb/console/command/searchindex/list_all.php
index 3db054f389..cfa26e7893 100644
--- a/phpBB/phpbb/console/command/searchindex/list_all.php
+++ b/phpBB/phpbb/console/command/searchindex/list_all.php
@@ -53,7 +53,7 @@ class list_all extends command
/**
* Sets the command name and description
*
- * @return null
+ * @return void
*/
protected function configure()
{
@@ -80,9 +80,14 @@ class list_all extends command
$search_backends = [];
foreach ($this->search_backend_collection as $search_backend)
{
- $name = get_class($search_backend);
- $active = ($name == $this->config['search_type']) ? '(' . $this->language->lang('ACTIVE') . ') ' : '';
+ $name = $search_backend->get_type();
+ $active = ($name === $this->config['search_type']) ? '(' . $this->language->lang('ACTIVE') . ') ' : '';
$search_backends[] = '' . $name . ' ' . $active . $search_backend->get_name();
+
+ if ($name === $this->config['search_type'] && !$search_backend->index_created())
+ {
+ $io->error($this->language->lang('CLI_SEARCHINDEX_ACTIVE_NOT_INDEXED'));
+ }
}
$io->listing($search_backends);
diff --git a/phpBB/phpbb/post/post_helper.php b/phpBB/phpbb/post/post_helper.php
new file mode 100644
index 0000000000..f039771e10
--- /dev/null
+++ b/phpBB/phpbb/post/post_helper.php
@@ -0,0 +1,44 @@
+
+ * @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\post;
+
+
+use phpbb\db\driver\driver_interface;
+
+class post_helper
+{
+ /**
+ * @var driver_interface
+ */
+ protected $db;
+
+ public function __construct(driver_interface $db)
+ {
+ $this->db = $db;
+ }
+
+ /**
+ * Get last post id
+ */
+ public function get_max_post_id(): int
+ {
+ $sql = 'SELECT MAX(post_id) as max_post_id
+ FROM '. POSTS_TABLE;
+ $result = $this->db->sql_query($sql);
+ $max_post_id = (int) $this->db->sql_fetchfield('max_post_id');
+ $this->db->sql_freeresult($result);
+
+ return $max_post_id;
+ }
+}
diff --git a/phpBB/phpbb/search/backend/base.php b/phpBB/phpbb/search/backend/base.php
index 3a0049947d..e1b0f142a2 100644
--- a/phpBB/phpbb/search/backend/base.php
+++ b/phpBB/phpbb/search/backend/base.php
@@ -16,6 +16,8 @@ namespace phpbb\search\backend;
use phpbb\cache\service;
use phpbb\config\config;
use phpbb\db\driver\driver_interface;
+use phpbb\search\exception\index_created_exception;
+use phpbb\search\exception\index_empty_exception;
use phpbb\user;
/**
@@ -323,6 +325,11 @@ abstract class base implements search_backend_interface
*/
public function create_index(int &$post_counter = 0): ?array
{
+ if ($this->index_created())
+ {
+ throw new index_created_exception();
+ }
+
$max_post_id = $this->get_max_post_id();
$forums_indexing_enabled = $this->forum_ids_with_indexing_enabled();
@@ -385,6 +392,11 @@ abstract class base implements search_backend_interface
*/
public function delete_index(int &$post_counter = null): ?array
{
+ if (!$this->index_created())
+ {
+ throw new index_empty_exception();
+ }
+
$max_post_id = $this->get_max_post_id();
$starttime = microtime(true);
diff --git a/phpBB/phpbb/search/backend/fulltext_mysql.php b/phpBB/phpbb/search/backend/fulltext_mysql.php
index 3e47cb4668..febaee3495 100644
--- a/phpBB/phpbb/search/backend/fulltext_mysql.php
+++ b/phpBB/phpbb/search/backend/fulltext_mysql.php
@@ -17,6 +17,8 @@ use phpbb\config\config;
use phpbb\db\driver\driver_interface;
use phpbb\event\dispatcher_interface;
use phpbb\language\language;
+use phpbb\search\exception\index_created_exception;
+use phpbb\search\exception\index_empty_exception;
use phpbb\user;
use RuntimeException;
@@ -913,6 +915,11 @@ class fulltext_mysql extends base implements search_backend_interface
*/
public function create_index(int &$post_counter = 0): ?array
{
+ if ($this->index_created())
+ {
+ throw new index_created_exception();
+ }
+
// Make sure we can actually use MySQL with fulltext indexes
if ($error = $this->init())
{
@@ -985,6 +992,11 @@ class fulltext_mysql extends base implements search_backend_interface
*/
public function delete_index(int &$post_counter = null): ?array
{
+ if (!$this->index_created())
+ {
+ throw new index_empty_exception();
+ }
+
// Make sure we can actually use MySQL with fulltext indexes
if ($error = $this->init())
{
diff --git a/phpBB/phpbb/search/backend/fulltext_native.php b/phpBB/phpbb/search/backend/fulltext_native.php
index a5c9bb8202..f4d141dd59 100644
--- a/phpBB/phpbb/search/backend/fulltext_native.php
+++ b/phpBB/phpbb/search/backend/fulltext_native.php
@@ -17,6 +17,7 @@ use phpbb\config\config;
use phpbb\db\driver\driver_interface;
use phpbb\event\dispatcher_interface;
use phpbb\language\language;
+use phpbb\search\exception\index_empty_exception;
use phpbb\user;
/**
@@ -1598,6 +1599,11 @@ class fulltext_native extends base implements search_backend_interface
*/
public function delete_index(int &$post_counter = null): ?array
{
+ if (!$this->index_created())
+ {
+ throw new index_empty_exception();
+ }
+
$sql_queries = [];
switch ($this->db->get_sql_layer())
diff --git a/phpBB/phpbb/search/backend/fulltext_postgres.php b/phpBB/phpbb/search/backend/fulltext_postgres.php
index bd2c24224c..077eee4f30 100644
--- a/phpBB/phpbb/search/backend/fulltext_postgres.php
+++ b/phpBB/phpbb/search/backend/fulltext_postgres.php
@@ -17,6 +17,8 @@ use phpbb\config\config;
use phpbb\db\driver\driver_interface;
use phpbb\event\dispatcher_interface;
use phpbb\language\language;
+use phpbb\search\exception\index_created_exception;
+use phpbb\search\exception\index_empty_exception;
use phpbb\user;
use RuntimeException;
@@ -868,6 +870,11 @@ class fulltext_postgres extends base implements search_backend_interface
*/
public function create_index(int &$post_counter = 0): ?array
{
+ if ($this->index_created())
+ {
+ throw new index_created_exception();
+ }
+
// Make sure we can actually use PostgreSQL with fulltext indexes
if ($error = $this->init())
{
@@ -927,6 +934,11 @@ class fulltext_postgres extends base implements search_backend_interface
*/
public function delete_index(int &$post_counter = null): ?array
{
+ if (!$this->index_created())
+ {
+ throw new index_empty_exception();
+ }
+
// Make sure we can actually use PostgreSQL with fulltext indexes
if ($error = $this->init())
{
diff --git a/phpBB/phpbb/search/backend/fulltext_sphinx.php b/phpBB/phpbb/search/backend/fulltext_sphinx.php
index 709690b4f2..74ff23bbf8 100644
--- a/phpBB/phpbb/search/backend/fulltext_sphinx.php
+++ b/phpBB/phpbb/search/backend/fulltext_sphinx.php
@@ -20,6 +20,7 @@ use phpbb\db\tools\tools_interface;
use phpbb\event\dispatcher_interface;
use phpbb\language\language;
use phpbb\log\log;
+use phpbb\search\exception\index_empty_exception;
use phpbb\user;
/**
@@ -633,23 +634,28 @@ class fulltext_sphinx implements search_backend_interface
{
if (!$this->index_created())
{
- $table_data = array(
- 'COLUMNS' => array(
- 'counter_id' => array('UINT', 0),
- 'max_doc_id' => array('UINT', 0),
- ),
- 'PRIMARY_KEY' => 'counter_id',
- );
- $this->db_tools->sql_create_table(SPHINX_TABLE, $table_data);
-
- $data = array(
- 'counter_id' => '1',
- 'max_doc_id' => '0',
- );
- $sql = 'INSERT INTO ' . SPHINX_TABLE . ' ' . $this->db->sql_build_array('INSERT', $data);
- $this->db->sql_query($sql);
+ throw new index_empty_exception();
}
+ $table_data = array(
+ 'COLUMNS' => array(
+ 'counter_id' => array('UINT', 0),
+ 'max_doc_id' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'counter_id',
+ );
+ $this->db_tools->sql_create_table(SPHINX_TABLE, $table_data);
+
+ $sql = 'TRUNCATE TABLE ' . SPHINX_TABLE;
+ $this->db->sql_query($sql);
+
+ $data = array(
+ 'counter_id' => '1',
+ 'max_doc_id' => '0',
+ );
+ $sql = 'INSERT INTO ' . SPHINX_TABLE . ' ' . $this->db->sql_build_array('INSERT', $data);
+ $this->db->sql_query($sql);
+
return null;
}
@@ -658,11 +664,13 @@ class fulltext_sphinx implements search_backend_interface
*/
public function delete_index(int &$post_counter = null): ?array
{
- if ($this->index_created())
+ if (!$this->index_created())
{
- $this->db_tools->sql_table_drop(SPHINX_TABLE);
+ throw new index_empty_exception();
}
+ $this->db_tools->sql_table_drop(SPHINX_TABLE);
+
return null;
}
diff --git a/phpBB/phpbb/search/exception/index_created_exception.php b/phpBB/phpbb/search/exception/index_created_exception.php
new file mode 100644
index 0000000000..9be91bfbb8
--- /dev/null
+++ b/phpBB/phpbb/search/exception/index_created_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 index_created_exception extends search_exception
+{
+
+}
diff --git a/phpBB/phpbb/search/exception/index_empty_exception.php b/phpBB/phpbb/search/exception/index_empty_exception.php
new file mode 100644
index 0000000000..a6a55698de
--- /dev/null
+++ b/phpBB/phpbb/search/exception/index_empty_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 index_empty_exception extends search_exception
+{
+
+}