Problem/Motivation

While working on #2321721: Provide a views relationship for each dynamic entity reference field when I tried to add extra condition(target_type = $entity_type_id) on left table it started giving SQL syntex error. After some research I discovered that JoinPluginBase::buildJoin() doesn't take left table field and value as an extra condition in join.

Proposed resolution

Allow adding left table field and value as an extra condition in join.

Remaining tasks

Reveiw the patch

User interface changes

None

API changes

JoinPluginBase::buildJoin() allows to add left table field and value as an extra condition in join.

      array(
        'left_field' => 'status',
        'value' => 0,
        'numeric' => TRUE,
      ),

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category This is a task because it improves the DX for people writing views integrations
Issue priority Normal because it does not affect a lot of people
Unfrozen changes Unfrozen because it only changes JoinPluginBase ... so no existing contrib code will break. This class also has quite some good test coverage to be honest.
Disruption No disruption at all.

Comments

Status: Needs review » Needs work

The last submitted patch, join-pluginbase-extra-test-only.patch, failed testing.

jibran’s picture

Status: Needs work » Needs review
dawehner’s picture

Category: Bug report » Task
Issue summary: View changes
Priority: Major » Normal
Status: Needs review » Reviewed & tested by the community
Issue tags: +VDC, +DX (Developer Experience)

Sorry but this is not a bug, but rather a feature/task.

Awesome!

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs issue summary update

This issue is a normal task so we need to outline how it fits within the allowable Drupal 8 beta criteria. Can someone add Drupal 8 beta phase evaluation template to the issue summary.

dawehner’s picture

Status: Needs work » Reviewed & tested by the community

@alexpott
Automated answer?

jibran’s picture

Thanks @dawehner for the IS update :)

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

@dawehner unfortunately

Unfrozen because it only changes JoinPluginBase ...

Is not true. There is no agreement that internal refactors are unfrozen.

jibran’s picture

It is not re-factoring it just adds the missing option which should be already there that is why I reported it as bug report. In other words it is only api addition to incomplete api.
This is a sample query for ER

SELECT entity_test.id AS id, entity_test_entity_test__field_test.id AS entity_test_entity_test__field_test_id, entity_test.id AS entity_test_id
FROM 
{entity_test} entity_test
LEFT JOIN {entity_test__field_test} entity_test__field_test ON entity_test.id = entity_test__field_test.entity_id AND entity_test__field_test.deleted = '0'
LEFT JOIN {entity_test} entity_test_entity_test__field_test ON entity_test__field_test.field_test_target_id = entity_test_entity_test__field_test.id
ORDER BY entity_test_id ASC

This is a sample query for DER

SELECT entity_test.id AS id, entity_test_entity_test__field_test.id AS entity_test_entity_test__field_test_id, entity_test.id AS entity_test_id
FROM 
{entity_test} entity_test
LEFT JOIN {entity_test__field_test} entity_test__field_test ON entity_test.id = entity_test__field_test.entity_id AND entity_test__field_test.deleted = '0'
LEFT JOIN {entity_test} entity_test_entity_test__field_test ON entity_test__field_test.field_test_target_id = entity_test_entity_test__field_test.id AND entity_test__field_test.field_test_target_type = 'entity_test'
ORDER BY entity_test_id ASC

You can see it only adds AND entity_test__field_test.field_test_target_type = 'entity_test' which imho I should be able to do with views while defining relationship.
Hope this helps.

jibran’s picture

In IRC @alexpott said

a concrete use case from contrib

Relationship module is already working on using DER as backend for 8.x branch. See #2315599-2: Consider Dynamic Entity Reference for storage needs. 9,373 sites currently report using relation module in D7. Is this a concrete use case from contrib?
Please let me if you still need anything else and if you are still not convinced please postpone this and move to 8.1.x.
Thanks.

jibran’s picture

Status: Needs work » Needs review
Issue tags: -Needs issue summary update
dawehner’s picture

