There's no consistent way to find an entity when an object is passing through the theme system. I propose that all entity themes in the registry be annotated (overloaded) with the name of the entity's key in the render element array. Then this module's preprocess function should only be only added to specific entity themes where it can be supported.

Currently all entities (that I could find) are themed with a render element instead of variables. field_attach_view() adds entity type and bundle info to the render elements, so it appears to be a requirement that entities be themed with a render element.

This patch renames entity_view_mode_preprocess to entity_view_mode_template_suggest_view_mode so it is only called when it can actually do something useful and not for every single theme call. Then entity_view_mode_template_suggest_view_mode (the preprocess function) loads the theme registry (as a ThemeRegistry object) and grabs the name of the entity key and the name of the render element from the registry.

Comments

Anonymous’s picture

Status: Active » Needs review
StatusFileSize
new5.16 KB

Here's a patch.

Anonymous’s picture

Issue summary: View changes

correcting my mistaken description of problem.

Anonymous’s picture

StatusFileSize
new3.36 KB

This patch changes indentation, which is really making it difficult for me to work with other patches in the queue. This is a patch that doesn't change indentation in the entity_view_mode_preprocess function that is renamed to entity_view_mode_template_suggest_view_mode.

dave reid’s picture

I agree that the current approach is crap, but I am doubting that anything that requires a module to add something in it's theme registry and relying on magic keys to get the entity object is also not the optimal solution. I'm working on something that may work a bit more reliably.

dave reid’s picture

So if we were to try and get away from a theme registry / preprocess approach for detection, what else do we have?

Well we have the hook_field_attach_*() hooks, including hook_field_attach_preprocess_alter() which sounds like it could be useful, but those hooks are only available to entities that are fieldable, which may leave some entities that are viewable but not fieldable out.

Next up is hook_entity_view() and hook_entity_view_alter(). Using hook_entity_view_alter() is out since at that point we've lost the easy context/variable of the entity object and we're back to the same problem. But hook_entity_view() is very interesting. We're provided with specific variables for entity type, entity, view mode, and language code, all the things we need later. If we can store this information in the render API, and then detect this information later in the preprocess, this is pretty much a fool-proof method I think. As for reliability across all entity types, as far as I know, all entity types should to implement both of these hooks if they are viewable (and better yet in D8 it actually is enforced). The one entity type that violated this assumption was Fieldable Panels Panes, and I committed a fix to add the hook invocation: #1900528: PanelsPaneController::view() invokes hook_entity_view_alter() but doesn't invoke hook_entity_view().

Patch incoming.

dave reid’s picture

Patch attached for review that implements #4. The only unexpected thing I found is that when rendering a user account via theme_user_profile, core also somehow puts the user render API array into a block, which then also runs preprocess and unwantingly detects our variables. I accounted for this by checking to make sure that the $hook variable actually matched the #theme function set in the entity's view callback.

dave reid’s picture

This really helps clean up the preprocess, and should really speed it up since we don't need to call entity_get_info() every time. What I didn't also express about the solution in #2 is that this also requires every entity module to add our preprocess function into their theme registry information as well. This alternate way, doesn't require anything of them at all, aside from implementing the required APIs that they normally would have to.

Anonymous’s picture

This looks really great, and it is a much better method than my patch!

+++ b/entity_view_mode.moduleundefined
@@ -222,6 +222,28 @@ function field_entity_view_mode_delete($view_mode, $entity_type) {
+  $entity->content['#entity_view_mode'] = array(
+    'entity_type' => $entity_type,
+    'id' => $id,
+    'bundle' => $bundle,
+    'view_mode' => $view_mode,
+    'langcode' => &$langcode,
+    'has_bundles' => TRUE,

Why is $langcode passed by reference?

I've tested this on my current projects, and the correct templates are still being used.

Anonymous’s picture

I can't find any cases where entities do not use 'elements' as their render element in hook_theme. Is it safe to assume?

This is the code I was using to check for the render element key.

   $hooks = theme_get_registry(FALSE);
   $render_element = $variables[$hooks[$hook]['render element']];

Maybe if 'elements' isn't set in the variables, it can dig into the theme registry?

dave reid’s picture

I passed in langcode by reference, because I was thinking what if it changed somehow, but then I realized that is very silly and it should never happen, so it should be removed.

I wonder if checking for the render element would actually solve the weird issue I had with user entities and blocks.

dave reid’s picture

Just checked, both $hook = 'user_profile' and $hook = 'block' use render element of 'element'. I think my concern with checking the actual render element on the preprocess means we have to do it first, which means that it has to happen for every single invocation of the preprocess function. I think we can just be ok with relying on that entity types always use the standard render element. If we encounter problems down the road we can deal with them then.

dave reid’s picture

Patch includes tests now as well.

Status: Needs review » Needs work

The last submitted patch, 1795812-use-hook-entity-view-for-template-detection.patch, failed testing.

dave reid’s picture

Status: Needs work » Needs review
StatusFileSize
new9.13 KB

Helps to include the new testing module.

dave reid’s picture

dave reid’s picture

Patch in #13 also prevents template suggestions with entity bundles from being added to entities that have no bundles.

dave reid’s picture

Status: Needs review » Fixed

Confirmed that #14 fails if 1831766 was reverted, so committed to 7.x-1.x! http://drupalcode.org/project/entity_view_mode.git/commit/6ec3774

Thanks for your help in getting this resolved bangpound!

Status: Fixed » Closed (fixed)

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

Anonymous’s picture

Issue summary: View changes

added a patch so i can rewrite description.