Problem/Motivation

If you have a DsField plugin that calculates the contents of its result you must always include the cacheable metadata. Returning FALSE will cause your plugin to be forever cached as empty.

Example:

$build = [];
$cache = CacheableMetadata::createFromRenderArray($build)->addCacheableDependency($obj);
$cache->applyTo($build);
if ($obj->doSomething()) {
  $build['#markup'] = 'something here');
}

return $build;

In this instance where doSomething() returned FALSE, then you won't have anything to actually render, only some cache tags, which might look like:

    $build = [
      '#cache' => [
        'tags' => ['obj:1'],
      ],
    ];

In ds_entity_view_alter we do if (!empty($field_value)) { and then add our #theme field as a wrapper. This is added even when all that was returned was cache data and the field output should have been empty. Furthermore, if you do return FALSE from your plugin, you don't have the chance to add any cache data.

Proposed resolution

I can see a couple of different approaches. We could do something pretty gross like this:

if (!empty(Element::children($field_value)) && !isset($field_value['#type']) && !isset($field_value['#theme']) && !isset($field_value['#markup'])) {

Or, we can go ahead and track the cache data separately, which would mean that we pass in a BubbleableMetadata object.

$cache = BubbleableMetadata::createFromRenderArray($build);
$field_value = $field_instance->build($cache);

Then we can continue to check !empty($field_value) but always apply the cache data later on.

API changes

I think we can avoid any API breaks if we make the $cache parameter to build() optional and then merge in any cache data that is also returned to $field_value for others that were already doing that.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

benjy created an issue. See original summary.

benjy’s picture

Version: 8.x-3.x-dev » 8.x-2.x-dev
Status: Active » Needs review
FileSize
1.17 KB

We can't add a new method to the interface at all without causing a BC break, having a dual return is another alternative to option 1 in the issue summary. Equally as hacky but preserves BC.

Any thoughts on a BC break and adding a new parameter to $build? We could have our own object to wrap the cache data, similar to core's FilterProcessResult

This issue does apply to 8.3 as well but i'm using 8.2 for now.

swentel’s picture

Wow, interesting and good analysis.

Not a fan of a BC break right now. We're currently focusing hard getting up to speed with Drupal 8.3.x where we have some problems as we rely on layout_discovery in core which might end up to be a bad decision. We don't want to make the upgrade path (if needed) even more annoying :)

Patch looks good like this imo, I'm wondering whether we can write a test for that ?

benjy’s picture

Sorry for the delay on this one, started on the test and then got distracted....for 2 weeks.

Status: Needs review » Needs work

The last submitted patch, 4: 2862753-4-FAIL.patch, failed testing.

benjy’s picture

Status: Needs work » Needs review
benjy’s picture

Version: 8.x-2.x-dev » 8.x-3.x-dev
FileSize
3.83 KB

Re-rolled against 8.x-3.x

swentel’s picture

Status: Needs review » Reviewed & tested by the community

very nice! Looks good to me, will let aspilicious have a look at it as well.

  • aspilicious committed 2c67637 on 8.x-3.x authored by benjy
    Issue #2862753 by benjy: Field should not be rendered when DsField...
aspilicious’s picture

Status: Reviewed & tested by the community » Fixed

Status: Fixed » Closed (fixed)

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