diff --git a/core/modules/views/src/Plugin/views/join/JoinPluginBase.php b/core/modules/views/src/Plugin/views/join/JoinPluginBase.php index a0bbedf7315dd95bf08989c9ec8509e1a8ea65ae..6811dcddc78daa3a05dd0355ccd3bd7d4814d841 100644 --- a/core/modules/views/src/Plugin/views/join/JoinPluginBase.php +++ b/core/modules/views/src/Plugin/views/join/JoinPluginBase.php @@ -37,6 +37,30 @@ * Note that the default join type is a LEFT join when 'type' is not supplied in * the join plugin configuration. * + * If an SQL expression is needed for the first part of the left table join + * condition, 'left_formula' can be used instead of 'left_field'. + * For this SQL: + * @code + * LEFT JOIN {two} ON MAX(one.field_a) = two.field_b AND one.field_c = 'some_val' + * @endcode + * Use this configuration: + * @code + * $configuration = array( + * 'table' => 'two', + * 'field' => 'field_b', + * 'left_table' => 'one', + * 'left_formula' => 'MAX(one.field_a)', + * 'operator' => '=', + * 'extra' => array( + * 0 => array( + * 'left_field' => 'field_c', + * 'value' => 'some_val', + * ), + * ), + * ); + * $join = Views::pluginManager('join')->createInstance('standard', $configuration); + * @endcode + * * For this SQL: * @code * INNER JOIN {two} ON one.field_a = two.field_b AND one.field_c = 'some_val' @@ -156,6 +180,13 @@ class JoinPluginBase extends PluginBase implements JoinPluginInterface { */ public $leftField; + /** + * A formula to be used instead of the left field. + * + * @var string + */ + public $leftFormula; + /** * An array of extra conditions on the join. * @@ -238,6 +269,10 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition $this->leftField = $configuration['left_field']; $this->field = $configuration['field']; + if (!empty($configuration['left_formula'])) { + $this->leftFormula = $configuration['left_formula']; + } + if (!empty($configuration['extra'])) { $this->extra = $configuration['extra']; } @@ -263,7 +298,7 @@ public function buildJoin($select_query, $table, $view_query) { if ($this->leftTable) { $left_table = $view_query->getTableInfo($this->leftTable); - $left_field = "$left_table[alias].$this->leftField"; + $left_field = $this->leftFormula ?: "$left_table[alias].$this->leftField"; } else { // This can be used if left_field is a formula or something. It should be used only *very* rarely. diff --git a/core/modules/views/tests/src/Kernel/Plugin/JoinTest.php b/core/modules/views/tests/src/Kernel/Plugin/JoinTest.php index 6a35d5259359cc094f3ef84018cbee321510ca44..bf7042030feca418bf8bad8f029b13a5272e33b6 100644 --- a/core/modules/views/tests/src/Kernel/Plugin/JoinTest.php +++ b/core/modules/views/tests/src/Kernel/Plugin/JoinTest.php @@ -202,6 +202,20 @@ public function testBasePlugin() { $this->assertTrue(strpos($join_info['condition'], "views_test_data.status = :views_join_condition_5") !== 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.'); $this->assertEqual(array_values($join_info['arguments']), ['en', 0], 'Make sure the arguments are in the right order'); + + // Test that joins using 'left_formula' are properly built. + $configuration['left_formula'] = 'MAX(views_test_data.uid)'; + $join = $this->manager->createInstance('standard', $configuration); + $table = ['alias' => 'users6']; + $join->buildJoin($query, $table, $view->query); + + $tables = $query->getTables(); + $join_info = $tables['users6']; + $this->assertTrue(strpos($join_info['condition'], "MAX(views_test_data.uid) = users6.uid") !== FALSE, 'Make sure the join condition appears in the query.'); + $this->assertTrue(strpos($join_info['condition'], "users6.langcode = :views_join_condition_7") !== 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_8") !== FALSE, 'Make sure the second extra join condition appears in the query.'); + $this->assertTrue(strpos($join_info['condition'], "users6.name = views_test_data.name") !== FALSE, 'Make sure the third extra join condition appears in the query.'); + $this->assertEqual(array_values($join_info['arguments']), ['en', 0], 'Make sure the arguments are in the right order'); } } diff --git a/core/modules/workspaces/src/ViewsQueryAlter.php b/core/modules/workspaces/src/ViewsQueryAlter.php index a6e4e0d528e80f2c18e4c71c8e252fec6adfea24..485f51a81e57a0d2d675a609b74bd508c88f7c95 100644 --- a/core/modules/workspaces/src/ViewsQueryAlter.php +++ b/core/modules/workspaces/src/ViewsQueryAlter.php @@ -187,8 +187,7 @@ protected function alterQueryForEntityType(Sql $query, EntityTypeInterface $enti // Update the join to use our COALESCE. $revision_field = $entity_type->getKey('revision'); - $table_info['join']->leftTable = NULL; - $table_info['join']->leftField = "COALESCE($workspace_association_table.target_entity_revision_id, $relationship.$revision_field)"; + $table_info['join']->leftFormula = "COALESCE($workspace_association_table.target_entity_revision_id, $relationship.$revision_field)"; // Update the join and the table info to our new table name, and to join // on the revision key. diff --git a/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php b/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php index 1bb7d2f1096f64a4a275368dfc8c018c376a321d..d57849fbff0ee56b80bd1cce7fa4cec1911011fe 100644 --- a/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php +++ b/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php @@ -101,8 +101,8 @@ protected function setUp(): void { // Create two nodes, a published and an unpublished one, so we can test the // behavior of the module with default/existing content. $this->createdTimestamp = \Drupal::time()->getRequestTime(); - $this->nodes[] = $this->createNode(['title' => 'live - 1 - r1 - published', 'created' => $this->createdTimestamp++, 'status' => TRUE]); - $this->nodes[] = $this->createNode(['title' => 'live - 2 - r2 - unpublished', 'created' => $this->createdTimestamp++, 'status' => FALSE]); + $this->nodes[] = $this->createNode(['title' => 'live - 1 - r1 - published', 'body' => 'node 1', 'created' => $this->createdTimestamp++, 'status' => TRUE]); + $this->nodes[] = $this->createNode(['title' => 'live - 2 - r2 - unpublished', 'body' => 'node 2', 'created' => $this->createdTimestamp++, 'status' => FALSE]); $translation = $this->nodes[0]->addTranslation('de'); $translation->setTitle('live - 1 - r1 - published - de'); @@ -794,6 +794,23 @@ protected function assertWorkspaceStatus(array $expected, $entity_type_id) { $this->assertNoRaw($expected_entity_values[$entity_keys['label']]); } } + + // Add a filter on a field that is stored in a dedicated table in order to + // test field joins with extra conditions (e.g. 'deleted' and 'langcode'). + $view->destroy(); + $view->setDisplay('page_1'); + $filters = $view->displayHandlers->get('page_1')->getOption('filters'); + $view->displayHandlers->get('page_1')->overrideOption('filters', $filters + [ + 'body_value' => [ + 'id' => 'body_value', + 'table' => 'node__body', + 'field' => 'body_value', + 'operator' => 'not empty', + 'plugin_id' => 'string', + ], + ]); + $view->execute(); + $this->assertIdenticalResultset($view, $expected_frontpage, ['nid' => 'nid']); } }