Problem/Motivation

I'm currently in the process of making an entity type translatable through an update. That entity type has views. I noticed that the view does a very nice job of updating the table of all the field, sort, relationship, ... handlers but it doesn't update the base table, so the result is a completely broken view.

Proposed resolution

Similar to baes table rename, update the base_table in the view.

Remaining tasks

Pretty sure that this won't work for revision views and the logic there in general might not work, as it would need to use different table mappings. I think that could be a separate issue.

User interface changes

API changes

Data model changes

Comments

Berdir created an issue. See original summary.

berdir’s picture

Issue tags: +Needs tests
StatusFileSize
new1.1 KB
berdir’s picture

Status: Active » Needs review

Status: Needs review » Needs work

The last submitted patch, 2: views-data-table-addition-2904686-2.patch, failed testing. View results

amateescu’s picture

I looked a bit at the failures and I think that at least the test_view_entity_test_data view used by \Drupal\Tests\views\Kernel\EventSubscriber\ViewsEntitySchemaSubscriberIntegrationTest::testDataTableRename() is wrong.

It is supposed to be a view of a translatable entity type, so I just tested manually by creating a view of nodes through the UI and the base table of the view is indeed the data table of the entity type, not its base table.

$this->assertEqual('entity_test_update', $display['display_options']['fields']['id']['table']); this assertion from that test is also wrong. In the same view that I created earlier I added the ID field and, surely enough, it was using the data table to retrieve it, not the base table :)

In conclusion, the "needs tests" part of this issue is actually "fix broken tests" :)

berdir’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
StatusFileSize
new11.62 KB
new11.48 KB

Right, that's what I thought. And for the same reason, the logic about keeping base fields on the base table is also wrong, we need to move that to the data table as well, the only exception are fields that only exist on the base table. Which is only the UUID.

Had to hold myself back *really* hard to not change all those assertEqual() to assertEquals() because they already use the new argument order of expected, actual and then the errors are vey confusing.

amateescu’s picture

+++ b/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php
@@ -150,9 +150,9 @@ public function testDataTableRename() {
-    $this->assertEqual('entity_test_update', $view->get('base_table'));
+    $this->assertEqual('entity_test_update_data', $view->get('base_table'));

How come we can change this assertion before running the updates and not get any fails? The actual view has base_table: entity_test_update in the yml file.

berdir’s picture

@amateescu: The first thing in that test is to make the entity type translatable and apply updates, then we check. By default, it is not translatable, so using the base table in the view yml is correct.

amateescu’s picture

Status: Needs review » Reviewed & tested by the community

Ahh, you're right, I wrote #7 from memory, without looking at the actual test method.

dawehner’s picture

+++ b/core/modules/views/src/EventSubscriber/ViewsEntitySchemaSubscriber.php
index 2319a7064a..0ecfc2b08a 100644
--- a/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php

--- a/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php
+++ b/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php

+++ b/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php
+++ b/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php
@@ -150,9 +150,9 @@ public function testDataTableRename() {

Does this bug basically mean we need some more kind of integration level testing?

berdir’s picture

Status: Reviewed & tested by the community » Needs work

I'll try to extend the test by executing the view, as without the correct conversion, it is completely broken.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

berdir’s picture

One year later :)

So this was fun. I added code to the test to actually execute the view and it failed horribly, completely broken query, both with and without the fix, there were no fields, so it was a SELECT FROM ... query. There is a field but it did a fallback to the broken plugin and didn't add any fields to the query.

First thought it was because of a stale views data cache, which also was the case but that wasn't enough. Turns out, EntityTestUpdate did *not* have a views_data handler. So we've been testing views with an entity type that did not actually have any views integration ;)

Adding that fixed it for some test methods, but it started to fail on the crazier ones like testVariousTableUpdates(), because we actually started to run code that we didn't before, for example the views cacheability calculation. And in test test, we do several iterations of entity definition changes and then reseting it again. Including enabling and disabling revisions and somehow, that results in base_table of revision views to be NULL and then the next time they are saved (after updateEntityTypeToRevisionable()), it fails with an exception on save.

Stay tuned for part 2.

berdir’s picture

Status: Needs work » Needs review
StatusFileSize
new21.29 KB
new14.49 KB

Ah, found the problems I think.

The first was a test problem. updateEntityTypeToTranslatable() also sets the revision_data_table key if the entity type is revisionable, but updateEntityTypeToRevisionable() didn't do that if the entity type was translatable already, so calling it in that order resulted setting an empty base_table as having a revision data table is required/expected when being translatable.

The second was an actual bug. When going from revisionable + translatable to neither, we detected that as a REVISION_TABLE_REMOVAL *and* REVISION_DATA_TABLE_REMOVAL. But the revision data table tried to switch it back to the revision table and runs after disabling those views. revisionRemoval() already looks at the revision *and* revision data table, so I changed the conditions so that REVISION_TABLE_REMOVAL is only triggered if an entity type is still revisionable.

