It seems that a site install from existing config might fail because it triggers the new caching stuff.
To be concrete:
Error: Call to a member function getCacheTags() on null
cms/shop/web/modules/contrib/commerce/modules/store/src/Plugin/views/argument_default/CurrentStore.php:86

In our case current store is used as contextual filter on a view that is used as facet source.

Issue fork facets-3281408

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mkalkbrenner created an issue. See original summary.

mkalkbrenner’s picture

Priority: Major » Critical
Related issues: +#2939710: Add support for "Search API (tags based)" caching in Views
Error: Call to a member function getCacheTags() on null
cms/shop/web/modules/contrib/commerce/modules/store/src/Plugin/views/argument_default/CurrentStore.php:86
cms/shop/web/core/modules/views/src/Plugin/views/argument/ArgumentPluginBase.php:1315
cms/shop/web/core/lib/Drupal/Core/Cache/CacheableMetadata.php:172
cms/shop/web/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php:2351
cms/shop/web/core/modules/views/src/Entity/View.php:330
cms/shop/web/core/modules/views/src/Entity/View.php:304
cms/shop/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php:566
cms/shop/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php:521
cms/shop/web/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php:253
cms/shop/web/core/lib/Drupal/Core/Entity/EntityBase.php:339
cms/shop/web/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php:607
cms/shop/web/core/modules/views/src/ViewExecutable.php:485
cms/shop/web/modules/contrib/facets/src/Plugin/facets/facet_source/SearchApiDisplay.php:462
cms/shop/web/modules/contrib/facets/src/Entity/Facet.php:1067
cms/shop/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php:601
cms/shop/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php:527
cms/shop/web/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php:253
cms/shop/web/core/lib/Drupal/Core/Entity/EntityBase.php:339
cms/shop/web/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php:607
cms/shop/web/core/lib/Drupal/Core/Config/ConfigInstaller.php:392
mkalkbrenner’s picture

  public function registerFacet(FacetInterface $facet) {
    // Alter views view cache metadata.
    // @see \Drupal\search_api\Plugin\views\cache\SearchApiCachePluginTrait::generateResultsKey()
    // @see \Drupal\views\Plugin\views\cache\CachePluginBase::alterCacheMetadata()
    $this->getViewsDisplay()->save();
  }

I think save() is the Problem here.
@BAHbKA, could you explain the intention here more detailed?
At least we have to turn that off during config import. Or find a different solution which seems the better way.

mkalkbrenner’s picture

Could we check if there's a change before saving the display?

BAHbKA made their first commit to this issue’s fork.

bahbka’s picture

This is done to add newly created facet as a dependency to the views view search api result query. I'm also running site install from existing config and don'e see this kind of issues on my side. I guess that problem lies in the Commerce Store Default argument, which is obviously will be null upon site install and causing issues.

bahbka’s picture

I agree that it doesn't make sense todo this resaving while synchronising configuration. Standard scenario should be:
- developer will create new facet locally
- developer will export both configuration views view source (updated by ::registerFacet()and will include facet configuration in cache tags) and newly created facet config.
So when this two configurations will be deployed elsewhere, we don't need to recalculate views cache meta, it will be imported via drush sync.

But as this is very hard to reproduce for me, can you test site install with the attached patch?

mkalkbrenner’s picture

Status: Active » Needs work

Unfortunately the same exception is still triggered. So it seems that isSyncing() returns false.

bahbka’s picture

I've managed to reproduce the issue:
- install drupal/commerce
- enable commerce_store commerce_product
- add commerce store entity through the commerce admin UI
- add search api index for the commerce product entity
- add product store and title to the index
- create views view based on the index above
- add context filter for Store field and select "Store ID from the current store" as a default value for it.
- create "Store" (or any other) facet for this view display.
- export configuration
- install website from scratch.

After these steps user will receive an exception described here https://www.drupal.org/project/facets/issues/3281408#comment-14531352.
However patch https://www.drupal.org/project/facets/issues/3281408#comment-14531473 has resolved issue for me on the install.
Note that when you will navigate to the view display edit page, and will try to just resave it, you will get the same exception, with different trace though. Same will happen when you will try to add a facet for such view source and there is no commerce store.

mkalkbrenner, can it be that your install script ran composer install/update or something like this and override fix from #8?
P.S: approach with !$this->isSyncing() is taken from \Drupal\views\Entity\View::preSave()

mkalkbrenner’s picture

I reviewed the current approach again. It seems wrong to me that facets saves a view display.
A view could be used independently from a facet and can have its own cache settings. A facet has to work with the views result, regardless if it is a cached result or not and regardless if its display is cached.

