diff --git a/phpBB/config/default/container/services_profilefield.yml b/phpBB/config/default/container/services_profilefield.yml index 90b22836e5..8b519e5c7c 100644 --- a/phpBB/config/default/container/services_profilefield.yml +++ b/phpBB/config/default/container/services_profilefield.yml @@ -2,6 +2,7 @@ services: profilefields.manager: class: phpbb\profilefields\manager arguments: + - '@service_container' - '@auth' - '@dbal.conn' - '@dispatcher' diff --git a/phpBB/phpbb/profilefields/manager.php b/phpBB/phpbb/profilefields/manager.php index 73b8cdd38e..bb76d39f85 100644 --- a/phpBB/phpbb/profilefields/manager.php +++ b/phpBB/phpbb/profilefields/manager.php @@ -13,11 +13,19 @@ namespace phpbb\profilefields; +use Symfony\Component\DependencyInjection\ContainerInterface; + /** * Custom Profile Fields */ class manager { + /** + * Container interface + * @var ContainerInterface + */ + protected $container; + /** * Auth object * @var \phpbb\auth\auth @@ -68,9 +76,14 @@ class manager protected $profile_cache = array(); + protected $config_text; + + protected $db_tools; + /** * Construct * + * @param ContainerInterface $container A container * @param \phpbb\auth\auth $auth Auth object * @param \phpbb\db\driver\driver_interface $db Database object * @param \phpbb\event\dispatcher_interface $dispatcher Event dispatcher object @@ -82,8 +95,9 @@ class manager * @param string $fields_language_table * @param string $fields_data_table */ - public function __construct(\phpbb\auth\auth $auth, \phpbb\db\driver\driver_interface $db, \phpbb\event\dispatcher_interface $dispatcher, \phpbb\request\request $request, \phpbb\template\template $template, \phpbb\di\service_collection $type_collection, \phpbb\user $user, $fields_table, $fields_language_table, $fields_data_table) + public function __construct(ContainerInterface $container, \phpbb\auth\auth $auth, \phpbb\db\driver\driver_interface $db, \phpbb\event\dispatcher_interface $dispatcher, \phpbb\request\request $request, \phpbb\template\template $template, \phpbb\di\service_collection $type_collection, \phpbb\user $user, $fields_table, $fields_language_table, $fields_data_table) { + $this->container = $container; $this->auth = $auth; $this->db = $db; $this->dispatcher = $dispatcher; @@ -95,6 +109,9 @@ class manager $this->fields_table = $fields_table; $this->fields_language_table = $fields_language_table; $this->fields_data_table = $fields_data_table; + + $this->config_text = $this->container->get('config_text'); + $this->db_tools = $this->container->get('dbal.tools'); } /** @@ -499,4 +516,161 @@ class manager return $cp_data; } + + /** + * Disable all profile fields of a certain type + * + * This should be called when an extension which has profile field types + * is disabled so that all those profile fields are hidden and do not + * cause errors + * + * @param string $profilefield_type_name Type identifier of the profile fields + */ + public function disable_profilefields($profilefield_type_name) + { + // Get list of profile fields affected by this operation, if any + $pfs = array(); + $sql = 'SELECT field_id, field_ident + FROM ' . PROFILE_FIELDS_TABLE . " + WHERE field_active = 1 + AND field_type = '" . $this->db->sql_escape($profilefield_type_name) . "'"; + $result = $this->db->sql_query($sql); + while ($row = $this->db->sql_fetchrow($result)) + { + $pfs[(int) $row['field_id']] = $row['field_ident']; + } + $this->db->sql_freeresult($result); + + // If no profile fields affected, then nothing to do + if (!sizeof($pfs)) + { + return; + } + + // Update the affected profile fields to "inactive" + $sql = 'UPDATE ' . PROFILE_FIELDS_TABLE . " + SET field_active = 0 + WHERE field_active = 1 + AND field_type = '" . $this->db->sql_escape($profilefield_type_name) . "'"; + $this->db->sql_query($sql); + + // Save modified information into a config_text field to recover on enable + $this->config_text->set($profilefield_type_name . '.saved', base64_encode(serialize($pfs))); + + // Log activity + foreach ($pfs as $field_ident) + { + add_log('admin', 'LOG_PROFILE_FIELD_DEACTIVATE', $field_ident); + } + } + + /** + * Purge all profile fields of a certain type + * + * This should be called when an extension which has profile field types + * is purged so that all those profile fields are removed + * + * @param string $profilefield_type_name Type identifier of the profile fields + */ + public function purge_profilefields($profilefield_type_name) + { + // Remove the information saved on disable in a config_text field, not needed any longer + $this->config_text->delete($profilefield_type_name . '.saved'); + + // Get list of profile fields affected by this operation, if any + $pfs = array(); + $sql = 'SELECT field_id, field_ident + FROM ' . PROFILE_FIELDS_TABLE . " + WHERE field_type = '" . $this->db->sql_escape($profilefield_type_name) . "'"; + $result = $this->db->sql_query($sql); + while ($row = $this->db->sql_fetchrow($result)) + { + $pfs[(int) $row['field_id']] = $row['field_ident']; + } + $this->db->sql_freeresult($result); + + // If no profile fields exist, then nothing to do + if (!sizeof($pfs)) + { + return; + } + + $this->db->sql_transaction('begin'); + + // Delete entries from all profile field definition tables + $where = $this->db->sql_in_set('field_id', array_keys($pfs)); + $this->db->sql_query('DELETE FROM ' . PROFILE_FIELDS_TABLE . ' WHERE ' . $where); + $this->db->sql_query('DELETE FROM ' . PROFILE_FIELDS_LANG_TABLE . ' WHERE ' . $where); + $this->db->sql_query('DELETE FROM ' . PROFILE_LANG_TABLE . ' WHERE ' . $where); + + // Drop columns from the Profile Fields data table + foreach ($pfs as $field_ident) + { + $this->db_tools->sql_column_remove(PROFILE_FIELDS_DATA_TABLE, 'pf_' . $field_ident); + } + + // Reset the order of the remaining fields + $order = 0; + + $sql = 'SELECT * + FROM ' . PROFILE_FIELDS_TABLE . ' + ORDER BY field_order'; + $result = $this->db->sql_query($sql); + + while ($row = $this->db->sql_fetchrow($result)) + { + $order++; + if ($row['field_order'] != $order) + { + $sql = 'UPDATE ' . PROFILE_FIELDS_TABLE . " + SET field_order = $order + WHERE field_id = {$row['field_id']}"; + $this->db->sql_query($sql); + } + } + $this->db->sql_freeresult($result); + + $this->db->sql_transaction('commit'); + + // Log activity + foreach ($pfs as $field_ident) + { + add_log('admin', 'LOG_PROFILE_FIELD_REMOVED', $field_ident); + } + } + + /** + * Enable the profile fields of a certain type + * + * This should be called when an extension which has profile field types + * that was disabled is re-enabled so that all those profile fields that + * were disabled are enabled again + * + * @param string $profilefield_type_name Type identifier of the profile fields + */ + public function enable_profilefields($profilefield_type_name) + { + // Read the modified information saved on disable from a config_text field to recover values, then remove it + $pfs = $this->config_text->get($profilefield_type_name . '.saved'); + $this->config_text->delete($profilefield_type_name . '.saved'); + + // If nothing saved, then nothing to do + if ($pfs == '') + { + return; + } + + $pfs = unserialize(base64_decode($pfs)); + + // Restore the affected profile fields to "active" + $sql = 'UPDATE ' . PROFILE_FIELDS_TABLE . " + SET field_active = 1 + WHERE field_active = 0 + AND " . $this->db->sql_in_set('field_id', array_keys($pfs)); + $this->db->sql_query($sql); + foreach ($pfs as $field_ident) + { + add_log('admin', 'LOG_PROFILE_FIELD_ACTIVATE', $field_ident); + } + } }