A test only patch is likely not very useful, it would fail on the first wrong condition already and/or fail completely without a bunch of the necessary fixes.

dawehner’s picture

+++ b/core/modules/views/src/EventSubscriber/ViewsEntitySchemaSubscriber.php
@@ -97,6 +107,9 @@ public static function getSubscribedEvents() {
+    // Invalidate stored views data.
+    $this->viewsData->clear();
+

@@ -217,6 +232,9 @@ public function onEntityTypeDelete(EntityTypeInterface $entity_type) {
     }
+
+    // Invalidate stored views data.
+    $this->viewsData->clear();

Instead of saying what happens, could we document why we need to invalidate?

berdir’s picture

Fair point, something like this?

dawehner’s picture

  1. +++ b/core/modules/views/src/EventSubscriber/ViewsEntitySchemaSubscriber.php
    @@ -140,7 +150,9 @@ public function onEntityTypeUpdate(EntityTypeInterface $entity_type, EntityTypeI
    +    // if an entity type is still revisioanble but no longer translatable.
    +    elseif ($original->isRevisionable() && $original->isTranslatable() && !$revision_remove && $translation_remove) {
    

    The comment talks about the concept of revisioan-ble, is this a new concept just berdir understands?

  2. +++ b/core/modules/views/src/EventSubscriber/ViewsEntitySchemaSubscriber.php
    @@ -318,14 +338,21 @@ protected function dataTableAddition($all_views, EntityTypeInterface $entity_typ
    +    // If the entity base table was the view base table, then switch to the
    +    // entity data table.
    +    foreach ($all_views as $view) {
    +      if ($view->get('base_table') === $base_table) {
    +        $view->set('base_table', $data_table);
    +      }
    +    }
    
    @@ -345,6 +372,15 @@ protected function dataTableAddition($all_views, EntityTypeInterface $entity_typ
    +
    +    // If the entity data table was the view base table, then switch to the
    +    // entity base table.
    +    foreach ($all_views as $view) {
    +      if ($view->get('base_table') === $old_data_table) {
    +        $view->set('base_table', $base_table);
    +      }
    +    }
    +
    

    Nice, this does make sense.

  3. +++ b/core/modules/views/tests/src/Kernel/EventSubscriber/ViewsEntitySchemaSubscriberIntegrationTest.php
    @@ -139,6 +139,9 @@ public function testBaseTableRename() {
    +
    +    // Ensure the view can be executed without errors.
    +    $view->getExecutable()->preview('default');
    
    @@ -164,10 +167,13 @@ public function testDataTableRename() {
    +
    +    // Ensure the view can be executed without errors.
    +    $view->getExecutable()->preview('default');
    
    @@ -197,6 +203,9 @@ public function testRevisionBaseTableRename() {
    +
    +    // Ensure the view can be executed without errors.
    +    $view->getExecutable()->preview('default');
    
    @@ -226,10 +235,13 @@ public function testRevisionDataTableRename() {
    +
    +    // Ensure the view can be executed without errors.
    +    $view->getExecutable()->preview('default');
    
    @@ -244,10 +256,13 @@ public function testDataTableAddition() {
    +
    +    // Ensure the view can be executed without errors.
    +    $view->getExecutable()->preview('default');
    
    @@ -266,6 +281,9 @@ public function testRevisionEnabling() {
    +
    +    // Ensure the view can be executed without errors.
    +    $view->getExecutable()->preview('default');
    
    @@ -312,6 +331,7 @@ public function testVariousTableUpdates() {
    +    $view->getExecutable()->preview('default');
    
    @@ -320,25 +340,28 @@ public function testVariousTableUpdates() {
    +    $view->getExecutable()->preview('default');
    ...
    +    $view->getExecutable()->preview('default');
    ...
    +    $view->getExecutable()->preview('default');
    
    @@ -349,14 +372,16 @@ public function testVariousTableUpdates() {
    +    $view->getExecutable()->preview('default');
    ...
    +    $view->getExecutable()->preview('default');
    
    @@ -365,6 +390,7 @@ public function testVariousTableUpdates() {
    +    $view->getExecutable()->preview('default');
    
    @@ -376,6 +402,7 @@ public function testVariousTableUpdates() {
    +    $view->getExecutable()->preview('default');
    
    @@ -393,9 +421,13 @@ public function testVariousTableUpdates() {
    +    $view->getExecutable()->preview('default');
    

    Shouldn't we check somehow the result of that as well? Maybe check whether $view->build_info['fail'] wasn't set?

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

berdir’s picture

Status: Needs review » Needs work
berdir’s picture

Status: Needs work » Needs review
StatusFileSize
new22.05 KB
new4.6 KB

#18.1 That's revisionable with a moan. As in, the sound that Drupal makes when it has has to update all those views.
#18.3 Will have a look that, but preview() explodes with an exception when a query fails, not sure when fail would be set.

Did a reroll, pretty ugly conflicts and I can only assume that a bunch more will come with the current changes and refactorings on that handler. Had to add a lot of extra views to the changed-views assertion because we're now updating things that we didn't do before.

As pointed out earlier, on HEAD, we are still testing all those changes *without a views data handler* on this entity type, which means that many things aren't reflecting how it really works. One specific example is that I wasn't yet able to fix \Drupal\Tests\views\Kernel\EventSubscriber\ViewsEntitySchemaSubscriberIntegrationTest::testRevisionDisabling(). What's happening is that the view doesn't get saved, because as part of saving, we build the entity views data that is now being cleared as part of doing this change. However, in \Drupal\views\EntityViewsData::getViewsData(), we have the old problem that the table mapping returns confusing data, specifically, because the entity type hasn't been updated yet, it still returns a revision_id, that then results in a PHP notice on this line: $this->mapFieldDefinition($table, $field_name, $field_definitions[$field_name], $table_mapping, $data[$table]);. The problem is that we fetch that information as part of the event, which happens before the information is saved *and* before the instantiated entity handlers are dropped.

Adding an isset() there seems like a hack, changing \Drupal\Core\Entity\Sql\DefaultTableMapping::getFieldNames() to only return fields that actually exist as field definition, even if they are keys, could mask some other errors/inconsistencies. I tried updating \Drupal\Core\Entity\Sql\SqlContentEntityStorage::onFieldableEntityTypeUpdate() so that it updates the stored entity type and table mapping like onEntityTypeUpdate does (no idea why it doesn't do that right now), but that didn't help.

Status: Needs review » Needs work

The last submitted patch, 21: views-data-table-addition-2904686-21.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

amateescu’s picture

Status: Needs work » Needs review
StatusFileSize
new25.49 KB
new51.59 KB
new6.22 KB

Finally managed to take a look at this, sorry @Berdir for the delay :/ The patch looks very very good to me, it clearly shows all the deficiencies of this subscriber and its test coverage in HEAD.

For the problem detailed in #21, the fix is to make \Drupal\views\EntityViewsData and views_views_data() use the "active" entity type and field storage definitions.

That means we're blocked on #3056816: Installing a new field storage definition during a fieldable entity type update is not possible, so posting a combined patch as well to prove that everything works nicely together :)

The last submitted patch, 23: 2904686-23.patch, failed testing. View results

Status: Needs review » Needs work

The last submitted patch, 23: 2904686-23-combined.patch, failed testing. View results

amateescu’s picture

Status: Needs work » Needs review
StatusFileSize
new39.59 KB
new15.03 KB

#3056816: Installing a new field storage definition during a fieldable entity type update is not possible was committed (only to 8.8.x for now, but it should be backported to 8.7.x), so here's a fix for the remaining test failures.

amateescu’s picture

StatusFileSize
new41.5 KB
new62.28 KB
new2.02 KB

#3056816: Installing a new field storage definition during a fieldable entity type update is not possible has been reverted and the patch that will be re-committed won't have the cache clears needed by this issue, so we need to add them here.

Status: Needs review » Needs work

The last submitted patch, 27: 2904686-27-combined.patch, failed testing. View results

amateescu’s picture

Status: Needs work » Needs review
StatusFileSize
new41.96 KB
new62.75 KB
new770 bytes

A new test method was added to EntityViewsDataTest in #2973137: EntityViewsData missed revisionable validation so we need to apply the same changes as the ones from the interdiff in #26.

amateescu’s picture

#3056816: Installing a new field storage definition during a fieldable entity type update is not possible was re-committed so the non-combined patch should be good to go for 8.8.x at least.

amateescu’s picture

StatusFileSize
new39.94 KB

Rerolled after #3056816: Installing a new field storage definition during a fieldable entity type update is not possible, which was re-re-committed with the necessary cache clears.

Status: Needs review » Needs work

The last submitted patch, 31: 2904686-31.patch, failed testing. View results

andrew answer’s picture

Patch #31 re-rolled.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

andrew answer’s picture

Patch #33 re-rolled for D 8.7.x.

andrew answer’s picture

Fixed inconsistences (tested on live site).

hardik_patel_12’s picture

Status: Needs work » Needs review
StatusFileSize
new25.85 KB
new3.61 KB

Patch #36 re-rolled for 8.9.x-dev.

Status: Needs review » Needs work

The last submitted patch, 37: drupal-views_base_table_bug-2904686-37.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

amateescu’s picture

StatusFileSize
new39.66 KB

The changes in #36 were wrong, the entity manager was deprecated and shouldn't be used anymore.

Here's a proper reroll for 9.1.x. Some tests are still failing and needs to be looked at properly so leaving at NW.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.