+++ b/core/modules/views/src/Plugin/views/join/JoinPluginBase.php
+++ b/core/modules/views/src/Plugin/views/join/JoinPluginBase.php
@@ -257,18 +257,27 @@ public function buildJoin($select_query, $table, $view_query) {

@@ -257,18 +257,27 @@ public function buildJoin($select_query, $table, $view_query) {
           else {
             // With a single value, the '=' operator is implicit.
             $operator = !empty($info['operator']) ? $info['operator'] : '=';
+            $placeholder = ':views_join_condition_' . $select_query->nextPlaceholder();
+          }
+          // Set 'field' as join table field if available or set 'left field' as
+          // join table field is not set.
+          if (isset($info['field'])) {
+            $join_table_field = "$join_table$info[field]";
             // Allow the value to be set either with the 'value' element or
             // with 'left_field'.
             if (isset($info['left_field'])) {
               $placeholder = "$left[alias].$info[left_field]";
             }
             else {
-              $placeholder = ':views_join_condition_' . $select_query->nextPlaceholder();
               $arguments[$placeholder] = $info['value'];
             }
           }
-
-          $extras[] = "$join_table$info[field] $operator $placeholder";
+          // Set 'left field' as join table field is not set.
+          else {
+            $join_table_field = "$left[alias].$info[left_field]";
+            $arguments[$placeholder] = $info['value'];
+          }
+          $extras[] = "$join_table_field $operator $placeholder";
         }

... It would be so great if you could add an example at the top of the class, which would explain how to join on a field with a given value.

You added the appropriate test coverage, so things are nice, and nearly RTBC.

jibran’s picture

StatusFileSize
new4.46 KB
new8.87 KB

Thanks for the review. I have added some docs. Do you think we need change notice as well?

jibran’s picture

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

We have some good docs, we have some tests

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/views/src/Tests/Plugin/JoinTest.php
@@ -174,7 +175,36 @@ public function testBasePlugin() {
+    $configuration['extra'] = array(
+      array(
+        'field' => 'langcode',
+        'value' => 'en'
+      ),
+      array(
+        'left_field' => 'status',
+        'value' => 0,
+        'numeric' => TRUE,
+      ),
+      array(
+        'field' => 'name',
+        'left_field' => 'name'
+      ),
+    );
+    $join = $this->manager->createInstance('standard', $configuration);
+    $table = array('alias' => 'users5');
+    $join->buildJoin($query, $table, $view->query);
+
+    $tables = $query->getTables();
+    $join_info = $tables['users5'];
+    $this->assertTrue(strpos($join_info['condition'], "views_test_data.uid = users5.uid") !== FALSE, 'Make sure the join condition appears in the query.');
+    $this->assertTrue(strpos($join_info['condition'], "users5.langcode = :views_join_condition_6") !== FALSE, 'Make sure the first extra join condition appears in the query.');
+    $this->assertTrue(strpos($join_info['condition'], "views_test_data.status = :views_join_condition_7") !== FALSE, 'Make sure the second extra join condition appears in the query.');
+    $this->assertTrue(strpos($join_info['condition'], "users5.name = views_test_data.name") !== FALSE, 'Make sure the third extra join condition appears in the query.');

It feels like we should also be testing the $join_info['arguments'] contains the expected values.

jibran’s picture

Status: Needs work » Needs review
StatusFileSize
new983 bytes
new8.99 KB

It feels like we should also be testing the $join_info['arguments'] contains the expected values.

Seems a fair point. We are already doing in previous tests but added new assert for this case as well.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

The feedback from alex got adressed

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

I'm committing this because it helps contrib modules do more with core and is not disruptive. Committed 155a314 and pushed to 8.0.x. Thanks!

Thanks for adding the beta evaluation to the issue summary.

  • alexpott committed 155a314 on 8.0.x
    Issue #2378729 by jibran: JoinPluginBase doesn't allow extra conditions...

Status: Fixed » Closed (fixed)

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

tunic’s picture

This issue shoud be backported to D7. There's a separate issue with a patch tests in green: #2642100: views_join doesn't allow extra conditions on left table.