1
0
mirror of https://github.com/phpbb/phpbb.git synced 2025-07-30 21:40:43 +02:00

[feature/extension-manager] Use an incremental process for enable and purge

The enable or purge operation of an extension could take a long time if an
expensive operation needs to be executed on a large set of data. To allow
this to succeed from a web interface with max_execution_time set in the
webserver's php configuration, subsequent requests must continue the
operation started earlier. So individual enable and purge implementations
must be able to spread their work across multiple steps.

PHPBB3-10323
This commit is contained in:
Nils Adermann
2011-08-29 17:17:40 -04:00
parent 897063d3e2
commit c7a986eccd
13 changed files with 151 additions and 22 deletions

View File

@@ -16,20 +16,38 @@ if (!defined('IN_PHPBB'))
}
/**
* A base class for extensions without custom enable/disbale/purge code.
*
* @package extension
*/
class phpbb_extension_base implements phpbb_extension_interface
{
public function enable()
/**
* Single enable step that does nothing
*
* @return false Indicates no further steps are required
*/
public function enable_step($old_state)
{
return false;
}
/**
* Empty disable method
*
* @return null
*/
public function disable()
{
}
public function purge()
/**
* Single purge step that does nothing
*
* @return false Indicates no further steps are required
*/
public function purge_step($old_state)
{
return false;
}
}

View File

@@ -16,12 +16,47 @@ if (!defined('IN_PHPBB'))
}
/**
* The interface extension meta classes have to implement to run custom code
* on enable/disable/purge.
*
* @package extension
*/
interface phpbb_extension_interface
{
public function enable();
/**
* enable_step is executed on enabling an extension until it returns false.
*
* 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 mixed Returns false after last step, otherwise
* temporary state which is passed as an
* argument to the next step
*/
public function enable_step($old_state);
/**
* Disables the extension.
*
* Must be a quick operation, that finishes within max_execution_time.
*
* @return null
*/
public function disable();
public function purge();
/**
* purge_step is executed on purging an extension until it returns false.
*
* 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 mixed Returns false after last step, otherwise
* temporary state which is passed as an
* argument to the next step
*/
public function purge_step($old_state);
}

View File

@@ -109,28 +109,34 @@ class phpbb_extension_manager
}
/**
* Enables an extension
* Runs a step of the extension enabling process.
*
* Calls the enable method on the extension's meta class to allow it to
* make database changes and execute other initialisation code.
* Allows the exentension to enable in a long running script that works
* in multiple steps across requests. State is kept for the extension
* in the extensions table.
*
* @param string $name The extension's name
* @return null
* @param string $name The extension's name
* @return bool Whether another run of enable_step is required
*/
public function enable($name)
public function enable_step($name)
{
// ignore extensions that are already enabled
if (isset($this->extensions[$name]) && $this->extensions[$name]['ext_active'])
{
return;
return false;
}
$old_state = (isset($this->extensions[$name]['ext_state'])) ? unserialize($this->extensions[$name]['ext_state']) : false;
$extension = $this->get_extension($name);
$extension->enable();
$state = $extension->enable_step($old_state);
$active = ($state === false);
$extension_data = array(
'ext_name' => $name,
'ext_active' => true,
'ext_name' => $name,
'ext_active' => $active,
'ext_state' => serialize($state),
);
$this->extensions[$name] = $extension_data;
@@ -148,6 +154,22 @@ class phpbb_extension_manager
' . $this->db->sql_build_array('INSERT', $extension_data);
$this->db->sql_query($sql);
}
return !$active;
}
/**
* Enables an extension
*
* This method completely enables an extension. But it could be long running
* so never call this in a script that has a max_execution time.
*
* @param string $name The extension's name
* @return null
*/
public function enable($name)
{
while ($this->enable_step($name));
}
/**
@@ -172,9 +194,10 @@ class phpbb_extension_manager
$extension_data = array(
'ext_active' => false,
'ext_state' => serialize(false),
);
$this->extensions[$name]['ext_active'] = false;
ksort($this->extensions);
$this->extensions[$name]['ext_state'] = serialize(false);
$sql = 'UPDATE ' . $this->extension_table . '
SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
@@ -191,12 +214,12 @@ class phpbb_extension_manager
* @param string $name The extension's name
* @return null
*/
public function purge($name)
public function purge_step($name)
{
// ignore extensions that do not exist
if (!isset($this->extensions[$name]))
{
return;
return false;
}
// disable first if necessary
@@ -205,14 +228,48 @@ class phpbb_extension_manager
$this->disable($name);
}
$old_state = unserialize($this->extensions[$name]['ext_state']);
$extension = $this->get_extension($name);
$extension->purge();
$state = $extension->purge_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;
}
unset($this->extensions[$name]);
$sql = 'DELETE FROM ' . $this->extension_table . "
WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
$this->db->sql_query($sql);
return false;
}
/**
* Purge an extension
*
* Purges 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 purge($name)
{
while ($this->purge_step($name));
}
/**