mongodb_block.module

Tracking 7.x-1.x branch
  1. drupal
    1. 7 contributions/mongodb/mongodb_block/mongodb_block.module

Controls the visual building blocks a page is constructed with.

Resembles very closely the core block module but without an UI.

Functions & methods

NameDescription
mongodb_block_flush_cachesImplements hook_flush_caches().
mongodb_block_form_system_modules_alterImplements hook_form_system_modules_alter().
mongodb_block_get_cache_idAssemble the cache_id to use for a given block.
mongodb_block_get_renderable_arrayGets an array of blocks suitable for drupal_render().
mongodb_block_menuImplements hook_menu().
mongodb_block_mongodb_block_info_alterImplements hook_mongodb_block_info_alter().
mongodb_block_page_buildImplements hook_page_build().
mongodb_block_rehashRun _mongodb_block_rehash and go to admin/structure.
mongodb_block_render_blocksRender the content and subject for a set of blocks.
mongodb_block_save_blockUnset block data and save the block collection.
mongodb_block_themeImplements hook_theme().
template_preprocess_blockProcess variables for block.tpl.php
_mongodb_block_rehashUpdates the block collection with the blocks currently exported by modules.

Constants

NameDescription
MONGODB_BLOCK_REGION_NONE

File

View source
  1. <?php
  2. /**
  3. * @file
  4. * Controls the visual building blocks a page is constructed with.
  5. *
  6. * Resembles very closely the core block module but without an UI.
  7. */
  8. // Denotes that a block is not enabled in any region and should not be shown.
  9. define('MONGODB_BLOCK_REGION_NONE', -1);
  10. /**
  11. * Implements hook_menu().
  12. */
  13. function mongodb_block_menu() {
  14. return array(
  15. 'admin/structure/block-rebuild' => array(
  16. 'title' => t('Block rebuild'),
  17. 'description' => 'Rebuilds blocks in MongoDB',
  18. 'page callback' => 'mongodb_block_rehash',
  19. 'access arguments' => array('administer site configuration'),
  20. ),
  21. );
  22. }
  23. /**
  24. * Implements hook_flush_caches().
  25. */
  26. function mongodb_block_flush_caches() {
  27. return array('cache_block');
  28. }
  29. /**
  30. * Implements hook_theme().
  31. */
  32. function mongodb_block_theme() {
  33. return array(
  34. 'block' => array(
  35. 'render element' => 'elements',
  36. 'template' => 'block',
  37. 'path' => drupal_get_path('module', 'block'),
  38. ),
  39. );
  40. }
  41. /**
  42. * Implements hook_form_system_modules_alter().
  43. *
  44. * Hide block, dashboard module.
  45. */
  46. function mongodb_block_form_system_modules_alter(&$form, &$form_state) {
  47. unset($form['modules']['Core']['block']);
  48. unset($form['modules']['Core']['dashboard']);
  49. }
  50. /**
  51. * Implements hook_page_build().
  52. *
  53. * Render blocks into their regions.
  54. */
  55. function mongodb_block_page_build(&$page) {
  56. global $theme;
  57. // The theme system might not yet be initialized. We need $theme.
  58. drupal_theme_initialize();
  59. // Grab only the current regions.
  60. $all_regions = system_region_list($theme);
  61. $collection = mongodb_collection('block', $theme);
  62. if (!$collection->findOne()) {
  63. _mongodb_block_rehash($theme);
  64. }
  65. $query = array();
  66. if ($node = menu_get_object()) {
  67. $query['node_type']['$in'] = array('*', $node->type);
  68. }
  69. $parts = array_slice(arg(), 0, MENU_MAX_PARTS);
  70. $ancestors = menu_get_ancestors($parts);
  71. if ($_GET['q'] != request_path()) {
  72. $request_parts = array_slice(explode('/', request_path()), 0, MENU_MAX_PARTS);
  73. $ancestors = array_merge($ancestors, menu_get_ancestors($request_parts));
  74. }
  75. $ancestors[] = '%';
  76. if (drupal_is_front_page()) {
  77. $ancestors[] = '<front>';
  78. }
  79. $query['pages']['$in'] = $ancestors;
  80. $query['pages_exclude']['$nin'] = $ancestors;
  81. $query['region']['$in'] = array_keys($all_regions);
  82. $blocks = mongodb_block_render_blocks($collection->find($query)->sort(array('weight' => 1)));
  83. foreach ($blocks as $region => $region_blocks) {
  84. $page[$region] = mongodb_block_get_renderable_array($region_blocks);
  85. }
  86. }
  87. /**
  88. * Render the content and subject for a set of blocks.
  89. *
  90. * @param array $blocks_result
  91. * An array of block objects such as returned for one region by
  92. * _block_load_blocks()
  93. */
  94. function mongodb_block_render_blocks($blocks_result) {
  95. $return = array();
  96. foreach ($blocks_result as $block) {
  97. // Copy module and delta out of the _id.
  98. $block += $block['_id'];
  99. $block = (object) $block;
  100. // Render the block content if it has not been created already.
  101. if (!isset($block->content)) {
  102. // Try fetching the block from cache. Block caching is not compatible
  103. // with node_access modules. We also preserve the submission of forms in
  104. // blocks, by fetching from cache only if the request method is 'GET'
  105. // (or 'HEAD').
  106. if (($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD') && ($cid = mongodb_block_get_cache_id($block)) && ($cache = cache_get($cid, 'cache_block'))) {
  107. $array = $cache->data;
  108. }
  109. else {
  110. $array = module_invoke($block->module, 'block_view', $block->delta);
  111. // Allow modules to modify the block before it is viewed, via either
  112. // hook_block_view_MODULE_DELTA_alter() or hook_block_view_alter().
  113. drupal_alter("block_view_{$block->module}_{$block->delta}", $array, $block);
  114. drupal_alter('block_view', $array, $block);
  115. if (isset($cid)) {
  116. cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);
  117. }
  118. }
  119. if (isset($array) && is_array($array)) {
  120. foreach ($array as $k => $v) {
  121. $block->$k = $v;
  122. }
  123. }
  124. }
  125. if (isset($block->content) && $block->content) {
  126. // Normalize to the drupal_render() structure.
  127. if (is_string($block->content)) {
  128. $block->content = array('#markup' => $block->content);
  129. }
  130. // Override default block title if a custom display title is present.
  131. if (!empty($block->title)) {
  132. // Check plain here to allow module generated titles to keep any
  133. // markup.
  134. $block->subject = $block->title == '<none>' ? '' : check_plain($block->title);
  135. }
  136. if (!isset($block->subject)) {
  137. $block->subject = '';
  138. }
  139. $return[$block->region]["{$block->module}_{$block->delta}"] = $block;
  140. }
  141. }
  142. return $return;
  143. }
  144. /**
  145. * Assemble the cache_id to use for a given block.
  146. *
  147. * The cache_id string reflects the viewing context for the current block
  148. * instance, obtained by concatenating the relevant context information
  149. * (user, page, ...) according to the block's cache settings (BLOCK_CACHE_*
  150. * constants). Two block instances can use the same cached content when
  151. * they share the same cache_id.
  152. *
  153. * Theme and language contexts are automatically differentiated.
  154. *
  155. * @param object $block
  156. * The block object.
  157. *
  158. * @return string
  159. * The string used as cache_id for the block.
  160. */
  161. function mongodb_block_get_cache_id($block) {
  162. global $user;
  163. // Not all block definitions define caching.
  164. if (!isset($block->cache)) {
  165. $block->cache = DRUPAL_NO_CACHE;
  166. }
  167. // User 1 being out of the regular 'roles define permissions' schema,
  168. // it brings too many chances of having unwanted output get in the cache
  169. // and later be served to other users. We therefore exclude user 1 from
  170. // block caching.
  171. if (variable_get('block_cache', 0) && !in_array($block->cache, array(DRUPAL_NO_CACHE, DRUPAL_CACHE_CUSTOM)) && $user->uid != 1) {
  172. // Start with common sub-patterns: block identification, theme, language.
  173. $cid_parts[] = $block->module;
  174. $cid_parts[] = $block->delta;
  175. $cid_parts = array_merge($cid_parts, drupal_render_cid_parts($block->cache));
  176. return implode(':', $cid_parts);
  177. }
  178. }
  179. /**
  180. * Gets an array of blocks suitable for drupal_render().
  181. *
  182. * @param array $region_blocks
  183. * A list of blocks.
  184. */
  185. function mongodb_block_get_renderable_array($region_blocks) {
  186. global $theme;
  187. $weight = 0;
  188. $build = array();
  189. foreach ($region_blocks as $key => $block) {
  190. $build[$key] = $block->content;
  191. unset($block->content);
  192. // Add contextual links for this block; skip the main content block, since
  193. // contextual links are basically output as tabs/local tasks already. Also
  194. // skip the help block, since we assume that most users do not need or want
  195. // to perform contextual actions on the help block, and the links needlessly
  196. // draw attention on it.
  197. // @see _block_get_renderable_array();
  198. if (module_exists('mongodb_block_ui') && $key != 'system_main' && $key != 'system_help') {
  199. $build[$key]['#contextual_links']['mongodb_block_ui'] = array('admin/structure/mongodb_block/manage', array($theme, $block->module, $block->delta));
  200. }
  201. $build[$key] += array(
  202. '#block' => $block,
  203. '#weight' => ++$weight,
  204. );
  205. $build[$key]['#theme_wrappers'][] = 'block';
  206. }
  207. $build['#sorted'] = TRUE;
  208. return $build;
  209. }
  210. /**
  211. * Implements hook_mongodb_block_info_alter().
  212. */
  213. function mongodb_block_mongodb_block_info_alter(&$blocks) {
  214. // Enable the main content block if it is not already enabled.
  215. if (empty($blocks['system_main']['status'])) {
  216. $blocks['system_main']['region'] = 'content';
  217. $blocks['system_main']['weight'] = 0;
  218. $blocks['system_main']['status'] = 1;
  219. }
  220. }
  221. /**
  222. * Run _mongodb_block_rehash and go to admin/structure.
  223. */
  224. function mongodb_block_rehash() {
  225. _mongodb_block_rehash(variable_get('theme_default', 'garland'));
  226. drupal_set_message('Blocks rebuild done.');
  227. drupal_goto('admin/structure');
  228. }
  229. /**
  230. * Updates the block collection with the blocks currently exported by modules.
  231. *
  232. * @param string $theme
  233. * The theme to rehash blocks for. If not provided, defaults to the
  234. * currently used theme.
  235. */
  236. function _mongodb_block_rehash($theme) {
  237. $collection = mongodb_collection('block', $theme);
  238. $regions = system_region_list($theme);
  239. $ids = array();
  240. foreach (module_implements('block_info') as $module) {
  241. if ($blocks_current = module_invoke($module, 'block_info')) {
  242. foreach ($blocks_current as $delta => $block) {
  243. $block = array(
  244. '_id' => array('module' => $module, 'delta' => $delta),
  245. 'module' => $module,
  246. 'delta' => $delta,
  247. ) + $block + array(
  248. 'weight' => 0,
  249. 'pages' => array('%'),
  250. 'pages_exclude' => array(),
  251. 'status' => 0,
  252. 'region' => MONGODB_BLOCK_REGION_NONE,
  253. );
  254. if (isset($block['node_type']) && $block['pages'] == array('%')) {
  255. $block['pages'] = array('node/%');
  256. }
  257. else if (!isset($block['node_type'])) {
  258. $block['node_type'] = array('*');
  259. }
  260. $blocks[$module . '_' . $delta] = $block;
  261. }
  262. }
  263. }
  264. drupal_alter('mongodb_block_info', $blocks, $theme);
  265. // Only store the block in the mongodb, if the status is enabled.
  266. foreach ($blocks as $key => $block) {
  267. if ($block['region'] != MONGODB_BLOCK_REGION_NONE && !isset($regions[$block['region']])) {
  268. $blocks[$key]['status'] = 0;
  269. $blocks[$key]['region'] = MONGODB_BLOCK_REGION_NONE;
  270. $block = $blocks[$key];
  271. }
  272. if ($block['status']) {
  273. $ids[] = $block['_id'];
  274. mongodb_block_save_block($collection, $block);
  275. }
  276. }
  277. $collection->remove(array('_id' => array('$nin' => $ids)));
  278. return $blocks;
  279. }
  280. /**
  281. * Unset block data and save the block collection.
  282. *
  283. * @param object $collection
  284. * MongoDB collection to use
  285. * @param array $block
  286. * The block array
  287. */
  288. function mongodb_block_save_block($collection, $block) {
  289. unset($block['module'], $block['delta'], $block['status']);
  290. $collection->save($block);
  291. }
  292. /**
  293. * Process variables for block.tpl.php
  294. *
  295. * Prepare the values passed to the theme_block function to be passed
  296. * into a pluggable template engine. Uses block properties to generate a
  297. * series of template file suggestions. If none are found, the default
  298. * block.tpl.php is used.
  299. *
  300. * Most themes utilize their own copy of block.tpl.php. The default is located
  301. * inside "modules/block/block.tpl.php". Look in there for the full list of
  302. * variables.
  303. *
  304. * The $variables array contains the following arguments:
  305. * - $block
  306. *
  307. * @see block.tpl.php
  308. */
  309. function template_preprocess_block(&$variables) {
  310. $block_counter = &drupal_static(__FUNCTION__, array());
  311. $variables['block'] = $variables['elements']['#block'];
  312. // All blocks get an independent counter for each region.
  313. if (!isset($block_counter[$variables['block']->region])) {
  314. $block_counter[$variables['block']->region] = 1;
  315. }
  316. // Same with zebra striping.
  317. $variables['block_zebra'] = ($block_counter[$variables['block']->region] % 2) ? 'odd' : 'even';
  318. $variables['block_id'] = $block_counter[$variables['block']->region]++;
  319. // Create the $content variable that templates expect.
  320. $variables['content'] = $variables['elements']['#children'];
  321. $variables['classes_array'][] = drupal_html_class('block-' . $variables['block']->module);
  322. $variables['theme_hook_suggestions'][] = 'block__' . $variables['block']->region;
  323. $variables['theme_hook_suggestions'][] = 'block__' . $variables['block']->module;
  324. $variables['theme_hook_suggestions'][] = 'block__' . $variables['block']->module . '__' . $variables['block']->delta;
  325. // Create a valid HTML ID and make sure it is unique.
  326. $variables['block_html_id'] = drupal_html_id('block-' . $variables['block']->module . '-' . $variables['block']->delta);
  327. }