But facets have to inject their cache meta data into the search_api query because that's what is altered by facets. And this query will influence view's caching.

bahbka’s picture

Unfortunately this is the only way to let Search API views view to know that it has additional cache dependency. This is needed only on facet insert op. We can change an approach to:
- Change implementation Drupal\facets\Plugin\facets\facet_source\SearchApiDisplay\registerFacet() to system status message that will inform user that view has to be resaved.
- wrap in try {Drupal\facets\Plugin\facets\facet_source\SearchApiDisplay\registerFacet()} catch{ display same information as above} <code>Drupal\facets\Plugin\facets\facet_source\SearchApiDisplay\registerFacet()

I took an approach from view resaving from the previous facet settings form submit implementation: views cache was programatically disabled.
facet_summary settings form does the same Drupal\facets_summary\Form\FacetsSummarySettingsForm::submitForm()

mkalkbrenner’s picture

Did you consider to add the cache dependencies to the query?

I think the approach in facets was rather old.

bahbka’s picture

Well $view->save() op is actually adds it to the query() but not in obvious way: https://www.drupal.org/project/search_api/issues/3197050#comment-14483368 .
- Upon saving views, view will collect all cache metadata from all its plugins, including Search API cache plugin.
- Search Api cache plugin will prexecute search query \Drupal\search_api\Plugin\views\cache\SearchApiTagCache::alterCacheMetadata()
- When query is pre-executed it will be altered with \Drupal\facets\FacetManager\DefaultFacetManager::alterQuery() that will include all necessary facet cache information.

mkalkbrenner’s picture

If I understood Search API correctly, the cachable dependencies on queries are respected in real time. So I don't see the requirement to add the dependencies to the view itself.
But you already took a closer look. So are you of the opinion that this will not work?

mkalkbrenner’s picture

BTW, could you take a quick look at #3281382: fine tune processor cache meta data.

bahbka’s picture

This option will not work(or at least I can't see another way around) because of views cache mechanism:
- View will cache the results
- SAPI: Query will not be triggered
We need to inject facet as a dependency on a Views level and It seems very logical to me: facet source search plugin needs to be aware of a facet entity and take it into consideration every time it builds a query or results set.

mkalkbrenner’s picture

wrap in try {Drupal\facets\Plugin\facets\facet_source\SearchApiDisplay\registerFacet()} catch{ display same information as above} Drupal\facets\Plugin\facets\facet_source\SearchApiDisplay\registerFacet()

Unfortunately this does not help because it is not an exception but a fatal error.

bahbka’s picture

So let's go with a message that will be displayed to user once he/she have created new facet:
- Please update %view_name in order to make sure that facet results will be correctly cached.

As alternative:
Submit ticket to the Commerce Store module:
- on clean install, no Store has been created yet.
- create views view
- add contextual filter and select "Store ID from the current store" as a default value for it.
- Save a view.

Expected result:
- View will be created.
Actual:
- Fatal error.

bahbka’s picture

mkalkbrenner I'll do the both:

  1. raise a ticket for the commerce store module
  2. Will replace $view->save() with a notification to a user.
mkalkbrenner’s picture

Thanks for your help! I was very busy today.
I started debugging the issue but had no time to finish it.

The message is a good idea.
I wonder if we should provide a button and/or drush command to "fix" or "update" views displays.
Maybe a message on the on the status report page would be helpful, too.

I still wonder if there's a way to detect if save() is required, in other words if something really changed. In this case we would be able to trigger the save.

bahbka’s picture

I still wonder if there's a way to detect if save() is required, in other words if something really changed. In this case we would be able to trigger the save.

Save is required when views are actually caching the results and facets module can work with that specific cache type.
Here is an updated patch with this logic, resave a view only in case:

  1. Source is actually doing caching
  2. Source cache type is one of the following: search_api_tag, search_api_time
  3. Since "isSyncing" worked for me but not for you, we can rely on facet cache tag presence in the view instead.

In general when developers will update facets version to 2.0.x-dev, and for some reason they have a view with enabled cache, they will have (it is standard drupal practise after module updates) to execute:

  • drush updb, which will resave all views with enabled cache and facets attached to it
  • drush cex, which will export views view config. This one will let to ignore the view in (3) when code will be deployed.

Please let me know if you still want to get rid of $this->getViewsDisplay()->save(); logic and replace it with message.

  • mkalkbrenner committed 763981d on 2.0.x authored by BAHbKA
    Issue #3281408 by BAHbKA, mkalkbrenner: New Search API Tag based caching...
mkalkbrenner’s picture

The last patch seems to work.

mkalkbrenner’s picture

Status: Needs work » Fixed

Status: Fixed » Closed (fixed)

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