2

I need to write an impossible view and I achieve to retrieve the correct list of nodes in two different views and now I need to merge the results in one single table.

How can I merge it?

If the views_1 give me nodes: [2, 52, 68, 41] and the views_2 give me nodes: [2, 66, 88]
I want ONE table with the nodes: [2, 52, 68, 41, 66, 88]

I can't just merge filter's views because they are based on two relationships so I can't say to require one relationship OR the other one, but only to require one or both relationship.

3

Output one view as you normally would.

  1. Implement views_pre_render.
  2. Call view::preview on the second view.
  3. Manually merge the results from 2 into 1.
1

To expand on @Letharion's Answer here's an example:

function HOOK_views_pre_render(&$view) {

  if($view->name == 'views_1' && $view->current_display == 'default') {

    //Load views_2
    $view2 = views_get_view('views_2'); //View Name
    $view2->preview('default'); //View Display

    //Check for empty results
    if(empty($view2->result)){
      return;
    }

    $view->result = array_merge($view->result, $view2->result);
  }
}
0

Here is alternative way of merging results from two impossible views by using hook_views_post_render:

/**
 * Implements hook_views_post_render().
 */
function foo_views_post_render(&$view, &$output, &$cache) {
  if ($view->name == 'my_view_1') {

    // API: http://api.drupal.org/api/views/includes!view.inc/class/view/7
    $view2 = views_get_view('my_view_2');
    $view2->preview('page');
    if (empty($view2->result)) {
      return; // Return on empty results.
    }

    $dom = new DOMdocument();
    $dom->loadHTML($output); // Load HTML from a string into DOM object.

    foreach ($view2->result as $item) {

      // Create field values.
      $row1 = clone $row2 = clone $row3 = clone $row4 = clone $row5 = $dom->createDocumentFragment();
      // TODO: Here, get the values assigned from $item ($view2->result).
      $row2_title = 'same value from view2';
      $url = 'some/url';
      $row1->appendXML('<div>foo</div>');
      $row2->appendXML(l($row2_title, $url)); // Link example.
      $row3->appendXML('<div>foo</div>');
      $row4->appendXML('<div>foo</div>');
      $row5->appendXML('<div>foo</div>');

      // Create columns and append content.
      $td1 = $dom->createElement('td'); // row1
      $td1->appendChild($row1);
      $td2 = $dom->createElement('td'); // row2
      $td2->appendChild($row2);
      $td3 = $dom->createElement('td'); // row3
      $td3->appendChild($row3);
      $td4 = $dom->createElement('td'); // row4
      $td4->appendChild($row4);
      $td5 = $dom->createElement('td'); // row5
      $td5->appendChild($row5);

      // Create row and append columns.
      $tr = $dom->createElement('tr');
      $tr->appendChild($td1)->setAttribute('class', 'views-field views-field-row1');
      $tr->appendChild($td2)->setAttribute('class', 'views-field views-field-row2');
      $tr->appendChild($td3)->setAttribute('class', 'views-field views-field-row3');
      $tr->appendChild($td4)->setAttribute('class', 'views-field views-field-row4');
      $tr->appendChild($td5)->setAttribute('class', 'views-field views-field-row5');

      // Apply changes to table and document.
      $table = $dom->getElementsByTagName('table')->item(0)->getElementsByTagName('tbody')->item(0);
      $table->appendChild($tr);
    }

    $output = $dom->saveHTML();
  }
}

This solution is for table display only and it's adding new items of view2 into view1 results by parsing directly html output.

It has advantage of merging different type of views which doesn't share the same data, not using SQL or proper node objects or using different hooks (e.g. Search API, or YQL View).

0

The below code combines two views based on message table which have different relationships. Same should apply on node table.

/**
 * Implements hook_views_pre_execute().
 */
function MY_MODULE_views_pre_execute(&$view) {
  if ($view->name == 'VIEW_1' && $view->current_display == 'DISPLAY_OF_VIEW_1') {

    $view2 = views_get_view('VIEW_2');
    $view2->build('DISPLAY_OF_VIEW_2');

    $view->build_info['query'] = db_select( //this is for cardinality errrors
      $view->build_info['query']
        ->fields('table_alias', array('timestamp'))
        ->range() //unset offset and limit to set them after the union
        ->union(
          $view2->build_info['query']
            ->fields('table_alias', array('timestamp'))
            ->range()
      ), 'table_alias'
    )
      ->fields('table_alias', array('mid', 'timestamp'))
      ->orderBy('timestamp', 'DESC') //you should order manually
      ->range(
        $view->query->pager->current_page * $view->query->limit, 
        $view->query->limit);

    $view->build_info['count_query'] = $view->build_info['query'];
  };
}

The evolution of above code has been like this:

/**
 * Implements hook_views_pre_execute().
 */
function MY_MODULE_views_pre_execute(&$view) {
  if ($view->name == 'VIEW_1' && $view->current_display == 'DISPLAY_OF_VIEW_1') {

    $view2 = views_get_view('VIEW_2');
    $view2->build('DISPLAY_OF_VIEW_2');

    $view->build_info['query']
      ->fields('table_alias', array('timestamp'))
      ->union(
          $view2->build_info['query']
            ->range()
            ->fields('table_alias', array('timestamp'))
            ->orderBy('timestamp', 'DESC')
      );

    $view->build_info['count_query']
      ->union(
          $view2->build_info['count_query']
          ->range()
      );
  };
}
0

From what I understood you have two different content types, you want to select the content of both of them but the result should be distinct values. Create a view of both content types and set Use aggregation:Yes to create distinct values.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.