Query metadata get lost when $view->query->query() is called multiple times during page build

Created on 17 February 2023, over 1 year ago

Problem/Motivation

In some rare circumstances \Drupal\views\Plugin\views\query\Sql::query() could be called multiple times during the page build. When this happens subsequent calls , usually happening outside of \Drupal\views\ViewExecutable::build() , are getting new query object which doesn't have the metadata which was set on it during initial call to \Drupal\views\ViewExecutable::build() because $view->query->query() doesn't include call to \Drupal\views\Plugin\views\query\Sql::alter().

I believe the problem is that there are many way to get access to the Drupal\Core\Database\Query\Select query:

  1. $view->build_info['query'] - once views query was built with $view->query->build() or with \Drupal\views\ViewExecutable::build()
  2. $view->query->query()

but the problem is the query only would be altered when built with \Drupal\views\ViewExecutable::build() .

Steps to reproduce

I haven't figured out the set up based on core only the would show the problem, but it's quite easy to reproduce this with group and views_data_export modules:

  • install core using standard profile
  • install group and views_data_export modules
  • modify the Content (/admin/structure/views/view/content) view by adding data export display, like CSV, N.B. it must be configured to use batch in the Export settings
  • access path of just configured export display and observe :
The website encountered an unexpected error. Please try again later.<br><br><em class="placeholder">Drupal\Component\Plugin\Exception\PluginNotFoundException</em>: The &quot;&quot; entity type does not exist. in <em class="placeholder">Drupal\Core\Entity\EntityTypeManager-&gt;getDefinition()</em> (line <em class="placeholder">139</em> of <em class="placeholder">core/lib/Drupal/Core/Entity/EntityTypeManager.php</em>). <pre class="backtrace">group_query_entity_query_alter(Object) (Line: 343)
group_query_views_entity_query_alter(Object, NULL, NULL) (Line: 562)
Drupal\Core\Extension\ModuleHandler-&gt;alter(&#039;query&#039;, Object) (Line: 484)

\Drupal\views_data_export\Plugin\views\display\DataExport::buildBatch() calls $view->build();
$view->build(); calls $this->query->alter($this);
in group_views_query_alter() group is building a views query and then adds metadata to the sql query ()
then views_data_export calls $view->query->query()->countQuery()->execute(); to get total rows count, but that generates a new SQL Drupal\Core\Database\Query\Select query which wasn't altered , but received additional tag set by group on the views query \Drupal\views\Plugin\views\query\Sql

There are questions/concern around views integration in group and views_data_export, but I believe those could only be answered/fixed once the views APIs are clarified and/or tightened.

Proposed resolution

The resolution is not clear , but a good starting point should be answers to these questions:

  • should the views query \Drupal\views\Plugin\views\query\Sql be passing additional metadata to the SQL query in the same way it passes tags in \Drupal\views\Plugin\views\query\Sql::query()? However I see that query tags are only make sense on the SQL queries and are no for part of the QueryPluginBase and not implemented in SearchApiQuery
  • should the views query alter be called in \Drupal\views\ViewExecutable::build() or maybe it would be better done \Drupal\views\Plugin\views\query\Sql::query() or \Drupal\views\Plugin\views\query\Sql::build()?
  • should the \Drupal\views\ViewExecutable::$build_info be public ? views place SQL query object in it , while search_api stores there as string representation of the built query

Writing this I see how there are many SQL specifics here and I'm missing the big picture. In the beginning I was trying to fix the issue in the group module here πŸ› _access tag can leading to fatal error Closed: won't fix , but then agreed with [3232105-8] in thinking that the problem is caused by other module. In the end I don't see anything terribly wrong in the way both group and views_data_export modules interact with views, but I feel the problem in a fact that views allows to to get expectedly the same underlying query object via different methods which would produce different objects.

Remaining tasks

Confirm there is bug or clarify API mis/use

User interface changes

TBD

API changes

TBD

Data model changes

TBD

Release notes snippet

TBD

πŸ› Bug report
Status

Active

Version

10.0 ✨

Component
ViewsΒ  β†’

Last updated about 6 hours ago

Created by

πŸ‡³πŸ‡ΏNew Zealand RoSk0 Wellington

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @RoSk0
  • πŸ‡§πŸ‡ͺBelgium kristiaanvandeneynde Antwerp, Belgium

    Fully agree with the assessment that a View returning a query object should always return one with the same metadata.

    So either if multiple query instances can be created during a VIew's lifetime, then all instances should always run through tag alters and what-have-you. The tag alters can then decide when to add their stuff to a query, e.g.: They could for instance choose not to do anything to count queries.

    Another solution would be to add some methods to a "Views query" that allows us to set metadata which gets copied onto every "real query" that gets generated within there. But this would take away some powerful decision-making abilities from modules so I'd rather we just always run the tag alters on any "real query" generated in a "view query" to be consistent.

Production build 0.69.0 2024