diff options
45 files changed, 2716 insertions, 148 deletions
diff --git a/phpBB/assets/javascript/core.js b/phpBB/assets/javascript/core.js index 8bbea8b8c9..642d513cb6 100644 --- a/phpBB/assets/javascript/core.js +++ b/phpBB/assets/javascript/core.js @@ -136,7 +136,7 @@ phpbb.confirm = function(msg, callback, fadedark) { }); var clickHandler = function(e) { - var res = this.className === 'button1'; + var res = this.name === 'confirm'; var fade = (typeof fadedark !== 'undefined' && !fadedark && res) ? div : dark; fade.fadeOut(phpbb.alertTime, function() { div.hide(); @@ -164,11 +164,11 @@ phpbb.confirm = function(msg, callback, fadedark) { $(document).bind('keydown', function(e) { if (e.keyCode === keymap.ENTER) { - $('input[type="button"].button1').trigger('click'); + $('input[name="confirm"]').trigger('click'); e.preventDefault(); e.stopPropagation(); } else if (e.keyCode === keymap.ESC) { - $('input[type="button"].button2').trigger('click'); + $('input[name="cancel"]').trigger('click'); e.preventDefault(); e.stopPropagation(); } diff --git a/phpBB/docs/coding-guidelines.html b/phpBB/docs/coding-guidelines.html index 14c2281323..e73c563d5b 100644 --- a/phpBB/docs/coding-guidelines.html +++ b/phpBB/docs/coding-guidelines.html @@ -1060,6 +1060,8 @@ $action_ary = request_var('action', array('' => 0)); <h4>Login checks/redirection: </h4> <p>To show a forum login box use <code>login_forum_box($forum_data)</code>, else use the <code>login_box()</code> function.</p> + <p><code>$forum_data</code> should contain at least the <code>forum_id</code> and <code>forum_password</code> fields. If the field <code>forum_name</code> is available, then it is displayed on the forum login page.</p> + <p>The <code>login_box()</code> function can have a redirect as the first parameter. As a thumb of rule, specify an empty string if you want to redirect to the users current location, else do not add the <code>$SID</code> to the redirect string (for example within the ucp/login we redirect to the board index because else the user would be redirected to the login screen).</p> <h4>Sensitive Operations: </h4> @@ -2490,7 +2492,7 @@ if (utf8_case_fold_nfc($string1) == utf8_case_fold_nfc($string2)) <hr /> -<a name="disclaimer"></a><h2>8. Copyright and disclaimer</h2> +<a name="disclaimer"></a><h2>7. Copyright and disclaimer</h2> <div class="paragraph"> <div class="inner"><span class="corners-top"><span></span></span> diff --git a/phpBB/includes/acp/acp_extensions.php b/phpBB/includes/acp/acp_extensions.php index e4defa0400..c52e4e0473 100644 --- a/phpBB/includes/acp/acp_extensions.php +++ b/phpBB/includes/acp/acp_extensions.php @@ -54,7 +54,7 @@ class acp_extensions // If they've specified an extension, let's load the metadata manager and validate it. if ($ext_name) { - $md_manager = new phpbb_extension_metadata_manager($ext_name, $db, $phpbb_extension_manager, $phpbb_root_path, $phpEx, $template, $config); + $md_manager = new phpbb_extension_metadata_manager($ext_name, $config, $phpbb_extension_manager, $template, $phpbb_root_path); try { diff --git a/phpBB/includes/acp/acp_prune.php b/phpBB/includes/acp/acp_prune.php index a5dc02849a..4234ec1505 100644 --- a/phpBB/includes/acp/acp_prune.php +++ b/phpBB/includes/acp/acp_prune.php @@ -331,7 +331,7 @@ class acp_prune $s_find_active_time .= '<option value="' . $key . '">' . $value . '</option>'; } - $s_group_list = ''; + $s_group_list = '<option value="0"></option>'; $sql = 'SELECT group_id, group_name FROM ' . GROUPS_TABLE . ' WHERE group_type <> ' . GROUP_SPECIAL . ' @@ -340,7 +340,7 @@ class acp_prune while ($row = $db->sql_fetchrow($result)) { - $s_group_list .= '<option value="' . $row['group_id'] . '">' . $row['group_name'] . '</select>'; + $s_group_list .= '<option value="' . $row['group_id'] . '">' . $row['group_name'] . '</option>'; } $db->sql_freeresult($result); @@ -491,11 +491,12 @@ class acp_prune if ($group_id) { - $sql = 'SELECT user_id - FROM ' . USER_GROUP_TABLE . ' - WHERE group_id = ' . (int) $group_id . ' - AND user_pending = 0 - AND ' . $db->sql_in_set('user_id', $user_ids, false, true); + $sql = 'SELECT u.user_id, u.username + FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . ' u + WHERE ug.group_id = ' . (int) $group_id . ' + AND ug.user_pending = 0 + AND ' . $db->sql_in_set('ug.user_id', $user_ids, false, true) . ' + AND u.user_id = ug.user_id'; $result = $db->sql_query($sql); // we're performing an intersection operation, so all the relevant users @@ -504,24 +505,19 @@ class acp_prune $user_ids = $usernames = array(); while ($row = $db->sql_fetchrow($result)) { - $user_ids[] = $row['poster_id']; + $user_ids[] = $row['user_id']; + $usernames[$row['user_id']] = $row['username']; } $db->sql_freeresult($result); - - // only get usernames if they are needed (not part of some later query) - if (!$posts_on_queue) - { - // this is an additional query aginst the users table - user_get_id_name($user_ids, $usernames); - } } if ($posts_on_queue) { - $sql = 'SELECT poster_id, COUNT(post_id) AS queue_posts - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('poster_id', $user_ids, false, true) . ' - GROUP BY poster_id + $sql = 'SELECT u.user_id, u.username, COUNT(p.post_id) AS queue_posts + FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u + WHERE ' . $db->sql_in_set('p.poster_id', $user_ids, false, true) . ' + AND u.user_id = p.poster_id + GROUP BY p.poster_id HAVING queue_posts ' . $key_match[$queue_select] . ' ' . $posts_on_queue; $result = $db->sql_query($result); @@ -529,12 +525,10 @@ class acp_prune $user_ids = $usernames = array(); while ($row = $db->sql_fetchrow($result)) { - $user_ids[] = $row['poster_id']; + $user_ids[] = $row['user_id']; + $usernames[$row['user_id']] = $row['username']; } $db->sql_freeresult($result); - - // do an additional query to get the correct set of usernames - user_get_id_name($user_ids, $usernames); } } } diff --git a/phpBB/includes/extension/manager.php b/phpBB/includes/extension/manager.php index a1022762b8..653117adfa 100644 --- a/phpBB/includes/extension/manager.php +++ b/phpBB/includes/extension/manager.php @@ -155,7 +155,7 @@ class phpbb_extension_manager */ public function create_extension_metadata_manager($name, phpbb_template $template) { - return new phpbb_extension_metadata_manager($name, $this->db, $this, $this->phpbb_root_path, $this->php_ext, $template, $this->config); + return new phpbb_extension_metadata_manager($name, $this->config, $this, $template, $this->phpbb_root_path); } /** diff --git a/phpBB/includes/extension/metadata_manager.php b/phpBB/includes/extension/metadata_manager.php index 1637abd340..14b77c085b 100644 --- a/phpBB/includes/extension/metadata_manager.php +++ b/phpBB/includes/extension/metadata_manager.php @@ -22,31 +22,64 @@ if (!defined('IN_PHPBB')) */ class phpbb_extension_metadata_manager { - protected $phpEx; + /** + * phpBB Config instance + * @var phpbb_config + */ + protected $config; + + /** + * phpBB Extension Manager + * @var phpbb_extension_manager + */ protected $extension_manager; - protected $db; - protected $phpbb_root_path; + + /** + * phpBB Template instance + * @var phpbb_template + */ protected $template; + + /** + * phpBB root path + * @var string + */ + protected $phpbb_root_path; + + /** + * Name (including vendor) of the extension + * @var string + */ protected $ext_name; + + /** + * Metadata from the composer.json file + * @var array + */ protected $metadata; + + /** + * Link (including root path) to the metadata file + * @var string + */ protected $metadata_file; /** * Creates the metadata manager * - * @param phpbb_db_driver $db A database connection - * @param string $extension_manager An instance of the phpbb extension manager - * @param string $phpbb_root_path Path to the phpbb includes directory. - * @param string $phpEx php file extension + * @param string $ext_name Name (including vendor) of the extension + * @param phpbb_config $config phpBB Config instance + * @param phpbb_extension_manager $extension_manager An instance of the phpBBb extension manager + * @param phpbb_template $template phpBB Template instance + * @param string $phpbb_root_path Path to the phpbb includes directory. */ - public function __construct($ext_name, phpbb_db_driver $db, phpbb_extension_manager $extension_manager, $phpbb_root_path, $phpEx = 'php', phpbb_template $template, phpbb_config $config) + public function __construct($ext_name, phpbb_config $config, phpbb_extension_manager $extension_manager, phpbb_template $template, $phpbb_root_path) { - $this->phpbb_root_path = $phpbb_root_path; - $this->db = $db; $this->config = $config; - $this->phpEx = $phpEx; - $this->template = $template; $this->extension_manager = $extension_manager; + $this->template = $template; + $this->phpbb_root_path = $phpbb_root_path; + $this->ext_name = $ext_name; $this->metadata = array(); $this->metadata_file = ''; diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 3a650b37fc..0dc2f314f1 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -3467,6 +3467,7 @@ function login_forum_box($forum_data) page_header($user->lang['LOGIN'], false); $template->assign_vars(array( + 'FORUM_NAME' => isset($forum_data['forum_name']) ? $forum_data['forum_name'] : '', 'S_LOGIN_ACTION' => build_url(array('f')), 'S_HIDDEN_FIELDS' => build_hidden_fields(array('f' => $forum_data['forum_id']))) ); diff --git a/phpBB/includes/functions_download.php b/phpBB/includes/functions_download.php index 9ae647d806..ee4e2f5135 100644 --- a/phpBB/includes/functions_download.php +++ b/phpBB/includes/functions_download.php @@ -625,7 +625,7 @@ function phpbb_increment_downloads($db, $ids) */ function phpbb_download_handle_forum_auth($db, $auth, $topic_id) { - $sql = 'SELECT t.forum_id, f.forum_password, f.parent_id + $sql = 'SELECT t.forum_id, f.forum_name, f.forum_password, f.parent_id FROM ' . TOPICS_TABLE . ' t, ' . FORUMS_TABLE . " f WHERE t.topic_id = " . (int) $topic_id . " AND t.forum_id = f.forum_id"; diff --git a/phpBB/includes/lock/db.php b/phpBB/includes/lock/db.php index ccdaed0b28..5cc0821aa0 100644 --- a/phpBB/includes/lock/db.php +++ b/phpBB/includes/lock/db.php @@ -117,6 +117,17 @@ class phpbb_lock_db } /** + * Does this process own the lock? + * + * @return bool true if lock is owned + * false otherwise + */ + public function owns_lock() + { + return (bool) $this->locked; + } + + /** * Releases the lock. * * The lock must have been previously obtained, that is, acquire() call diff --git a/phpBB/includes/lock/flock.php b/phpBB/includes/lock/flock.php index 97bc7dd2b9..17de0847c0 100644 --- a/phpBB/includes/lock/flock.php +++ b/phpBB/includes/lock/flock.php @@ -111,6 +111,17 @@ class phpbb_lock_flock } /** + * Does this process own the lock? + * + * @return bool true if lock is owned + * false otherwise + */ + public function owns_lock() + { + return (bool) $this->lock_fp; + } + + /** * Releases the lock. * * The lock must have been previously obtained, that is, acquire() call diff --git a/phpBB/includes/search/fulltext_postgres.php b/phpBB/includes/search/fulltext_postgres.php index eeb628b18f..5080587681 100644 --- a/phpBB/includes/search/fulltext_postgres.php +++ b/phpBB/includes/search/fulltext_postgres.php @@ -214,7 +214,7 @@ class phpbb_search_fulltext_postgres extends phpbb_search_base { if ($terms == 'all') { - $match = array('#\sand\s#iu', '#\sor\s#iu', '#\snot\s#iu', '#\+#', '#-#', '#\|#'); + $match = array('#\sand\s#iu', '#\sor\s#iu', '#\snot\s#iu', '#(^|\s)\+#', '#(^|\s)-#', '#(^|\s)\|#'); $replace = array(' +', ' |', ' -', ' +', ' -', ' |'); $keywords = preg_replace($match, $replace, $keywords); diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 9e8ad2fef0..c2c100e93e 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -224,28 +224,34 @@ class phpbb_template_filter extends php_user_filter } /* - Preserve whitespace. - PHP removes a newline after the closing tag (if it's there). This is by design. + Preserve whitespace. + PHP removes a newline after the closing tag (if it's there). + This is by design: - Consider the following template: + http://www.php.net/manual/en/language.basic-syntax.phpmode.php + http://www.php.net/manual/en/language.basic-syntax.instruction-separation.php - <!-- IF condition --> - some content - <!-- ENDIF --> - If we were to simply preserve all whitespace, we could simply replace all "?>" tags - with "?>\n". - Doing that, would add additional newlines to the compiled tempalte in place of the - IF and ENDIF statements. These newlines are unwanted (and one is conditional). - The IF and ENDIF are usually on their own line for ease of reading. + Consider the following template: - This replacement preserves newlines only for statements that aren't the only statement on a line. - It will NOT preserve newlines at the end of statements in the above examle. - It will preserve newlines in situations like: + <!-- IF condition --> + some content + <!-- ENDIF --> - <!-- IF condition -->inline content<!-- ENDIF --> + If we were to simply preserve all whitespace, we could simply + replace all "?>" tags with "?>\n". + Doing that, would add additional newlines to the compiled + template in place of the IF and ENDIF statements. These + newlines are unwanted (and one is conditional). The IF and + ENDIF are usually on their own line for ease of reading. + This replacement preserves newlines only for statements that + are not the only statement on a line. It will NOT preserve + newlines at the end of statements in the above example. + It will preserve newlines in situations like: + + <!-- IF condition -->inline content<!-- ENDIF --> */ diff --git a/phpBB/includes/tree/interface.php b/phpBB/includes/tree/interface.php new file mode 100644 index 0000000000..cc8aab2115 --- /dev/null +++ b/phpBB/includes/tree/interface.php @@ -0,0 +1,122 @@ +<?php +/** +* +* @package tree +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +interface phpbb_tree_interface +{ + /** + * Inserts an item into the database table and into the tree. + * + * @param array $item The item to be added + * @return array Array with item data as set in the database + */ + public function insert(array $additional_data); + + /** + * Delete an item from the tree and from the database table + * + * Also deletes the subtree from the tree and from the database table + * + * @param int $item_id The item to be deleted + * @return array Item ids that have been deleted + */ + public function delete($item_id); + + /** + * Move an item by a given delta + * + * An item is only moved up/down within the same parent. If the delta is + * larger then the number of children, the item is moved to the top/bottom + * of the list of children within this parent. + * + * @param int $item_id The item to be moved + * @param int $delta Number of steps to move this item, < 0 => down, > 0 => up + * @return bool True if the item was moved + */ + public function move($item_id, $delta); + + /** + * Move an item down by 1 + * + * @param int $item_id The item to be moved + * @return bool True if the item was moved + */ + public function move_down($item_id); + + /** + * Move an item up by 1 + * + * @param int $item_id The item to be moved + * @return bool True if the item was moved + */ + public function move_up($item_id); + + /** + * Moves all children of one item to another item + * + * If the new parent already has children, the new children are appended + * to the list. + * + * @param int $current_parent_id The current parent item + * @param int $new_parent_id The new parent item + * @return bool True if any items where moved + */ + public function move_children($current_parent_id, $new_parent_id); + + /** + * Change parent item + * + * Moves the item to the bottom of the new parent's list of children + * + * @param int $item_id The item to be moved + * @param int $new_parent_id The new parent item + * @return bool True if the parent was set successfully + */ + public function change_parent($item_id, $new_parent_id); + + /** + * Get all items that are either ancestors or descendants of the item + * + * @param int $item_id Id of the item to retrieve the ancestors/descendants from + * @param bool $order_asc Order the items ascendingly (most outer ancestor first) + * @param bool $include_item Should the item matching the given item id be included in the list as well + * @return array Array of items (containing all columns from the item table) + * ID => Item data + */ + public function get_path_and_subtree_data($item_id, $order_asc, $include_item); + + /** + * Get all of the item's ancestors + * + * @param int $item_id Id of the item to retrieve the ancestors from + * @param bool $order_asc Order the items ascendingly (most outer ancestor first) + * @param bool $include_item Should the item matching the given item id be included in the list as well + * @return array Array of items (containing all columns from the item table) + * ID => Item data + */ + public function get_path_data($item_id, $order_asc, $include_item); + + /** + * Get all of the item's descendants + * + * @param int $item_id Id of the item to retrieve the descendants from + * @param bool $order_asc Order the items ascendingly + * @param bool $include_item Should the item matching the given item id be included in the list as well + * @return array Array of items (containing all columns from the item table) + * ID => Item data + */ + public function get_subtree_data($item_id, $order_asc, $include_item); +} diff --git a/phpBB/includes/tree/nestedset.php b/phpBB/includes/tree/nestedset.php new file mode 100644 index 0000000000..4d851a87a8 --- /dev/null +++ b/phpBB/includes/tree/nestedset.php @@ -0,0 +1,850 @@ +<?php +/** +* +* @package tree +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +abstract class phpbb_tree_nestedset implements phpbb_tree_interface +{ + /** @var phpbb_db_driver */ + protected $db; + + /** @var phpbb_lock_db */ + protected $lock; + + /** @var string */ + protected $table_name; + + /** + * Prefix for the language keys returned by exceptions + * @var string + */ + protected $message_prefix = ''; + + /** + * Column names in the table + * @var string + */ + protected $column_item_id = 'item_id'; + protected $column_left_id = 'left_id'; + protected $column_right_id = 'right_id'; + protected $column_parent_id = 'parent_id'; + protected $column_item_parents = 'item_parents'; + + /** + * Additional SQL restrictions + * Allows to have multiple nested sets in one table + * @var string + */ + protected $sql_where = ''; + + /** + * List of item properties to be cached in the item_parents column + * @var array + */ + protected $item_basic_data = array('*'); + + /** + * Construct + * + * @param phpbb_db_driver $db Database connection + * @param phpbb_lock_db $lock Lock class used to lock the table when moving forums around + * @param string $table_name Table name + * @param string $message_prefix Prefix for the messages thrown by exceptions + * @param string $sql_where Additional SQL restrictions for the queries + * @param array $item_basic_data Array with basic item data that is stored in item_parents + * @param array $columns Array with column names to overwrite + */ + public function __construct(phpbb_db_driver $db, phpbb_lock_db $lock, $table_name, $message_prefix = '', $sql_where = '', $item_basic_data = array(), $columns = array()) + { + $this->db = $db; + $this->lock = $lock; + + $this->table_name = $table_name; + $this->message_prefix = $message_prefix; + $this->sql_where = $sql_where; + $this->item_basic_data = (!empty($item_basic_data)) ? $item_basic_data : array('*'); + + if (!empty($columns)) + { + foreach ($columns as $column => $name) + { + $column_name = 'column_' . $column; + $this->$column_name = $name; + } + } + } + + /** + * Returns additional sql where restrictions + * + * @param string $operator SQL operator that needs to be prepended to sql_where, + * if it is not empty. + * @param string $column_prefix Prefix that needs to be prepended to column names + * @return string Returns additional where statements to narrow down the tree, + * prefixed with operator and prepended column_prefix to column names + */ + public function get_sql_where($operator = 'AND', $column_prefix = '') + { + return (!$this->sql_where) ? '' : $operator . ' ' . sprintf($this->sql_where, $column_prefix); + } + + /** + * Acquires a lock on the item table + * + * @return bool True if the lock was acquired, false if it has been acquired previously + * + * @throws RuntimeException If the lock could not be acquired + */ + protected function acquire_lock() + { + if ($this->lock->owns_lock()) + { + return false; + } + + if (!$this->lock->acquire()) + { + throw new RuntimeException($this->message_prefix . 'LOCK_FAILED_ACQUIRE'); + } + + return true; + } + + /** + * @inheritdoc + */ + public function insert(array $additional_data) + { + $item_data = $this->reset_nestedset_values($additional_data); + + $sql = 'INSERT INTO ' . $this->table_name . ' ' . $this->db->sql_build_array('INSERT', $item_data); + $this->db->sql_query($sql); + + $item_data[$this->column_item_id] = (int) $this->db->sql_nextid(); + + return array_merge($item_data, $this->add_item_to_nestedset($item_data[$this->column_item_id])); + } + + /** + * Add an item which already has a database row at the end of the tree + * + * @param int $item_id The item to be added + * @return array Array with updated data, if the item was added successfully + * Empty array otherwise + */ + protected function add_item_to_nestedset($item_id) + { + $sql = 'SELECT MAX(' . $this->column_right_id . ') AS ' . $this->column_right_id . ' + FROM ' . $this->table_name . ' + ' . $this->get_sql_where('WHERE'); + $result = $this->db->sql_query($sql); + $current_max_right_id = (int) $this->db->sql_fetchfield($this->column_right_id); + $this->db->sql_freeresult($result); + + $update_item_data = array( + $this->column_parent_id => 0, + $this->column_left_id => $current_max_right_id + 1, + $this->column_right_id => $current_max_right_id + 2, + $this->column_item_parents => '', + ); + + $sql = 'UPDATE ' . $this->table_name . ' + SET ' . $this->db->sql_build_array('UPDATE', $update_item_data) . ' + WHERE ' . $this->column_item_id . ' = ' . (int) $item_id . ' + AND ' . $this->column_parent_id . ' = 0 + AND ' . $this->column_left_id . ' = 0 + AND ' . $this->column_right_id . ' = 0'; + $this->db->sql_query($sql); + + return ($this->db->sql_affectedrows() == 1) ? $update_item_data : array(); + } + + /** + * Remove an item from the tree without deleting it from the database + * + * Also removes all subitems from the tree without deleting them from the database either + * + * @param int $item_id The item to be deleted + * @return array Item ids that have been removed + */ + protected function remove_item_from_nestedset($item_id) + { + $item_id = (int) $item_id; + if (!$item_id) + { + throw new OutOfBoundsException($this->message_prefix . 'INVALID_ITEM'); + } + + $items = $this->get_subtree_data($item_id); + $item_ids = array_keys($items); + + if (empty($items) || !isset($items[$item_id])) + { + throw new OutOfBoundsException($this->message_prefix . 'INVALID_ITEM'); + } + + $this->remove_subset($item_ids, $items[$item_id]); + + return $item_ids; + } + + /** + * @inheritdoc + */ + public function delete($item_id) + { + $removed_items = $this->remove_item_from_nestedset($item_id); + + $sql = 'DELETE FROM ' . $this->table_name . ' + WHERE ' . $this->db->sql_in_set($this->column_item_id, $removed_items) . ' + ' . $this->get_sql_where('AND'); + $this->db->sql_query($sql); + + return $removed_items; + } + + /** + * @inheritdoc + */ + public function move($item_id, $delta) + { + if ($delta == 0) + { + return false; + } + + $this->acquire_lock(); + + $action = ($delta > 0) ? 'move_up' : 'move_down'; + $delta = abs($delta); + + // Keep $this->get_sql_where() here, to ensure we are in the right tree. + $sql = 'SELECT * + FROM ' . $this->table_name . ' + WHERE ' . $this->column_item_id . ' = ' . (int) $item_id . ' + ' . $this->get_sql_where(); + $result = $this->db->sql_query_limit($sql, $delta); + $item = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + if (!$item) + { + $this->lock->release(); + throw new OutOfBoundsException($this->message_prefix . 'INVALID_ITEM'); + } + + /** + * Fetch all the siblings between the item's current spot + * and where we want to move it to. If there are less than $delta + * siblings between the current spot and the target then the + * item will move as far as possible + */ + $sql = "SELECT {$this->column_item_id}, {$this->column_parent_id}, {$this->column_left_id}, {$this->column_right_id}, {$this->column_item_parents} + FROM " . $this->table_name . ' + WHERE ' . $this->column_parent_id . ' = ' . (int) $item[$this->column_parent_id] . ' + ' . $this->get_sql_where() . ' + AND '; + + if ($action == 'move_up') + { + $sql .= $this->column_right_id . ' < ' . (int) $item[$this->column_right_id] . ' ORDER BY ' . $this->column_right_id . ' DESC'; + } + else + { + $sql .= $this->column_left_id . ' > ' . (int) $item[$this->column_left_id] . ' ORDER BY ' . $this->column_left_id . ' ASC'; + } + + $result = $this->db->sql_query_limit($sql, $delta); + + $target = false; + while ($row = $this->db->sql_fetchrow($result)) + { + $target = $row; + } + $this->db->sql_freeresult($result); + + if (!$target) + { + $this->lock->release(); + // The item is already on top or bottom + return false; + } + + /** + * $left_id and $right_id define the scope of the items that are affected by the move. + * $diff_up and $diff_down are the values to substract or add to each item's left_id + * and right_id in order to move them up or down. + * $move_up_left and $move_up_right define the scope of the items that are moving + * up. Other items in the scope of ($left_id, $right_id) are considered to move down. + */ + if ($action == 'move_up') + { + $left_id = (int) $target[$this->column_left_id]; + $right_id = (int) $item[$this->column_right_id]; + + $diff_up = (int) $item[$this->column_left_id] - (int) $target[$this->column_left_id]; + $diff_down = (int) $item[$this->column_right_id] + 1 - (int) $item[$this->column_left_id]; + + $move_up_left = (int) $item[$this->column_left_id]; + $move_up_right = (int) $item[$this->column_right_id]; + } + else + { + $left_id = (int) $item[$this->column_left_id]; + $right_id = (int) $target[$this->column_right_id]; + + $diff_up = (int) $item[$this->column_right_id] + 1 - (int) $item[$this->column_left_id]; + $diff_down = (int) $target[$this->column_right_id] - (int) $item[$this->column_right_id]; + + $move_up_left = (int) $item[$this->column_right_id] + 1; + $move_up_right = (int) $target[$this->column_right_id]; + } + + // Now do the dirty job + $sql = 'UPDATE ' . $this->table_name . ' + SET ' . $this->column_left_id . ' = ' . $this->column_left_id . ' + CASE + WHEN ' . $this->column_left_id . " BETWEEN {$move_up_left} AND {$move_up_right} THEN -{$diff_up} + ELSE {$diff_down} + END, + " . $this->column_right_id . ' = ' . $this->column_right_id . ' + CASE + WHEN ' . $this->column_right_id . " BETWEEN {$move_up_left} AND {$move_up_right} THEN -{$diff_up} + ELSE {$diff_down} + END + WHERE + " . $this->column_left_id . " BETWEEN {$left_id} AND {$right_id} + AND " . $this->column_right_id . " BETWEEN {$left_id} AND {$right_id} + " . $this->get_sql_where(); + $this->db->sql_query($sql); + + $this->lock->release(); + + return true; + } + + /** + * @inheritdoc + */ + public function move_down($item_id) + { + return $this->move($item_id, -1); + } + + /** + * @inheritdoc + */ + public function move_up($item_id) + { + return $this->move($item_id, 1); + } + + /** + * @inheritdoc + */ + public function move_children($current_parent_id, $new_parent_id) + { + $current_parent_id = (int) $current_parent_id; + $new_parent_id = (int) $new_parent_id; + + if ($current_parent_id == $new_parent_id) + { + return false; + } + + if (!$current_parent_id) + { + throw new OutOfBoundsException($this->message_prefix . 'INVALID_ITEM'); + } + + $this->acquire_lock(); + + $item_data = $this->get_subtree_data($current_parent_id); + if (!isset($item_data[$current_parent_id])) + { + $this->lock->release(); + throw new OutOfBoundsException($this->message_prefix . 'INVALID_ITEM'); + } + + $current_parent = $item_data[$current_parent_id]; + unset($item_data[$current_parent_id]); + $move_items = array_keys($item_data); + + if (($current_parent[$this->column_right_id] - $current_parent[$this->column_left_id]) <= 1) + { + $this->lock->release(); + return false; + } + + if (in_array($new_parent_id, $move_items)) + { + $this->lock->release(); + throw new OutOfBoundsException($this->message_prefix . 'INVALID_PARENT'); + } + + $diff = sizeof($move_items) * 2; + $sql_exclude_moved_items = $this->db->sql_in_set($this->column_item_id, $move_items, true); + + $this->db->sql_transaction('begin'); + + $this->remove_subset($move_items, $current_parent, false, true); + + if ($new_parent_id) + { + // Retrieve new-parent again, it may have been changed... + $sql = 'SELECT * + FROM ' . $this->table_name . ' + WHERE ' . $this->column_item_id . ' = ' . $new_parent_id; + $result = $this->db->sql_query($sql); + $new_parent = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + if (!$new_parent) + { + $this->db->sql_transaction('rollback'); + $this->lock->release(); + throw new OutOfBoundsException($this->message_prefix . 'INVALID_PARENT'); + } + + $new_right_id = $this->prepare_adding_subset($move_items, $new_parent, true); + + if ($new_right_id > $current_parent[$this->column_right_id]) + { + $diff = ' + ' . ($new_right_id - $current_parent[$this->column_right_id]); + } + else + { + $diff = ' - ' . abs($new_right_id - $current_parent[$this->column_right_id]); + } + } + else + { + $sql = 'SELECT MAX(' . $this->column_right_id . ') AS ' . $this->column_right_id . ' + FROM ' . $this->table_name . ' + WHERE ' . $sql_exclude_moved_items . ' + ' . $this->get_sql_where('AND'); + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $diff = ' + ' . ($row[$this->column_right_id] - $current_parent[$this->column_left_id]); + } + + $sql = 'UPDATE ' . $this->table_name . ' + SET ' . $this->column_left_id . ' = ' . $this->column_left_id . $diff . ', + ' . $this->column_right_id . ' = ' . $this->column_right_id . $diff . ', + ' . $this->column_parent_id . ' = ' . $this->db->sql_case($this->column_parent_id . ' = ' . $current_parent_id, $new_parent_id, $this->column_parent_id) . ', + ' . $this->column_item_parents . " = '' + WHERE " . $this->db->sql_in_set($this->column_item_id, $move_items) . ' + ' . $this->get_sql_where('AND'); + $this->db->sql_query($sql); + + $this->db->sql_transaction('commit'); + $this->lock->release(); + + return true; + } + + /** + * @inheritdoc + */ + public function change_parent($item_id, $new_parent_id) + { + $item_id = (int) $item_id; + $new_parent_id = (int) $new_parent_id; + + if ($item_id == $new_parent_id) + { + return false; + } + + if (!$item_id) + { + throw new OutOfBoundsException($this->message_prefix . 'INVALID_ITEM'); + } + + $this->acquire_lock(); + + $item_data = $this->get_subtree_data($item_id); + if (!isset($item_data[$item_id])) + { + $this->lock->release(); + throw new OutOfBoundsException($this->message_prefix . 'INVALID_ITEM'); + } + + $item = $item_data[$item_id]; + $move_items = array_keys($item_data); + + if (in_array($new_parent_id, $move_items)) + { + $this->lock->release(); + throw new OutOfBoundsException($this->message_prefix . 'INVALID_PARENT'); + } + + $diff = sizeof($move_items) * 2; + $sql_exclude_moved_items = $this->db->sql_in_set($this->column_item_id, $move_items, true); + + $this->db->sql_transaction('begin'); + + $this->remove_subset($move_items, $item, false, true); + + if ($new_parent_id) + { + // Retrieve new-parent again, it may have been changed... + $sql = 'SELECT * + FROM ' . $this->table_name . ' + WHERE ' . $this->column_item_id . ' = ' . $new_parent_id; + $result = $this->db->sql_query($sql); + $new_parent = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + if (!$new_parent) + { + $this->db->sql_transaction('rollback'); + $this->lock->release(); + throw new OutOfBoundsException($this->message_prefix . 'INVALID_PARENT'); + } + + $new_right_id = $this->prepare_adding_subset($move_items, $new_parent, true); + + if ($new_right_id > (int) $item[$this->column_right_id]) + { + $diff = ' + ' . ($new_right_id - (int) $item[$this->column_right_id] - 1); + } + else + { + $diff = ' - ' . abs($new_right_id - (int) $item[$this->column_right_id] - 1); + } + } + else + { + $sql = 'SELECT MAX(' . $this->column_right_id . ') AS ' . $this->column_right_id . ' + FROM ' . $this->table_name . ' + WHERE ' . $sql_exclude_moved_items . ' + ' . $this->get_sql_where('AND'); + $result = $this->db->sql_query($sql); + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $diff = ' + ' . ($row[$this->column_right_id] - (int) $item[$this->column_left_id] + 1); + } + + $sql = 'UPDATE ' . $this->table_name . ' + SET ' . $this->column_left_id . ' = ' . $this->column_left_id . $diff . ', + ' . $this->column_right_id . ' = ' . $this->column_right_id . $diff . ', + ' . $this->column_parent_id . ' = ' . $this->db->sql_case($this->column_item_id . ' = ' . $item_id, $new_parent_id, $this->column_parent_id) . ', + ' . $this->column_item_parents . " = '' + WHERE " . $this->db->sql_in_set($this->column_item_id, $move_items) . ' + ' . $this->get_sql_where('AND'); + $this->db->sql_query($sql); + + $this->db->sql_transaction('commit'); + $this->lock->release(); + + return true; + } + + /** + * @inheritdoc + */ + public function get_path_and_subtree_data($item_id, $order_asc = true, $include_item = true) + { + $condition = 'i2.' . $this->column_left_id . ' BETWEEN i1.' . $this->column_left_id . ' AND i1.' . $this->column_right_id . ' + OR i1.' . $this->column_left_id . ' BETWEEN i2.' . $this->column_left_id . ' AND i2.' . $this->column_right_id; + + return $this->get_set_of_nodes_data($item_id, $condition, $order_asc, $include_item); + } + + /** + * @inheritdoc + */ + public function get_path_data($item_id, $order_asc = true, $include_item = true) + { + $condition = 'i1.' . $this->column_left_id . ' BETWEEN i2.' . $this->column_left_id . ' AND i2.' . $this->column_right_id . ''; + + return $this->get_set_of_nodes_data($item_id, $condition, $order_asc, $include_item); + } + + /** + * @inheritdoc + */ + public function get_subtree_data($item_id, $order_asc = true, $include_item = true) + { + $condition = 'i2.' . $this->column_left_id . ' BETWEEN i1.' . $this->column_left_id . ' AND i1.' . $this->column_right_id . ''; + + return $this->get_set_of_nodes_data($item_id, $condition, $order_asc, $include_item); + } + + /** + * Get items that are related to the given item by the condition + * + * @param int $item_id Id of the item to retrieve the node set from + * @param string $condition Query string restricting the item list + * @param bool $order_asc Order the items ascending by their left_id + * @param bool $include_item Should the item matching the given item id be included in the list as well + * @return array Array of items (containing all columns from the item table) + * ID => Item data + */ + protected function get_set_of_nodes_data($item_id, $condition, $order_asc = true, $include_item = true) + { + $rows = array(); + + $sql = 'SELECT i2.* + FROM ' . $this->table_name . ' i1 + LEFT JOIN ' . $this->table_name . " i2 + ON (($condition) " . $this->get_sql_where('AND', 'i2.') . ') + WHERE i1.' . $this->column_item_id . ' = ' . (int) $item_id . ' + ' . $this->get_sql_where('AND', 'i1.') . ' + ORDER BY i2.' . $this->column_left_id . ' ' . ($order_asc ? 'ASC' : 'DESC'); + $result = $this->db->sql_query($sql); + + while ($row = $this->db->sql_fetchrow($result)) + { + if (!$include_item && $item_id == $row[$this->column_item_id]) + { + continue; + } + + $rows[(int) $row[$this->column_item_id]] = $row; + } + $this->db->sql_freeresult($result); + + return $rows; + } + + /** + * Get basic data of all parent items + * + * Basic data is defined in the $item_basic_data property. + * Data is cached in the item_parents column in the item table + * + * @param array $item The item to get the path from + * @return array Array of items (containing basic columns from the item table) + * ID => Item data + */ + public function get_path_basic_data(array $item) + { + $parents = array(); + if ($item[$this->column_parent_id]) + { + if (!$item[$this->column_item_parents]) + { + $sql = 'SELECT ' . implode(', ', $this->item_basic_data) . ' + FROM ' . $this->table_name . ' + WHERE ' . $this->column_left_id . ' < ' . (int) $item[$this->column_left_id] . ' + AND ' . $this->column_right_id . ' > ' . (int) $item[$this->column_right_id] . ' + ' . $this->get_sql_where('AND') . ' + ORDER BY ' . $this->column_left_id . ' ASC'; + $result = $this->db->sql_query($sql); + + while ($row = $this->db->sql_fetchrow($result)) + { + $parents[$row[$this->column_item_id]] = $row; + } + $this->db->sql_freeresult($result); + + $item_parents = serialize($parents); + + $sql = 'UPDATE ' . $this->table_name . ' + SET ' . $this->column_item_parents . " = '" . $this->db->sql_escape($item_parents) . "' + WHERE " . $this->column_parent_id . ' = ' . (int) $item[$this->column_parent_id]; + $this->db->sql_query($sql); + } + else + { + $parents = unserialize($item[$this->column_item_parents]); + } + } + + return $parents; + } + + /** + * Remove a subset from the nested set + * + * @param array $subset_items Subset of items to remove + * @param array $bounding_item Item containing the right bound of the subset + * @param bool $set_subset_zero Should the parent, left and right id of the items be set to 0, or kept unchanged? + * In case of removing an item from the tree, we should the values to 0 + * In case of moving an item, we shouldkeep the original values, in order to allow "+ diff" later + * @return null + */ + protected function remove_subset(array $subset_items, array $bounding_item, $set_subset_zero = true) + { + $acquired_new_lock = $this->acquire_lock(); + + $diff = sizeof($subset_items) * 2; + $sql_subset_items = $this->db->sql_in_set($this->column_item_id, $subset_items); + $sql_not_subset_items = $this->db->sql_in_set($this->column_item_id, $subset_items, true); + + $sql_is_parent = $this->column_left_id . ' <= ' . (int) $bounding_item[$this->column_right_id] . ' + AND ' . $this->column_right_id . ' >= ' . (int) $bounding_item[$this->column_right_id]; + + $sql_is_right = $this->column_left_id . ' > ' . (int) $bounding_item[$this->column_right_id]; + + $set_left_id = $this->db->sql_case($sql_is_right, $this->column_left_id . ' - ' . $diff, $this->column_left_id); + $set_right_id = $this->db->sql_case($sql_is_parent . ' OR ' . $sql_is_right, $this->column_right_id . ' - ' . $diff, $this->column_right_id); + + if ($set_subset_zero) + { + $set_left_id = $this->db->sql_case($sql_subset_items, 0, $set_left_id); + $set_right_id = $this->db->sql_case($sql_subset_items, 0, $set_right_id); + } + + $sql = 'UPDATE ' . $this->table_name . ' + SET ' . (($set_subset_zero) ? $this->column_parent_id . ' = ' . $this->db->sql_case($sql_subset_items, 0, $this->column_parent_id) . ',' : '') . ' + ' . $this->column_left_id . ' = ' . $set_left_id . ', + ' . $this->column_right_id . ' = ' . $set_right_id . ' + ' . ((!$set_subset_zero) ? ' WHERE ' . $sql_not_subset_items . ' ' . $this->get_sql_where('AND') : $this->get_sql_where('WHERE')); + $this->db->sql_query($sql); + + if ($acquired_new_lock) + { + $this->lock->release(); + } + } + + /** + * Prepare adding a subset to the nested set + * + * @param array $subset_items Subset of items to add + * @param array $new_parent Item containing the right bound of the new parent + * @return int New right id of the parent item + */ + protected function prepare_adding_subset(array $subset_items, array $new_parent) + { + $diff = sizeof($subset_items) * 2; + $sql_not_subset_items = $this->db->sql_in_set($this->column_item_id, $subset_items, true); + + $set_left_id = $this->db->sql_case($this->column_left_id . ' > ' . (int) $new_parent[$this->column_right_id], $this->column_left_id . ' + ' . $diff, $this->column_left_id); + $set_right_id = $this->db->sql_case($this->column_right_id . ' >= ' . (int) $new_parent[$this->column_right_id], $this->column_right_id . ' + ' . $diff, $this->column_right_id); + + $sql = 'UPDATE ' . $this->table_name . ' + SET ' . $this->column_left_id . ' = ' . $set_left_id . ', + ' . $this->column_right_id . ' = ' . $set_right_id . ' + WHERE ' . $sql_not_subset_items . ' + ' . $this->get_sql_where('AND'); + $this->db->sql_query($sql); + + return $new_parent[$this->column_right_id] + $diff; + } + + /** + * Resets values required for the nested set system + * + * @param array $item Original item data + * @return array Original item data + nested set defaults + */ + protected function reset_nestedset_values(array $item) + { + $item_data = array_merge($item, array( + $this->column_parent_id => 0, + $this->column_left_id => 0, + $this->column_right_id => 0, + $this->column_item_parents => '', + )); + + unset($item_data[$this->column_item_id]); + + return $item_data; + } + + /** + * Regenerate left/right ids from parent/child relationship + * + * This method regenerates the left/right ids for the tree based on + * the parent/child relations. This function executes three queries per + * item, so it should only be called, when the set has one of the following + * problems: + * - The set has a duplicated value inside the left/right id chain + * - The set has a missing value inside the left/right id chain + * - The set has items that do not have a left/right id set + * + * When regenerating the items, the items are sorted by parent id and their + * current left id, so the current child/parent relationships are kept + * and running the function on a working set will not change the order. + * + * @param int $new_id First left_id to be used (should start with 1) + * @param int $parent_id parent_id of the current set (default = 0) + * @param bool $reset_ids Should we reset all left_id/right_id on the first call? + * @return int $new_id The next left_id/right_id that should be used + */ + public function regenerate_left_right_ids($new_id, $parent_id = 0, $reset_ids = false) + { + if ($acquired_new_lock = $this->acquire_lock()) + { + $this->db->sql_transaction('begin'); + + if (!$reset_ids) + { + $sql = 'UPDATE ' . $this->table_name . ' + SET ' . $this->column_item_parents . " = '' + " . $this->get_sql_where('WHERE'); + $this->db->sql_query($sql); + } + } + + if ($reset_ids) + { + $sql = 'UPDATE ' . $this->table_name . ' + SET ' . $this->db->sql_build_array('UPDATE', array( + $this->column_left_id => 0, + $this->column_right_id => 0, + $this->column_item_parents => '', + )) . ' + ' . $this->get_sql_where('WHERE'); + $this->db->sql_query($sql); + } + + $sql = 'SELECT * + FROM ' . $this->table_name . ' + WHERE ' . $this->column_parent_id . ' = ' . (int) $parent_id . ' + ' . $this->get_sql_where('AND') . ' + ORDER BY ' . $this->column_left_id . ', ' . $this->column_item_id . ' ASC'; + $result = $this->db->sql_query($sql); + while ($row = $this->db->sql_fetchrow($result)) + { + // First we update the left_id for this module + if ($row[$this->column_left_id] != $new_id) + { + $sql = 'UPDATE ' . $this->table_name . ' + SET ' . $this->db->sql_build_array('UPDATE', array($this->column_left_id => $new_id)) . ' + WHERE ' . $this->column_item_id . ' = ' . (int) $row[$this->column_item_id]; + $this->db->sql_query($sql); + } + $new_id++; + + // Then we go through any children and update their left/right id's + $new_id = $this->regenerate_left_right_ids($new_id, $row[$this->column_item_id]); + + // Then we come back and update the right_id for this module + if ($row[$this->column_right_id] != $new_id) + { + $sql = 'UPDATE ' . $this->table_name . ' + SET ' . $this->db->sql_build_array('UPDATE', array($this->column_right_id => $new_id)) . ' + WHERE ' . $this->column_item_id . ' = ' . (int) $row[$this->column_item_id]; + $this->db->sql_query($sql); + } + $new_id++; + } + $this->db->sql_freeresult($result); + + if ($acquired_new_lock) + { + $this->db->sql_transaction('commit'); + $this->lock->release(); + } + + return $new_id; + } +} diff --git a/phpBB/includes/tree/nestedset_forum.php b/phpBB/includes/tree/nestedset_forum.php new file mode 100644 index 0000000000..ff09ef55d0 --- /dev/null +++ b/phpBB/includes/tree/nestedset_forum.php @@ -0,0 +1,46 @@ +<?php +/** +* +* @package tree +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +class phpbb_tree_nestedset_forum extends phpbb_tree_nestedset +{ + /** + * Construct + * + * @param phpbb_db_driver $db Database connection + * @param phpbb_lock_db $lock Lock class used to lock the table when moving forums around + * @param string $table_name Table name + */ + public function __construct(phpbb_db_driver $db, phpbb_lock_db $lock, $table_name) + { + parent::__construct( + $db, + $lock, + $table_name, + 'FORUM_NESTEDSET_', + '', + array( + 'forum_id', + 'forum_name', + 'forum_type', + ), + array( + 'item_id' => 'forum_id', + 'item_parents' => 'forum_parents', + ) + ); + } +} diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index c2d12d17c2..e0e7a46494 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -265,19 +265,16 @@ function compose_pm($id, $mode, $action, $user_folders = array()) // Passworded forum? if ($post['forum_id']) { - $sql = 'SELECT forum_password + $sql = 'SELECT forum_id, forum_name, forum_password FROM ' . FORUMS_TABLE . ' WHERE forum_id = ' . (int) $post['forum_id']; $result = $db->sql_query($sql); - $forum_password = (string) $db->sql_fetchfield('forum_password'); + $forum_data = $db->sql_fetchrow($result); $db->sql_freeresult($result); - if ($forum_password) + if (!empty($forum_data['forum_password'])) { - login_forum_box(array( - 'forum_id' => $post['forum_id'], - 'forum_password' => $forum_password, - )); + login_forum_box($forum_data); } } } diff --git a/phpBB/language/en/acp/prune.php b/phpBB/language/en/acp/prune.php index fcc085205b..3e890182c0 100644 --- a/phpBB/language/en/acp/prune.php +++ b/phpBB/language/en/acp/prune.php @@ -51,7 +51,7 @@ $lang = array_merge($lang, array( 'LAST_ACTIVE_EXPLAIN' => 'Enter a date in <kbd>YYYY-MM-DD</kbd> format. Enter <kbd>0000-00-00</kbd> to prune users who never logged in, <em>Before</em> and <em>After</em> conditions will be ignored.', 'POSTS_ON_QUEUE' => 'Posts Awaiting Approval', - 'PRUNE_USERS_GROUP_EXPLAIN' => 'Selects all members of the group for pruning.', + 'PRUNE_USERS_GROUP_EXPLAIN' => 'Limit to users within the selected group.', 'PRUNE_USERS_LIST' => 'Users to be pruned', 'PRUNE_USERS_LIST_DELETE' => 'With the selected critera for pruning users the following accounts will be removed. You can remove individual users from the deletion list by unchecking the box next to their username.', 'PRUNE_USERS_LIST_DEACTIVATE' => 'With the selected critera for pruning users the following accounts will be deactivated. You can remove individual users from the deactivation list by unchecking the box next to their username.', diff --git a/phpBB/posting.php b/phpBB/posting.php index d32f7e33d9..c6b9ff4cce 100644 --- a/phpBB/posting.php +++ b/phpBB/posting.php @@ -228,6 +228,7 @@ if ($post_data['forum_password']) { login_forum_box(array( 'forum_id' => $forum_id, + 'forum_name' => $post_data['forum_name'], 'forum_password' => $post_data['forum_password']) ); } diff --git a/phpBB/styles/prosilver/template/confirm_body.html b/phpBB/styles/prosilver/template/confirm_body.html index eb0cad2597..bf575c20fa 100644 --- a/phpBB/styles/prosilver/template/confirm_body.html +++ b/phpBB/styles/prosilver/template/confirm_body.html @@ -4,7 +4,7 @@ <p>{MESSAGE_TEXT}</p> <fieldset class="submit-buttons"> - <input type="button" name="confirm" value="{L_YES}" class="button1" /> + <input type="button" name="confirm" value="{L_YES}" class="button2" /> <input type="button" name="cancel" value="{L_NO}" class="button2" /> </fieldset> diff --git a/phpBB/styles/prosilver/template/editor.js b/phpBB/styles/prosilver/template/editor.js index 93506b8d4a..0a749347ad 100644 --- a/phpBB/styles/prosilver/template/editor.js +++ b/phpBB/styles/prosilver/template/editor.js @@ -298,9 +298,12 @@ function storeCaret(textEl) { * Color pallette */ function colorPalette(dir, width, height) { - var r = 0, g = 0, b = 0; - var numberList = new Array(6); - var color = ''; + var r = 0, + g = 0, + b = 0, + numberList = new Array(6); + color = '', + html = ''; numberList[0] = '00'; numberList[1] = '40'; @@ -308,37 +311,46 @@ function colorPalette(dir, width, height) { numberList[3] = 'BF'; numberList[4] = 'FF'; - document.writeln('<table cellspacing="1" cellpadding="0" border="0">'); + html += '<table cellspacing="1" cellpadding="0" border="0">'; for (r = 0; r < 5; r++) { - if (dir === 'h') { - document.writeln('<tr>'); + if (dir == 'h') { + html += '<tr>'; } for (g = 0; g < 5; g++) { - if (dir === 'v') { - document.writeln('<tr>'); + if (dir == 'v') { + html += '<tr>'; } for (b = 0; b < 5; b++) { color = String(numberList[r]) + String(numberList[g]) + String(numberList[b]); - document.write('<td bgcolor="#' + color + '" style="width: ' + width + 'px; height: ' + height + 'px;">'); - document.write('<a href="#" onclick="bbfontstyle(\'[color=#' + color + ']\', \'[/color]\'); return false;"><img src="images/spacer.gif" width="' + width + '" height="' + height + '" alt="#' + color + '" title="#' + color + '" /></a>'); - document.writeln('</td>'); + html += '<td bgcolor="#' + color + '" style="width: ' + width + 'px; height: ' + height + 'px;">'; + html += '<a href="#" onclick="bbfontstyle(\'[color=#' + color + ']\', \'[/color]\'); return false;" style="display: block; width: ' + width + 'px; height: ' + height + 'px; " alt="#' + color + '" title="#' + color + '"></a>'; + html += '</td>'; } - if (dir === 'v') { - document.writeln('</tr>'); + if (dir == 'v') { + html += '</tr>'; } } - if (dir === 'h') { - document.writeln('</tr>'); + if (dir == 'h') { + html += '</tr>'; } } - document.writeln('</table>'); + html += '</table>'; + return html; } +(function($) { + $(document).ready(function() { + $('#color_palette_placeholder').each(function() { + $(this).html(colorPalette('h', 15, 12)); + }); + }); +})(jQuery); + /** * Caret Position object */ diff --git a/phpBB/styles/prosilver/template/login_forum.html b/phpBB/styles/prosilver/template/login_forum.html index 63f0b2e0f7..c83a625b3f 100644 --- a/phpBB/styles/prosilver/template/login_forum.html +++ b/phpBB/styles/prosilver/template/login_forum.html @@ -1,31 +1,36 @@ <!-- INCLUDE overall_header.html --> -<h2 class="solo">{L_LOGIN} {FORUM_NAME}</h2> +<!-- IF FORUM_NAME --><h2><a href="{U_VIEW_FORUM}">{FORUM_NAME}</a></h2><!-- ENDIF --> <form id="login_forum" method="post" action="{S_LOGIN_ACTION}"> {S_FORM_TOKEN} <div class="panel"> <div class="inner"> - <p>{L_LOGIN_FORUM}</p> - - <fieldset class="fields2"> - <!-- IF LOGIN_ERROR --> - <dl> - <dt> </dt> - <dd class="error">{LOGIN_ERROR}</dd> - </dl> - <!-- ENDIF --> - <dl> - <dt><label for="password">{L_PASSWORD}{L_COLON}</label></dt> - <dd><input class="inputbox narrow" type="password" name="password" id="password" size="25" tabindex="1" /></dd> - </dl> - <dl class="fields2"> - <dt> </dt> - <dd>{S_HIDDEN_FIELDS}<input type="submit" name="login" id="login" class="button1" value="{L_LOGIN}" tabindex="2" /></dd> - </dl> - {S_LOGIN_REDIRECT} - </fieldset> + <div class="content"> + <h2>{L_LOGIN}</h2> + + <p>{L_LOGIN_FORUM}</p> + + <fieldset class="fields1"> + <!-- IF LOGIN_ERROR --> + <dl> + <dt> </dt> + <dd class="error">{LOGIN_ERROR}</dd> + </dl> + <!-- ENDIF --> + + <dl> + <dt><label for="password">{L_PASSWORD}{L_COLON}</label></dt> + <dd><input type="password" tabindex="1" id="password" name="password" size="25" class="inputbox narrow" /></dd> + </dl> + {S_LOGIN_REDIRECT} + <dl> + <dt> </dt> + <dd>{S_HIDDEN_FIELDS}<input type="submit" name="login" id="login" class="button1" value="{L_LOGIN}" tabindex="2" /></dd> + </dl> + </fieldset> + </div> </div> </div> diff --git a/phpBB/styles/prosilver/template/posting_buttons.html b/phpBB/styles/prosilver/template/posting_buttons.html index 8e87407757..fadbc9b3ca 100644 --- a/phpBB/styles/prosilver/template/posting_buttons.html +++ b/phpBB/styles/prosilver/template/posting_buttons.html @@ -35,37 +35,30 @@ var panels = new Array('options-panel', 'attach-panel', 'poll-panel'); var show_panel = 'options-panel'; + function change_palette() + { + dE('colour_palette'); + e = document.getElementById('colour_palette'); + + if (e.style.display == 'block') + { + document.getElementById('bbpalette').value = '{LA_FONT_COLOR_HIDE}'; + } + else + { + document.getElementById('bbpalette').value = '{LA_FONT_COLOR}'; + } + } // ]]> </script> -<script type="text/javascript" src="{T_SUPER_TEMPLATE_PATH}/editor.js"></script> +<!-- INCLUDEJS template/editor.js --> <!-- IF S_BBCODE_ALLOWED --> <div id="colour_palette" style="display: none;"> <dl style="clear: left;"> <dt><label>{L_FONT_COLOR}{L_COLON}</label></dt> - <dd> - <script type="text/javascript"> - // <![CDATA[ - function change_palette() - { - dE('colour_palette'); - e = document.getElementById('colour_palette'); - - if (e.style.display == 'block') - { - document.getElementById('bbpalette').value = '{LA_FONT_COLOR_HIDE}'; - } - else - { - document.getElementById('bbpalette').value = '{LA_FONT_COLOR}'; - } - } - - colorPalette('h', 15, 10); - // ]]> - </script> - </dd> + <dd id="color_palette_placeholder"></dd> </dl> </div> diff --git a/phpBB/styles/prosilver/theme/common.css b/phpBB/styles/prosilver/theme/common.css index ed462c770d..26ec23b2e6 100644 --- a/phpBB/styles/prosilver/theme/common.css +++ b/phpBB/styles/prosilver/theme/common.css @@ -476,6 +476,8 @@ dl.details dd { margin-bottom: 5px; float: left; width: 65%; + overflow: hidden; + text-overflow: ellipsis; } .clearfix, #tabs, #minitabs, fieldset dl, ul.topiclist dl, dl.polls { diff --git a/phpBB/styles/prosilver/theme/content.css b/phpBB/styles/prosilver/theme/content.css index b6012f8a63..bf9e587ce1 100644 --- a/phpBB/styles/prosilver/theme/content.css +++ b/phpBB/styles/prosilver/theme/content.css @@ -669,6 +669,11 @@ fieldset.polls dd div { margin-left: 8px; } +.postprofile dd { + overflow: hidden; + text-overflow: ellipsis; +} + .postprofile strong { font-weight: normal; } diff --git a/phpBB/styles/subsilver2/template/confirm_body.html b/phpBB/styles/subsilver2/template/confirm_body.html index 7516196b3c..1712017c38 100644 --- a/phpBB/styles/subsilver2/template/confirm_body.html +++ b/phpBB/styles/subsilver2/template/confirm_body.html @@ -9,7 +9,7 @@ <th>{MESSAGE_TITLE}</th> </tr> <tr> - <td class="row1" align="center"><br /><p class="gen">{MESSAGE_TEXT}</p><br />{S_HIDDEN_FIELDS}<input type="submit" name="confirm" value="{YES_VALUE}" class="btnmain" /> <input type="submit" name="cancel" value="{L_NO}" class="btnlite" /></td> + <td class="row1" align="center"><br /><p class="gen">{MESSAGE_TEXT}</p><br />{S_HIDDEN_FIELDS}<input type="submit" name="confirm" value="{YES_VALUE}" class="btnlite" /> <input type="submit" name="cancel" value="{L_NO}" class="btnlite" /></td> </tr> </table> diff --git a/phpBB/styles/subsilver2/template/login_forum.html b/phpBB/styles/subsilver2/template/login_forum.html index c9b2c7277e..9a141fc295 100644 --- a/phpBB/styles/subsilver2/template/login_forum.html +++ b/phpBB/styles/subsilver2/template/login_forum.html @@ -1,5 +1,13 @@ <!-- INCLUDE overall_header.html --> +<!-- IF FORUM_NAME --> + <div id="pageheader"> + <h2><a class="titles" href="{U_VIEW_FORUM}">{FORUM_NAME}</a></h2> + </div> + + <br clear="all" /><br /> +<!-- ENDIF --> + <div id="pagecontent"> <form name="login_forum" method="post" action="{S_LOGIN_ACTION}"> diff --git a/tests/extension/metadata_manager_test.php b/tests/extension/metadata_manager_test.php index 05d1cbccc3..2f38a26217 100644 --- a/tests/extension/metadata_manager_test.php +++ b/tests/extension/metadata_manager_test.php @@ -7,7 +7,9 @@ * */ -class metadata_manager_test extends phpbb_database_test_case +require_once dirname(__FILE__) . '/../../phpBB/includes/db/db_tools.php'; + +class phpbb_extension_metadata_manager_test extends phpbb_database_test_case { protected $class_loader; protected $extension_manager; @@ -416,31 +418,16 @@ class metadata_manager_test extends phpbb_database_test_case * Get an instance of the metadata manager * * @param string $ext_name - * @return phpbb_extension_metadata_manager_test + * @return phpbb_mock_metadata_manager */ private function get_metadata_manager($ext_name) { - return new phpbb_extension_metadata_manager_test( + return new phpbb_mock_metadata_manager( $ext_name, - $this->db, + $this->config, $this->extension_manager, - $this->phpbb_root_path, - $this->phpEx, $this->template, - $this->config + $this->phpbb_root_path ); } } - -class phpbb_extension_metadata_manager_test extends phpbb_extension_metadata_manager -{ - public function set_metadata($metadata) - { - $this->metadata = $metadata; - } - - public function merge_metadata($metadata) - { - $this->metadata = array_merge($this->metadata, $metadata); - } -}
\ No newline at end of file diff --git a/tests/functional/fixtures/ext/foo/bar/composer.json b/tests/functional/fixtures/ext/foo/bar/composer.json new file mode 100644 index 0000000000..067a9d38eb --- /dev/null +++ b/tests/functional/fixtures/ext/foo/bar/composer.json @@ -0,0 +1,23 @@ +{ + "name": "foo/bar", + "type": "phpbb3-extension", + "description": "Testing extensions", + "homepage": "", + "version": "1.0.0", + "time": "2013-03-21 01:01:01", + "licence": "GPL-2.0", + "authors": [{ + "name": "Joas Schilling", + "username": "nickvergessen", + "email": "nickvergessen@phpbb.com", + "homepage": "http://www.phpbb.com", + "role": "Developer" + }], + "require": { + "php": ">=5.3", + "phpbb": ">=3.1.0-dev" + }, + "extra": { + "display-name": "phpBB 3.1 Extension Testing" + } +} diff --git a/tests/functional/metadata_manager_test.php b/tests/functional/metadata_manager_test.php new file mode 100644 index 0000000000..0125886e04 --- /dev/null +++ b/tests/functional/metadata_manager_test.php @@ -0,0 +1,111 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +require_once dirname(__FILE__) . '/../../phpBB/includes/db/db_tools.php'; + +/** +* @group functional +*/ +class phpbb_functional_metadata_manager_test extends phpbb_functional_test_case +{ + protected $phpbb_extension_manager; + + static private $helpers; + + static protected $fixtures = array( + 'foo/bar/', + ); + + /** + * This should only be called once before the tests are run. + * This is used to copy the fixtures to the phpBB install + */ + static public function setUpBeforeClass() + { + global $phpbb_root_path; + parent::setUpBeforeClass(); + + self::$helpers = new phpbb_test_case_helpers(self); + + if (!file_exists($phpbb_root_path . 'ext/foo/bar/')) + { + self::$helpers->makedirs($phpbb_root_path . 'ext/foo/bar/'); + } + + foreach (self::$fixtures as $fixture) + { + self::$helpers->copy_dir(dirname(__FILE__) . '/fixtures/ext/' . $fixture, $phpbb_root_path . 'ext/' . $fixture); + } + } + + /** + * This should only be called once after the tests are run. + * This is used to remove the fixtures from the phpBB install + */ + static public function tearDownAfterClass() + { + global $phpbb_root_path; + + foreach (self::$fixtures as $fixture) + { + self::$helpers->empty_dir($phpbb_root_path . 'ext/' . $fixture); + } + self::$helpers->empty_dir($phpbb_root_path . 'ext/foo/'); + } + + public function setUp() + { + parent::setUp(); + + $this->phpbb_extension_manager = $this->get_extension_manager(); + + $this->purge_cache(); + $this->phpbb_extension_manager->enable('foo/bar'); + + $this->login(); + $this->admin_login(); + $this->add_lang('acp/extensions'); + } + + public function test_extensions_list() + { + $crawler = $this->request('GET', 'adm/index.php?i=acp_extensions&mode=main&sid=' . $this->sid); + $this->assert_response_success(); + + $this->assertContains($this->lang('EXTENSIONS_EXPLAIN'), $crawler->filter('#main')->text()); + $this->assertContains('phpBB 3.1 Extension Testing', $crawler->filter('#main')->text()); + $this->assertContains('Details', $crawler->filter('#main')->text()); + } + + public function test_extensions_details() + { + $crawler = $this->request('GET', 'adm/index.php?i=acp_extensions&mode=main&action=details&ext_name=foo%2Fbar&sid=' . $this->sid); + $this->assert_response_success(); + + // Test whether the details are displayed + $this->assertContains($this->lang('CLEAN_NAME'), $crawler->filter('#main')->text()); + $this->assertContains('foo/bar', $crawler->filter('#meta_name')->text()); + + $this->assertContains($this->lang('PHP_VERSION'), $crawler->filter('#main')->text()); + $this->assertContains('>=5.3', $crawler->filter('#require_php')->text()); + // Details should be html escaped + // However, text() only returns the displayed text, so HTML Special Chars are decoded. + // So we test this directly on the content of the response. + $this->assertContains('<p id="require_php">>=5.3</p>', $this->client->getResponse()->getContent()); + } + + public function test_extensions_details_notexists() + { + $crawler = $this->request('GET', 'adm/index.php?i=acp_extensions&mode=main&action=details&ext_name=not%2Fexists&sid=' . $this->sid); + $this->assert_response_success(); + + // Error message because the files do not exist + $this->assertContains('The required file does not exist:', $crawler->filter('#main')->text()); + } +} diff --git a/tests/lock/db_test.php b/tests/lock/db_test.php index f7b1557a0c..de7a23fd05 100644 --- a/tests/lock/db_test.php +++ b/tests/lock/db_test.php @@ -32,13 +32,18 @@ class phpbb_lock_db_test extends phpbb_database_test_case public function test_new_lock() { + $this->assertFalse($this->lock->owns_lock()); + $this->assertTrue($this->lock->acquire()); + $this->assertTrue($this->lock->owns_lock()); $this->assertTrue(isset($this->config['test_lock']), 'Lock was created'); $lock2 = new phpbb_lock_db('test_lock', $this->config, $this->db); $this->assertFalse($lock2->acquire()); + $this->assertFalse($lock2->owns_lock()); $this->lock->release(); + $this->assertFalse($this->lock->owns_lock()); $this->assertEquals('0', $this->config['test_lock'], 'Lock was released'); } @@ -50,31 +55,40 @@ class phpbb_lock_db_test extends phpbb_database_test_case public function test_double_lock() { + $this->assertFalse($this->lock->owns_lock()); + $this->assertTrue($this->lock->acquire()); + $this->assertTrue($this->lock->owns_lock()); $this->assertTrue(isset($this->config['test_lock']), 'Lock was created'); $value = $this->config['test_lock']; $this->assertFalse($this->lock->acquire()); + $this->assertTrue($this->lock->owns_lock()); $this->assertEquals($value, $this->config['test_lock'], 'Second lock failed'); $this->lock->release(); + $this->assertFalse($this->lock->owns_lock()); $this->assertEquals('0', $this->config['test_lock'], 'Lock was released'); } public function test_double_unlock() { $this->assertTrue($this->lock->acquire()); + $this->assertTrue($this->lock->owns_lock()); $this->assertFalse(empty($this->config['test_lock']), 'First lock is acquired'); $this->lock->release(); + $this->assertFalse($this->lock->owns_lock()); $this->assertEquals('0', $this->config['test_lock'], 'First lock is released'); $lock2 = new phpbb_lock_db('test_lock', $this->config, $this->db); $this->assertTrue($lock2->acquire()); + $this->assertTrue($lock2->owns_lock()); $this->assertFalse(empty($this->config['test_lock']), 'Second lock is acquired'); $this->lock->release(); + $this->assertTrue($lock2->owns_lock()); $this->assertFalse(empty($this->config['test_lock']), 'Double release of first lock is ignored'); $lock2->release(); diff --git a/tests/lock/flock_test.php b/tests/lock/flock_test.php index 1edc96b3a4..8f0b866ab3 100644 --- a/tests/lock/flock_test.php +++ b/tests/lock/flock_test.php @@ -26,15 +26,21 @@ class phpbb_lock_flock_test extends phpbb_test_case $lock = new phpbb_lock_flock($path); $ok = $lock->acquire(); $this->assertTrue($ok); + $this->assertTrue($lock->owns_lock()); $lock->release(); + $this->assertFalse($lock->owns_lock()); $ok = $lock->acquire(); $this->assertTrue($ok); + $this->assertTrue($lock->owns_lock()); $lock->release(); + $this->assertFalse($lock->owns_lock()); $ok = $lock->acquire(); $this->assertTrue($ok); + $this->assertTrue($lock->owns_lock()); $lock->release(); + $this->assertFalse($lock->owns_lock()); } /* This hangs the process. @@ -77,15 +83,18 @@ class phpbb_lock_flock_test extends phpbb_test_case $ok = $lock->acquire(); $delta = time() - $start; $this->assertTrue($ok); + $this->assertTrue($lock->owns_lock()); $this->assertGreaterThan(0.5, $delta, 'First lock acquired too soon'); $lock->release(); + $this->assertFalse($lock->owns_lock()); // acquire again, this should be instantaneous $start = time(); $ok = $lock->acquire(); $delta = time() - $start; $this->assertTrue($ok); + $this->assertTrue($lock->owns_lock()); $this->assertLessThan(0.1, $delta, 'Second lock not acquired instantaneously'); // reap the child @@ -99,8 +108,10 @@ class phpbb_lock_flock_test extends phpbb_test_case $lock = new phpbb_lock_flock($path); $ok = $lock->acquire(); $this->assertTrue($ok); + $this->assertTrue($lock->owns_lock()); sleep(2); $lock->release(); + $this->assertFalse($lock->owns_lock()); // and go away silently pcntl_exec('/usr/bin/env', array('true')); diff --git a/tests/mock/metadata_manager.php b/tests/mock/metadata_manager.php new file mode 100644 index 0000000000..a7fbf0681c --- /dev/null +++ b/tests/mock/metadata_manager.php @@ -0,0 +1,21 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +class phpbb_mock_metadata_manager extends phpbb_extension_metadata_manager +{ + public function set_metadata($metadata) + { + $this->metadata = $metadata; + } + + public function merge_metadata($metadata) + { + $this->metadata = array_merge($this->metadata, $metadata); + } +} diff --git a/tests/search/common_test_case.php b/tests/search/common_test_case.php index dd04f7048c..029637b00b 100644 --- a/tests/search/common_test_case.php +++ b/tests/search/common_test_case.php @@ -86,6 +86,104 @@ abstract class phpbb_search_common_test_case extends phpbb_search_test_case array('-fooo', '-baar'), array(), ), + array( + 'fooo -fooo', + 'all', + true, + array('fooo', '-fooo'), + array(), + ), + array( + 'fooo fooo-', + 'all', + true, + array('fooo', 'fooo'), + array(), + ), + array( + '-fooo fooo', + 'all', + true, + array('-fooo', 'fooo'), + array(), + ), + array( + 'fooo- fooo', + 'all', + true, + array('fooo', 'fooo'), + array(), + ), + array( + 'fooo-baar fooo', + 'all', + true, + array('fooo', 'baar', 'fooo'), + array(), + ), + array( + 'fooo-baar -fooo', + 'all', + true, + array('fooo', 'baar', '-fooo'), + array(), + ), + array( + 'fooo-baar fooo-', + 'all', + true, + array('fooo', 'baar', 'fooo'), + array(), + ), + array( + 'fooo-baar baar', + 'all', + true, + array('fooo', 'baar', 'baar'), + array(), + ), + array( + 'fooo-baar -baar', + 'all', + true, + array('fooo', 'baar', '-baar'), + array(), + ), + array( + 'fooo-baar baar-', + 'all', + true, + array('fooo', 'baar', 'baar'), + array(), + ), + array( + 'fooo-baar fooo-baar', + 'all', + true, + array('fooo', 'baar', 'fooo', 'baar'), + array(), + ), + array( + 'fooo-baar -fooo-baar', + 'all', + true, + array('fooo', 'baar', '-fooo', 'baar'), + array(), + ), + array( + 'fooo-baar fooo-baar-', + 'all', + true, + array('fooo', 'baar', 'fooo', 'baar'), + array(), + ), + array( + 'fooo-baar-baaz', + 'all', + true, + array('fooo', 'baar', 'baaz'), + array(), + ), ); } diff --git a/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/event_variable_spacing.html b/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/event_variable_spacing.html new file mode 100644 index 0000000000..028f8aa0d1 --- /dev/null +++ b/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/event_variable_spacing.html @@ -0,0 +1,6 @@ +|{VARIABLE}| +{VARIABLE}|{VARIABLE}| + +|{VARIABLE} + +<div class="{VARIABLE}">test</div> diff --git a/tests/template/datasets/ext_trivial/styles/silver/template/variable_spacing.html b/tests/template/datasets/ext_trivial/styles/silver/template/variable_spacing.html new file mode 100644 index 0000000000..49d8a6b873 --- /dev/null +++ b/tests/template/datasets/ext_trivial/styles/silver/template/variable_spacing.html @@ -0,0 +1 @@ +<!-- EVENT event_variable_spacing --> diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php index 6cea9b92e3..0ac50c7f2b 100644 --- a/tests/template/template_events_test.php +++ b/tests/template/template_events_test.php @@ -16,9 +16,10 @@ class phpbb_template_template_events_test extends phpbb_template_template_test_c return array( /* array( - '', // file + '', // Description '', // dataset array(), // style names + '', // file array(), // vars array(), // block vars array(), // destroy diff --git a/tests/template/template_spacing_test.php b/tests/template/template_spacing_test.php new file mode 100644 index 0000000000..fb4161066a --- /dev/null +++ b/tests/template/template_spacing_test.php @@ -0,0 +1,91 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +require_once dirname(__FILE__) . '/template_test_case.php'; + +class phpbb_template_template_spacing_test extends phpbb_template_template_test_case +{ + public function template_data() + { + return array( + /* + array( + '', // Description + '', // dataset + array(), // style names + '', // file + array(), // vars + array(), // block vars + array(), // destroy + '', // expected result + ), + */ + array( + 'Spacing in templates', + 'ext_trivial', + array(), + 'variable_spacing.html', + array( + 'VARIABLE' => '{}', + ), + array(), + array(), + '|{}| +{}|{}| +|{} +<div class="{}">test</div>', + ), + ); + } + + /** + * @dataProvider template_data + */ + public function test_template($desc, $dataset, $style_names, $file, array $vars, array $block_vars, array $destroy, $expected) + { + // Run test + $cache_file = $this->template->cachepath . str_replace('/', '.', $file) . '.php'; + $this->run_template($file, $vars, $block_vars, $destroy, $expected, $cache_file); + } + + /** + * @dataProvider template_data + */ + public function test_event($desc, $dataset, $style_names, $file, array $vars, array $block_vars, array $destroy, $expected) + { + $this->markTestIncomplete( + 'This test will fail until PHPBB3-11435 is fixed' + ); + + // Reset the engine state + $this->setup_engine_for_events($dataset, $style_names); + + // Run test + $cache_file = $this->template->cachepath . str_replace('/', '.', $file) . '.php'; + $this->run_template($file, $vars, $block_vars, $destroy, $expected, $cache_file); + } + + protected function setup_engine_for_events($dataset, $style_names, array $new_config = array()) + { + global $phpbb_root_path, $phpEx, $user; + + $defaults = $this->config_defaults(); + $config = new phpbb_config(array_merge($defaults, $new_config)); + + $this->template_path = dirname(__FILE__) . "/datasets/$dataset/styles/silver/template"; + $this->style_resource_locator = new phpbb_style_resource_locator(); + $this->extension_manager = new phpbb_mock_filesystem_extension_manager( + dirname(__FILE__) . "/datasets/$dataset/" + ); + $this->template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, new phpbb_template_context, $this->extension_manager); + $this->style_provider = new phpbb_style_path_provider(); + $this->style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->style_provider, $this->template); + $this->style->set_custom_style('silver', array($this->template_path), $style_names, ''); + } +} diff --git a/tests/template/templates/variable_spacing.html b/tests/template/templates/variable_spacing.html new file mode 100644 index 0000000000..028f8aa0d1 --- /dev/null +++ b/tests/template/templates/variable_spacing.html @@ -0,0 +1,6 @@ +|{VARIABLE}| +{VARIABLE}|{VARIABLE}| + +|{VARIABLE} + +<div class="{VARIABLE}">test</div> diff --git a/tests/tree/fixtures/phpbb_forums.xml b/tests/tree/fixtures/phpbb_forums.xml new file mode 100644 index 0000000000..8f133078a9 --- /dev/null +++ b/tests/tree/fixtures/phpbb_forums.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_forums"> + <column>forum_id</column> + <column>parent_id</column> + <column>left_id</column> + <column>right_id</column> + <column>forum_parents</column> + <column>forum_name</column> + <column>forum_desc</column> + <column>forum_rules</column> + </table> +</dataset> diff --git a/tests/tree/nestedset_forum_base.php b/tests/tree/nestedset_forum_base.php new file mode 100644 index 0000000000..776e822280 --- /dev/null +++ b/tests/tree/nestedset_forum_base.php @@ -0,0 +1,90 @@ +<?php +/** +* +* @package tree +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +class phpbb_tests_tree_nestedset_forum_base extends phpbb_database_test_case +{ + public function getDataSet() + { + return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/phpbb_forums.xml'); + } + + protected $forum_data = array( + // \__/ + 1 => array('forum_id' => 1, 'parent_id' => 0, 'user_id' => 0, 'left_id' => 1, 'right_id' => 6, 'forum_parents' => 'a:0:{}'), + 2 => array('forum_id' => 2, 'parent_id' => 1, 'user_id' => 0, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + 3 => array('forum_id' => 3, 'parent_id' => 1, 'user_id' => 0, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + + // \ / + // \/ + 4 => array('forum_id' => 4, 'parent_id' => 0, 'user_id' => 0, 'left_id' => 7, 'right_id' => 12, 'forum_parents' => 'a:0:{}'), + 5 => array('forum_id' => 5, 'parent_id' => 4, 'user_id' => 0, 'left_id' => 8, 'right_id' => 11, 'forum_parents' => 'a:0:{}'), + 6 => array('forum_id' => 6, 'parent_id' => 5, 'user_id' => 0, 'left_id' => 9, 'right_id' => 10, 'forum_parents' => 'a:0:{}'), + + // \_ _/ + // \/ + 7 => array('forum_id' => 7, 'parent_id' => 0, 'user_id' => 0, 'left_id' => 13, 'right_id' => 22, 'forum_parents' => 'a:0:{}'), + 8 => array('forum_id' => 8, 'parent_id' => 7, 'user_id' => 0, 'left_id' => 14, 'right_id' => 15, 'forum_parents' => 'a:0:{}'), + 9 => array('forum_id' => 9, 'parent_id' => 7, 'user_id' => 0, 'left_id' => 16, 'right_id' => 19, 'forum_parents' => 'a:0:{}'), + 10 => array('forum_id' => 10, 'parent_id' => 9, 'user_id' => 0, 'left_id' => 17, 'right_id' => 18, 'forum_parents' => 'a:0:{}'), + 11 => array('forum_id' => 11, 'parent_id' => 7, 'user_id' => 0, 'left_id' => 20, 'right_id' => 21, 'forum_parents' => 'a:0:{}'), + + // Non-existent forums + 0 => array('forum_id' => 0, 'parent_id' => 0, 'user_id' => 0, 'left_id' => 0, 'right_id' => 0, 'forum_parents' => 'a:0:{}'), + 200 => array('forum_id' => 200, 'parent_id' => 0, 'user_id' => 0, 'left_id' => 0, 'right_id' => 0, 'forum_parents' => 'a:0:{}'), + ); + + protected $set, + $config, + $lock, + $db; + + public function setUp() + { + parent::setUp(); + + $this->db = $this->new_dbal(); + + global $config; + + $config = $this->config = new phpbb_config(array('nestedset_forum_lock' => 0)); + set_config(null, null, null, $this->config); + + $this->lock = new phpbb_lock_db('nestedset_forum_lock', $this->config, $this->db); + $this->set = new phpbb_tree_nestedset_forum($this->db, $this->lock, 'phpbb_forums'); + + $this->set_up_forums(); + + $sql = "UPDATE phpbb_forums + SET forum_parents = 'a:0:{}'"; + $this->db->sql_query($sql); + } + + protected function set_up_forums() + { + $this->create_forum('Parent with two flat children'); + $this->create_forum('Flat child #1', 1); + $this->create_forum('Flat child #2', 1); + + $this->create_forum('Parent with two nested children'); + $this->create_forum('Nested child #1', 4); + $this->create_forum('Nested child #2', 5); + + $this->create_forum('Parent with flat and nested children'); + $this->create_forum('Mixed child #1', 7); + $this->create_forum('Mixed child #2', 7); + $this->create_forum('Nested child #1 of Mixed child #2', 9); + $this->create_forum('Mixed child #3', 7); + } + + protected function create_forum($name, $parent_id = 0) + { + $forum = $this->set->insert(array('forum_name' => $name, 'forum_desc' => '', 'forum_rules' => '')); + $this->set->change_parent($forum['forum_id'], $parent_id); + } +} diff --git a/tests/tree/nestedset_forum_get_data_test.php b/tests/tree/nestedset_forum_get_data_test.php new file mode 100644 index 0000000000..ca1863e55e --- /dev/null +++ b/tests/tree/nestedset_forum_get_data_test.php @@ -0,0 +1,119 @@ +<?php +/** +* +* @package tree +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +require_once dirname(__FILE__) . '/nestedset_forum_base.php'; + +class phpbb_tests_tree_nestedset_forum_get_data_test extends phpbb_tests_tree_nestedset_forum_base +{ + public function get_path_and_subtree_data_data() + { + return array( + array(1, true, true, array(1, 2, 3)), + array(1, true, false, array(2, 3)), + array(1, false, true, array(3, 2, 1)), + array(1, false, false, array(3, 2)), + + array(2, true, true, array(1, 2)), + array(2, true, false, array(1)), + array(2, false, true, array(2, 1)), + array(2, false, false, array(1)), + + array(5, true, true, array(4, 5, 6)), + array(5, true, false, array(4, 6)), + array(5, false, true, array(6, 5, 4)), + array(5, false, false, array(6, 4)), + ); + } + + /** + * @dataProvider get_path_and_subtree_data_data + */ + public function test_get_path_and_subtree_data($forum_id, $order_asc, $include_item, $expected) + { + $this->assertEquals($expected, array_keys($this->set->get_path_and_subtree_data($forum_id, $order_asc, $include_item))); + } + + public function get_path_data_data() + { + return array( + array(1, true, true, array(1)), + array(1, true, false, array()), + array(1, false, true, array(1)), + array(1, false, false, array()), + + array(2, true, true, array(1, 2)), + array(2, true, false, array(1)), + array(2, false, true, array(2, 1)), + array(2, false, false, array(1)), + + array(5, true, true, array(4, 5)), + array(5, true, false, array(4)), + array(5, false, true, array(5, 4)), + array(5, false, false, array(4)), + ); + } + + /** + * @dataProvider get_path_data_data + */ + public function test_get_path_data($forum_id, $order_asc, $include_item, $expected) + { + $this->assertEquals($expected, array_keys($this->set->get_path_data($forum_id, $order_asc, $include_item))); + } + + public function get_subtree_data_data() + { + return array( + array(1, true, true, array(1, 2, 3)), + array(1, true, false, array(2, 3)), + array(1, false, true, array(3, 2, 1)), + array(1, false, false, array(3, 2)), + + array(2, true, true, array(2)), + array(2, true, false, array()), + array(2, false, true, array(2)), + array(2, false, false, array()), + + array(5, true, true, array(5, 6)), + array(5, true, false, array(6)), + array(5, false, true, array(6, 5)), + array(5, false, false, array(6)), + ); + } + + /** + * @dataProvider get_subtree_data_data + */ + public function test_get_subtree_data($forum_id, $order_asc, $include_item, $expected) + { + $this->assertEquals($expected, array_keys($this->set->get_subtree_data($forum_id, $order_asc, $include_item))); + } + + public function get_path_basic_data_data() + { + return array( + array(1, '', array()), + array(1, serialize(array()), array()), + array(2, '', array(1)), + array(2, serialize(array(1 => array())), array(1)), + array(10, '', array(7, 9)), + array(10, serialize(array(7 => array(), 9 => array())), array(7, 9)), + ); + } + + /** + * @dataProvider get_path_basic_data_data + */ + public function test_get_path_basic_data($forum_id, $forum_parents, $expected) + { + $forum_data = $this->forum_data[$forum_id]; + $forum_data['forum_parents'] = $forum_parents; + $this->assertEquals($expected, array_keys($this->set->get_path_basic_data($forum_data))); + } +} diff --git a/tests/tree/nestedset_forum_insert_delete_test.php b/tests/tree/nestedset_forum_insert_delete_test.php new file mode 100644 index 0000000000..d0e9e02c2e --- /dev/null +++ b/tests/tree/nestedset_forum_insert_delete_test.php @@ -0,0 +1,120 @@ +<?php +/** +* +* @package tree +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +require_once dirname(__FILE__) . '/nestedset_forum_base.php'; + +class phpbb_tests_tree_nestedset_forum_add_remove_test extends phpbb_tests_tree_nestedset_forum_base +{ + public function delete_data() + { + return array( + array(1, array(1, 2, 3), array( + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 2, 'right_id' => 5), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 3, 'right_id' => 4), + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 16), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 8, 'right_id' => 9), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 10, 'right_id' => 13), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 11, 'right_id' => 12), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15), + )), + array(2, array(2), array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 4), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3), + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 5, 'right_id' => 10), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 6, 'right_id' => 9), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 7, 'right_id' => 8), + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 11, 'right_id' => 20), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 12, 'right_id' => 13), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 17), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 15, 'right_id' => 16), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 18, 'right_id' => 19), + )), + ); + } + + /** + * @dataProvider delete_data + */ + public function test_delete($forum_id, $expected_deleted, $expected) + { + $this->assertEquals($expected_deleted, $this->set->delete($forum_id)); + + $result = $this->db->sql_query("SELECT forum_id, parent_id, left_id, right_id + FROM phpbb_forums + ORDER BY left_id, forum_id ASC"); + $this->assertEquals($expected, $this->db->sql_fetchrowset($result)); + } + + public function delete_throws_data() + { + return array( + array('Not an item', 0), + array('Item does not exist', 200), + ); + } + + /** + * @dataProvider delete_throws_data + * + * @expectedException OutOfBoundsException + * @expectedExceptionMessage FORUM_NESTEDSET_INVALID_ITEM + */ + public function test_delete_throws($explain, $forum_id) + { + $this->set->delete($forum_id); + } + + public function insert_data() + { + return array( + array(array( + 'forum_desc' => '', + 'forum_rules' => '', + 'forum_id' => 12, + 'parent_id' => 0, + 'left_id' => 23, + 'right_id' => 24, + 'forum_parents' => '', + ), array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 12), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 8, 'right_id' => 11), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 9, 'right_id' => 10), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21), + + array('forum_id' => 12, 'parent_id' => 0, 'left_id' => 23, 'right_id' => 24), + )), + ); + } + + /** + * @dataProvider insert_data + */ + public function test_insert($expected_data, $expected) + { + $this->assertEquals($expected_data, $this->set->insert(array( + 'forum_desc' => '', + 'forum_rules' => '', + ))); + + $result = $this->db->sql_query('SELECT forum_id, parent_id, left_id, right_id + FROM phpbb_forums + ORDER BY left_id, forum_id ASC'); + $this->assertEquals($expected, $this->db->sql_fetchrowset($result)); + } +} diff --git a/tests/tree/nestedset_forum_move_test.php b/tests/tree/nestedset_forum_move_test.php new file mode 100644 index 0000000000..fe506c8278 --- /dev/null +++ b/tests/tree/nestedset_forum_move_test.php @@ -0,0 +1,569 @@ +<?php +/** +* +* @package tree +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +require_once dirname(__FILE__) . '/nestedset_forum_base.php'; + +class phpbb_tests_tree_nestedset_forum_move_test extends phpbb_tests_tree_nestedset_forum_base +{ + public function move_data() + { + return array( + array('Move first item up', + 1, 1, false, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5), + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 12), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 8, 'right_id' => 11), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 9, 'right_id' => 10), + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21), + )), + array('Move last item down', + 7, -1, false, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5), + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 12), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 8, 'right_id' => 11), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 9, 'right_id' => 10), + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21), + )), + array('Move first item down', + 1, -1, true, array( + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 2, 'right_id' => 5), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 3, 'right_id' => 4), + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 12), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 8, 'right_id' => 9), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 10, 'right_id' => 11), + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21), + )), + array('Move second item up', + 4, 1, true, array( + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 2, 'right_id' => 5), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 3, 'right_id' => 4), + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 12), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 8, 'right_id' => 9), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 10, 'right_id' => 11), + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21), + )), + array('Move last item up', + 7, 1, true, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5), + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 16), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 8, 'right_id' => 9), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 10, 'right_id' => 13), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 11, 'right_id' => 12), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15), + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 17, 'right_id' => 22), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 18, 'right_id' => 21), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 19, 'right_id' => 20), + )), + array('Move last item up by 2', + 7, 2, true, array( + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 10), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 2, 'right_id' => 3), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 4, 'right_id' => 7), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 5, 'right_id' => 6), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 8, 'right_id' => 9), + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 11, 'right_id' => 16), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 12, 'right_id' => 13), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 14, 'right_id' => 15), + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 17, 'right_id' => 22), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 18, 'right_id' => 21), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 19, 'right_id' => 20), + )), + array('Move last item up by 100', + 7, 100, true, array( + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 10), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 2, 'right_id' => 3), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 4, 'right_id' => 7), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 5, 'right_id' => 6), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 8, 'right_id' => 9), + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 11, 'right_id' => 16), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 12, 'right_id' => 13), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 14, 'right_id' => 15), + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 17, 'right_id' => 22), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 18, 'right_id' => 21), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 19, 'right_id' => 20), + )), + ); + } + + /** + * @dataProvider move_data + */ + public function test_move($explain, $forum_id, $delta, $expected_moved, $expected) + { + $this->assertEquals($expected_moved, $this->set->move($forum_id, $delta)); + + $result = $this->db->sql_query("SELECT forum_id, parent_id, left_id, right_id + FROM phpbb_forums + ORDER BY left_id, forum_id ASC"); + $this->assertEquals($expected, $this->db->sql_fetchrowset($result)); + } + + public function move_down_data() + { + return array( + array('Move last item down', + 7, false, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5), + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 12), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 8, 'right_id' => 11), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 9, 'right_id' => 10), + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21), + )), + array('Move first item down', + 1, true, array( + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 2, 'right_id' => 5), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 3, 'right_id' => 4), + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 12), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 8, 'right_id' => 9), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 10, 'right_id' => 11), + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21), + )), + ); + } + + /** + * @dataProvider move_down_data + */ + public function test_move_down($explain, $forum_id, $expected_moved, $expected) + { + $this->assertEquals($expected_moved, $this->set->move_down($forum_id)); + + $result = $this->db->sql_query("SELECT forum_id, parent_id, left_id, right_id + FROM phpbb_forums + ORDER BY left_id, forum_id ASC"); + $this->assertEquals($expected, $this->db->sql_fetchrowset($result)); + } + + public function move_up_data() + { + return array( + array('Move first item up', + 1, false, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5), + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 12), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 8, 'right_id' => 11), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 9, 'right_id' => 10), + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21), + )), + array('Move second item up', + 4, true, array( + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 2, 'right_id' => 5), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 3, 'right_id' => 4), + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 12), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 8, 'right_id' => 9), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 10, 'right_id' => 11), + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21), + )), + ); + } + + /** + * @dataProvider move_up_data + */ + public function test_move_up($explain, $forum_id, $expected_moved, $expected) + { + $this->assertEquals($expected_moved, $this->set->move_up($forum_id)); + + $result = $this->db->sql_query("SELECT forum_id, parent_id, left_id, right_id + FROM phpbb_forums + ORDER BY left_id, forum_id ASC"); + $this->assertEquals($expected, $this->db->sql_fetchrowset($result)); + } + + public function move_children_data() + { + return array( + array('Item has no children', + 2, 1, false, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 12, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 8, 'right_id' => 11, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 9, 'right_id' => 10, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21, 'forum_parents' => 'a:0:{}'), + )), + array('Move to same parent', + 4, 4, false, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 12, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 8, 'right_id' => 11, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 9, 'right_id' => 10, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21, 'forum_parents' => 'a:0:{}'), + )), + array('Move single child up', + 5, 1, true, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 8, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 6, 'parent_id' => 1, 'left_id' => 6, 'right_id' => 7, 'forum_parents' => ''), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 9, 'right_id' => 12, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 10, 'right_id' => 11, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21, 'forum_parents' => 'a:0:{}'), + )), + array('Move nested children up', + 4, 1, true, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 10, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 5, 'parent_id' => 1, 'left_id' => 6, 'right_id' => 9, 'forum_parents' => ''), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 7, 'right_id' => 8, 'forum_parents' => ''), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 11, 'right_id' => 12, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21, 'forum_parents' => 'a:0:{}'), + )), + array('Move single child down', + 5, 7, true, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 10, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 8, 'right_id' => 9, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 11, 'right_id' => 22, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 12, 'right_id' => 13, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 17, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 15, 'right_id' => 16, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 18, 'right_id' => 19, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 6, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21, 'forum_parents' => ''), + + )), + array('Move nested children down', + 4, 7, true, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 8, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 9, 'right_id' => 22, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 10, 'right_id' => 11, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 12, 'right_id' => 15, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 13, 'right_id' => 14, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 17, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 5, 'parent_id' => 7, 'left_id' => 18, 'right_id' => 21, 'forum_parents' => ''), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 19, 'right_id' => 20, 'forum_parents' => ''), + )), + array('Move single child to parent 0', + 5, 0, true, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 10, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 8, 'right_id' => 9, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 11, 'right_id' => 20, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 12, 'right_id' => 13, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 17, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 15, 'right_id' => 16, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 18, 'right_id' => 19, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 6, 'parent_id' => 0, 'left_id' => 21, 'right_id' => 22, 'forum_parents' => ''), + )), + array('Move nested children to parent 0', + 4, 0, true, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 8, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 9, 'right_id' => 18, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 10, 'right_id' => 11, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 12, 'right_id' => 15, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 13, 'right_id' => 14, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 17, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 5, 'parent_id' => 0, 'left_id' => 19, 'right_id' => 22, 'forum_parents' => ''), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 20, 'right_id' => 21, 'forum_parents' => ''), + )), + ); + } + + /** + * @dataProvider move_children_data + */ + public function test_move_children($explain, $forum_id, $target_id, $expected_moved, $expected) + { + $this->assertEquals($expected_moved, $this->set->move_children($forum_id, $target_id)); + + $result = $this->db->sql_query("SELECT forum_id, parent_id, left_id, right_id, forum_parents + FROM phpbb_forums + ORDER BY left_id, forum_id ASC"); + $this->assertEquals($expected, $this->db->sql_fetchrowset($result)); + } + + public function move_children_throws_item_data() + { + return array( + array('Item 0 does not exist', 0, 5), + array('Item does not exist', 200, 5), + ); + } + + /** + * @dataProvider move_children_throws_item_data + * + * @expectedException OutOfBoundsException + * @expectedExceptionMessage FORUM_NESTEDSET_INVALID_ITEM + */ + public function test_move_children_throws_item($explain, $forum_id, $target_id) + { + $this->set->move_children($forum_id, $target_id); + } + + public function move_children_throws_parent_data() + { + return array( + array('New parent is child', 4, 5), + array('New parent is child 2', 7, 9), + array('New parent does not exist', 1, 200), + ); + } + + /** + * @dataProvider move_children_throws_parent_data + * + * @expectedException OutOfBoundsException + * @expectedExceptionMessage FORUM_NESTEDSET_INVALID_PARENT + */ + public function test_move_children_throws_parent($explain, $forum_id, $target_id) + { + $this->set->move_children($forum_id, $target_id); + } + + public function change_parent_data() + { + return array( + array('Move single child up', + 6, 1, true, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 8, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 6, 'parent_id' => 1, 'left_id' => 6, 'right_id' => 7, 'forum_parents' => ''), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 9, 'right_id' => 12, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 10, 'right_id' => 11, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21, 'forum_parents' => 'a:0:{}'), + )), + array('Move nested children up', + 5, 1, true, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 10, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 5, 'parent_id' => 1, 'left_id' => 6, 'right_id' => 9, 'forum_parents' => ''), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 7, 'right_id' => 8, 'forum_parents' => ''), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 11, 'right_id' => 12, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21, 'forum_parents' => 'a:0:{}'), + )), + array('Move single child down', + 6, 7, true, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 10, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 8, 'right_id' => 9, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 11, 'right_id' => 22, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 12, 'right_id' => 13, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 17, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 15, 'right_id' => 16, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 18, 'right_id' => 19, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 6, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21, 'forum_parents' => ''), + )), + array('Move nested children down', + 5, 7, true, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 8, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 9, 'right_id' => 22, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 10, 'right_id' => 11, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 12, 'right_id' => 15, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 13, 'right_id' => 14, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 17, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 5, 'parent_id' => 7, 'left_id' => 18, 'right_id' => 21, 'forum_parents' => ''), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 19, 'right_id' => 20, 'forum_parents' => ''), + )), + array('Move single child to parent 0', + 6, 0, true, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 10, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 8, 'right_id' => 9, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 11, 'right_id' => 20, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 12, 'right_id' => 13, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 17, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 15, 'right_id' => 16, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 18, 'right_id' => 19, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 6, 'parent_id' => 0, 'left_id' => 21, 'right_id' => 22, 'forum_parents' => ''), + )), + array('Move nested children to parent 0', + 5, 0, true, array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 8, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 9, 'right_id' => 18, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 10, 'right_id' => 11, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 12, 'right_id' => 15, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 13, 'right_id' => 14, 'forum_parents' => 'a:0:{}'), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 17, 'forum_parents' => 'a:0:{}'), + + array('forum_id' => 5, 'parent_id' => 0, 'left_id' => 19, 'right_id' => 22, 'forum_parents' => ''), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 20, 'right_id' => 21, 'forum_parents' => ''), + )), + ); + } + + /** + * @dataProvider change_parent_data + */ + public function test_change_parent($explain, $forum_id, $target_id, $expected_moved, $expected) + { + $this->assertEquals($expected_moved, $this->set->change_parent($forum_id, $target_id)); + + $result = $this->db->sql_query("SELECT forum_id, parent_id, left_id, right_id, forum_parents + FROM phpbb_forums + ORDER BY left_id, forum_id ASC"); + $this->assertEquals($expected, $this->db->sql_fetchrowset($result)); + } + + public function change_parent_throws_item_data() + { + return array( + array('Item 0 does not exist', 0, 5), + array('Item does not exist', 200, 5), + ); + } + + /** + * @dataProvider change_parent_throws_item_data + * + * @expectedException OutOfBoundsException + * @expectedExceptionMessage FORUM_NESTEDSET_INVALID_ITEM + */ + public function test_change_parent_throws_item($explain, $forum_id, $target_id) + { + $this->set->change_parent($forum_id, $target_id); + } + + public function change_parent_throws_parent_data() + { + return array( + array('New parent is child', 4, 5), + array('New parent is child 2', 7, 9), + array('New parent does not exist', 1, 200), + ); + } + + /** + * @dataProvider change_parent_throws_parent_data + * + * @expectedException OutOfBoundsException + * @expectedExceptionMessage FORUM_NESTEDSET_INVALID_PARENT + */ + public function test_change_parent_throws_parent($explain, $forum_id, $target_id) + { + $this->set->change_parent($forum_id, $target_id); + } +} diff --git a/tests/tree/nestedset_forum_regenerate_test.php b/tests/tree/nestedset_forum_regenerate_test.php new file mode 100644 index 0000000000..38338dbc4d --- /dev/null +++ b/tests/tree/nestedset_forum_regenerate_test.php @@ -0,0 +1,72 @@ +<?php +/** +* +* @package tree +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +require_once dirname(__FILE__) . '/nestedset_forum_base.php'; + +class phpbb_tests_tree_nestedset_forum_regenerate_test extends phpbb_tests_tree_nestedset_forum_base +{ + protected $fixed_set = array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6, 'forum_parents' => ''), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3, 'forum_parents' => ''), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5, 'forum_parents' => ''), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 12, 'forum_parents' => ''), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 8, 'right_id' => 11, 'forum_parents' => ''), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 9, 'right_id' => 10, 'forum_parents' => ''), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22, 'forum_parents' => ''), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15, 'forum_parents' => ''), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19, 'forum_parents' => ''), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18, 'forum_parents' => ''), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21, 'forum_parents' => ''), + ); + + public function regenerate_left_right_ids_data() + { + return array( + array('UPDATE phpbb_forums + SET left_id = 0, + right_id = 0', false), + array('UPDATE phpbb_forums + SET left_id = 28, + right_id = 28 + WHERE left_id > 12', false), + array('UPDATE phpbb_forums + SET left_id = left_id * 2, + right_id = right_id * 2', false), + array('UPDATE phpbb_forums + SET left_id = left_id * 2, + right_id = right_id * 2 + WHERE left_id > 12', false), + array('UPDATE phpbb_forums + SET left_id = left_id - 4, + right_id = right_id * 4 + WHERE left_id > 4', false), + array('UPDATE phpbb_forums + SET left_id = 0, + right_id = 0 + WHERE left_id > 12', true), + ); + } + + /** + * @dataProvider regenerate_left_right_ids_data + */ + public function test_regenerate_left_right_ids($breaking_query, $reset_ids) + { + $result = $this->db->sql_query($breaking_query); + + $this->assertEquals(23, $this->set->regenerate_left_right_ids(1, 0, $reset_ids)); + + $result = $this->db->sql_query('SELECT forum_id, parent_id, left_id, right_id, forum_parents + FROM phpbb_forums + ORDER BY left_id, forum_id ASC'); + $this->assertEquals($this->fixed_set, $this->db->sql_fetchrowset($result)); + } +} diff --git a/tests/tree/nestedset_forum_test.php b/tests/tree/nestedset_forum_test.php new file mode 100644 index 0000000000..516c794ffc --- /dev/null +++ b/tests/tree/nestedset_forum_test.php @@ -0,0 +1,116 @@ +<?php +/** +* +* @package tree +* @copyright (c) 2013 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +require_once dirname(__FILE__) . '/nestedset_forum_base.php'; + +class pphpbb_tests_tree_nestedset_forum_test extends phpbb_tests_tree_nestedset_forum_base +{ + public function forum_constructor_data() + { + return array( + array(array( + array('forum_id' => 1, 'parent_id' => 0, 'left_id' => 1, 'right_id' => 6), + array('forum_id' => 2, 'parent_id' => 1, 'left_id' => 2, 'right_id' => 3), + array('forum_id' => 3, 'parent_id' => 1, 'left_id' => 4, 'right_id' => 5), + + array('forum_id' => 4, 'parent_id' => 0, 'left_id' => 7, 'right_id' => 12), + array('forum_id' => 5, 'parent_id' => 4, 'left_id' => 8, 'right_id' => 11), + array('forum_id' => 6, 'parent_id' => 5, 'left_id' => 9, 'right_id' => 10), + + array('forum_id' => 7, 'parent_id' => 0, 'left_id' => 13, 'right_id' => 22), + array('forum_id' => 8, 'parent_id' => 7, 'left_id' => 14, 'right_id' => 15), + array('forum_id' => 9, 'parent_id' => 7, 'left_id' => 16, 'right_id' => 19), + array('forum_id' => 10, 'parent_id' => 9, 'left_id' => 17, 'right_id' => 18), + array('forum_id' => 11, 'parent_id' => 7, 'left_id' => 20, 'right_id' => 21), + )), + ); + } + + /** + * @dataProvider forum_constructor_data + */ + public function test_forum_constructor($expected) + { + $result = $this->db->sql_query('SELECT forum_id, parent_id, left_id, right_id + FROM phpbb_forums + ORDER BY left_id, forum_id ASC'); + $this->assertEquals($expected, $this->db->sql_fetchrowset($result)); + } + + public function get_sql_where_data() + { + return array( + array('SELECT forum_id + FROM phpbb_forums + %s + ORDER BY forum_id ASC', + 'WHERE', '', array( + array('forum_id' => 1), + array('forum_id' => 2), + array('forum_id' => 3), + + array('forum_id' => 4), + array('forum_id' => 5), + array('forum_id' => 6), + + array('forum_id' => 7), + array('forum_id' => 8), + array('forum_id' => 9), + array('forum_id' => 10), + array('forum_id' => 11), + )), + array('SELECT f.forum_id + FROM phpbb_forums f + %s + ORDER BY f.forum_id ASC', + 'WHERE', 'f.', array( + array('forum_id' => 1), + array('forum_id' => 2), + array('forum_id' => 3), + + array('forum_id' => 4), + array('forum_id' => 5), + array('forum_id' => 6), + + array('forum_id' => 7), + array('forum_id' => 8), + array('forum_id' => 9), + array('forum_id' => 10), + array('forum_id' => 11), + )), + array('SELECT forum_id + FROM phpbb_forums + WHERE forum_id < 4 %s + ORDER BY forum_id ASC', + 'AND', '', array( + array('forum_id' => 1), + array('forum_id' => 2), + array('forum_id' => 3), + )), + array('SELECT f.forum_id + FROM phpbb_forums f + WHERE f.forum_id < 4 %s + ORDER BY f.forum_id ASC', + 'AND', 'f.', array( + array('forum_id' => 1), + array('forum_id' => 2), + array('forum_id' => 3), + )), + ); + } + + /** + * @dataProvider get_sql_where_data + */ + public function test_get_sql_where($sql_query, $operator, $column_prefix, $expected) + { + $result = $this->db->sql_query(sprintf($sql_query, $this->set->get_sql_where($operator, $column_prefix))); + $this->assertEquals($expected, $this->db->sql_fetchrowset($result)); + } +} |
