diff --git a/phpBB/includes/extension/base.php b/phpBB/includes/extension/base.php index fed120c51b..d9159d57d2 100644 --- a/phpBB/includes/extension/base.php +++ b/phpBB/includes/extension/base.php @@ -25,6 +25,7 @@ class phpbb_extension_base implements phpbb_extension_interface /** * Single enable step that does nothing * + * @param mixed $old_state State returned by previous call of this method * @return false Indicates no further steps are required */ public function enable_step($old_state) @@ -33,17 +34,20 @@ class phpbb_extension_base implements phpbb_extension_interface } /** - * Empty disable method + * Single disable step that does nothing * - * @return null + * @param mixed $old_state State returned by previous call of this method + * @return false Indicates no further steps are required */ - public function disable() + public function disable_step($old_state) { + return false; } /** * Single purge step that does nothing * + * @param mixed $old_state State returned by previous call of this method * @return false Indicates no further steps are required */ public function purge_step($old_state) diff --git a/phpBB/includes/extension/interface.php b/phpBB/includes/extension/interface.php index 7d0ecd72c7..b37cd24d77 100644 --- a/phpBB/includes/extension/interface.php +++ b/phpBB/includes/extension/interface.php @@ -40,11 +40,14 @@ interface phpbb_extension_interface /** * Disables the extension. * - * Must be a quick operation, that finishes within max_execution_time. + * Calls to this function can be made in subsequent requests, when the + * function is invoked through a webserver with a too low max_execution_time. * + * @param mixed $old_state The return value of the previous call + * of this method, or false on the first call * @return null */ - public function disable(); + public function disable_step($old_state); /** * purge_step is executed on purging an extension until it returns false. diff --git a/phpBB/includes/extension/manager.php b/phpBB/includes/extension/manager.php index 29cd89fb34..bcdd21f7f1 100644 --- a/phpBB/includes/extension/manager.php +++ b/phpBB/includes/extension/manager.php @@ -128,7 +128,7 @@ class phpbb_extension_manager * in the extensions table. * * @param string $name The extension's name - * @return bool Whether another run of enable_step is required + * @return bool False if enabling is finished, true otherwise */ public function enable_step($name) { @@ -191,18 +191,36 @@ class phpbb_extension_manager * process the event. * * @param string $name The extension's name - * @return null + * @return bool False if disabling is finished, true otherwise */ - public function disable($name) + public function disable_step($name) { // ignore extensions that are already disabled if (!isset($this->extensions[$name]) || !$this->extensions[$name]['ext_active']) { - return; + return false; } + $old_state = unserialize($this->extensions[$name]['ext_state']); + $extension = $this->get_extension($name); - $extension->disable(); + $state = $extension->disable_step($old_state); + + // continue until the state is false + if ($state !== false) + { + $extension_data = array( + 'ext_state' => serialize($state), + ); + $this->extensions[$name]['ext_state'] = serialize($state); + + $sql = 'UPDATE ' . $this->extension_table . ' + SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . " + WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; + $this->db->sql_query($sql); + + return true; + } $extension_data = array( 'ext_active' => false, @@ -215,6 +233,22 @@ class phpbb_extension_manager SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . " WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; $this->db->sql_query($sql); + + return false; + } + + /** + * Disables an extension + * + * Disables an extension completely at once. This process could run for a + * while so never call this in a script that has a max_execution time. + * + * @param string $name The extension's name + * @return null + */ + public function disable($name) + { + while ($this->disable_step($name)); } /** @@ -224,7 +258,7 @@ class phpbb_extension_manager * extension's meta class to delete the extension's database content. * * @param string $name The extension's name - * @return null + * @return bool False if purging is finished, true otherwise */ public function purge_step($name) { diff --git a/tests/extension/ext/foo/ext.php b/tests/extension/ext/foo/ext.php index 2968a64a97..60b3ad1f16 100644 --- a/tests/extension/ext/foo/ext.php +++ b/tests/extension/ext/foo/ext.php @@ -2,4 +2,12 @@ class phpbb_ext_foo_ext extends phpbb_extension_base { + static public $disabled; + + public function disable_step($old_state) + { + self::$disabled = true; + + return false; + } } diff --git a/tests/extension/manager_test.php b/tests/extension/manager_test.php index ba7f227a56..891f1b287a 100644 --- a/tests/extension/manager_test.php +++ b/tests/extension/manager_test.php @@ -9,6 +9,7 @@ require_once dirname(__FILE__) . '/../mock/cache.php'; require_once dirname(__FILE__) . '/ext/bar/ext.php'; +require_once dirname(__FILE__) . '/ext/foo/ext.php'; require_once dirname(__FILE__) . '/ext/vendor/moo/ext.php'; class phpbb_extension_manager_test extends phpbb_database_test_case @@ -63,10 +64,14 @@ class phpbb_extension_manager_test extends phpbb_database_test_case public function test_disable() { + phpbb_ext_foo_ext::$disabled = false; + $this->assertEquals(array('foo'), array_keys($this->extension_manager->all_enabled())); $this->extension_manager->disable('foo'); $this->assertEquals(array(), array_keys($this->extension_manager->all_enabled())); $this->assertEquals(array('foo', 'vendor/moo'), array_keys($this->extension_manager->all_configured())); + + $this->assertTrue(phpbb_ext_foo_ext::$disabled); } public function test_purge()