Commit 9d1402ab authored by Damyon Wiese's avatar Damyon Wiese
Browse files

MDL-57232 blocks: Split undeletableblocktypes

There are 2 kinds of blocks that are undeletable. Those required by the
theme and those protected via the admin page ui. We only want the theme
ones to be auto created site wide if they don't exist - so we need to
rename the theme ones and split the logic.
parent a0352aa9
......@@ -4,6 +4,7 @@
require_once('../config.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/blocklib.php');
require_once($CFG->libdir.'/tablelib.php');
admin_externalpage_setup('manageblocks');
......@@ -49,36 +50,18 @@
admin_get_root(true, false); // settings not required - only pages
}
if (!isset($CFG->undeletableblocktypes) || (!is_array($CFG->undeletableblocktypes) && !is_string($CFG->undeletableblocktypes))) {
$undeletableblocktypes = array('navigation', 'settings');
} else if (is_string($CFG->undeletableblocktypes)) {
$undeletableblocktypes = explode(',', $CFG->undeletableblocktypes);
} else {
$undeletableblocktypes = $CFG->undeletableblocktypes;
}
if (!empty($protect) && confirm_sesskey()) {
if (!$block = $DB->get_record('block', array('id'=>$protect))) {
print_error('blockdoesnotexist', 'error');
}
if (!in_array($block->name, $undeletableblocktypes)) {
$undeletableblocktypes[] = $block->name;
set_config('undeletableblocktypes', implode(',', $undeletableblocktypes));
}
block_manager::protect_block((int)$protect);
admin_get_root(true, false); // settings not required - only pages
}
if (!empty($unprotect) && confirm_sesskey()) {
if (!$block = $DB->get_record('block', array('id'=>$unprotect))) {
print_error('blockdoesnotexist', 'error');
}
if (in_array($block->name, $undeletableblocktypes)) {
$undeletableblocktypes = array_diff($undeletableblocktypes, array($block->name));
set_config('undeletableblocktypes', implode(',', $undeletableblocktypes));
}
block_manager::unprotect_block((int)$unprotect);
admin_get_root(true, false); // settings not required - only pages
}
$undeletableblocktypes = block_manager::get_undeletable_block_types();
echo $OUTPUT->header();
echo $OUTPUT->heading($strmanageblocks);
......
......@@ -215,12 +215,14 @@ class block_manager {
}
$unaddableblocks = self::get_undeletable_block_types();
$requiredbythemeblocks = self::get_required_by_theme_block_types();
$pageformat = $this->page->pagetype;
foreach($allblocks as $block) {
if (!$bi = block_instance($block->name)) {
continue;
}
if ($block->visible && !in_array($block->name, $unaddableblocks) &&
!in_array($block->name, $requiredbythemeblocks) &&
($bi->instance_allow_multiple() || !$this->is_block_present($block->name)) &&
blocks_name_allowed_in_format($block->name, $pageformat) &&
$bi->user_can_addto($this->page)) {
......@@ -376,6 +378,80 @@ class block_manager {
}
/**
* @return array names of block types that must exist on every page with this theme.
*/
public static function get_required_by_theme_block_types() {
global $CFG, $PAGE;
$requiredbythemeblocks = false;
if (isset($PAGE->theme->requiredblocks)) {
$requiredbythemeblocks = $PAGE->theme->requiredblocks;
}
if ($requiredbythemeblocks === false) {
return array('navigation', 'settings');
} else if ($requiredbythemeblocks === '') {
return array();
} else if (is_string($requiredbythemeblocks)) {
return explode(',', $requiredbythemeblocks);
} else {
return $requiredbythemeblocks;
}
}
/**
* Make this block type undeletable and unaddable.
*
* @param mixed $blockidorname string or int
*/
public static function protect_block($blockidorname) {
global $DB;
$syscontext = context_system::instance();
require_capability('moodle/site:config', $syscontext);
$block = false;
if (is_int($blockidorname)) {
$block = $DB->get_record('block', array('id' => $blockidorname), 'id, name', MUST_EXIST);
} else {
$block = $DB->get_record('block', array('name' => $blockidorname), 'id, name', MUST_EXIST);
}
$undeletableblocktypes = self::get_undeletable_block_types();
if (!in_array($block->name, $undeletableblocktypes)) {
$undeletableblocktypes[] = $block->name;
set_config('undeletableblocktypes', implode(',', $undeletableblocktypes));
}
}
/**
* Make this block type deletable and addable.
*
* @param mixed $blockidorname string or int
*/
public static function unprotect_block($blockidorname) {
global $DB;
$syscontext = context_system::instance();
require_capability('moodle/site:config', $syscontext);
$block = false;
if (is_int($blockidorname)) {
$block = $DB->get_record('block', array('id' => $blockidorname), 'id, name', MUST_EXIST);
} else {
$block = $DB->get_record('block', array('name' => $blockidorname), 'id, name', MUST_EXIST);
}
$undeletableblocktypes = self::get_undeletable_block_types();
if (in_array($block->name, $undeletableblocktypes)) {
$undeletableblocktypes = array_diff($undeletableblocktypes, array($block->name));
set_config('undeletableblocktypes', implode(',', $undeletableblocktypes));
}
}
/**
* Get the list of "protected" blocks via admin block manager ui.
*
* @return array names of block types that cannot be added or deleted. E.g. array('navigation','settings').
*/
public static function get_undeletable_block_types() {
......@@ -383,13 +459,9 @@ class block_manager {
$undeletableblocks = false;
if (isset($CFG->undeletableblocktypes)) {
$undeletableblocks = $CFG->undeletableblocktypes;
} else if (isset($PAGE->theme->undeletableblocktypes)) {
$undeletableblocks = $PAGE->theme->undeletableblocktypes;
}
if ($undeletableblocks === false) {
return array('navigation','settings');
} else if ($undeletableblocks === '') {
if (empty($undeletableblocks)) {
return array();
} else if (is_string($undeletableblocks)) {
return explode(',', $undeletableblocks);
......@@ -596,17 +668,18 @@ class block_manager {
}
// Exclude auto created blocks if they are not undeletable in this theme.
$undeletable = $this->get_undeletable_block_types();
$undeletablecheck = '';
$undeletableparams = array();
$undeletablenotparams = array();
if (!empty($undeletable)) {
list($testsql, $undeletableparams) = $DB->get_in_or_equal($undeletable, SQL_PARAMS_NAMED, 'undeletable');
list($testnotsql, $undeletablenotparams) = $DB->get_in_or_equal($undeletable, SQL_PARAMS_NAMED, 'deletable', false);
$undeletablecheck = 'AND ((bi.blockname ' . $testsql . ' AND bi.requiredbytheme = 1) OR ' .
$requiredbytheme = $this->get_required_by_theme_block_types();
$requiredbythemecheck = '';
$requiredbythemeparams = array();
$requiredbythemenotparams = array();
if (!empty($requiredbytheme)) {
list($testsql, $requiredbythemeparams) = $DB->get_in_or_equal($requiredbytheme, SQL_PARAMS_NAMED, 'requiredbytheme');
list($testnotsql, $requiredbythemenotparams) = $DB->get_in_or_equal($requiredbytheme, SQL_PARAMS_NAMED,
'notrequiredbytheme', false);
$requiredbythemecheck = 'AND ((bi.blockname ' . $testsql . ' AND bi.requiredbytheme = 1) OR ' .
' (bi.blockname ' . $testnotsql . ' AND bi.requiredbytheme = 0))';
} else {
$undeletablecheck = 'AND (bi.requiredbytheme = 0)';
$requiredbythemecheck = 'AND (bi.requiredbytheme = 0)';
}
if (is_null($includeinvisible)) {
......@@ -680,14 +753,14 @@ class block_manager {
AND (bi.subpagepattern IS NULL OR bi.subpagepattern = :subpage2)
$visiblecheck
AND b.visible = 1
$undeletablecheck
$requiredbythemecheck
ORDER BY
COALESCE(bp.region, bi.defaultregion),
COALESCE(bp.weight, bi.defaultweight),
bi.id";
$allparams = $params + $parentcontextparams + $pagetypepatternparams + $undeletableparams + $undeletablenotparams;
$allparams = $params + $parentcontextparams + $pagetypepatternparams + $requiredbythemeparams + $requiredbythemenotparams;
$blockinstances = $DB->get_recordset_sql($sql, $allparams);
$this->birecordsbyregion = $this->prepare_per_region_arrays();
......@@ -992,7 +1065,7 @@ class block_manager {
* chance to initialise themselves via the {@link block_base::specialize()}
* method, before any output is done.
*
* It is also used to create any blocks that are "undeletable" by the current theme.
* It is also used to create any blocks that are "requiredbytheme" by the current theme.
* These blocks that are auto-created have requiredbytheme set on the block instance
* so they are only visible on themes that require them.
*/
......@@ -1001,9 +1074,9 @@ class block_manager {
$missing = false;
// If there are any un-removable blocks that were not created - force them.
$undeletable = $this->get_undeletable_block_types();
$requiredbytheme = $this->get_required_by_theme_block_types();
if (!$this->fakeblocksonly) {
foreach ($undeletable as $forced) {
foreach ($requiredbytheme as $forced) {
if (empty($forced)) {
continue;
}
......@@ -1283,7 +1356,8 @@ class block_manager {
protected function user_can_delete_block($block) {
return $this->page->user_can_edit_blocks() && $block->user_can_edit() &&
$block->user_can_addto($this->page) &&
!in_array($block->instance->blockname, self::get_undeletable_block_types());
!in_array($block->instance->blockname, self::get_undeletable_block_types()) &&
!in_array($block->instance->blockname, self::get_required_by_theme_block_types());
}
/**
......@@ -2453,7 +2527,7 @@ function blocks_add_default_system_blocks() {
$page = new moodle_page();
$page->set_context(context_system::instance());
$page->blocks->add_blocks(array(BLOCK_POS_LEFT => block_manager::get_undeletable_block_types()), '*', null, true);
// We don't add blocks required by the theme, they will be auto-created.
$page->blocks->add_blocks(array(BLOCK_POS_LEFT => array('admin_bookmarks')), 'admin-*', null, null, 2);
if ($defaultmypage = $DB->get_record('my_pages', array('userid' => null, 'name' => '__default', 'private' => 1))) {
......
......@@ -349,10 +349,10 @@ class theme_config {
public $doctype = 'html5';
/**
* @var string undeletableblocktypes If set to a string, will list the block types that cannot be deleted. Defaults to
* @var string requiredblocks If set to a string, will list the block types that cannot be deleted. Defaults to
* navigation and settings.
*/
public $undeletableblocktypes = false;
public $requiredblocks = false;
//==Following properties are not configurable from theme config.php==
......@@ -542,7 +542,7 @@ class theme_config {
$configurable = array(
'parents', 'sheets', 'parents_exclude_sheets', 'plugins_exclude_sheets',
'javascripts', 'javascripts_footer', 'parents_exclude_javascripts',
'layouts', 'enable_dock', 'enablecourseajax', 'undeletableblocktypes',
'layouts', 'enable_dock', 'enablecourseajax', 'requiredblocks',
'rendererfactory', 'csspostprocess', 'editor_sheets', 'rarrow', 'larrow', 'uarrow', 'darrow',
'hidefromselector', 'doctype', 'yuicssmodules', 'blockrtlmanipulations',
'lessfile', 'extralesscallback', 'lessvariablescallback', 'blockrendermethod',
......
......@@ -545,6 +545,7 @@ class core_blocklib_testcase extends advanced_testcase {
public function test_create_all_block_instances() {
global $CFG, $PAGE, $DB;
$this->setAdminUser();
$this->resetAfterTest();
$regionname = 'side-pre';
$context = context_system::instance();
......@@ -557,6 +558,7 @@ class core_blocklib_testcase extends advanced_testcase {
$blockmanager->load_blocks();
$blockmanager->create_all_block_instances();
$blocks = $blockmanager->get_blocks_for_region($regionname);
// Assert that we no auto created blocks in boost by default.
$this->assertEmpty($blocks);
// There should be no blocks in the DB.
......@@ -571,6 +573,7 @@ class core_blocklib_testcase extends advanced_testcase {
$blockmanager->load_blocks();
$blockmanager->create_all_block_instances();
$blocks = $blockmanager->get_blocks_for_region($regionname);
// Assert that we no auto created blocks when viewing a fake blocks only page.
$this->assertEmpty($blocks);
$PAGE->reset_theme_and_output();
......@@ -581,10 +584,22 @@ class core_blocklib_testcase extends advanced_testcase {
$blockmanager->load_blocks();
$blockmanager->create_all_block_instances();
$blocks = $blockmanager->get_blocks_for_region($regionname);
// Assert that we get the required block for this theme auto-created.
$this->assertCount(2, $blocks);
$PAGE->reset_theme_and_output();
list($page, $blockmanager) = $this->get_a_page_and_block_manager(array($regionname),
$context, 'page-type');
$blockmanager->protect_block('html');
$blockmanager->load_blocks();
$blockmanager->create_all_block_instances();
$blocks = $blockmanager->get_blocks_for_region($regionname);
// Assert that protecting a block does not make it auto-created.
$this->assertCount(2, $blocks);
$undeletable = block_manager::get_undeletable_block_types();
foreach ($undeletable as $blockname) {
$requiredbytheme = block_manager::get_required_by_theme_block_types();
foreach ($requiredbytheme as $blockname) {
$instance = $DB->get_record('block_instances', array('blockname' => $blockname));
$this->assertEquals(1, $instance->requiredbytheme);
}
......@@ -598,9 +613,10 @@ class core_blocklib_testcase extends advanced_testcase {
$blockmanager->load_blocks();
$blockmanager->create_all_block_instances();
$blocks = $blockmanager->get_blocks_for_region($regionname);
// Assert that we do not return requiredbytheme blocks when they are not required.
$this->assertEmpty($blocks);
// But they should exist in the DB.
foreach ($undeletable as $blockname) {
foreach ($requiredbytheme as $blockname) {
$count = $DB->count_records('block_instances', array('blockname' => $blockname));
$this->assertEquals(1, $count);
}
......
......@@ -151,5 +151,5 @@ $THEME->extrascsscallback = 'theme_boost_get_extra_scss';
$THEME->prescsscallback = 'theme_boost_get_pre_scss';
$THEME->yuicssmodules = array();
$THEME->rendererfactory = 'theme_overridden_renderer_factory';
$THEME->undeletableblocktypes = '';
$THEME->requiredblocks = '';
$THEME->addblockposition = BLOCK_ADDBLOCK_POSITION_FLATNAV;
......@@ -35,7 +35,7 @@ information provided here is intended especially for theme designer.
* A new class .text-ltr may be used to force the direction to LTR. This is especially useful
for forms fields (numbers, emails, URLs must not be RTL'd), and for displaying code
snippets or configuration samples.
* A new theme config 'undeletableblocktypes' allows a theme to define which blocks are deletable.
* A new theme config 'requiredblocks' allows a theme to define which blocks are deletable.
* You may no longer override the following core_course_renderer methods.
See course/upgrade.txt for more information:
- course_modchooser_module_types
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment