diff options
34 files changed, 1049 insertions, 15 deletions
diff --git a/phpBB/common.php b/phpBB/common.php index 524c05ae70..7ff06e68d7 100644 --- a/phpBB/common.php +++ b/phpBB/common.php @@ -96,7 +96,7 @@ require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);  set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler');  // Setup class loader first -$class_loader = new phpbb_class_loader($phpbb_root_path, '.' . $phpEx); +$class_loader = new phpbb_class_loader($phpbb_root_path . 'includes/', $phpbb_root_path . 'ext/', '.' . $phpEx);  $class_loader->register();  // set up caching diff --git a/phpBB/develop/create_schema_files.php b/phpBB/develop/create_schema_files.php index 2057d292b7..9f2015f38e 100644 --- a/phpBB/develop/create_schema_files.php +++ b/phpBB/develop/create_schema_files.php @@ -1031,6 +1031,17 @@ function get_schema_struct()  		),  	); +	$schema_data['phpbb_ext'] = array( +		'COLUMNS'		=> array( +			'ext_name'				=> array('VCHAR', ''), +			'ext_active'			=> array('BOOL', 0), +		), +		'KEYS'			=> array( +			'ext_name'				=> array('UNIQUE', 'ext_name'), +			'ext_active'			=> array('INDEX', 'ext_active'), +		), +	); +  	$schema_data['phpbb_extensions'] = array(  		'COLUMNS'		=> array(  			'extension_id'		=> array('UINT', NULL, 'auto_increment'), diff --git a/phpBB/download/file.php b/phpBB/download/file.php index ec15d36e08..956af75c81 100644 --- a/phpBB/download/file.php +++ b/phpBB/download/file.php @@ -46,7 +46,7 @@ if (isset($_GET['avatar']))  	require($phpbb_root_path . 'includes/functions_download' . '.' . $phpEx);  	require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); -	$class_loader = new phpbb_class_loader($phpbb_root_path, '.' . $phpEx); +	$class_loader = new phpbb_class_loader($phpbb_root_path . 'includes/', $phpbb_root_path . 'ext/', '.' . $phpEx);  	$class_loader->register();  	// set up caching diff --git a/phpBB/includes/class_loader.php b/phpBB/includes/class_loader.php index a28d745983..bcf1ba1650 100644 --- a/phpBB/includes/class_loader.php +++ b/phpBB/includes/class_loader.php @@ -31,22 +31,25 @@ if (!defined('IN_PHPBB'))  */  class phpbb_class_loader  { -	private $phpbb_root_path; +	private $core_path; +	private $ext_path;  	private $php_ext;  	private $cache;  	private $cached_paths = array();  	/**  	* Creates a new phpbb_class_loader, which loads files with the given -	* file extension from the given phpbb root path. +	* file extension from the given core or extension path.  	* -	* @param string $phpbb_root_path phpBB's root directory containing includes/ -	* @param string $php_ext         The file extension for PHP files +	* @param string $core_path phpBB's include directory for core files +	* @param string $ext_path  phpBB's extension directory +	* @param string $php_ext   The file extension for PHP files  	* @param phpbb_cache_driver_interface $cache An implementation of the phpBB cache interface.  	*/ -	public function __construct($phpbb_root_path, $php_ext = '.php', phpbb_cache_driver_interface $cache = null) +	public function __construct($core_path, $ext_path, $php_ext = '.php', phpbb_cache_driver_interface $cache = null)  	{ -		$this->phpbb_root_path = $phpbb_root_path; +		$this->core_path = $core_path; +		$this->ext_path = $ext_path;  		$this->php_ext = $php_ext;  		$this->set_cache($cache); @@ -100,7 +103,16 @@ class phpbb_class_loader  	*/  	public function resolve_path($class)  	{ -		$path_prefix = $this->phpbb_root_path . 'includes/'; +		if (substr($class, 6, 4) === 'ext_') +		{ +			$path_prefix = $this->ext_path; +			$prefix_length = 10; +		} +		else +		{ +			$path_prefix = $this->core_path; +			$prefix_length = 6; +		}  		if (isset($this->cached_paths[$class]))  		{ @@ -112,7 +124,7 @@ class phpbb_class_loader  			return false;  		} -		$parts = explode('_', substr($class, 6)); +		$parts = explode('_', substr($class, $prefix_length));  		$dirs = ''; diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index 8ef1a4655d..d5b398b7bf 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -226,6 +226,7 @@ define('CONFIG_TABLE',				$table_prefix . 'config');  define('CONFIRM_TABLE',				$table_prefix . 'confirm');  define('DISALLOW_TABLE',			$table_prefix . 'disallow');  define('DRAFTS_TABLE',				$table_prefix . 'drafts'); +define('EXT_TABLE',					$table_prefix . 'ext');  define('EXTENSIONS_TABLE',			$table_prefix . 'extensions');  define('EXTENSION_GROUPS_TABLE',	$table_prefix . 'extension_groups');  define('FORUMS_TABLE',				$table_prefix . 'forums'); diff --git a/phpBB/includes/extension/base.php b/phpBB/includes/extension/base.php new file mode 100644 index 0000000000..0e6c89491d --- /dev/null +++ b/phpBB/includes/extension/base.php @@ -0,0 +1,35 @@ +<?php +/** +* +* @package extension +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +/** +* +* @package extension +*/ +class phpbb_extension_base implements phpbb_extension_interface +{ +	public function enable() +	{ +	} + +	public function disable() +	{ +	} + +	public function purge() +	{ +	} +} diff --git a/phpBB/includes/extension/finder.php b/phpBB/includes/extension/finder.php new file mode 100644 index 0000000000..fb532e52f8 --- /dev/null +++ b/phpBB/includes/extension/finder.php @@ -0,0 +1,246 @@ +<?php +/** +* +* @package extension +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +/** +* The extension finder provides a simple way to locate files in active extensions +* +* @package extension +*/ +class phpbb_extension_finder +{ +	protected $extension_manager; +	protected $phpbb_root_path; +	protected $cache; +	protected $phpEx; + +	protected $query; +	protected $cached_queries; + +	/** +	* Creates a new finder instance with its dependencies +	* +	* @param phpbb_extension_manager $extension_manager An extension manager +	*            instance that provides the finder with a list of active +	*            extensions and their locations +	* @param string $phpbb_root_path Path to the phpbb root directory +	* @param phpbb_cache_driver_interface $cache A cache instance or null +	* @param string $phpEx php file extension +	*/ +	public function __construct(phpbb_extension_manager $extension_manager, $phpbb_root_path = '', phpbb_cache_driver_interface $cache = null, $phpEx = '.php') +	{ +		$this->extension_manager = $extension_manager; +		$this->phpbb_root_path = $phpbb_root_path; +		$this->cache = $cache; +		$this->phpEx = $phpEx; + +		$this->query = array( +			'default_path' => false, +			'default_suffix' => false, +			'default_directory' => false, +			'suffix' => false, +			'directory' => false, +		); + +		$this->cached_queries = ($this->cache) ? $this->cache->get('_extension_finder') : false; +	} + +	/** +	* Sets a default path to be searched in addition to extensions +	* +	* @param string $default_path The path relative to / +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function default_path($default_path) +	{ +		$this->query['default_path'] = $default_path; +		return $this; +	} + +	/** +	* Sets a suffix all files found in extensions must match +	* +	* Automatically sets the default_suffix if its value does not differ from +	* the current suffix. +	* +	* @param string $default_path A filename suffix +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function suffix($suffix) +	{ +		if ($this->query['default_suffix'] === $this->query['suffix']) +		{ +			$this->query['default_suffix'] = $suffix; +		} + +		$this->query['suffix'] = $suffix; +		return $this; +	} + +	/** +	* Sets a suffix all files found in the default path must match +	* +	* @param string $default_suffix A filename suffix +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function default_suffix($default_suffix) +	{ +		$this->query['default_suffix'] = $default_suffix; +		return $this; +	} + +	/** +	* Sets a directory all files found in extensions must be contained in +	* +	* Automatically sets the default_directory if its value does not differ from +	* the current directory. +	* +	* @param string $directory +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function directory($directory) +	{ +		if (strlen($directory) > 1 && $directory[strlen($directory) - 1] === '/') +		{ +			$directory = substr($directory, 0, -1); +		} + +		if ($this->query['default_directory'] === $this->query['directory']) +		{ +			$this->query['default_directory'] = $directory; +		} + +		$this->query['directory'] = $directory; +		return $this; +	} + +	/** +	* Sets a directory all files found in the default path must be contained in +	* +	* @param string $default_directory +	* @return phpbb_extension_finder This object for chaining calls +	*/ +	public function default_directory($default_directory) +	{ +		if (strlen($default_directory) > 1 && $default_directory[strlen($default_directory) - 1] === '/') +		{ +			$default_directory = substr($default_directory, 0, -1); +		} + +		$this->query['default_directory'] = $default_directory; +		return $this; +	} + +	/** +	* Finds auto loadable php classes matching the configured options. +	* +	* The php file extension is automatically added to suffixes. +	* +	* @param bool $cache Whether the result should be cached +	* @return array An array of found class names +	*/ +	public function get_classes($cache = true) +	{ +		$this->query['suffix'] .= $this->phpEx; +		$this->query['default_suffix'] .= $this->phpEx; + +		$files = $this->get_files($cache); + +		$classes = array(); +		foreach ($files as $file) +		{ +			$file = preg_replace('#^includes/#', '', $file); + +			$classes[] = 'phpbb_' . str_replace('/', '_', substr($file, 0, -strlen($this->phpEx))); +		} +		return $classes; +	} + +	/** +	* Finds all files matching the configured options. +	* +	* @param bool $cache Whether the result should be cached +	* @return array An array of found class names +	*/ +	public function get_files($cache = true) +	{ +		$query = md5(serialize($this->query)); + +		if ($cache && isset($this->cached_queries[$query])) +		{ +			return $this->cached_queries[$query]; +		} + +		$files = array(); + +		$extensions = $this->extension_manager->all_enabled(); + +		if ($this->query['default_path']) +		{ +			$extensions['/'] = $this->phpbb_root_path . $this->query['default_path']; +		} + +		foreach ($extensions as $name => $path) +		{ +			if (!file_exists($path)) +			{ +				continue; +			} + +			if ($name === '/') +			{ +				$prefix = $this->query['default_path']; +				$name = ''; +				$suffix = $this->query['default_suffix']; +				$directory = $this->query['default_directory']; +			} +			else +			{ +				$prefix = 'ext/'; +				$name .= '/'; +				$suffix = $this->query['suffix']; +				$directory = $this->query['directory']; +			} + +			// match only first directory if leading slash is given +			$directory_pattern = ($directory && $directory[0] === '/') ? '#^' : '#' . DIRECTORY_SEPARATOR; +			$directory_pattern .= preg_quote($directory . DIRECTORY_SEPARATOR, '#') . '#'; + +			$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)); +			foreach ($iterator as $file_info) +			{ +				if (!$file_info->isDir()) +				{ +					$relative_path = $iterator->getInnerIterator()->getSubPathname(); + +					if ((!$suffix || substr($relative_path, -strlen($suffix)) == $suffix) && +						(!$directory || preg_match($directory_pattern, DIRECTORY_SEPARATOR . $relative_path))) +					{ +						$files[] = str_replace(DIRECTORY_SEPARATOR, '/', $prefix . $name . $relative_path); +					} +				} +			} +		} + +		if ($cache && $this->cache) +		{ +			$this->cached_queries[$query] = $files; +			$this->cache->put('_extension_finder', $this->cached_queries); +		} + +		return $files; +	} +} diff --git a/phpBB/includes/extension/interface.php b/phpBB/includes/extension/interface.php new file mode 100644 index 0000000000..40a5a066a3 --- /dev/null +++ b/phpBB/includes/extension/interface.php @@ -0,0 +1,27 @@ +<?php +/** +* +* @package extension +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +/** +* +* @package extension +*/ +interface phpbb_extension_interface +{ +	public function enable(); +	public function disable(); +	public function purge(); +} diff --git a/phpBB/includes/extension/manager.php b/phpBB/includes/extension/manager.php new file mode 100644 index 0000000000..736c706e77 --- /dev/null +++ b/phpBB/includes/extension/manager.php @@ -0,0 +1,301 @@ +<?php +/** +* +* @package extension +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ +	exit; +} + +/** +* The extension manager provides means to activate/deactivate extensions. +* +* @package extension +*/ +class phpbb_extension_manager +{ +	protected $cache; +	protected $phpEx; +	protected $extensions; +	protected $extension_table; +	protected $phpbb_root_path; + +	/** +	* Creates a manager and loads information from database +	* +	* @param dbal $db A database connection +	* @param string $extension_table The name of the table holding extensions +	* @param string $phpbb_root_path Path to the phpbb includes directory. +	* @param string $phpEx php file extension +	* @param phpbb_cache_driver_interface $cache A cache instance or null +	*/ +	public function __construct(dbal $db, $extension_table, $phpbb_root_path, $phpEx = '.php', phpbb_cache_driver_interface $cache = null) +	{ +		$this->phpbb_root_path = $phpbb_root_path; +		$this->db = $db; +		$this->cache = $cache; +		$this->phpEx = $phpEx; +		$this->extension_table = $extension_table; + +		if (false === ($this->extensions = $this->cache->get('_extensions'))) +		{ +			$this->load_extensions(); +		} +	} + +	/** +	* Loads all extension information from the database +	* +	* @return null +	*/ +	protected function load_extensions() +	{ +		$sql = 'SELECT * +			FROM ' . $this->extension_table; + +		$result = $this->db->sql_query($sql); +		$extensions = $this->db->sql_fetchrowset($result); + +		$this->extensions = array(); +		foreach ($extensions as $extension) +		{ +			$extension['ext_path'] = $this->get_extension_path($extension['ext_name']); +			$this->extensions[$extension['ext_name']] = $extension; +		} + +		ksort($this->extensions); +		$this->cache->put('_extensions', $this->extensions); +	} + +	/** +	* Generates the path to an extension +	* +	* @param string $name The name of the extension +	* @return string Path to an extension +	*/ +	public function get_extension_path($name) +	{ +		return $this->phpbb_root_path . 'ext/' . basename($name) . '/'; +	} + +	/** +	* Instantiates the extension meta class for the given name. +	* +	* @param string $name The extension name +	* @return phpbb_extension_interface Instance of the extension meta class or +	*                     phpbb_extension_base if the class does not exist +	*/ +	public function get_extension($name) +	{ +		$extension_class_name = 'phpbb_ext_' . $name; + +		if (class_exists($extension_class_name)) +		{ +			return new $extension_class_name; +		} +		else +		{ +			return new phpbb_extension_base; +		} +	} + +	/** +	* Enables an extension +	* +	* Calls the enable method on the extension's meta class to allow it to +	* make database changes and execute other initialisation code. +	* +	* @param string $name The extension's name +	* @return null +	*/ +	public function enable($name) +	{ +		// ignore extensions that are already enabled +		if (isset($this->extensions[$name]) && $this->extensions[$name]['ext_active']) +		{ +			return; +		} + +		$extension = $this->get_extension($name); +		$extension->enable(); + +		$extension_data = array( +			'ext_name'	=> $name, +			'ext_active'	=> true, +		); + +		$this->extensions[$name] = $extension_data; +		$this->extensions[$name]['ext_path'] = $this->get_extension_path($extension_data['ext_name']); +		ksort($this->extensions); + +		$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); + +		if (!$this->db->sql_affectedrows()) +		{ +			$sql = 'INSERT INTO ' . $this->extension_table . ' +				' . $this->db->sql_build_array('INSERT', $extension_data); +			$this->db->sql_query($sql); +		} +	} + +	/** +	* Disables an extension +	* +	* Calls the disable method on the extension's meta class to allow it to +	* process the event. +	* +	* @param string $name The extension's name +	* @return null +	*/ +	public function disable($name) +	{ +		// ignore extensions that are already disabled +		if (!isset($this->extensions[$name]) || !$this->extensions[$name]['ext_active']) +		{ +			return; +		} + +		$extension = $this->get_extension($name); +		$extension->disable(); + +		$extension_data = array( +			'ext_active'	=> false, +		); +		$this->extensions[$name]['ext_active'] = false; +		ksort($this->extensions); + +		$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); +	} + +	/** +	* Purge an extension +	* +	* Disables the extension first if active, and then calls purge on the +	* extension's meta class to delete the extension's database content. +	* +	* @param string $name The extension's name +	* @return null +	*/ +	public function purge($name) +	{ +		// ignore extensions that do not exist +		if (!isset($this->extensions[$name])) +		{ +			return; +		} + +		// disable first if necessary +		if ($this->extensions[$name]['ext_active']) +		{ +			$this->disable($name); +		} + +		$extension = $this->get_extension($name); +		$extension->purge(); + +		unset($this->extensions[$name]); + +		$sql = 'DELETE FROM ' . $this->extension_table . " +			WHERE ext_name = '" . $this->db->sql_escape($name) . "'"; +		$this->db->sql_query($sql); +	} + +	/** +	* Retrieves a list of all available extensions on the filesystem +	* +	* @return array An array with extension names as keys and paths to the +	*               extension as values +	*/ +	public function all_available() +	{ +		$available = array(); + +		$iterator = new DirectoryIterator($this->phpbb_root_path . 'ext/'); +		foreach ($iterator as $file_info) +		{ +			$path = $this->phpbb_root_path . 'ext/' . $file_info->getBasename() . '/'; +			if (!$file_info->isDot() && $file_info->isDir() && file_exists($path)) +			{ +				$available[$file_info->getBasename()] = $path; +			} +		} +		ksort($available); +		return $available; +	} + +	/** +	* Retrieves all configured extensions. +	* +	* All enabled and disabled extensions are considered configured. A purged +	* extension that is no longer in the database is not configured. +	* +	* @return array An array with extension names as keys and and the +	*               database stored extension information as values +	*/ +	public function all_configured() +	{ +		return $this->extensions; +	} + +	/** +	* Retrieves all enabled extensions. +	* +	* @return array An array with extension names as keys and and the +	*               database stored extension information as values +	*/ +	public function all_enabled() +	{ +		$enabled = array(); +		foreach ($this->extensions as $name => $data) +		{ +			if ($data['ext_active']) +			{ +				$enabled[$name] = $data['ext_path']; +			} +		} +		return $enabled; +	} + +	/** +	* Retrieves all disabled extensions. +	* +	* @return array An array with extension names as keys and and the +	*               database stored extension information as values +	*/ +	public function all_disabled() +	{ +		$disabled = array(); +		foreach ($this->extensions as $name => $data) +		{ +			if (!$data['ext_active']) +			{ +				$disabled[$name] = $data['ext_path']; +			} +		} +		return $disabled; +	} + +	/** +	* Instantiates a phpbb_extension_finder. +	* +	* @return phpbb_extension_finder An extension finder instance +	*/ +	public function get_finder() +	{ +		return new phpbb_extension_finder($this, $this->phpbb_root_path, $this->cache, $this->phpEx); +	} +} diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 18741191d8..b2419df3c9 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -104,8 +104,12 @@ if (!defined('LOGIN_ATTEMPT_TABLE'))  {  	define('LOGIN_ATTEMPT_TABLE', $table_prefix . 'login_attempts');  } +if (!defined('EXT_TABLE')) +{ +	define('EXT_TABLE', $table_prefix . 'ext'); +} -$class_loader = new phpbb_class_loader($phpbb_root_path, '.' . $phpEx); +$class_loader = new phpbb_class_loader($phpbb_root_path . 'includes/', $phpbb_root_path . 'ext/', '.' . $phpEx);  $class_loader->register();  // set up caching @@ -1048,6 +1052,18 @@ function database_update_info()  		// Changes from 3.1.0-dev to 3.1.0-A1  		'3.1.0-dev'		=> array( +			'add_tables'		=> array( +				EXT_TABLE				=> array( +					'COLUMNS'			=> array( +						'ext_name'		=> array('VCHAR', ''), +						'ext_active'	=> array('BOOL', 0), +					), +					'KEYS'				=> array( +						'ext_name'		=> array('UNIQUE', 'ext_name'), +						'ext_active'	=> array('INDEX', 'ext_active'), +					), +				), +			),  			'add_columns'		=> array(  				GROUPS_TABLE		=> array(  					'group_teampage'	=> array('UINT', 0, 'after' => 'group_legend'), diff --git a/phpBB/install/index.php b/phpBB/install/index.php index a4ff93e701..fbe8ae63a7 100644 --- a/phpBB/install/index.php +++ b/phpBB/install/index.php @@ -82,7 +82,7 @@ include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);  include($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);  require($phpbb_root_path . 'includes/functions_install.' . $phpEx); -$class_loader = new phpbb_class_loader($phpbb_root_path, '.' . $phpEx); +$class_loader = new phpbb_class_loader($phpbb_root_path . 'includes/', $phpbb_root_path . 'ext/', '.' . $phpEx);  $class_loader->register();  // set up caching diff --git a/phpBB/install/schemas/firebird_schema.sql b/phpBB/install/schemas/firebird_schema.sql index 67e5547bb6..5f5aaaaa45 100644 --- a/phpBB/install/schemas/firebird_schema.sql +++ b/phpBB/install/schemas/firebird_schema.sql @@ -281,6 +281,15 @@ BEGIN  END;; +# Table: 'phpbb_ext' +CREATE TABLE phpbb_ext ( +	ext_name VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL, +	ext_active INTEGER DEFAULT 0 NOT NULL +);; + +CREATE UNIQUE INDEX phpbb_ext_ext_name ON phpbb_ext(ext_name);; +CREATE INDEX phpbb_ext_ext_active ON phpbb_ext(ext_active);; +  # Table: 'phpbb_extensions'  CREATE TABLE phpbb_extensions (  	extension_id INTEGER NOT NULL, diff --git a/phpBB/install/schemas/mssql_schema.sql b/phpBB/install/schemas/mssql_schema.sql index fe69670ded..052531993f 100644 --- a/phpBB/install/schemas/mssql_schema.sql +++ b/phpBB/install/schemas/mssql_schema.sql @@ -359,6 +359,22 @@ GO  /* +	Table: 'phpbb_ext' +*/ +CREATE TABLE [phpbb_ext] ( +	[ext_name] [varchar] (255) DEFAULT ('') NOT NULL , +	[ext_active] [int] DEFAULT (0) NOT NULL  +) ON [PRIMARY] +GO + +CREATE  UNIQUE  INDEX [ext_name] ON [phpbb_ext]([ext_name]) ON [PRIMARY] +GO + +CREATE  INDEX [ext_active] ON [phpbb_ext]([ext_active]) ON [PRIMARY] +GO + + +/*  	Table: 'phpbb_extensions'  */  CREATE TABLE [phpbb_extensions] ( diff --git a/phpBB/install/schemas/mysql_40_schema.sql b/phpBB/install/schemas/mysql_40_schema.sql index da6ce35be3..03402d7ed1 100644 --- a/phpBB/install/schemas/mysql_40_schema.sql +++ b/phpBB/install/schemas/mysql_40_schema.sql @@ -191,6 +191,15 @@ CREATE TABLE phpbb_drafts (  ); +# Table: 'phpbb_ext' +CREATE TABLE phpbb_ext ( +	ext_name varbinary(255) DEFAULT '' NOT NULL, +	ext_active tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, +	UNIQUE ext_name (ext_name), +	KEY ext_active (ext_active) +); + +  # Table: 'phpbb_extensions'  CREATE TABLE phpbb_extensions (  	extension_id mediumint(8) UNSIGNED NOT NULL auto_increment, diff --git a/phpBB/install/schemas/mysql_41_schema.sql b/phpBB/install/schemas/mysql_41_schema.sql index cdbe377178..8876b52a30 100644 --- a/phpBB/install/schemas/mysql_41_schema.sql +++ b/phpBB/install/schemas/mysql_41_schema.sql @@ -191,6 +191,15 @@ CREATE TABLE phpbb_drafts (  ) CHARACTER SET `utf8` COLLATE `utf8_bin`; +# Table: 'phpbb_ext' +CREATE TABLE phpbb_ext ( +	ext_name varchar(255) DEFAULT '' NOT NULL, +	ext_active tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, +	UNIQUE ext_name (ext_name), +	KEY ext_active (ext_active) +) CHARACTER SET `utf8` COLLATE `utf8_bin`; + +  # Table: 'phpbb_extensions'  CREATE TABLE phpbb_extensions (  	extension_id mediumint(8) UNSIGNED NOT NULL auto_increment, diff --git a/phpBB/install/schemas/oracle_schema.sql b/phpBB/install/schemas/oracle_schema.sql index 8797457e87..df31f6d3d6 100644 --- a/phpBB/install/schemas/oracle_schema.sql +++ b/phpBB/install/schemas/oracle_schema.sql @@ -408,6 +408,19 @@ END;  /* +	Table: 'phpbb_ext' +*/ +CREATE TABLE phpbb_ext ( +	ext_name varchar2(255) DEFAULT '' , +	ext_active number(1) DEFAULT '0' NOT NULL, +	CONSTRAINT u_phpbb_ext_name UNIQUE (ext_name) +) +/ + +CREATE INDEX phpbb_ext_ext_active ON phpbb_ext (ext_active) +/ + +/*  	Table: 'phpbb_extensions'  */  CREATE TABLE phpbb_extensions ( diff --git a/phpBB/install/schemas/postgres_schema.sql b/phpBB/install/schemas/postgres_schema.sql index 3c79aacd6b..dbe891a3ac 100644 --- a/phpBB/install/schemas/postgres_schema.sql +++ b/phpBB/install/schemas/postgres_schema.sql @@ -313,6 +313,17 @@ CREATE TABLE phpbb_drafts (  CREATE INDEX phpbb_drafts_save_time ON phpbb_drafts (save_time);  /* +	Table: 'phpbb_ext' +*/ +CREATE TABLE phpbb_ext ( +	ext_name varchar(255) DEFAULT '' NOT NULL, +	ext_active INT2 DEFAULT '0' NOT NULL CHECK (ext_active >= 0) +); + +CREATE UNIQUE INDEX phpbb_ext_ext_name ON phpbb_ext (ext_name); +CREATE INDEX phpbb_ext_ext_active ON phpbb_ext (ext_active); + +/*  	Table: 'phpbb_extensions'  */  CREATE SEQUENCE phpbb_extensions_seq; diff --git a/phpBB/install/schemas/sqlite_schema.sql b/phpBB/install/schemas/sqlite_schema.sql index e0631160fd..3c1d476daa 100644 --- a/phpBB/install/schemas/sqlite_schema.sql +++ b/phpBB/install/schemas/sqlite_schema.sql @@ -186,6 +186,15 @@ CREATE TABLE phpbb_drafts (  CREATE INDEX phpbb_drafts_save_time ON phpbb_drafts (save_time); +# Table: 'phpbb_ext' +CREATE TABLE phpbb_ext ( +	ext_name varchar(255) NOT NULL DEFAULT '', +	ext_active INTEGER UNSIGNED NOT NULL DEFAULT '0' +); + +CREATE UNIQUE INDEX phpbb_ext_ext_name ON phpbb_ext (ext_name); +CREATE INDEX phpbb_ext_ext_active ON phpbb_ext (ext_active); +  # Table: 'phpbb_extensions'  CREATE TABLE phpbb_extensions (  	extension_id INTEGER PRIMARY KEY NOT NULL , diff --git a/tests/bootstrap.php b/tests/bootstrap.php index b7c3534cde..fbe23c1835 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -32,7 +32,7 @@ else  require_once $phpbb_root_path . 'includes/constants.php';  require_once $phpbb_root_path . 'includes/class_loader.' . $phpEx; -$class_loader = new phpbb_class_loader($phpbb_root_path, '.php'); +$class_loader = new phpbb_class_loader($phpbb_root_path . 'includes/', $phpbb_root_path . 'ext/', '.php');  $class_loader->register();  require_once 'test_framework/phpbb_test_case_helpers.php'; diff --git a/tests/class_loader/class_loader_test.php b/tests/class_loader/class_loader_test.php index 0c7fe3f97a..7d5f57aac3 100644 --- a/tests/class_loader/class_loader_test.php +++ b/tests/class_loader/class_loader_test.php @@ -26,7 +26,7 @@ class phpbb_class_loader_test extends PHPUnit_Framework_TestCase  	public function test_resolve_path()  	{  		$prefix = dirname(__FILE__) . '/'; -		$class_loader = new phpbb_class_loader($prefix); +		$class_loader = new phpbb_class_loader($prefix . 'includes/', $prefix . 'ext/');  		$prefix .= 'includes/'; @@ -56,6 +56,11 @@ class phpbb_class_loader_test extends PHPUnit_Framework_TestCase  			$class_loader->resolve_path('phpbb_dir2'),  			'Class with name of dir within dir (short class name)'  		); +		$this->assertEquals( +			dirname(__FILE__) . '/ext/foo/class.php', +			$class_loader->resolve_path('phpbb_ext_foo_class'), +			'Extension class' +		);  	}  	public function test_resolve_cached() @@ -64,7 +69,7 @@ class phpbb_class_loader_test extends PHPUnit_Framework_TestCase  		$cache = new phpbb_mock_cache($cacheMap);  		$prefix = dirname(__FILE__) . '/'; -		$class_loader = new phpbb_class_loader($prefix, '.php', $cache); +		$class_loader = new phpbb_class_loader($prefix . 'includes/', $prefix . 'ext/', '.php', $cache);  		$prefix .= 'includes/'; diff --git a/tests/class_loader/ext/foo/class.php b/tests/class_loader/ext/foo/class.php new file mode 100644 index 0000000000..7b1555c98d --- /dev/null +++ b/tests/class_loader/ext/foo/class.php @@ -0,0 +1,6 @@ +<?php + +class phpbb_ext_foo_class +{ +} + diff --git a/tests/extension/ext/bar/my/hidden_class.php b/tests/extension/ext/bar/my/hidden_class.php new file mode 100644 index 0000000000..b3c910a8c2 --- /dev/null +++ b/tests/extension/ext/bar/my/hidden_class.php @@ -0,0 +1,5 @@ +<?php + +class phpbb_ext_bar_my_hidden_class +{ +}
\ No newline at end of file diff --git a/tests/extension/ext/foo/a_class.php b/tests/extension/ext/foo/a_class.php new file mode 100644 index 0000000000..03253139f9 --- /dev/null +++ b/tests/extension/ext/foo/a_class.php @@ -0,0 +1,5 @@ +<?php + +class phpbb_ext_foo_a_class +{ +}
\ No newline at end of file diff --git a/tests/extension/ext/foo/b_class.php b/tests/extension/ext/foo/b_class.php new file mode 100644 index 0000000000..04644a9d9d --- /dev/null +++ b/tests/extension/ext/foo/b_class.php @@ -0,0 +1,5 @@ +<?php + +class phpbb_ext_foo_b_class +{ +}
\ No newline at end of file diff --git a/tests/extension/ext/foo/foo.php b/tests/extension/ext/foo/foo.php new file mode 100644 index 0000000000..78a8c95f65 --- /dev/null +++ b/tests/extension/ext/foo/foo.php @@ -0,0 +1,5 @@ +<?php + +class phpbb_ext_foo extends phpbb_extension_base +{ +}
\ No newline at end of file diff --git a/tests/extension/ext/foo/sub/type/alternative.php b/tests/extension/ext/foo/sub/type/alternative.php new file mode 100644 index 0000000000..2ea7353f4b --- /dev/null +++ b/tests/extension/ext/foo/sub/type/alternative.php @@ -0,0 +1,5 @@ +<?php + +class phpbb_ext_foo_sub_type_alternative +{ +} diff --git a/tests/extension/ext/foo/type/alternative.php b/tests/extension/ext/foo/type/alternative.php new file mode 100644 index 0000000000..b43a293b1d --- /dev/null +++ b/tests/extension/ext/foo/type/alternative.php @@ -0,0 +1,5 @@ +<?php + +class phpbb_ext_foo_type_alternative +{ +}
\ No newline at end of file diff --git a/tests/extension/ext/foo/typewrong/error.php b/tests/extension/ext/foo/typewrong/error.php new file mode 100644 index 0000000000..ba22cfae9a --- /dev/null +++ b/tests/extension/ext/foo/typewrong/error.php @@ -0,0 +1,5 @@ +<?php + +class phpbb_ext_foo_typewrong_error +{ +} diff --git a/tests/extension/ext/moo/feature_class.php b/tests/extension/ext/moo/feature_class.php new file mode 100644 index 0000000000..20ea13054f --- /dev/null +++ b/tests/extension/ext/moo/feature_class.php @@ -0,0 +1,5 @@ +<?php + +class phpbb_ext_moo_feature_class +{ +}
\ No newline at end of file diff --git a/tests/extension/finder_test.php b/tests/extension/finder_test.php new file mode 100644 index 0000000000..a1b216face --- /dev/null +++ b/tests/extension/finder_test.php @@ -0,0 +1,133 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +require_once dirname(__FILE__) . '/../mock/cache.php'; +require_once dirname(__FILE__) . '/../mock/extension_manager.php'; + +class phpbb_extension_finder_test extends phpbb_test_case +{ +	protected $extension_manager; +	protected $finder; + +	public function setUp() +	{ +		$this->extension_manager = new phpbb_mock_extension_manager(array( +			'foo' => array( +				'ext_name' => 'foo', +				'ext_active' => '1', +				'ext_path' => dirname(__FILE__) . '/ext/foo/', +			), +			'bar' => array( +				'ext_name' => 'bar', +				'ext_active' => '1', +				'ext_path' => dirname(__FILE__) . '/ext/bar/', +			), +		)); + +		$this->finder = new phpbb_extension_finder($this->extension_manager, dirname(__FILE__) . '/'); +	} + +	public function test_suffix_get_classes() +	{ +		$classes = $this->finder +			->default_path('includes/default/') +			->suffix('_class') +			->default_suffix('') +			->get_classes(); + +		sort($classes); +		$this->assertEquals( +			array( +				'phpbb_default_implementation', +				'phpbb_ext_bar_my_hidden_class', +				'phpbb_ext_foo_a_class', +				'phpbb_ext_foo_b_class', +			), +			$classes +		); +	} + +	public function test_directory_get_classes() +	{ +		$classes = $this->finder +			->default_path('includes/default/') +			->directory('type') +			->default_directory('') +			->get_classes(); + +		sort($classes); +		$this->assertEquals( +			array( +				'phpbb_default_implementation', +				'phpbb_ext_foo_sub_type_alternative', +				'phpbb_ext_foo_type_alternative', +			), +			$classes +		); +	} + +	public function test_absolute_directory_get_classes() +	{ +		$classes = $this->finder +			->directory('/type/') +			->get_classes(); + +		sort($classes); +		$this->assertEquals( +			array( +				'phpbb_ext_foo_type_alternative', +			), +			$classes +		); +	} + +	public function test_sub_directory_get_classes() +	{ +		$classes = $this->finder +			->directory('/sub/type') +			->get_classes(); + +		sort($classes); +		$this->assertEquals( +			array( +				'phpbb_ext_foo_sub_type_alternative', +			), +			$classes +		); +	} + +	public function test_cached_get_files() +	{ +		$query = array( +			'default_path' => 'includes/foo', +			'default_suffix' => false, +			'default_directory' => 'bar', +			'suffix' => false, +			'directory' => false, +		); + + +		$finder = new phpbb_extension_finder($this->extension_manager, dirname(__FILE__) . '/includes/', new phpbb_mock_cache(array( +			'_extension_finder' => array( +				md5(serialize($query)) => array('file_name'), +			), +		))); + +		$classes = $finder +			->default_path($query['default_path']) +			->default_directory($query['default_directory']) +			->get_files(); + +		sort($classes); +		$this->assertEquals( +			array('file_name'), +			$classes +		); +	} +} diff --git a/tests/extension/fixtures/extensions.xml b/tests/extension/fixtures/extensions.xml new file mode 100644 index 0000000000..f3acdd2575 --- /dev/null +++ b/tests/extension/fixtures/extensions.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> +	<table name="phpbb_ext"> +		<column>ext_name</column> +		<column>ext_active</column> +		<row> +			<value>foo</value> +			<value>1</value> +		</row> +		<row> +			<value>moo</value> +			<value>0</value> +		</row> +	</table> +</dataset> diff --git a/tests/extension/includes/default/implementation.php b/tests/extension/includes/default/implementation.php new file mode 100644 index 0000000000..91d5f8aa2f --- /dev/null +++ b/tests/extension/includes/default/implementation.php @@ -0,0 +1,5 @@ +<?php + +class phpbb_default_impl_class implements phpbb_default_interface +{ +} diff --git a/tests/extension/manager_test.php b/tests/extension/manager_test.php new file mode 100644 index 0000000000..ebd92a728d --- /dev/null +++ b/tests/extension/manager_test.php @@ -0,0 +1,89 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +require_once dirname(__FILE__) . '/../mock/cache.php'; + +class phpbb_extension_manager_test extends phpbb_database_test_case +{ +	protected $extension_manager; +	protected $class_loader; + +	public function getDataSet() +	{ +		return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/extensions.xml'); +	} + +	protected function setUp() +	{ +		parent::setUp(); + +		// disable the regular class loader to replace it with one that loads +		// test extensions +		global $class_loader; +		$class_loader->unregister(); + +		$prefix = dirname(__FILE__) . '/'; +		$this->class_loader = new phpbb_class_loader($prefix . '../../phpBB/includes/', $prefix . 'ext/'); +		$this->class_loader->register(); + +		$this->extension_manager = new phpbb_extension_manager( +			$this->new_dbal(), +			'phpbb_ext', +			$prefix, +			'.php', +			new phpbb_mock_cache +		); +	} + +	protected function tearDown() +	{ +		global $class_loader; +		$class_loader->register(); +	} + +	public function test_available() +	{ +		$this->assertEquals(array('bar', 'foo', 'moo'), array_keys($this->extension_manager->all_available())); +	} + +	public function test_enabled() +	{ +		$this->assertEquals(array('foo'), array_keys($this->extension_manager->all_enabled())); +	} + +	public function test_configured() +	{ +		$this->assertEquals(array('foo', 'moo'), array_keys($this->extension_manager->all_configured())); +	} + +	public function test_enable() +	{ +		$this->assertEquals(array('foo'), array_keys($this->extension_manager->all_enabled())); +		$this->extension_manager->enable('bar'); +		$this->assertEquals(array('bar', 'foo'), array_keys($this->extension_manager->all_enabled())); +		$this->assertEquals(array('bar', 'foo', 'moo'), array_keys($this->extension_manager->all_configured())); +	} + +	public function test_disable() +	{ +		$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', 'moo'), array_keys($this->extension_manager->all_configured())); +	} + +	public function test_purge() +	{ +		$this->assertEquals(array('foo'), array_keys($this->extension_manager->all_enabled())); +		$this->assertEquals(array('foo', 'moo'), array_keys($this->extension_manager->all_configured())); +		$this->extension_manager->purge('moo'); +		$this->assertEquals(array('foo'), array_keys($this->extension_manager->all_enabled())); +		$this->assertEquals(array('foo'), array_keys($this->extension_manager->all_configured())); +	} +} diff --git a/tests/mock/extension_manager.php b/tests/mock/extension_manager.php new file mode 100644 index 0000000000..49d727db37 --- /dev/null +++ b/tests/mock/extension_manager.php @@ -0,0 +1,16 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +class phpbb_mock_extension_manager extends phpbb_extension_manager +{ +	public function __construct($extensions = array()) +	{ +		$this->extensions = $extensions; +	} +}  | 
