Problem/Motivation

If we have multi-language setup and want to create a view for non-translatable entities (entities with no langcode key) we will get a nice SQL exception as a notification that is not possible to do it. This started to fail since #2342045: Standard views base fields need to use same rendering as Field UI fields, for formatting, access checking, and translation consistency.

Steps to reproduce:

  1. Enable language_test, entity_test and content_translation modules. (Note: Make sure you have extension_discovery_scan_tests set to TRUE in your settings.php . This will allow you to install test modules)
  2. Go to admin/config/regional/language and add a new language.
  3. Edit NoLanguageEntityTest.php and add a Views data handler. Check #24 interdiff how to do it.
  4. After you make the annotation changes, we have to clear the cache. Go to admin/config/development/performance and hit "Clear all caches".
  5. Go to admin/structure/views/add, fill the view name, machine name. From View settings choose "Test entity without language support". Click the "Create a page", fill "Page title" and "Path" (e.g no-view) fields.
  6. Go to /no-view (or your custom) path.
  7. You should get an exception: Drupal\Core\Database\DatabaseExceptionWrapper: Exception in test[tes]: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax...

Proposed resolution

Instead of the assumption made in TranslationLanguageRenderer that all entities have a langcode key, we should add a condition to check if it is the case. To complete the issue, we also have to provide tests.

Remaining tasks

Get the patch in.

User interface changes

No.

API changes

No.

No data model changes either.

RC Eval

This patch is just a bug fix. No data model changes, no API changes, no disruption. It has a test. It changes only a few lines of code, which are made clearer than they were and it fixes a bad assumption in those few lines of code. I think it blocks at least one contrib project. It should be good for RC.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Berdir’s picture

Status: Active » Needs review
FileSize
1.32 KB

Status: Needs review » Needs work

The last submitted patch, 1: views-langcode-key-2453551-1.patch, failed testing.

Status: Needs work » Needs review
effulgentsia’s picture

