From 3af5725b74a127d905d743962593380c4c8c4801 Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Thu, 27 Nov 2014 14:26:28 +0800 Subject: [PATCH 1/2] MDL-40419 blocks: Function to get page type patterns from pattern --- lib/blocklib.php | 24 ++++++++++++++++++ lib/tests/blocklib_test.php | 50 +++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/lib/blocklib.php b/lib/blocklib.php index f8d12bf31c4..9a2eaf45040 100644 --- a/lib/blocklib.php +++ b/lib/blocklib.php @@ -1721,6 +1721,30 @@ function matching_page_type_patterns($pagetype) { return $patterns; } +/** + * Give an specific pattern, return all the page type patterns that would also match it. + * + * @param string $pattern the pattern, e.g. 'mod-forum-*' or 'mod-quiz-view'. + * @return array of all the page type patterns matching. + */ +function matching_page_type_patterns_from_pattern($pattern) { + $patterns = array($pattern); + if ($pattern === '*') { + return $patterns; + } + + // Only keep the part before the star because we will append -* to all the bits. + $star = strpos($pattern, '-*'); + if ($star !== false) { + $pattern = substr($pattern, 0, $star); + } + + $patterns = array_merge($patterns, matching_page_type_patterns($pattern)); + $patterns = array_unique($patterns); + + return $patterns; +} + /** * Given a specific page type, parent context and currect context, return all the page type patterns * that might be used by this block. diff --git a/lib/tests/blocklib_test.php b/lib/tests/blocklib_test.php index 49b064a77a7..44a18a694eb 100644 --- a/lib/tests/blocklib_test.php +++ b/lib/tests/blocklib_test.php @@ -408,6 +408,56 @@ class core_blocklib_testcase extends advanced_testcase { $blocks = $blockmanager->get_blocks_for_region($regionname); $this->assertContainsBlocksOfType(array($blockname), $blocks); } + + public function test_matching_page_type_patterns_from_pattern() { + $pattern = '*'; + $expected = array('*'); + $this->assertEquals($expected, array_values(matching_page_type_patterns_from_pattern($pattern))); + + $pattern = 'admin-*'; + $expected = array('admin-*', 'admin', '*'); + $this->assertEquals($expected, array_values(matching_page_type_patterns_from_pattern($pattern))); + + $pattern = 'blog-index'; + $expected = array('blog-index', 'blog-index-*', 'blog-*', '*'); + $this->assertEquals($expected, array_values(matching_page_type_patterns_from_pattern($pattern))); + + $pattern = 'course-index-*'; + $expected = array('course-index-*', 'course-index', 'course-*', '*'); + $this->assertEquals($expected, array_values(matching_page_type_patterns_from_pattern($pattern))); + + $pattern = 'course-index-category'; + $expected = array('course-index-category', 'course-index-category-*', 'course-index-*', 'course-*', '*'); + $this->assertEquals($expected, array_values(matching_page_type_patterns_from_pattern($pattern))); + + $pattern = 'mod-assign-view'; + $expected = array('mod-assign-view', 'mod-*-view', 'mod-assign-view-*', 'mod-assign-*', 'mod-*', '*'); + $this->assertEquals($expected, array_values(matching_page_type_patterns_from_pattern($pattern))); + + $pattern = 'mod-assign-index'; + $expected = array('mod-assign-index', 'mod-*-index', 'mod-assign-index-*', 'mod-assign-*', 'mod-*', '*'); + $this->assertEquals($expected, array_values(matching_page_type_patterns_from_pattern($pattern))); + + $pattern = 'mod-forum-*'; + $expected = array('mod-forum-*', 'mod-forum', 'mod-*', '*'); + $this->assertEquals($expected, array_values(matching_page_type_patterns_from_pattern($pattern))); + + $pattern = 'mod-*-view'; + $expected = array('mod-*-view', 'mod', 'mod-*', '*'); + $this->assertEquals($expected, array_values(matching_page_type_patterns_from_pattern($pattern))); + + $pattern = 'mod-*-index'; + $expected = array('mod-*-index', 'mod', 'mod-*', '*'); + $this->assertEquals($expected, array_values(matching_page_type_patterns_from_pattern($pattern))); + + $pattern = 'my-index'; + $expected = array('my-index', 'my-index-*', 'my-*', '*'); + $this->assertEquals($expected, array_values(matching_page_type_patterns_from_pattern($pattern))); + + $pattern = 'user-profile'; + $expected = array('user-profile', 'user-profile-*', 'user-*', '*'); + $this->assertEquals($expected, array_values(matching_page_type_patterns_from_pattern($pattern))); + } } /** From dc8ee30eda3a4cfb7b60fc65b1924bb27ba7326b Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Wed, 12 Nov 2014 15:19:10 +0800 Subject: [PATCH 2/2] MDL-40419 backup: Advanced comparison when restoring blocks in course --- backup/moodle2/restore_stepslib.php | 51 ++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php index fc4fe154ca6..716f32392cc 100644 --- a/backup/moodle2/restore_stepslib.php +++ b/backup/moodle2/restore_stepslib.php @@ -3147,11 +3147,52 @@ class restore_block_instance_structure_step extends restore_structure_step { } if (!$bi->instance_allow_multiple()) { - if ($DB->record_exists_sql("SELECT bi.id - FROM {block_instances} bi - JOIN {block} b ON b.name = bi.blockname - WHERE bi.parentcontextid = ? - AND bi.blockname = ?", array($data->parentcontextid, $data->blockname))) { + // The block cannot be added twice, so we will check if the same block is already being + // displayed on the same page. For this, rather than mocking a page and using the block_manager + // we use a similar query to the one in block_manager::load_blocks(), this will give us + // a very good idea of the blocks already displayed in the context. + $params = array( + 'blockname' => $data->blockname + ); + + // Context matching test. + $context = context::instance_by_id($data->parentcontextid); + $contextsql = 'bi.parentcontextid = :contextid'; + $params['contextid'] = $context->id; + + $parentcontextids = $context->get_parent_context_ids(); + if ($parentcontextids) { + list($parentcontextsql, $parentcontextparams) = + $DB->get_in_or_equal($parentcontextids, SQL_PARAMS_NAMED); + $contextsql = "($contextsql OR (bi.showinsubcontexts = 1 AND bi.parentcontextid $parentcontextsql))"; + $params = array_merge($params, $parentcontextparams); + } + + // Page type pattern test. + $pagetypepatterns = matching_page_type_patterns_from_pattern($data->pagetypepattern); + list($pagetypepatternsql, $pagetypepatternparams) = + $DB->get_in_or_equal($pagetypepatterns, SQL_PARAMS_NAMED); + $params = array_merge($params, $pagetypepatternparams); + + // Sub page pattern test. + $subpagepatternsql = 'bi.subpagepattern IS NULL'; + if ($data->subpagepattern !== null) { + $subpagepatternsql = "($subpagepatternsql OR bi.subpagepattern = :subpagepattern)"; + $params['subpagepattern'] = $data->subpagepattern; + } + + $exists = $DB->record_exists_sql("SELECT bi.id + FROM {block_instances} bi + JOIN {block} b ON b.name = bi.blockname + WHERE bi.blockname = :blockname + AND $contextsql + AND bi.pagetypepattern $pagetypepatternsql + AND $subpagepatternsql", $params); + if ($exists) { + // There is at least one very similar block visible on the page where we + // are trying to restore the block. In these circumstances the block API + // would not allow the user to add another instance of the block, so we + // apply the same rule here. return false; } }