Problem/Motivation

EntityViewsData adds the entity type to all tables that it exposes.

\Drupal\views\Plugin\views\query\QueryPluginBase::getEntityTableInfo() loops over all relationships and if it finds entity type, it assumes it is an entity base table and attempts to add the id/revision id field to it.

For those additional fields, that fails badly.

Proposed resolution

Check if the table actually has the field that we want to add, just skip it if not.

As an alternative, don't add the entity type, but according to @dawehner, that's not correct either.

Remaining tasks

  • Fix getEntityTableInfo()
  • Fix broken tests
  • Add new test coverage
  • Decide new test coverage is adequate and relevant

User interface changes

NA

API changes

NA

Data model changes

Views query is more selective when adding entities from relationships.

CommentFileSizeAuthor
#34 drupal_2729325_8.1.x_35.patch4.08 KBXano
#33 drupal_2729325_8.1.x_33.patch4.08 KBXano
#33 interdiff.txt617 bytesXano
#31 drupal_2729325_8.1.x.patch4.08 KBXano
#27 views-fields-entity-type-2729325-27.patch4.08 KByanniboi
#27 views-fields-entity-type-2729325-27-interdiff.txt987 bytesyanniboi
#24 views-fields-entity-type-2729325-23-interdiff.txt583 bytesBerdir
#24 views-fields-entity-type-2729325-23.patch4.09 KBBerdir
#22 views-fields-entity-type-2729325-21-interdiff.txt2.31 KBBerdir
#22 views-fields-entity-type-2729325-21.patch4.66 KBBerdir
#14 views-fields-entity-type-2729325-14.patch5.16 KByanniboi
#14 interdiff.txt1.07 KByanniboi
#11 views-fields-entity-type-2729325-10.patch5.01 KByanniboi
#10 views-fields-entity-type-2729325-10.patch5.01 KByanniboi
#10 interdiff.txt2.73 KByanniboi
#8 interdiff.txt1.1 KByanniboi
#8 views-fields-entity-type-2729325-8.patch2.82 KByanniboi
#5 interdiff.txt1.44 KByanniboi
#5 views-fields-entity-type-2729325-5.patch1.72 KByanniboi
#2 views-fields-entity-type-2729325-2.patch1.14 KBBerdir
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Berdir created an issue. See original summary.

Berdir’s picture

Status: Active » Needs review
FileSize
1.14 KB
dawehner’s picture

Its IMHO certainly better than not adding the flag to the multivalue base fields, but we should think about all the places where we use it maybe first.

Status: Needs review » Needs work

The last submitted patch, 2: views-fields-entity-type-2729325-2.patch, failed testing.

yanniboi’s picture

Status: Needs work » Needs review
FileSize
1.72 KB
1.44 KB

I've spotted a bug in TermViewsData. We changed the base table for node to node_field_data and that was breaking the test.

Status: Needs review » Needs work

The last submitted patch, 5: views-fields-entity-type-2729325-5.patch, failed testing.

jibran’s picture