I have an entity type that does not have a langcode entity key (It is a translation job, it actually has two languages, source and target language, but the job itself doesn't have a language and is also not translatable

I presume that this issue is just about content entities, but I'm wondering if the above premise conflicts with the change being proposed in #2451885: Config entities need to ship with language or are assumed undefined, specifically, this claim from that patch's docs:

+   * ... All configuration entities support third
+   * party settings, so even configuration entities that do not directly
+   * store settings involving text in a human language may have such third
+   * party settings attached. This means configuration entities should be in one
+   * of the configured languages or the built-in English.

Does it make sense for us to say that content entities (which can be extended with fields) are allowed to not have a langcode, but config entities (which can be extended with third party settings) are not?

Berdir’s picture

Interesting point.

It is now possible to add configurable fields to anything, so I can't prevent it, but there's no field_ui integration, so I don't really expect

Thinking about it, I guess I could make my source language the langcode, but not sure what I gain from that. A translation job *does* have a label that a user can enter, but it is a backend entity, nothing that is shown to normal users. There are filters in the default view, but nothing of the usual stuff (like displaying in the interface/content language) applies.

Config and content entities already have similar differences.. having a UUID for content entities is optional (aggregator feed items don't, they have a guid that is provided by the feed, but not a generated UUID) but required for config entities.

dawehner’s picture

Issue tags: +Needs tests

Do we have any entity type without a language in core?

Berdir’s picture

We do I think although possibly more accidentally because we forgot to add it.

EntityTestFieldOverride for example doesn't have a langcode.

dawehner’s picture

I'd argue that for those we should on top not allow people to select the TranslationRenderer in the UI.

Gábor Hojtsy’s picture

Issue tags: +D8MI, +language-content, +sprint
Berdir’s picture

We were able to fix our problem by changing the view by hand to use entity_default. Removing the contributed project blocker tag.

As suggested by @dawehner, a better fix might be to make sure that we use that renderer if there is no langcode key, and throw an exception if called for the other one, because that simply doesn't make sense.

jhodgdon’s picture

Regarding #8's suggestion, ... what would happen if the base table for the view was for a translatable entity, and it had a relationship to an entity that wasn't?

plach’s picture

Status: Needs review » Needs work

Jen has a good point in #11: the Translation renderer should be able to fall back to the Default language behavior if no langcode key is available. This way related non-translatable entities would be handled smoothly even if the translation renderer is configured in the view. I agree it should not be available if the view base table refers to a non-translatable entity type.

+++ b/core/modules/views/src/Entity/Render/TranslationLanguageRenderer.php
@@ -34,12 +34,13 @@ public function query(QueryPluginBase $query) {
+    if ($langcode_key = $this->entityType->getKey('langcode')) {
+      foreach (array('data_table', 'revision_table', 'base_table') as $key) {
+        if ($table = $this->entityType->get($key)) {

I know this line was not introduced here, but we should be using TableMappingInterface::getFieldTableName($langcode_key) now.

Setting to NW also for tests.

Saphyel’s picture

Status: Needs work » Needs review
Issue tags: +LONDON_2015_MAY
FileSize
1.37 KB

I rerolled the patch.

plach’s picture

Status: Needs review » Needs work

Thanks, setting back to needs work per #12.

Gábor Hojtsy’s picture

Issue tags: -sprint

Does not seem to be actually worked on.

edurenye’s picture

Status: Needs work » Needs review
FileSize
1.63 KB
1.66 KB

Done, I'm not sure if I did this in the best way, but it works.
Now I will work on the tests.

Status: Needs review » Needs work

The last submitted patch, 16: 2453551-16.patch, failed testing.

The last submitted patch, 16: 2453551-16.patch, failed testing.

andypost’s picture

Core should support content entities without langcode key
\Drupal\Core\Entity\Entity::language() already returns \Drupal\Core\Language\LanguageInterface::LANGCODE_NOT_SPECIFIED when no langcode key provided by annotation.

Also views needs to care about relation, and do not try to add non-existing field to query

There's a lot of reasons to have conetnt entities in contrib without language.

the Translation renderer should be able to fall back to the Default language behaviour if no langcode key is available

+1

mbovan’s picture

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

Rerolled and fixed some table mapping calls... Also, changed wrong variable type in RendererBase.
Tests are still needed.

Berdir’s picture

Status: Needs review » Needs work
+++ b/core/modules/views/src/Entity/Render/TranslationLanguageRenderer.php
@@ -35,12 +35,13 @@ public function query(QueryPluginBase $query, $relationship = NULL) {
         $this->langcodeAlias = $query->addField($table_alias, $langcode_key);
-        break;
       }
     }

I still don't understand why this removes the break?

Needs work for tests.

mbovan’s picture

^ As there is no loop anymore.

jhodgdon’s picture

Yeah, no loop => no break.

Leaving at Needs Work because this still needs a test.

mbovan’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
FileSize
2.86 KB
4.57 KB
2.86 KB

Adding tests... Btw, not sure whether core/modules/language/src/Tests/ is right place for this test.

The last submitted patch, 24: 2453551-24-TEST-ONLY.patch, failed testing.

jhodgdon’s picture

This test looks right to me!

But I'm not sure if it reproduces the problem in this issue. I think it does, but we really need an issue summary update, because the issue summary is difficult to understand (kind of garbled or incomplete or ... anyway not great).

Minor issue with the test:

+++ b/core/modules/language/src/Tests/LanguageViewsTest.php
@@ -0,0 +1,78 @@
+ * Tests the view creation of test language entities.

This should probably have more correct information about the purpose of the test, which is to verify that entities without translation don't break Views. I don't think it's really about test language entities.

Berdir’s picture

Status: Needs review » Needs work

Pff, the issue summary looks perfect to me! ;) (I wonder what I was drinking when I wrote that...)

I guess the test belongs in views module as the code is there as well?

  1. +++ b/core/modules/language/src/Tests/LanguageViewsTest.php
    @@ -0,0 +1,78 @@
    +    // Add a view for an entity type that does not have a language entity key.
    +    $edit = [
    +      'label' => 'No language entity test view',
    +      'id' => 'no_lang_test',
    +      'show[wizard_key]' => 'standard:no_language_entity_test',
    +      'page[create]' => TRUE,
    +      'page[title]' => 'No language entity test view',
    +      'page[path]' => 'no-lang',
    +    ];
    +    $this->drupalPostForm('admin/structure/views/add', $edit, t('Save and edit'));
    +    $this->drupalPostForm(NULL, [], t('Save'));
    

    It would probably be easier and definitely faster to just save that view as optional default config in the language_test module.

  2. +++ b/core/modules/language/src/Tests/LanguageViewsTest.php
    @@ -0,0 +1,78 @@
    +    // Visit the view page and assert it is displayed properly.
    +    $this->drupalGet('/no-lang');
    +    $this->assertResponse(200);
    +    $this->assertText('No language entity test view');
    

    Probably wouldn't hurt to actually create an entity and make sure the title or so is shown there?

    Same for the language, actually. Use the API, then we don't need an admin user and all that overhead. ConfigurableLanguage::createFromLangcode()->save() is all you need I think.

mbovan’s picture

Moved the test to View module and improved it a bit with API calls.

The last submitted patch, 28: 2453551-28-TEST-ONLY.patch, failed testing.

mbovan’s picture

Issue summary: View changes

Updated the issue summary. Hope it's a bit more clear how to reproduce the bug.

jhodgdon’s picture

Thanks for the summary update! Much nicer.

edurenye’s picture

Looks perfect now!

jhodgdon’s picture

Status: Needs review » Needs work

This all looks good, but:

+++ b/core/modules/views/src/Entity/Render/TranslationLanguageRenderer.php
@@ -35,12 +35,13 @@ public function query(QueryPluginBase $query, $relationship = NULL) {
     // If the data table is defined, we use the translation language as render
     // language, otherwise we fall back to the default entity language, which is
     // stored in the revision table for revisionable entity types.

It seems like this code comment needs to be revised, since the code below it got revised. I don't think it matches any more.

Berdir’s picture

What about dropping that code comment completely?

Unlike before, the code is pretty self-explanatory to me, we're using API methods whose names make it very clear what we are doing. I don't see that we could add something useful with a code comment there?

jhodgdon’s picture

Sure!

Berdir’s picture

Status: Needs work » Needs review
FileSize
9.29 KB
1.91 KB

Did just that, but noticed the existing condition above.. what if we just combine that into a single if condition? It's not really visible in the patch but with the previous patch, we had two different checks and did them differently (nested if vs. early return).

Also improved the initial comment a bit.

jhodgdon’s picture

+++ b/core/modules/views/src/Entity/Render/TranslationLanguageRenderer.php
@@ -27,21 +27,17 @@ class TranslationLanguageRenderer extends EntityTranslationRendererBase {
+    // Do not alter the query in case the site is not multilingual or the entity
+    // type has no langcode key.

Nitpick: this comment line goes over 80 chars.

I would also change "in case" to "if", which would bring it down below 80 chars. ;)

Or maybe explain what the method is actually doing... something like:

In order to render in the translation language of the entity, we need to add the language code of the entity to the query. Skip if the site is not multilingual or the entity is not translatable.

Anyway, this is just the comment. I think the code looks great! Very clear.

mbovan’s picture

Added the comment above.

jhodgdon’s picture

Status: Needs review » Needs work

Thanks! But:

+++ b/core/modules/views/src/Entity/Render/TranslationLanguageRenderer.php
@@ -27,21 +27,18 @@ class TranslationLanguageRenderer extends EntityTranslationRendererBase {
+    // add the language code of the entity to the query. Skip if the site is not

nitpick: comment line over 80 characters, please rewrap.

edurenye’s picture

Status: Needs work » Needs review

My IDE says that it's just 80 characters and that it's fine.

The last submitted patch, 24: 2453551-24-TEST-ONLY.patch, failed testing.

The last submitted patch, 28: 2453551-28-TEST-ONLY.patch, failed testing.

jhodgdon’s picture

Status: Needs review » Needs work

Hm. The line is 80 characters plus 1 for the \n at the end, totalling 81. dreditor complains, and that is what we normally go by... can you please rewrap? Thanks!

edurenye’s picture

Status: Needs work » Needs review
FileSize
3.02 KB
1.06 KB

Ok, done. I didn't know that, every day it's a school day.

jhodgdon’s picture

Status: Needs review » Needs work

Thanks! but that patch is missing files
core/modules/language/tests/language_test/config/optional/views.view.no_entity_translation_view.yml
core/modules/views/src/Tests/Entity/ViewNonTranslatableEntityTest.php
from the previous patch.

edurenye’s picture

Status: Needs work » Needs review
FileSize
9.39 KB

Sorry, I didn't realize. My gitignore did not add them :(
Now should be fine.

jhodgdon’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community
Issue tags: +rc target triage

Thanks! Yes, you have to be careful when making a patch, if there are new files added rather than just changes to existing files.

Anyway... the latest patch looks perfect. As in previous patches, we have a clear test that fails without the patch, and passes with the patch. The code is cleaner than it was, and the comments are clear. Let's get this in.

It should be RC eligible -- no API change, no disruption, just a bug fix and I think it's a contrib blocker though I'm not the reporter so I'm not sure. Adding RC eval notes to issue summary.

The last submitted patch, 24: 2453551-24-TEST-ONLY.patch, failed testing.

The last submitted patch, 28: 2453551-28-TEST-ONLY.patch, failed testing.

The last submitted patch, 36: 2453551-36.patch, failed testing.

effulgentsia’s picture

Issue tags: -rc target triage +rc target

Discussed with the other committers, and +1 to this being sufficiently non-disruptive and sufficiently beneficial in terms of solving a fatal bug for the conditions that trigger it.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed b412acf and pushed to 8.0.x. Thanks!

  • alexpott committed b412acf on 8.0.x
    Issue #2453551 by mbovan, edurenye, Berdir, Saphyel, jhodgdon:...

Status: Fixed » Closed (fixed)

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