Simpletest Coverage - modules/block/block.module

1 <?php
2 // $Id: block.module,v 1.359 2009/08/15 06:50:29 webchick Exp $
3
4 /**
5 * @file
6 * Controls the boxes that are displayed around the main content.
7 */
8
9 /**
10 * Denotes that a block is not enabled in any region and should not be shown.
11 */
12 define('BLOCK_REGION_NONE', -1);
13
14 /**
15 * Constants defining cache granularity for blocks.
16 *
17 * Modules specify the caching patterns for their blocks using binary
18 * combinations of these constants in their hook_block_list():
19 * $block[delta]['cache'] = BLOCK_CACHE_PER_ROLE | BLOCK_CACHE_PER_PAGE;
20 * BLOCK_CACHE_PER_ROLE is used as a default when no caching pattern is
21 * specified.
22 *
23 * The block cache is cleared in cache_clear_all(), and uses the same clearing
24 * policy than page cache (node, comment, user, taxonomy added or updated...).
25 * Blocks requiring more fine-grained clearing might consider disabling the
26 * built-in block cache (BLOCK_NO_CACHE) and roll their own.
27 *
28 * Note that user 1 is excluded from block caching.
29 */
30
31 /**
32 * The block should not get cached. This setting should be used:
33 * - for simple blocks (notably those that do not perform any db query),
34 * where querying the db cache would be more expensive than directly generating
35 * the content.
36 * - for blocks that change too frequently.
37 */
38 define('BLOCK_NO_CACHE', -1);
39
40 /**
41 * The block can change depending on the roles the user viewing the page belongs to.
42 * This is the default setting, used when the block does not specify anything.
43 */
44 define('BLOCK_CACHE_PER_ROLE', 0x0001);
45
46 /**
47 * The block can change depending on the user viewing the page.
48 * This setting can be resource-consuming for sites with large number of users,
49 * and thus should only be used when BLOCK_CACHE_PER_ROLE is not sufficient.
50 */
51 define('BLOCK_CACHE_PER_USER', 0x0002);
52
53 /**
54 * The block can change depending on the page being viewed.
55 */
56 define('BLOCK_CACHE_PER_PAGE', 0x0004);
57
58 /**
59 * The block is the same for every user on every page where it is visible.
60 */
61 define('BLOCK_CACHE_GLOBAL', 0x0008);
62
63 /**
64 * Implement hook_help().
65 */
66 function block_help($path, $arg) {
67 switch ($path) {
68 case 'admin/help#block':
69 $output = '<p>' . t('Blocks are boxes of content rendered into an area, or region, of a web page. The default theme Garland, for example, implements the regions "left sidebar", "right sidebar", "content", "header", and "footer", and a block may appear in any one of these areas. The <a href="@blocks">blocks administration page</a> provides a drag-and-drop interface for assigning a block to a region, and for controlling the order of blocks within regions.', array('@blocks' => url('admin/structure/block'))) . '</p>';
70 $output .= '<p>' . t('Although blocks are usually generated automatically by modules (like the <em>User login</em> block, for example), administrators can also define custom blocks. Custom blocks have a title, description, and body. The body of the block can be as long as necessary, and can contain content supported by any available <a href="@text-format">text format</a>.', array('@text-format' => url('admin/settings/filter'))) . '</p>';
71 $output .= '<p>' . t('When working with blocks, remember that:') . '</p>';
72 $output .= '<ul><li>' . t('since not all themes implement the same regions, or display regions in the same way, blocks are positioned on a per-theme basis.') . '</li>';
73 $output .= '<li>' . t('disabled blocks, or blocks not in a region, are never shown.') . '</li>';
74 $output .= '<li>' . t('blocks can be configured to be visible only on certain pages.') . '</li>';
75 $output .= '<li>' . t('blocks can be configured to be visible only when specific conditions are true.') . '</li>';
76 $output .= '<li>' . t('blocks can be configured to be visible only for certain user roles.') . '</li>';
77 $output .= '<li>' . t('when allowed by an administrator, specific blocks may be enabled or disabled on a per-user basis using the <em>My account</em> page.') . '</li>';
78 $output .= '<li>' . t('some dynamic blocks, such as those generated by modules, will be displayed only on certain pages.') . '</li></ul>';
79 $output .= '<p>' . t('For more information, see the online handbook entry for <a href="@block">Block module</a>.', array('@block' => 'http://drupal.org/handbook/modules/block/')) . '</p>';
80 return $output;
81 case 'admin/structure/block':
82 $output = '<p>' . t('This page provides a drag-and-drop interface for assigning a block to a region, and for controlling the order of blocks within regions. Since not all themes implement the same regions, or display regions in the same way, blocks are positioned on a per-theme basis. Remember that your changes will not be saved until you click the <em>Save blocks</em> button at the bottom of the page.') . '</p>';
83 $output .= '<p>' . t('Click the <em>configure</em> link next to each block to configure its specific title and visibility settings. Use the <a href="@add-block">add block page</a> to create a custom block.', array('@add-block' => url('admin/structure/block/add'))) . '</p>';
84 return $output;
85 case 'admin/structure/block/add':
86 return '<p>' . t('Use this page to create a new custom block. New blocks are disabled by default, and must be moved to a region on the <a href="@blocks">blocks administration page</a> to be visible.', array('@blocks' => url('admin/structure/block'))) . '</p>';
87 }
88 }
89
90 /**
91 * Implement hook_theme().
92 */
93 function block_theme() {
94 return array(
95 'block' => array(
96 'arguments' => array('elements' => NULL),
97 'template' => 'block',
98 ),
99 'block_admin_display_form' => array(
100 'template' => 'block-admin-display-form',
101 'file' => 'block.admin.inc',
102 'arguments' => array('form' => NULL),
103 ),
104 );
105 }
106
107 /**
108 * Implement hook_permission().
109 */
110 function block_permission() {
111 return array(
112 'administer blocks' => array(
113 'title' => t('Administer blocks'),
114 'description' => t('Select which blocks are displayed, and arrange them on the page.'),
115 ),
116 );
117 }
118
119 /**
120 * Implement hook_menu().
121 */
122 function block_menu() {
123 $items['admin/structure/block'] = array(
124 'title' => 'Blocks',
125 'description' => 'Configure what block content appears in your site\'s sidebars and other regions.',
126 'page callback' => 'block_admin_display',
127 'access arguments' => array('administer blocks'),
128 );
129 $items['admin/structure/block/list'] = array(
130 'title' => 'List',
131 'type' => MENU_DEFAULT_LOCAL_TASK,
132 'weight' => -10,
133 );
134 $items['admin/structure/block/list/js'] = array(
135 'title' => 'JavaScript List Form',
136 'page callback' => 'block_admin_display_js',
137 'access arguments' => array('administer blocks'),
138 'type' => MENU_CALLBACK,
139 );
140 $items['admin/structure/block/configure'] = array(
141 'title' => 'Configure block',
142 'page callback' => 'drupal_get_form',
143 'page arguments' => array('block_admin_configure'),
144 'access arguments' => array('administer blocks'),
145 'type' => MENU_CALLBACK,
146 );
147 $items['admin/structure/block/delete'] = array(
148 'title' => 'Delete block',
149 'page callback' => 'drupal_get_form',
150 'page arguments' => array('block_box_delete'),
151 'access arguments' => array('administer blocks'),
152 'type' => MENU_CALLBACK,
153 );
154 $items['admin/structure/block/add'] = array(
155 'title' => 'Add block',
156 'page callback' => 'drupal_get_form',
157 'page arguments' => array('block_add_block_form'),
158 'access arguments' => array('administer blocks'),
159 'type' => MENU_LOCAL_TASK,
160 );
161 $default = variable_get('theme_default', 'garland');
162 foreach (list_themes() as $key => $theme) {
163 $items['admin/structure/block/list/' . $key] = array(
164 'title' => check_plain($theme->info['name']),
165 'page arguments' => array($key),
166 'type' => $key == $default ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK,
167 'weight' => $key == $default ? -10 : 0,
168 'access callback' => '_block_themes_access',
169 'access arguments' => array($theme),
170 );
171 }
172 return $items;
173 }
174
175 /**
176 * Menu item access callback - only admin or enabled themes can be accessed.
177 */
178 function _block_themes_access($theme) {
179 $admin_theme = variable_get('admin_theme');
180 return user_access('administer blocks') && ($theme->status || ($admin_theme && ($theme->name == $admin_theme)));
181 }
182
183 /**
184 * Implement hook_block_list().
185 */
186 function block_block_list() {
187 $blocks = array();
188
189 $result = db_query('SELECT bid, info FROM {box} ORDER BY info');
190 foreach ($result as $block) {
191 $blocks[$block->bid]['info'] = $block->info;
192 // Not worth caching.
193 $blocks[$block->bid]['cache'] = BLOCK_NO_CACHE;
194 }
195 return $blocks;
196 }
197
198 /**
199 * Implement hook_block_configure().
200 */
201 function block_block_configure($delta = 0, $edit = array()) {
202 $box = array('format' => FILTER_FORMAT_DEFAULT);
203 if ($delta) {
204 $box = block_box_get($delta);
205 }
206 return block_box_form($box);
207 }
208
209 /**
210 * Implement hook_block_save().
211 */
212 function block_block_save($delta = 0, $edit = array()) {
213 block_box_save($edit, $delta);
214 }
215
216 /**
217 * Implement hook_block_view().
218 *
219 * Generates the administrator-defined blocks for display.
220 */
221 function block_block_view($delta = 0, $edit = array()) {
222 $block = db_query('SELECT body, format FROM {box} WHERE bid = :bid', array(':bid' => $delta))->fetchObject();
223 $data['content'] = check_markup($block->body, $block->format, '', FALSE);
224 return $data;
225 }
226
227 /**
228 * Implement hook_page_alter().
229 *
230 * Render blocks into their regions.
231 */
232 function block_page_alter($page) {
233 global $theme;
234
235 // The theme system might not yet be initialized. We need $theme.
236 drupal_theme_initialize();
237
238 // Populate all block regions
239 $all_regions = system_region_list($theme);
240
241 // Load all region content assigned via blocks.
242 foreach (array_keys($all_regions) as $region) {
243 // Prevent sidebar regions from rendering blocks when 'show_blocks' == FALSE.
244 if (!empty($page['#show_blocks']) || (strpos($region, 'sidebar_') !== 0)) {
245 // Assign blocks to region.
246 if ($blocks = block_get_blocks_by_region($region)) {
247 $page[$region] = $blocks;
248 }
249
250 // Append region description if we are rendering the block admin page.
251 $item = menu_get_item();
252 if ($item['path'] == 'admin/structure/block') {
253 $visible_regions = system_region_list($theme, REGIONS_VISIBLE);
254 if (isset($visible_regions[$region])) {
255 $description = '<div class="block-region">' . $all_regions[$region] . '</div>';
256 $page[$region]['block_description'] = array(
257 '#markup' => $description,
258 '#weight' => 15,
259 );
260 }
261 }
262 }
263 }
264 }
265
266 /**
267 * Get a renderable array of a region containing all enabled blocks.
268 *
269 * @param $region
270 * The requested region.
271 */
272 function block_get_blocks_by_region($region) {
273 $weight = 0;
274 $build = array();
275 if ($list = block_list($region)) {
276 foreach ($list as $key => $block) {
277 $build[$key] = $block->content;
278 unset($block->content);
279 $build[$key] += array(
280 '#block' => $block,
281 '#weight' => ++$weight,
282 );
283 $build[$key]['#theme_wrappers'][] ='block';
284 }
285 $build['#sorted'] = TRUE;
286 }
287 return $build;
288 }
289
290 /**
291 * Update the 'block' DB table with the blocks currently exported by modules.
292 *
293 * @return
294 * Blocks currently exported by modules.
295 */
296 function _block_rehash() {
297 global $theme_key;
298
299 drupal_theme_initialize();
300
301 $old_blocks = array();
302 $result = db_query("SELECT * FROM {block} WHERE theme = :theme", array(':theme' => $theme_key));
303 foreach ($result as $old_block) {
304 $old_block = is_object($old_block) ? get_object_vars($old_block) : $old_block;
305 $old_blocks[$old_block['module']][$old_block['delta']] = $old_block;
306 }
307
308 $blocks = array();
309 // Valid region names for the theme.
310 $regions = system_region_list($theme_key);
311
312 foreach (module_implements('block_list') as $module) {
313 $module_blocks = module_invoke($module, 'block_list');
314 if ($module_blocks) {
315 foreach ($module_blocks as $delta => $block) {
316 if (empty($old_blocks[$module][$delta])) {
317 // If it's a new block, add identifiers.
318 $block['module'] = $module;
319 $block['delta'] = $delta;
320 $block['theme'] = $theme_key;
321 if (!isset($block['pages'])) {
322 // {block}.pages is type 'text', so it cannot have a
323 // default value, and not null, so we need to provide
324 // value if the module did not.
325 $block['pages'] = '';
326 }
327 // Add defaults and save it into the database.
328 drupal_write_record('block', $block);
329 // Set region to none if not enabled.
330 $block['region'] = $block['status'] ? $block['region'] : BLOCK_REGION_NONE;
331 // Add to the list of blocks we return.
332 $blocks[] = $block;
333 }
334 else {
335 // If it's an existing block, database settings should overwrite
336 // the code. But aside from 'info' everything that's definable in
337 // code is stored in the database and we do not store 'info', so we
338 // do not need to update the database here.
339 // Add 'info' to this block.
340 $old_blocks[$module][$delta]['info'] = $block['info'];
341 // If the region name does not exist, disable the block and assign it to none.
342 if (!empty($old_blocks[$module][$delta]['region']) && !isset($regions[$old_blocks[$module][$delta]['region']])) {
343 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');
344 $old_blocks[$module][$delta]['status'] = 0;
345 $old_blocks[$module][$delta]['region'] = BLOCK_REGION_NONE;
346 }
347 else {
348 $old_blocks[$module][$delta]['region'] = $old_blocks[$module][$delta]['status'] ? $old_blocks[$module][$delta]['region'] : BLOCK_REGION_NONE;
349 }
350 // Add this block to the list of blocks we return.
351 $blocks[] = $old_blocks[$module][$delta];
352 // Remove this block from the list of blocks to be deleted.
353 unset($old_blocks[$module][$delta]);
354 }
355 }
356 }
357 }
358
359 // Remove blocks that are no longer defined by the code from the database.
360 foreach ($old_blocks as $module => $old_module_blocks) {
361 foreach ($old_module_blocks as $delta => $block) {
362 db_delete('block')
363 ->condition('module', $module)
364 ->condition('delta', $delta)
365 ->condition('theme', $theme_key)
366 ->execute();
367 }
368 }
369 return $blocks;
370 }
371
372 function block_box_get($bid) {
373 return db_query("SELECT * FROM {box} WHERE bid = :bid", array(':bid' => $bid))->fetchAssoc();
374 }
375
376 /**
377 * Define the custom block form.
378 */
379 function block_box_form($edit = array()) {
380 $edit += array(
381 'info' => '',
382 'body' => '',
383 );
384 $form['info'] = array(
385 '#type' => 'textfield',
386 '#title' => t('Block description'),
387 '#default_value' => $edit['info'],
388 '#maxlength' => 64,
389 '#description' => t('A brief description of your block. Used on the <a href="@overview">blocks administration page</a>.', array('@overview' => url('admin/structure/block'))),
390 '#required' => TRUE,
391 '#weight' => -19,
392 );
393 $form['body_field']['#weight'] = -17;
394 $form['body_field']['body'] = array(
395 '#type' => 'textarea',
396 '#title' => t('Block body'),
397 '#default_value' => $edit['body'],
398 '#text_format' => isset($edit['format']) ? $edit['format'] : FILTER_FORMAT_DEFAULT,
399 '#rows' => 15,
400 '#description' => t('The content of the block as shown to the user.'),
401 '#required' => TRUE,
402 '#weight' => -17,
403 '#access' => filter_access($edit['format']),
404 );
405
406 return $form;
407 }
408
409 function block_box_save($edit, $delta) {
410 db_update('box')
411 ->fields(array(
412 'body' => $edit['body'],
413 'info' => $edit['info'],
414 'format' => $edit['body_format'],
415 ))
416 ->condition('bid', $delta)
417 ->execute();
418 return TRUE;
419 }
420
421 /**
422 * Implement hook_user_form().
423 */
424 function block_user_form(&$edit, $account, $category) {
425 if ($category == 'account') {
426 $rids = array_keys($account->roles);
427 $result = db_query("SELECT DISTINCT b.* FROM {block} b LEFT JOIN {block_role} r ON b.module = r.module AND b.delta = r.delta WHERE b.status = 1 AND b.custom <> 0 AND (r.rid IN (:rids) OR r.rid IS NULL) ORDER BY b.weight, b.module", array(':rids' => $rids));
428 $form['block'] = array(
429 '#type' => 'fieldset',
430 '#title' => t('Personalize blocks'),
431 '#description' => t('Blocks consist of content or information that complements the main content of the page. Enable or disable optional blocks using the checkboxes below.'),
432 '#weight' => 3,
433 '#collapsible' => TRUE,
434 '#tree' => TRUE
435 );
436 foreach ($result as $block) {
437 $data = module_invoke($block->module, 'block_list');
438 if ($data[$block->delta]['info']) {
439 $return = TRUE;
440 $form['block'][$block->module][$block->delta] = array(
441 '#type' => 'checkbox',
442 '#title' => check_plain($data[$block->delta]['info']),
443 '#default_value' => isset($account->block[$block->module][$block->delta]) ? $account->block[$block->module][$block->delta] : ($block->custom == 1),
444 );
445 }
446 }
447
448 if (!empty($return)) {
449 return $form;
450 }
451 }
452 }
453
454 /**
455 * Implement hook_user_validate().
456 */
457 function block_user_validate(&$edit, $account, $category) {
458 if (empty($edit['block'])) {
459 $edit['block'] = array();
460 }
461 return $edit;
462 }
463
464 /**
465 * Implement hook_form_FORM_ID_alter().
466 */
467 function block_form_system_themes_form_alter(&$form, &$form_state) {
468 // This function needs to fire before the theme changes are recorded in the
469 // database, otherwise it will populate the default list of blocks from the
470 // new theme, which is empty.
471 array_unshift($form['#submit'], 'block_system_themes_form_submit');
472 }
473
474 /**
475 * Initialize blocks for enabled themes.
476 */
477 function block_system_themes_form_submit(&$form, &$form_state) {
478 if ($form_state['values']['op'] == t('Save configuration')) {
479 if (is_array($form_state['values']['status'])) {
480 foreach ($form_state['values']['status'] as $key => $choice) {
481 if ($choice || $form_state['values']['theme_default'] == $key) {
482 block_theme_initialize($key);
483 }
484 }
485 }
486 if ($form_state['values']['admin_theme'] && $form_state['values']['admin_theme'] !== variable_get('admin_theme', 0)) {
487 // If we're changing themes, make sure the theme has its blocks initialized.
488 $has_blocks = (bool) db_query_range('SELECT 1 FROM {block} WHERE theme = :theme', array(':theme' => $form_state['values']['admin_theme']), 0, 1)->fetchField();
489 if (!$has_blocks) {
490 block_theme_initialize($form_state['values']['admin_theme']);
491 }
492 }
493 }
494 }
495
496 /**
497 * Assign an initial, default set of blocks for a theme.
498 *
499 * This function is called the first time a new theme is enabled. The new theme
500 * gets a copy of the default theme's blocks, with the difference that if a
501 * particular region isn't available in the new theme, the block is assigned
502 * to the new theme's default region.
503 *
504 * @param $theme
505 * The name of a theme.
506 */
507 function block_theme_initialize($theme) {
508 // Initialize theme's blocks if none already registered.
509 $has_blocks = (bool) db_query_range('SELECT 1 FROM {block} WHERE theme = :theme', array(':theme' => $theme), 0, 1)->fetchField();
510 if (!$has_blocks) {
511 $default_theme = variable_get('theme_default', 'garland');
512 $regions = system_region_list($theme);
513 $result = db_query("SELECT * FROM {block} WHERE theme = :theme", array(':theme' => $default_theme), array('fetch' => PDO::FETCH_ASSOC));
514 $query = db_insert('block')->fields(array('module', 'delta', 'theme', 'status', 'weight', 'region', 'visibility', 'pages', 'custom', 'cache'));
515 foreach ($result as $block) {
516 // If the region isn't supported by the theme, assign the block to the theme's default region.
517 if (!array_key_exists($block['region'], $regions)) {
518 $block['region'] = system_default_region($theme);
519 }
520 $block['theme'] = $theme;
521 $query->values($block);
522 }
523 $query->execute();
524 }
525 }
526
527 /**
528 * Return all blocks in the specified region for the current user.
529 *
530 * @param $region
531 * The name of a region.
532 *
533 * @return
534 * An array of block objects, indexed with <i>module</i>_<i>delta</i>.
535 * If you are displaying your blocks in one or two sidebars, you may check
536 * whether this array is empty to see how many columns are going to be
537 * displayed.
538 *
539 * @todo
540 * Now that the blocks table has a primary key, we should use that as the
541 * array key instead of <i>module</i>_<i>delta</i>.
542 */
543 function block_list($region) {
544 $blocks = &drupal_static(__FUNCTION__, array());
545
546 if (empty($blocks)) {
547 $blocks = _block_load_blocks();
548 }
549
550 // Create an empty array if there were no entries.
551 if (!isset($blocks[$region])) {
552 $blocks[$region] = array();
553 }
554
555 $blocks[$region] = _block_render_blocks($blocks[$region]);
556
557 return $blocks[$region];
558 }
559
560 /**
561 * Load blocks information from the database.
562 */
563 function _block_load_blocks() {
564 global $theme_key;
565
566 $query = db_select('block', 'b');
567 $result = $query
568 ->fields('b')
569 ->condition('b.theme', $theme_key)
570 ->condition('b.status', 1)
571 ->orderBy('b.region')
572 ->orderBy('b.weight')
573 ->orderBy('b.module')
574 ->addTag('block_load')
575 ->execute();
576
577 $block_list = $result->fetchAllAssoc('bid');
578 // Allow modules to modify the block list.
579 drupal_alter('block_list', $block_list);
580
581 $blocks = array();
582 foreach ($block_list as $block) {
583 $blocks[$block->region]["{$block->module}_{$block->delta}"] = $block;
584 }
585 return $blocks;
586 }
587
588 /**
589 * Implement hook_block_list_alter().
590 *
591 * Check the page, user role, content type and user specific visibilty settings.
592 * Remove the block if the visibility conditions are not met.
593 */
594 function block_block_list_alter(&$blocks) {
595 global $user, $theme_key;
596
597 // Build an array of roles for each block.
598 $block_roles = array();
599 $result = db_query('SELECT module, delta, rid FROM {block_role}');
600 foreach ($result as $record) {
601 $block_roles[$record->module][$record->delta][] = $record->rid;
602 }
603
604 // Build an array of node types for each block.
605 $block_node_types = array();
606 $result = db_query('SELECT module, delta, type FROM {block_node_type}');
607 foreach ($result as $record) {
608 $block_node_types[$record->module][$record->delta][] = $record->type;
609 }
610
611 foreach ($blocks as $key => $block) {
612 if ($block->theme != $theme_key || $block->status != 1) {
613 // This block was added by a contrib module, leave it in the list.
614 continue;
615 }
616
617 // If a block has no roles associated, it is displayed for every role.
618 // For blocks with roles associated, if none of the user's roles matches
619 // the settings from this block, remove it from the block list.
620 if (isset($block_roles[$block->module][$block->delta]) && !array_intersect($block_roles[$block->module][$block->delta], array_keys($user->roles))) {
621 // No match.
622 unset($blocks[$key]);
623 continue;
624 }
625
626 // If a block has no node types associated, it is displayed for every type.
627 // For blocks with node types associated, if the node type does not match
628 // the settings from this block, remove it from the block list.
629 if (isset($block_node_types[$block->module][$block->delta])) {
630 $node = menu_get_object();
631 if (!empty($node)) {
632 // This is a node or node edit page.
633 if (!in_array($node->type, $block_node_types[$block->module][$block->delta])) {
634 // This block should not be displayed for this node type.
635 unset($blocks[$key]);
636 continue;
637 }
638 }
639 elseif (arg(0) == 'node' && arg(1) == 'add' && in_array(arg(2), array_keys(node_type_get_types()))) {
640 // This is a node creation page
641 if (!in_array(arg(2), $block_node_types[$block->module][$block->delta])) {
642 // This block should not be displayed for this node type.
643 unset($blocks[$key]);
644 continue;
645 }
646 }
647 else {
648 // This is not a node page, remove the block.
649 unset($blocks[$key]);
650 continue;
651 }
652 }
653
654 // Use the user's block visibility setting, if necessary.
655 if ($block->custom != 0) {
656 if ($user->uid && isset($user->block[$block->module][$block->delta])) {
657 $enabled = $user->block[$block->module][$block->delta];
658 }
659 else {
660 $enabled = ($block->custom == 1);
661 }
662 }
663 else {
664 $enabled = TRUE;
665 }
666 if (!$enabled) {
667 unset($blocks[$key]);
668 continue;
669 }
670
671 // Match path if necessary.
672 if ($block->pages) {
673 if ($block->visibility < 2) {
674 $path = drupal_get_path_alias($_GET['q']);
675 // Compare with the internal and path alias (if any).
676 $page_match = drupal_match_path($path, $block->pages);
677 if ($path != $_GET['q']) {
678 $page_match = $page_match || drupal_match_path($_GET['q'], $block->pages);
679 }
680 // When $block->visibility has a value of 0, the block is displayed on
681 // all pages except those listed in $block->pages. When set to 1, it
682 // is displayed only on those pages listed in $block->pages.
683 $page_match = !($block->visibility xor $page_match);
684 }
685 elseif (module_exists('php')) {
686 $page_match = php_eval($block->pages);
687 }
688 else {
689 $page_match = FALSE;
690 }
691 }
692 else {
693 $page_match = TRUE;
694 }
695 if (!$page_match) {
696 unset($blocks[$key]);
697 }
698 }
699 }
700
701 /**
702 * Render the content and subject for a set of blocks.
703 *
704 * @param $region_blocks
705 * An array of block objects such as returned for one region by _block_load_blocks().
706 *
707 * @return
708 * An array of visible blocks with subject and content rendered.
709 */
710 function _block_render_blocks($region_blocks) {
711 foreach ($region_blocks as $key => $block) {
712 // Render the block content if it has not been created already.
713 if (!isset($block->content)) {
714 // Erase the block from the static array - we'll put it back if it has
715 // content.
716 unset($region_blocks[$key]);
717 // Try fetching the block from cache. Block caching is not compatible
718 // with node_access modules. We also preserve the submission of forms in
719 // blocks, by fetching from cache only if the request method is 'GET'
720 // (or 'HEAD').
721 if (!count(module_implements('node_grants')) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD') && ($cid = _block_get_cache_id($block)) && ($cache = cache_get($cid, 'cache_block'))) {
722 $array = $cache->data;
723 }
724 else {
725 $array = module_invoke($block->module, 'block_view', $block->delta);
726 if (isset($cid)) {
727 cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);
728 }
729 }
730
731 if (isset($array) && is_array($array)) {
732 foreach ($array as $k => $v) {
733 $block->$k = $v;
734 }
735 }
736 if (isset($block->content) && $block->content) {
737 // Normalize to the drupal_render() structure.
738 if (is_string($block->content)) {
739 $block->content = array('#markup' => $block->content);
740 }
741 // Override default block title if a custom display title is present.
742 if ($block->title) {
743 // Check plain here to allow module generated titles to keep any
744 // markup.
745 $block->subject = $block->title == '<none>' ? '' : check_plain($block->title);
746 }
747 if (!isset($block->subject)) {
748 $block->subject = '';
749 }
750 $region_blocks["{$block->module}_{$block->delta}"] = $block;
751 }
752 }
753 }
754 return $region_blocks;
755 }
756
757 /**
758 * Assemble the cache_id to use for a given block.
759 *
760 * The cache_id string reflects the viewing context for the current block
761 * instance, obtained by concatenating the relevant context information
762 * (user, page, ...) according to the block's cache settings (BLOCK_CACHE_*
763 * constants). Two block instances can use the same cached content when
764 * they share the same cache_id.
765 *
766 * Theme and language contexts are automatically differentiated.
767 *
768 * @param $block
769 * @return
770 * The string used as cache_id for the block.
771 */
772 function _block_get_cache_id($block) {
773 global $theme, $base_root, $user;
774
775 // User 1 being out of the regular 'roles define permissions' schema,
776 // it brings too many chances of having unwanted output get in the cache
777 // and later be served to other users. We therefore exclude user 1 from
778 // block caching.
779 if (variable_get('block_cache', 0) && $block->cache != BLOCK_NO_CACHE && $user->uid != 1) {
780 $cid_parts = array();
781
782 // Start with common sub-patterns: block identification, theme, language.
783 $cid_parts[] = $block->module;
784 $cid_parts[] = $block->delta;
785 $cid_parts[] = $theme;
786 if (module_exists('locale')) {
787 global $language;
788 $cid_parts[] = $language->language;
789 }
790
791 // 'PER_ROLE' and 'PER_USER' are mutually exclusive. 'PER_USER' can be a
792 // resource drag for sites with many users, so when a module is being
793 // equivocal, we favor the less expensive 'PER_ROLE' pattern.
794 if ($block->cache & BLOCK_CACHE_PER_ROLE) {
795 $cid_parts[] = 'r.' . implode(',', array_keys($user->roles));
796 }
797 elseif ($block->cache & BLOCK_CACHE_PER_USER) {
798 $cid_parts[] = "u.$user->uid";
799 }
800
801 if ($block->cache & BLOCK_CACHE_PER_PAGE) {
802 $cid_parts[] = $base_root . request_uri();
803 }
804
805 return implode(':', $cid_parts);
806 }
807 }
808
809 /**
810 * Implement hook_flush_caches().
811 */
812 function block_flush_caches() {
813 return array('cache_block');
814 }
815
816 /**
817 * Process variables for block.tpl.php
818 *
819 * Prepare the values passed to the theme_block function to be passed
820 * into a pluggable template engine. Uses block properties to generate a
821 * series of template file suggestions. If none are found, the default
822 * block.tpl.php is used.
823 *
824 * Most themes utilize their own copy of block.tpl.php. The default is located
825 * inside "modules/block/block.tpl.php". Look in there for the full list of
826 * variables.
827 *
828 * The $variables array contains the following arguments:
829 * - $block
830 *
831 * @see block.tpl.php
832 */
833 function template_preprocess_block(&$variables) {
834 $block_counter = &drupal_static(__FUNCTION__, array());
835 $variables['block'] = $variables['elements']['#block'];
836 // All blocks get an independent counter for each region.
837 if (!isset($block_counter[$variables['block']->region])) {
838 $block_counter[$variables['block']->region] = 1;
839 }
840 // Same with zebra striping.
841 $variables['block_zebra'] = ($block_counter[$variables['block']->region] % 2) ? 'odd' : 'even';
842 $variables['block_id'] = $block_counter[$variables['block']->region]++;
843
844 // Create the $content variable that templates expect.
845 $variables['content'] = $variables['elements']['#children'];
846
847 $variables['classes_array'][] = 'block-' . $variables['block']->module;
848
849 $variables['template_files'][] = 'block-' . $variables['block']->region;
850 $variables['template_files'][] = 'block-' . $variables['block']->module;
851 $variables['template_files'][] = 'block-' . $variables['block']->module . '-' . $variables['block']->delta;
852 }
853

Legend

Missed
lines code that were not excersized during program execution.
Covered
lines code were excersized during program execution.
Comment/non executable
Comment or non-executable line of code.
Dead
lines of code that according to xdebug could not be executed. This is counted as coverage code because in almost all cases it is code that runnable.