+++ b/core/modules/taxonomy/src/TermViewsData.php
@@ -157,7 +157,7 @@ public function getViewsData() {
-        'base' => 'node',
+        'base' => 'node_field_data',

We need tests for this.

yanniboi’s picture

Status: Needs work » Needs review
FileSize
2.82 KB
1.1 KB
yanniboi’s picture

@jibran, I spoke to @alexpott yesterday, and that change is quite difficult to test. Also there is an issue to replace the term index relationship with a generic entity relationship, so as long as we have test coverage for the change in @berdir's patch that should be enough.

yanniboi’s picture

Added test to cover changes to getEntityTableInfo().

yanniboi’s picture

Version: 8.1.x-dev » 8.2.x-dev
FileSize
5.01 KB

Moving to 8.2.x

YesCT’s picture

Status: Needs review » Needs work

I talked to @yanniboi in person asking these questions (and included some of his nice answers here.)

  1. filling in the ...changes sections in the summary will help a committer evaluate this issue.
  2. +++ b/core/modules/taxonomy/src/TermViewsData.php
    @@ -157,7 +157,7 @@ public function getViewsData() {
    -        'base' => 'node',
    +        'base' => 'node_field_data',
    

    so this was already wrong, but we didn't know cause we weren't using the name of the base field to check things. And this new test does. So this fix was needed. See #5 interdiff (fixing previous patch fails)

  3. +++ b/core/modules/views/src/Plugin/views/query/QueryPluginBase.php
    --- a/core/modules/views/tests/src/Unit/Plugin/query/SqlTest.php
    +++ b/core/modules/views/tests/src/Unit/Plugin/query/SqlTest.php
    
    +++ b/core/modules/views/tests/src/Unit/Plugin/query/SqlTest.php
    +++ b/core/modules/views/tests/src/Unit/Plugin/query/SqlTest.php
    @@ -183,24 +183,34 @@ protected function setupEntityTypes($entities_by_type = [], $entity_revisions_by
    
    @@ -183,24 +183,34 @@ protected function setupEntityTypes($entities_by_type = [], $entity_revisions_by
             'entity type' => 'first',
             'entity revision' => FALSE,
           ],
    +      'id' => [],
         ]);
         $views_data->get('entity_first__revision')->willReturn([
           'table' => [
             'entity type' => 'first',
             'entity revision' => TRUE,
           ],
    +      'vid' => [],
    

    these added id's and vid's are needed now, cause without the fix to core, they were not being skipped (which is what this test wanted) but with the fix, they were being skipped. So explicitly set them so they are not skipped and this test works as intended. See #8 interdiff (fixing previous patch fails)

  4. +++ b/core/modules/views/tests/src/Unit/Plugin/query/SqlTest.php
    @@ -371,6 +381,54 @@ public function testLoadEntitiesWithRelationship() {
    +  public function testLoadEntitiesWithNonEntityRelationship() {
    +    // We don't use prophecy, because prophecy enforces methods.
    

    this test is copy and pasted from other similar tests. unknown if we want to repeat that here, or ... add a comment to the similar tests so they are related.

  5. +++ b/core/modules/views/tests/src/Unit/Plugin/query/SqlTest.php
    @@ -371,6 +381,54 @@ public function testLoadEntitiesWithRelationship() {
    +    $entity_information = $query->getEntityTableInfo();
    +
    +
    +    $this->assertSame($entities['first'][1], $result[0]->_entity);
    

    nit (double blank line)

  6. +++ b/core/modules/views/tests/src/Unit/Plugin/query/SqlTest.php
    @@ -371,6 +381,54 @@ public function testLoadEntitiesWithRelationship() {
    +    $this->assertTrue(in_array('first', array_keys($entity_information)));
    +    $this->assertFalse(in_array('entity_first_field_data__entity_first_field_data', array_keys($entity_information)));
    +  }
    

    these asserts seem to be the key. And it makes sense to test before that first is there, so that entity_first_field_data__entity_first_field_data not being there actually is meaningful. (if first wasn't there, then testing if the base field was not there wouldn't mean much)

So I guess the only real question about this... is if we want so much of the duplicated test here, that might not be strictly relevant to this particular test condition.
I kinda feel like the test could use some more comments about what the set up is... but it might also be that others wont need comments (and if the code is copy and pasted form another test, than commenting might be out of scope).

yanniboi’s picture

Issue summary: View changes

Updated issue summary

yanniboi’s picture

Status: Needs work » Needs review
FileSize
1.07 KB
5.16 KB

Removed @YesCT's nitpick and added some comments to the test.

YesCT’s picture

+++ b/core/modules/views/tests/src/Unit/Plugin/query/SqlTest.php
@@ -414,14 +414,15 @@ public function testLoadEntitiesWithNonEntityRelationship() {
+    // This is an entity table and should be in $entity_information.
     $this->assertTrue(in_array('first', array_keys($entity_information)));
+    // This is not an entity table and should not be in $entity_information.

Thanks!

uh, I thought first was a table, and entity_first_field_data__entity_first_field_data was a base field?

Also, why is this bug major? https://www.drupal.org/core/issue-priority#major-bug

YesCT’s picture

+++ b/core/modules/taxonomy/src/TermViewsData.php
--- a/core/modules/views/src/Plugin/views/query/QueryPluginBase.php
+++ b/core/modules/views/src/Plugin/views/query/QueryPluginBase.php

+++ b/core/modules/views/src/Plugin/views/query/QueryPluginBase.php
@@ -285,6 +285,14 @@ public function getEntityTableInfo() {
+        // If the table does not have the necessary base field, skip it.

This is the reason I'm asking about wording.

yanniboi’s picture

Also, why is this bug major?

This bug is major because it basically breaks any view with a relationship to an non entity table.

So according to @dawehner, we don't just want to exclude entity base tables, we want to exclude:

  • Entity base table (eg entity_name)
  • Entity revision table (like entity_name_revision)
  • Entity data table (like entity_name_field_data)
  • Entity data revision table (like entity_name_field_data_revision)

So while our current fix sort of works it feels a bit *hacky*.

Maybe we can think of a better way of doing this?

The last submitted patch, 10: views-fields-entity-type-2729325-10.patch, failed testing.

YesCT’s picture

Issue tags: +DevDaysMilan
Berdir’s picture

So while our current fix sort of works it feels a bit *hacky*.

I don't understand why or what the problem is.

We're looking for the presence of the ID or revision ID. All of the 4 tables you listed have those

dawehner’s picture

We're looking for the presence of the ID or revision ID. All of the 4 tables you listed have those

Well, we are talking about potentially arbitrary tables, which just happen to have the same columns. Just imagine maybe an entity type that has a 'entity_id' as 'id' key.

Berdir’s picture

Here's the approach we discussed, explicitly checking the entity base tables. Looks like the changes to SqlTest are no longer necessary then. Also removed a few unit test changes that are no longer necessary.

I still like my idea of not adding this information to those tables, will see about uploading a patch for that tomorrow.

dawehner’s picture

Thanks a ton @berdir!

I still like my idea of not adding this information to those tables, will see about uploading a patch for that tomorrow.

Its good to see whether alternative approaches also work.

  1. +++ b/core/modules/taxonomy/src/TermViewsData.php
    @@ -157,7 +157,7 @@ public function getViewsData() {
           'relationship' => array(
             'id' => 'standard',
    -        'base' => 'node',
    +        'base' => 'node_field_data',
             'base field' => 'nid',
    

    Can we create its own issue for this change? The most recent approach should still support it. ... The problem here is that we probably need an update path for it.

  2. +++ b/core/modules/views/src/Plugin/views/query/QueryPluginBase.php
    @@ -285,6 +285,14 @@ public function getEntityTableInfo() {
    +
    +        // If this is not one of the entity base tables, skip it.
    +        $entity_type = \Drupal::entityTypeManager()->getDefinition($table_data['table']['entity type']);
    +        $entity_base_tables = [$entity_type->getBaseTable(), $entity_type->getDataTable(), $entity_type->getRevisionTable(), $entity_type->getRevisionDataTable()];
    +        if (!in_array($relationship->definition['base'], $entity_base_tables)) {
    +          continue;
    +        }
    

    IMHO this approach is one with the least possible BC problems.

Berdir’s picture

Berdir’s picture

Tried my idea. You were right, of course. the entity type key is used, in \Drupal\views\ViewExecutable::addHandler() for example. Don't fully understand why it didn't work as I expected and maybe it could be worked around, but you're right, this is most BC approach.

dawehner’s picture

Just some quick nitpick ...

+++ b/core/modules/views/tests/src/Unit/Plugin/query/SqlTest.php
@@ -371,6 +377,55 @@ public function testLoadEntitiesWithRelationship() {
+    $this->assertTrue(in_array('first', array_keys($entity_information)));
...
+    $this->assertFalse(in_array('entity_first_field_data__entity_first_field_data', array_keys($entity_information)));

Let's use $this->assertContains and $this->assertNotContains

yanniboi’s picture

Xano’s picture

I tested @yanniboi's patch from #27 on Payment, of which the view on /admin/content/payment is broken because of this problem. I can confirm the patch fixes the problem. To reproduce:

  1. Go to a clean Drupal 8.2.x install.
  2. Include Plugin 8.x-1.x, Payment 8.x-2.x, Currency 8.x-3.x, and Currency's Composer dependencies in the code base.
  3. Install Payment and Views.
  4. Go to /admin/content/payment.
  5. Confirm you see an uncaught exception or a WSOD.
  6. Apply the patch from #27
  7. Go to /admin/content/payment again.
  8. Confirm you see a working view with an empty tabular list of payments.

I will leave the RTBC to someone else, because I do not know if this solution is the best possible one for this issue.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Thank you @yanniboi

In general I'm quite convinced of this solution. It provides the minimal chance of a BC break.

Xano’s picture

See #28 for the reason this is a blocker.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 31: drupal_2729325_8.1.x.patch, failed testing.

Xano’s picture

This should fix the last remaining test failure on 8.1.x.

Xano’s picture

#33's interdiff is correct, but its patch does not contain the changes.

Status: Needs review » Needs work

The last submitted patch, 34: drupal_2729325_8.1.x_35.patch, failed testing.

Xano’s picture

Status: Needs work » Needs review

Oh hello, weekend!

Xano’s picture

Status: Needs review » Reviewed & tested by the community

#27 contains the latest patch for 8.2.x.
#33 contains the latest patch for 8.1.x.

I am RTBC'ing this per #29, because all I did was fix an erroneous code comment, as proven by the tests passing.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Given what @dawehner says in #29 only going to commit the 8.2.x - I don't want to take any chance of BC break in 8.1.x.

Committed c7cc44e and pushed to 8.2.x. Thanks!

  • alexpott committed c7cc44e on 8.2.x
    Issue #2729325 by yanniboi, Berdir, Xano, dawehner, YesCT:...
Berdir’s picture

Version: 8.2.x-dev » 8.1.x-dev
Status: Fixed » Reviewed & tested by the community

Hm, I'm not sure that's what @dawehner meant with that comment :). We are not aware of any BC break and I can't imagine what could break it.

Note that for example payment.module is broken without this fix, so it would be a bit unfortunate if we have to wait for 8.2 to come out. And this is a regression in 8.1, caused by #2644088: DefaultTableMapping::getFieldTableName does not report table for fields with dedicated storage, it works in 8.0 because the field tables never have this key. And I have this patch applied in NP8 and never had a problem with it so far.

Just want to make sure you have all the information when making the 8.1 decision here, feel free to set it back to fixed if you want to keep it that way. I personally can live with maintaining my patch a while longer.

dawehner’s picture

Hm, I'm not sure that's what @dawehner meant with that comment :). We are not aware of any BC break and I can't imagine what could break it.

Right, the solution we went with is the one which has no known BC break yet, unless some of the earlier ones. If you join to the base table, adding the entity IDs should be safe.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed 126d2a1 and pushed to 8.1.x. Thanks!

  • alexpott committed 126d2a1 on 8.1.x
    Issue #2729325 by yanniboi, Berdir, Xano, dawehner, YesCT:...

  • alexpott committed c7cc44e on 8.3.x
    Issue #2729325 by yanniboi, Berdir, Xano, dawehner, YesCT:...

  • alexpott committed c7cc44e on 8.3.x
    Issue #2729325 by yanniboi, Berdir, Xano, dawehner, YesCT:...

Status: Fixed » Closed (fixed)

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