While testing the Persona module, I encountered a fatal error as described in #1967778: Fatal Error on vanilla site with just Persona and Session API where NULL $data variables are passed to hook_block_view_alter().

To reproduce, I created a new vanilla D7 instance with a single test module with this function:

function test_block_view_alter(&$data, $block) {
  if (!isset($data)) {
    drupal_set_message("\$block is " . var_export($block, TRUE));
  }
}

With some clicking around, I found two blocks that get sent to hook_block_view_alter() with a NULL $data:

$block is stdClass::__set_state(array( 'bid' => '2', 'module' => 'search', 'delta' => 'form', 'theme' => 'bartik', 'status' => '1', 'weight' => '-1', 'region' => 'sidebar_first', 'custom' => '0', 'visibility' => '0', 'pages' => '', 'title' => '', 'cache' => '-1', ))
    $block is stdClass::__set_state(array( 'bid' => '4', 'module' => 'user', 'delta' => 'login', 'theme' => 'bartik', 'status' => '1', 'weight' => '0', 'region' => 'sidebar_first', 'custom' => '0', 'visibility' => '0', 'pages' => '', 'title' => '', 'cache' => '-1', )

According to the hook_block_view_alter() documentation, it says:

$data: An array of data, as returned from the hook_block_view()

Therefore, NULL $data being sent to hook_block_view_alter() for certain core blocks is inconsistent with the documentation, and should be fixed.

Comments

neRok’s picture

Status: Active » Closed (works as designed)

_block_render_blocks is the controlling function. Here is the relevant snippet.

        $array = module_invoke($block->module, 'block_view', $block->delta);

        // Allow modules to modify the block before it is viewed, via either
        // hook_block_view_alter() or hook_block_view_MODULE_DELTA_alter().
        drupal_alter(array('block_view', "block_view_{$block->module}_{$block->delta}"), $array, $block);

So it gets the block_view from the module defining the block, and passes it straight to block_view_alter. If the module didnt define any return, then array is empty. As you have noted, multiple modules are doing this, and this is fine. Any module implementing hook_block_view_alter should check if the data is empty, before acting on it.

brianV’s picture

Status: Closed (works as designed) » Active

The documentation is inconsistent with the core behaviour. Therefore, one of the two has to be fixed.

This issue should not be closed until either the documentation is updated to indicate that $data may occasionally be NULL, or we update the code to prevent this situation.

neRok’s picture

Component: base system » documentation
jhodgdon’s picture

Issue tags: +Novice

I agree with brianV. We should add a bit to hook_block_view() to say modules can omit returning if the block should not be shown (which is, in practice, what search_block_view() is doing if the user has no permission to search, and what user_block_view() is doing with the 'login' block if the user is already logged in). Then we should add a bit to hook_block_view_alter() and hook_block_view_MODULE_DELTA_alter() to say that the $data input could be NULL.

The system is somewhat different in Drupal 8.x, since blocks are plugins... so I do not know if this problem exists there... I think not though. For instance SearchBlock::blockBuild() never returns NULL (there is a different block access mechanism in place), and neither does UserLoginBlock::blockBuild(), so I think this is a 7.x issue only.

Seems like a good Novice project to make these additions to the documentation...

ebargtuo’s picture

Status: Active » Needs review
StatusFileSize
new2.54 KB

Here's a try at a patch to the documentation to incorporate the changes in #4.

jhodgdon’s picture

Status: Needs review » Needs work

The documentation for hook_block_view() is being updated on a separate issue #2044791: hook_block_view() doesn't explain @return value for empty block, so let's leave that out of this patch.

In the alter hooks ...

  * @param $data
- *   An array of data, as returned from the hook_block_view() implementation of
+ *   An array of data or NULL, as returned from the hook_block_view()
+ *   implementation of
  *   the module that defined the block:

This is very awkward... How about if it says something like:
The data returned by the hook_block_view() implementation in the module that defined the block. This could be a string, a NULL value (if the block was empty), or a renderable array containing:

And if something like that wording is used, I think we can leave out:

+ *   If the block should not be shown, $data may be NULL. Any module
+ *   implementing this hook should check if $data is NULL, before acting on it.

since it would be redundant.

Also... If you modify documentation in a patch, you need to re-wrap surrounding lines so that each line wraps as close to 80 characters as possible without going over. Thanks!

ebargtuo’s picture

Status: Needs work » Needs review
StatusFileSize
new1.49 KB

Thanks for the feedback! Here's another go. I've left out the hook_block_view() change dealt with in the separate issue.

Still a bit awkward, but in the examples in #4 user_block_view() may end up returning an empty array and search_block_view() may end up not returning a value, making $data NULL.

jhodgdon’s picture

Status: Needs review » Fixed

I think that is quite clear and not awkward at all. Thanks! Committed to 7.x.

Automatically closed -- issue fixed for 2 weeks with no activity.

Anonymous’s picture

Issue summary: View changes

Fix typo