WidgetBase::form() / FormatterBase::view() both take care of nesting the generated render arrays in a wrapper keyed after the field name.

This matches the common use case of entity forms and entity views ($form['field_foo'] / $form_values['field_foo'] / $content['field_foo'])

However:
- In some other cases, that wrapper is not wanted, and needs to be manually unwrapped
- This being done in base methods, there is no guarantee that some widgets / formatters don't override it, and this results in unpredictability.

Widgets / formatters shouldn't do the wrapping themselves, they job should just be to return their own specific render array. The wrapping should be done by the calling code if needed.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

yched’s picture

plopesc’s picture

Status: Active » Needs review
FileSize
3.99 KB

Removing $element wrappers in WidgetBase::form() / FormatterBase::view().

Given that WidgetBase::form() is called from field_invoke_method(), I changed a bit its logic, but does not affect other methods called through this function.

I made some local tests and it works, let's see what testbot says...

yched’s picture

Issue tags: +Entity Field API

Cool!

  1. +++ b/core/modules/entity/lib/Drupal/entity/Entity/EntityViewDisplay.php
    @@ -231,7 +231,7 @@ public function buildMultiple(array $entities) {
    -          $build[$key] += $formatter->view($items);
    +          $build[$key] += array($field_name => $formatter->view($items));
    

    Minor: it would be slightly clearer to do
    $build[$key][$field_name] = $formatter->view();

  2. +++ b/core/modules/field/field.attach.inc
    +++ b/core/modules/field/field.attach.inc
    @@ -91,20 +91,13 @@ function field_invoke_method($method, $target_function, EntityInterface $entity,
    
    @@ -91,20 +91,13 @@ function field_invoke_method($method, $target_function, EntityInterface $entity,
         $target = call_user_func($target_function, $field_definition);
     
         if (method_exists($target, $method)) {
    -      $items = $entity->get($field_definition->getName());
    +      $field_name = $field_definition->getName();
    +      $items = $entity->get($field_name);
           $items->filterEmptyItems();
     
           $result = $target->$method($items, $a, $b);
    -
           if (isset($result)) {
    -        // For methods with array results, we merge results together.
    -        // For methods with scalar results, we collect results in an array.
    -        if (is_array($result)) {
    -          $return = array_merge($return, $result);
    -        }
    -        else {
    -          $return[] = $result;
    -        }
    +        $return[$field_name] = $result;
    

    Hah - true, a bit tedious.
    That function is going away in #2095195: Remove deprecated field_attach_form_*() anyway, at which point it's going to be up to EntityFormDisplay to add the $field_name key (like EntityViewDisplay does here)

Once 1. above is changed, this is RTBC IMO.

plopesc’s picture

Improving patch in #2

yched’s picture

Status: Needs review » Reviewed & tested by the community

Thanks !

catch’s picture

Status: Reviewed & tested by the community » Fixed

Much nicer. Committed/pushed to 8.x, thanks!

catch’s picture

I think this got smushed in with another commit, but don't have time to find that right now. If that's what happened please link the commit here and I'll revert and sort it out.

plopesc’s picture

Sorry, I only read the git log and I missed the commit related to this issue.

I found that this patch was committed in 0aa59382b25792ae46f6df193abe8abc0bf1ca0b, related to #2192649: Remove drupal_set_title() from installation and update process.

Regards

Status: Fixed » Closed (fixed)

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