Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.294
diff -u -r1.294 system.install
--- modules/system/system.install 26 Dec 2008 11:04:39 -0000 1.294
+++ modules/system/system.install 27 Dec 2008 22:24:30 -0000
@@ -367,10 +367,14 @@
db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", 'theme_default', 's:7:"garland";');
db_query("UPDATE {system} SET status = %d WHERE type = '%s' AND name = '%s'", 1, 'theme', 'garland');
- db_query("INSERT INTO {block} (module, delta, theme, status, weight, region, pages, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s', %d)", 'user', 'login', 'garland', 1, 0, 'left', '', -1);
- db_query("INSERT INTO {block} (module, delta, theme, status, weight, region, pages, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s', %d)", 'user', 'navigation', 'garland', 1, 0, 'left', '', -1);
- db_query("INSERT INTO {block} (module, delta, theme, status, weight, region, pages, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s', %d)", 'system', 'powered-by', 'garland', 1, 10, 'footer', '', -1);
-
+
+ // Add a user login block instance to the left sidebar of the default theme.
+ db_query("INSERT INTO {block_instance} (block_id, theme, region, weight, pages) VALUES ('%s', '%s', '%s', %d, '%s')", 'user_login','garland', 'left', 0, '');
+ // Add the main interactive navigation menu for the site to the left sidebar of the default theme.
+ db_query("INSERT INTO {block_instance} (block_id, theme, region, weight, pages) VALUES ('%s', '%s', '%s', %d, '%s')", 'user_navigation','garland', 'left', 1, '');
+ // Add the powered-by block to the footer of the default theme.
+ db_query("INSERT INTO {block_instance} (block_id, theme, region, weight, pages) VALUES ('%s', '%s', '%s', %d, '%s')", 'system_powerd_by','garland', 'footer', 0, '');
+
db_query("INSERT INTO {node_access} (nid, gid, realm, grant_view, grant_update, grant_delete) VALUES (%d, %d, '%s', %d, %d, %d)", 0, 0, 'all', 1, 0, 0);
// Add input formats.
Index: themes/garland/block.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/themes/garland/block.tpl.php,v
retrieving revision 1.4
diff -u -r1.4 block.tpl.php
--- themes/garland/block.tpl.php 14 Apr 2008 17:48:46 -0000 1.4
+++ themes/garland/block.tpl.php 27 Dec 2008 22:24:48 -0000
@@ -1,10 +1,10 @@
-
+
-subject)): ?>
-
subject ?>
+title)): ?>
+
title ?>
content ?>
Index: modules/block/block.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.module,v
retrieving revision 1.316
diff -u -r1.316 block.module
--- modules/block/block.module 16 Dec 2008 23:57:31 -0000 1.316
+++ modules/block/block.module 27 Dec 2008 22:23:56 -0000
@@ -184,7 +184,8 @@
*/
function block_block_list() {
$blocks = array();
-
+
+ // @TODO: convert to callbacks structure.
$result = db_query('SELECT bid, info FROM {box} ORDER BY info');
while ($block = db_fetch_object($result)) {
$blocks[$block->bid]['info'] = $block->info;
@@ -196,6 +197,9 @@
/**
* Implementation of hook_block_configure().
+
+ * @TODO: Remove this hook and instead add configuration options by altering the
+ * blocks configuration form.
*/
function block_block_configure($delta = 0, $edit = array()) {
$box = array('format' => FILTER_FORMAT_DEFAULT);
@@ -209,6 +213,8 @@
/**
* Implementation of hook_block_save().
+ * @TODO: Remove this hook and instead save configuration options by registering a submit
+ * handler in the blocks configuration form.
*/
function block_block_save($delta = 0, $edit = array()) {
block_box_save($edit, $delta);
@@ -226,6 +232,95 @@
}
/**
+ * Collect, alter and store the block definitions exported by enabled modules.
+ */
+function block_router_build($reset = FALSE) {
+ static $blocks;
+
+ if (!isset($blocks) || $reset) {
+ if (!$reset && ($cache = cache_get('router:', 'cache_block')) && isset($cache->data)) {
+ $blocks = $cache->data;
+ }
+ else {
+ // We need to manually call each module so that we can know which module
+ // a given block came from.
+ $blocks = array();
+ foreach (module_implements('block_list', TRUE) as $module) {
+ $module_blocks = call_user_func($module . '_block_list');
+ if (isset($module_blocks) && is_array($module_blocks)) {
+ foreach (array_keys($module_blocks) as $block_id) {
+ $module_blocks[$block_id]['module'] = $module;
+ }
+ $blocks = array_merge($blocks, $module_blocks);
+ }
+ }
+
+ // Alter the block callbacks.
+ drupal_alter('block', $callbacks);
+
+ // Delete the existing block router since we have some data to replace it.
+ db_delete('block_router')->execute();
+
+ // Prepare insert object.
+ $insert = db_insert('block_router')
+ ->fields(array(
+ 'block_id',
+ 'module',
+ 'block_name',
+ 'description',
+ 'cache',
+ 'title',
+ 'title_callback',
+ 'title_arguments',
+ 'block_callback',
+ 'block_arguments',
+ 'access_callback',
+ 'access_arguments'
+ ));
+
+ foreach ($blocks as $block_id => $v) {
+ $block = &$blocks[$block_id];
+
+ // Set defaults.
+ $block += array(
+ 'access arguments' => array(),
+ 'access callback' => 'user_access',
+ 'block arguments' => array(),
+ 'block callback' => '',
+ 'title' => '',
+ 'title arguments' => array(),
+ 'title callback' => 't',
+ 'description' => '',
+ 'cache' => BLOCK_CACHE_PER_ROLE,
+ );
+
+ // Fill in insert object values.
+ $insert->values(array(
+ 'block_id' => $block_id,
+ 'module' => $block['module'],
+ 'block_name' => $block['title'],
+ 'description' => $block['description'],
+ 'cache' => $block['cache'],
+ 'title' => $block['title'],
+ 'title_callback' => $block['title callback'],
+ 'title_arguments' => serialize($block['title arguments']),
+ 'block_callback' => $block['block callback'],
+ 'block_arguments' => serialize($block['block arguments']),
+ 'access_callback' => $block['access callback'],
+ 'access_arguments' => serialize($block['access arguments']),
+ ));
+ }
+ // Execute insert object.
+ $insert->execute();
+
+ // Sotore a copy in the block cache.
+ cache_set('router:', $blocks, 'cache_block');
+ }
+ }
+ return $blocks;
+}
+
+/**
* Update the 'block' DB table with the blocks currently exported by modules.
*
* @return
@@ -234,72 +329,25 @@
function _block_rehash() {
global $theme_key;
+ $blocks = block_router_build(TRUE);
+ $blocks_ids = array_keys($blocks);
+
init_theme();
-
- $result = db_query("SELECT * FROM {block} WHERE theme = '%s'", $theme_key);
- $old_blocks = array();
- while ($old_block = db_fetch_array($result)) {
- $old_blocks[$old_block['module']][$old_block['delta']] = $old_block;
- }
-
- $blocks = array();
+
// Valid region names for the theme.
- $regions = system_region_list($theme_key);
-
- foreach (module_implements('block_list') as $module) {
- $module_blocks = module_invoke($module, 'block_list');
- if ($module_blocks) {
- foreach ($module_blocks as $delta => $block) {
- if (empty($old_blocks[$module][$delta])) {
- // If it's a new block, add identifiers.
- $block['module'] = $module;
- $block['delta'] = $delta;
- $block['theme'] = $theme_key;
- if (!isset($block['pages'])) {
- // {block}.pages is type 'text', so it cannot have a
- // default value, and not null, so we need to provide
- // value if the module did not.
- $block['pages'] = '';
- }
- // Add defaults and save it into the database.
- drupal_write_record('block', $block);
- // Set region to none if not enabled.
- $block['region'] = $block['status'] ? $block['region'] : BLOCK_REGION_NONE;
- // Add to the list of blocks we return.
- $blocks[] = $block;
- }
- else {
- // If it's an existing block, database settings should overwrite
- // the code. But aside from 'info' everything that's definable in
- // code is stored in the database and we do not store 'info', so we
- // do not need to update the database here.
- // Add 'info' to this block.
- $old_blocks[$module][$delta]['info'] = $block['info'];
- // If the region name does not exist, disable the block and assign it to none.
- if (!empty($old_blocks[$module][$delta]['region']) && !isset($regions[$old_blocks[$module][$delta]['region']])) {
- drupal_set_message(t('The block %info was assigned to the invalid region %region and has been disabled.', array('%info' => $old_blocks[$module][$delta]['info'], '%region' => $old_blocks[$module][$delta]['region'])), 'warning');
- $old_blocks[$module][$delta]['status'] = 0;
- $old_blocks[$module][$delta]['region'] = BLOCK_REGION_NONE;
- }
- else {
- $old_blocks[$module][$delta]['region'] = $old_blocks[$module][$delta]['status'] ? $old_blocks[$module][$delta]['region'] : BLOCK_REGION_NONE;
- }
- // Add this block to the list of blocks we return.
- $blocks[] = $old_blocks[$module][$delta];
- // Remove this block from the list of blocks to be deleted.
- unset($old_blocks[$module][$delta]);
- }
- }
- }
- }
-
- // Remove blocks that are no longer defined by the code from the database.
- foreach ($old_blocks as $module => $old_module_blocks) {
- foreach ($old_module_blocks as $delta => $block) {
- db_query("DELETE FROM {block} WHERE module = '%s' AND delta = '%s' AND theme = '%s'", $module, $delta, $theme_key);
- }
- }
- return $blocks;
+ $regions = array_keys(system_region_list($theme_key));
+
+ // Remove all instances of blocks that are no longer defined,
+ // or that are assigned to an invalid region in the current theme.
+ db_delete('block_instance')
+ ->condition(db_or()
+ ->condition('block_id', $blocks_ids, 'NOT IN')
+ ->condition(db_and()
+ ->condition('region', $regions, 'NOT IN')
+ ->condition('theme' , $theme_key)
+ )
+ )
+ ->execute();
}
function block_box_get($bid) {
@@ -386,14 +434,10 @@
* The name of a region.
*
* @return
- * An array of block objects, indexed with
module_
delta.
+ * An array of block objects, indexed with the block ID.
* If you are displaying your blocks in one or two sidebars, you may check
* whether this array is empty to see how many columns are going to be
* displayed.
- *
- * @todo
- * Now that the blocks table has a primary key, we should use that as the
- * array key instead of
module_
delta.
*/
function block_list($region) {
static $blocks = array();
@@ -417,18 +461,28 @@
*/
function _block_load_blocks() {
global $user, $theme_key;
-
+
+ $block_router = block_router_build();
+
$blocks = array();
$rids = array_keys($user->roles);
- $result = db_query(db_rewrite_sql("SELECT DISTINCT b.* FROM {block} b LEFT JOIN {block_role} r ON b.module = r.module AND b.delta = r.delta WHERE b.theme = '%s' AND b.status = 1 AND (r.rid IN (" . db_placeholders($rids) . ") OR r.rid IS NULL) ORDER BY b.region, b.weight, b.module", 'b', 'bid'), array_merge(array($theme_key), $rids));
+ // @todo: join {block_instance_role} in this query
+ $result = db_query("SELECT * FROM {block_instance} WHERE theme = '%s' ORDER BY region, weight", $theme_key);
+
while ($block = db_fetch_object($result)) {
+ $block->router = $block_router[$block->block_id];
+ $block->module = $block_router[$block->block_id]['module'];
+
if (!isset($blocks[$block->region])) {
$blocks[$block->region] = array();
}
+ // Check access control.
+ // @todo: check access control
+
// Use the user's block visibility setting, if necessary.
- if ($block->custom != 0) {
- if ($user->uid && isset($user->block[$block->module][$block->delta])) {
- $enabled = $user->block[$block->module][$block->delta];
+ if (!empty($block->custom)) {
+ if ($user->uid && isset($user->block[$block->block_id])) {
+ $enabled = $user->block[$block->block_id];
}
else {
$enabled = ($block->custom == 1);
@@ -461,7 +515,7 @@
}
$block->enabled = $enabled;
$block->page_match = $page_match;
- $blocks[$block->region]["{$block->module}_{$block->delta}"] = $block;
+ $blocks[$block->region][] = $block;
}
return $blocks;
@@ -490,27 +544,30 @@
$array = $cache->data;
}
else {
- $array = module_invoke($block->module, 'block_view', $block->delta);
+ // Render block content using block callback function.
+ $block->content = call_user_func_array($block->router['block callback'], $block->router['block arguments']);
+ // Render block title using block title callback function.
+ // t() is a special case. Since it is used very close to all the time,
+ // we handle it directly instead of using indirect, slower methods.
+ if ($block->router['title callback'] == 't') {
+ $block->title = t($block->router['title'], $block->router['title arguments']);
+ }
+ else {
+ $block->title = call_user_func_array($block->router['title callback'], array($block->router['title arguments']));
+ }
+
if (isset($cid)) {
- cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);
+ cache_set($cid, $block, 'cache_block', CACHE_TEMPORARY);
}
}
- if (isset($array) && is_array($array)) {
- foreach ($array as $k => $v) {
- $block->$k = $v;
- }
- }
- if (isset($block->content) && $block->content) {
+ if (!empty($block->content)) {
// Override default block title if a custom display title is present.
- if ($block->title) {
+ if (!empty($block->custom_title)) {
// Check plain here to allow module generated titles to keep any markup.
- $block->subject = $block->title == '
' ? '' : check_plain($block->title);
- }
- if (!isset($block->subject)) {
- $block->subject = '';
+ $block->title = $block->custom_title == '' ? '' : check_plain($block->custom_title);
}
- $region_blocks["{$block->module}_{$block->delta}"] = $block;
+ $region_blocks[$block->block_id] = $block;
}
}
}
Index: modules/block/block.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.install,v
retrieving revision 1.17
diff -u -r1.17 block.install
--- modules/block/block.install 16 Dec 2008 23:57:31 -0000 1.17
+++ modules/block/block.install 27 Dec 2008 22:23:53 -0000
@@ -5,64 +5,148 @@
* Implementation of hook_schema().
*/
function block_schema() {
- $schema['block'] = array(
- 'description' => 'Stores block settings, such as region and visibility settings.',
+ $schema['block_router'] = array(
+ 'description' => 'Stores block\'s info and callbacks defined by enabled modules.',
'fields' => array(
- 'bid' => array(
- 'type' => 'serial',
+ 'block_id' => array(
+ 'description' => 'Primary Key: the block unique identifier',
+ 'type' => 'varchar',
+ 'length' => 255,
'not null' => TRUE,
- 'description' => 'Primary Key: Unique block ID.',
+ 'default' => '',
),
'module' => array(
'type' => 'varchar',
- 'length' => 64,
+ 'length' => 255,
'not null' => TRUE,
'default' => '',
'description' => "The module from which the block originates; for example, 'user' for the Who's Online block, and 'block' for any custom blocks.",
),
- 'delta' => array(
+ 'block_name' => array(
+ 'description' => 'The human readable name of the block, as shown to the user in the block admin pages.',
'type' => 'varchar',
- 'length' => 32,
+ 'length' => 255,
'not null' => TRUE,
- 'default' => '0',
- 'description' => 'Unique ID for block within a module.',
+ 'default' => '',
),
- 'theme' => array(
+ 'description' => array(
+ 'description' => 'Provide a more descriptive information about the block.',
'type' => 'varchar',
- 'length' => 64,
+ 'length' => 255,
'not null' => TRUE,
'default' => '',
- 'description' => 'The theme under which the block settings apply.',
),
- 'status' => array(
+ 'cache' => array(
'type' => 'int',
'not null' => TRUE,
- 'default' => 0,
+ 'default' => 1,
'size' => 'tiny',
- 'description' => 'Block enabled status. (1 = enabled, 0 = disabled)',
+ 'description' => 'Binary flag to indicate block cache mode. (-1: Do not cache, 1: Cache per role, 2: Cache per user, 4: Cache per page, 8: Block cache global) See BLOCK_CACHE_* constants in block.module for more detailed information.',
+ ),
+ 'title' => array(
+ 'type' => 'varchar',
+ 'length' => 64,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'Title for the block provided by modules through hook_blocks.)',
+ ),
+ 'title_callback' => array(
+ 'description' => 'A function which will alter the title. Defaults to )',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'title_arguments' => array(
+ 'description' => 'A serialized array of arguments for the title callback. If empty, the title will be used as the sole argument for the title callback.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'block_callback' => array(
+ 'description' => 'Name of a function used to render the block on the system administration page for this item.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => FALSE,
+ 'default' => '',
+ ),
+ 'block_arguments' => array(
+ 'description' => 'A serialized array of arguments for the block callback.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'access_callback' => array(
+ 'description' => 'The callback which determines the access to this block. Defaults to user_access.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'access_arguments' => array(
+ 'description' => 'A serialized array of arguments for the access callback.',
+ 'type' => 'text',
+ 'not null' => FALSE,
+ ),
+ ),
+
+ 'primary key' => array('block_id'),
+ );
+
+ $schema['block_instance'] = array(
+ 'description' => 'Stores blocks intances in themes and regions.',
+ 'fields' => array(
+ 'biid' => array(
+ 'type' => 'serial',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'description' => 'Primary key: The block instance unique identifier.',
+ ),
+ 'block_id' => array(
+ 'description' => 'The block unique identifier.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
),
+ 'theme' => array(
+ 'type' => 'varchar',
+ 'length' => 64,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'Theme name in which the block instance is set.',
+ ),
+ 'region' => array(
+ 'type' => 'varchar',
+ 'length' => 64,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'Theme region within which the block instance is set.',
+ ),
'weight' => array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
- 'description' => 'Block weight within region.',
+ 'description' => 'Block instance weight within region.',
),
- 'region' => array(
+ 'custom_title' => array(
'type' => 'varchar',
- 'length' => 64,
+ 'length' => 255,
'not null' => TRUE,
'default' => '',
- 'description' => 'Theme region within which the block is set.',
- ),
- 'custom' => array(
+ 'description' => 'Custom block title.',
+ ),
+ 'user_visibilty' => array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
'description' => 'Flag to indicate how users may control visibility of the block. (0 = Users cannot control, 1 = On by default, but can be hidden, 2 = Hidden by default, but can be shown)',
),
- 'visibility' => array(
+ 'page_visibility' => array(
'type' => 'int',
'not null' => TRUE,
'default' => 0,
@@ -73,45 +157,26 @@
'type' => 'text',
'not null' => TRUE,
'description' => 'Contents of the "Pages" block; contains either a list of paths on which to include/exclude the block or PHP code, depending on "visibility" setting.',
- ),
- 'title' => array(
- 'type' => 'varchar',
- 'length' => 64,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'Custom title for the block. (Empty string will use block default title, <none> will remove the title, text will cause block to use specified title.)',
- ),
- 'cache' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 1,
- 'size' => 'tiny',
- 'description' => 'Binary flag to indicate block cache mode. (-1: Do not cache, 1: Cache per role, 2: Cache per user, 4: Cache per page, 8: Block cache global) See BLOCK_CACHE_* constants in block.module for more detailed information.',
- ),
+ ),
),
- 'primary key' => array('bid'),
+ 'primary key' => array('biid'),
'unique keys' => array(
- 'tmd' => array('theme', 'module', 'delta'),
- ),
+ 'btr' => array('block_id', 'theme', 'region')
+ ),
'indexes' => array(
- 'list' => array('theme', 'status', 'region', 'weight', 'module'),
- ),
- );
+ 'list' => array('theme', 'region', 'weight')
+ )
+ );
- $schema['block_role'] = array(
- 'description' => 'Sets up access permissions for blocks based on user roles',
+ $schema['block_instance_role'] = array(
+ 'description' => 'Sets up access permissions for blocks instances based on user roles.',
'fields' => array(
- 'module' => array(
- 'type' => 'varchar',
- 'length' => 64,
- 'not null' => TRUE,
- 'description' => "The block's origin module, from {block}.module.",
- ),
- 'delta' => array(
+ 'biid' => array(
+ 'description' => 'The block instance ID from {block_instance}.biid.',
'type' => 'varchar',
- 'length' => 32,
+ 'length' => 255,
'not null' => TRUE,
- 'description' => "The block's unique delta within module, from {block}.delta.",
+ 'default' => '',
),
'rid' => array(
'type' => 'int',
@@ -120,10 +185,7 @@
'description' => "The user's role ID from {users_roles}.rid.",
),
),
- 'primary key' => array('module', 'delta', 'rid'),
- 'indexes' => array(
- 'rid' => array('rid'),
- ),
+ 'primary key' => array('biid', 'rid'),
);
$schema['box'] = array(
@@ -133,7 +195,7 @@
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
- 'description' => "The block's {block}.bid.",
+ 'description' => "Primary key: The box unique identifier.",
),
'body' => array(
'type' => 'text',