4

Is there a way, from anywhere in drupal, to get the current entity object? I'm using the hook hook_filter_FILTER_process() and I'd like to replace things in the $text with data from the entity, but it doesn't look like there is a way to access the entity without doing something like

if (!empty(arg(0)) && is_numeric(arg(1)) {
    $entity = entity_load(arg(0), array(arg(1)));
}

This works most of the time, but sometimes (like taxonomy terms) it doesn't. On top of that, this is really messy as it makes another call to the database.

Is there a better way to do this?

8

I think menu_get_object() might be helpful:

menu_get_object() provides access to objects loaded by the current router item. For example, on the page node/%node, the router loads the %node object, and calling menu_get_object() will return that. Normally, it is necessary to specify the type of object referenced, however node is the default. The following example tests to see whether the node being displayed is of the "story" content type:

<?php
$node = menu_get_object();
$story = $node->type == 'story';
?>

You can use this with any router-loaded object so it stands to reason that on entity pages (including taxonomy term pages) that this would get you the correct object:

$entity = menu_get_object($entity_type);

UPDATE

On further inspection you still have to pass the position of the ID in the URL as a parameter to menu_get_object() so it's pretty much the same as using arg(), but it's arguably a bit cleaner. For taxonomy terms the path is taxonomy/term/% so you would call:

$term = menu_get_object('taxonomy_term', 2);

It's worth bearing in mind that entity_load will only incur a database call if the entity hasn't previously been loaded in the current page request. If it's already been loaded, it will be served from the static cache.

UPDATE 2

Just to add an example of the static pattern to avoid reloading the entity over and over again if you're getting memory errors:

$loaded_entity = &drupal_static(__FUNCTION__, NULL);
if (!$loaded_entity) {
  $loaded_entity = menu_get_object();
}
return $loaded_entity;
  • when I try and use menu_get_object there, it throws a php memory warning. (too much memory being used). Any ideas on how to reduce the memory this uses? – David Barratt Feb 13 '12 at 15:52
  • You could try implementing the static pattern if you think it's being called too often (I'll stick it in the answer). – Clive Feb 13 '12 at 16:07
  • strange, I took that code and threw it until a function and I'm still running into memory errors. I just printed a simple message to see how many times its running and it's only twice. any ideas? – David Barratt Feb 13 '12 at 19:27
  • @DavidBarratt 'Fraid not, I've just added that code to a hook_filter_FILTER_process() function in a test site and get no memory errors :/ – Clive Feb 14 '12 at 14:26
  • If, to use menu_get_object(), you must already know the entity_type, and if by needing to know the url position of the entity_id you must be able to programmatically access the entity_id, why not just use entity_load()? ps I've got a seperate question on what to do if you don't already have all this information: drupal.stackexchange.com/questions/27747/… – user56reinstatemonica8 Apr 6 '12 at 17:16
2

The proper way is using menu_get_object().

2

Created this agnostic current entity loader function...

<?php
function my_module_menu_get_any_object() {
  // Figure out how this entity is loaded.
  $type = FALSE;
  $item = menu_get_item();
  $vals = array_values($item['load_functions']);
  $load_function = $vals[0];
  $arg_position = array_search($load_function, $item['load_functions']);

  // Compare to entity types.
  $entity_info = entity_get_info();
  foreach($entity_info as $i => $e) {
    if ($e['load hook'] == $load_function) {
      $type = $i;
    }
  }

  // Many happy returns.
  if($type && $obj = menu_get_object($type, $arg_position)) {
    if(is_object($obj)) {
      return $obj;
    }
    else {
      return FALSE;
    }
  }
  else {
    return FALSE;
  }
}
  • Looks very promising and so far it did provide me with all entities. You might want to add an extra check before line 6 to see if $item['load_functions'] exists before proceeding. It threw some errors if there was no entity on the page. – Neograph734 Aug 8 '15 at 13:06
  • 1
    This is actually taken from my Data Layer module, which does have that test included now. Checkout both _datalayer_menu_get_any_object() and datalayer_preprocess_page() in this file... github.com/tableau-mkt/datalayer/blob/7.x-1.x/datalayer.module – doublejosh Aug 15 '15 at 0:01
0

Input filters don't have any way to get the entity for which they are called to render.

Actually, an input filter could also be called in situations where an entity is not involved at all. For example, the Views module allows you to set the header of a view, and gives you the following options.

screenshot

screenshot

When you select Global: Text area, the following options are the following ones.

screenshot

When an input filter is called in this case, there isn't an entity associated with the header of the view; if you would use menu_get_object() you would probably get the wrong entity, or you would not get an entity at all. To get the correct entity with menu_get_object() you need to know which entity is associated with the viewed page, and where the entity ID is stored in the URL.

As general guideline, input filters should not take assumptions about how they are used, as they could be used to render any text obtained as input from the user; the view's header used from the Views module is just an example, but there is nothing that would stop another module from using the same method.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.