All views have the same content when you place viewfield twice with different args.
Steps to reproduce:
1. Create Content Type with a reference to taxonomy.
2. Create some nodes with a term ID 1 and several nodes with a term ID 2.
3. Create view “Node lists” with the list of nodes and contextual filter by taxonomy (Content: Has taxonomy term ID).
4. Create Custom block type with a viewfield and view “Node list”.
5. Create two blocks - one with a viewfield’s argument 1 and another one with an argument 2.
6. Place those blocks on the page.

Expected result: Views in blocks show different lists of nodes.
Current result: Views show the same nodes.

Some debug showed me that I have the same cache keys for both views after $view->buildRenderable($display_id, $arguments) here in viewfield/src/Plugin/Field/FieldFormatter/ViewfieldFormatterDefault.php

      if (!empty($view->result) || $always_build_output) {
        $elements[$delta] = [
          '#theme' => 'viewfield_item',
          '#content' => $view->buildRenderable($display_id, $arguments),
          '#title' => $view->getTitle(),
          '#label_display' => empty($view->result) ? $empty_view_title : $view_title,
          '#delta' => $delta,
          '#field_name' => $this->fieldDefinition->getName(),
          '#view_id' => $target_id,
          '#display_id' => $display_id,
        ];
      }

I can turn off cache keys by $view->buildRenderable($display_id, $arguments, FALSE) and all works well but it's not the solution.

Comments

ElegguaDP created an issue. See original summary.

pminf’s picture

I stumbled upon this issue while using multiple paragraphs with the same viewfield in a single node. Each paragraph embeds the same view but passes different argument values. Unfortunately all paragraphs embedded views list the rows of the first paragraph if cache is enabled.

I think there needs to be a cache context according to the contextual filter of the view or the value of the viewfield. But I don't know how.

And there might be some more work to do ;)

 public function viewElements(FieldItemListInterface $items, $langcode) {
    // [...]
    // @todo Design and implement a caching strategy.
    $elements = [
      '#cache' => [
        'max-age' => 0,
      ],
    ];

Any cache experts out there?!

pminf’s picture

pminf’s picture

Status: Active » Needs review
StatusFileSize
new793 bytes

I get different lists of nodes by adding the arguments as cache keys.

codesquatch’s picture

Thanks for the patch, it worked for me.

codesquatch’s picture

@pminf Thanks for the patch, it worked for me.

codesquatch’s picture

andypost’s picture

Looks the view should not use cache to leverage entity render cache

maxilein’s picture

StatusFileSize
new4.76 KB
new14.94 KB

what if content is empty?

The default display setting (on content type) for a viewsfield is to not render output: "Always build output:no"

If a view does not have any content there is an error in the line of your patch:

$cache_keys = array_merge($elements[$delta]['#content']['#cache']['keys'], $arguments);

Notice: Undefined index: #content in Drupal\viewfield\Plugin\Field\FieldFormatter\ViewfieldFormatterDefault->viewElements() (line 154 of modules/viewfield/src/Plugin/Field/FieldFormatter/ViewfieldFormatterDefault.php).

Drupal\viewfield\Plugin\Field\FieldFormatter\ViewfieldFormatterDefault->viewElements(Object, 'en') (Line: 80)
Drupal\Core\Field\FormatterBase->view(Object, 'en') (Line: 92)
Drupal\viewfield\Plugin\Field\FieldFormatter\ViewfieldFormatterDefault->view(Object, NULL) (Line: 262)
Drupal\Core\Entity\Entity\EntityViewDisplay->buildMultiple(Array) (Line: 235)
Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay->buildMultiple(Array) (Line: 321)
Drupal\Core\Entity\EntityViewBuilder->buildComponents(Array, Array, Array, 'full') (Line: 22)
Drupal\node\NodeViewBuilder->buildComponents(Array, Array, Array, 'full') (Line: 263)
Drupal\Core\Entity\EntityViewBuilder->buildMultiple(Array) (Line: 220)
Drupal\Core\Entity\EntityViewBuilder->build(Array)
call_user_func(Array, Array) (Line: 378)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 195)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 226)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 582)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 227)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 117)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 111)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.view', Object) (Line: 156)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 99)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 78)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 669)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

Warning: array_merge(): Argument #1 is not an array in Drupal\viewfield\Plugin\Field\FieldFormatter\ViewfieldFormatterDefault->viewElements() (line 154 of modules/viewfield/src/Plugin/Field/FieldFormatter/ViewfieldFormatterDefault.php).

Drupal\viewfield\Plugin\Field\FieldFormatter\ViewfieldFormatterDefault->viewElements(Object, 'en') (Line: 80)
Drupal\Core\Field\FormatterBase->view(Object, 'en') (Line: 92)
Drupal\viewfield\Plugin\Field\FieldFormatter\ViewfieldFormatterDefault->view(Object, NULL) (Line: 262)
Drupal\Core\Entity\Entity\EntityViewDisplay->buildMultiple(Array) (Line: 235)
Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay->buildMultiple(Array) (Line: 321)
Drupal\Core\Entity\EntityViewBuilder->buildComponents(Array, Array, Array, 'full') (Line: 22)
Drupal\node\NodeViewBuilder->buildComponents(Array, Array, Array, 'full') (Line: 263)
Drupal\Core\Entity\EntityViewBuilder->buildMultiple(Array) (Line: 220)
Drupal\Core\Entity\EntityViewBuilder->build(Array)
call_user_func(Array, Array) (Line: 378)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 195)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 226)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 582)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 227)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 117)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 111)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.view', Object) (Line: 156)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 99)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 78)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 669)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

If you set the the output to always output, then the warnings and notice go away.
Maybe use a different field for your keys?
Any suggestions are welcome!

maxilein’s picture

Solution to your code:

if the delta is null, we don't have anything to cache. Add this line:

if (isset($elements[$delta])){

if (!empty($view->result) || $always_build_output) {
        $elements[$delta] = views_embed_view($view->id(), $display_id, ...$arguments);
        if (isset($elements[$delta])){
	    // add arguments to view cache keys - if it returns something, otherwise this is not needed
            // to allow multiple viewfields with same view but different arguments per page
            $cache_keys = array_merge($elements[$delta]['#content']['#cache']['keys'], $arguments);
	    $elements[$delta]['#content']['#cache']['keys'] = $cache_keys; } 
}

I have added a patch to my proposed new dev release here: https://www.drupal.org/project/viewfield/issues/3014568#comment-12885275

pookmish’s picture

Attached an adjusted patch to remove the line that disables field caches.

jerdavis’s picture

Status: Needs review » Reviewed & tested by the community

Tested and verified patch from #11

  • jerdavis committed ebdd63d on 8.x-3.x
    Issue #2892073 by pookmish, pminf, maxilein, codesquatch, ElegguaDP,...
jerdavis’s picture

Status: Reviewed & tested by the community » Fixed
maxilein’s picture

jerdavis: thank you for taking over!

Status: Fixed » Closed (fixed)

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