Jak stworzyć unię dwóch widoków?

36

Usiłuję uzyskać połączenie węzłów użytkownika i komentarzy posortowane według „daty publikacji”. Ten post zawiera linki do projektów piaskownicy dla D6, ale nie ma nic dla 7.

Ten post zawiera przykład użycia hook_views_pre_execute () i SQL UNION w D6. To nie działa dla D7 z widokami 3.

Natknąłem się na komentarz merlinofchaos

Ponieważ teraz używamy nowego generatora zapytań Drupala, zapytanie jest obiektem SelectQuery, który będziesz musiał zmodyfikować lub wymienić. Wyszukaj nową warstwę bazy danych Drupal 7, aby uzyskać więcej informacji.

Czy ktoś ma przykład, jak to zrobić lub inne rozwiązanie, aby połączyć dwa widoki?

uwe
źródło
jest to raczej pomysł niż prawdziwa odpowiedź: powinieneś być w stanie stworzyć widok oparty na użytkownikach, który łączyłby zarówno węzły, jak i komentarze (czyż nie są one jednak tylko bytami :). Za pierwszym razem nie udało mi się tego zrobić, ponieważ widoki nie oferują relacji między użytkownikiem a komentarzem. Ale to powinno być łatwe do zmiany. (lub po prostu coś zapomniałem).
mojzis
Myślę, że to ta sama odpowiedź, co poniżej: kt wymagałby dwóch filtrów kontekstowych (content.author = zalogowany użytkownik LUB comment.author = zalogowany użytkownik).
uwe
nie sądzę :) mam na myśli widok oparty na użytkownikach, łączący węzły i komentarze. ale mam wrażenie, że jest jakiś problem z relacją między użytkownikiem a komentarzem - nie udało mi się wyświetlić komentarzy.
mojzis
Zgaduję, ale nie możesz użyć searchapi do indeksowania wielu typów jednostek jednocześnie? Kiedy już to zrobisz i będziesz mieć pole, które jest używane przez obie części, możesz użyć tego do zbudowania takiego widoku.
Daniel Wehner
1
Istnieje projekt piaskownicy „Views Unionize” dla drupal 7, sprawdź drupal.org/sandbox/jalama/1785294 ,
Anoop Joseph

Odpowiedzi:

15

Oto działający i przetestowany przykład:

/**
 * Implements hook_views_pre_execute().
 */
function mymodule_views_pre_execute(view &$view) {
  if ($view->name == 'my_view') {
    $query1 = &$view->build_info['query'];

    // Basic setup of the second query.
    $query2 = db_select('another_table', 'at')
      ->condition('some_field', 0, '>')
      ->condition('some_other_field', 12345);

    // The number of fields (and their aliases) must match query1.
    // Get the details with:
    // dpm($query1->getFields());
    $query2->addField('at', 'some_field', 'alias1');
    $query2->addField('at', 'some_other_field', 'alias2');
    $query2->addField('at', 'some_other_field2', 'alias3');
    $query2->addField('at', 'some_other_field3', 'alias4');

    // Verify that queries are very similar.
    // dpq($query1);
    // dpq($query2);

    // Matrimony.
    $query1 = $query2->union($query1, 'UNION ALL');

    // Manual test.
    // dpm($query1->execute()->fetchAll());

  }
}

Działa to w przypadku większości widoków. Jednak niektóre wtyczki stylu mogą robić wymyślne rzeczy, które nie będą działać z tą techniką (moduł kalendarza patrzę na ciebie).

Dalin
źródło
2

Skończyło się to na użyciu komendy db_query () do utworzenia SQL UNION, a następnie renderowaniu jej do układu tabeli, w tym pagerów przy użyciu funkcji theme ().

Dla użytkownika wygląda to jak domyślne widoki. Inną korzyścią było to, że mogłem bardzo zoptymalizować zapytanie. Pokazuję „działania mojego przyjaciela”, a jeśli użyjesz do tego widoków, utworzysz listę znajomych i użyjesz go w klauzuli „IN” SQL, która jest bardzo wolna, jeśli masz więcej niż 50 lub 100 rekordów.

Mógłbym zawęzić listę znajomych tylko do tych, którzy byli zalogowani na stronie w ciągu ostatnich x dni.

To jest przykładowy kod:

  // Two queries are required (friendships can be represented in 2 ways in the
  // same table). No point making two db calls though so a UNION it is.

  // Build up the first query.
  $query = db_select('flag_friend', 'f')
    ->condition('f.uid', $account->uid)
    ->condition('u.login', $timestamp, '>');
  $query->addExpression('f.friend_uid', 'uid');
  $query->innerJoin('users', 'u', 'u.uid = f.friend_uid');

  // Build up the second query.
  $query2 = db_select('flag_friend', 'f')
    ->condition('f.friend_uid', $account->uid)
    ->condition('u.login', $timestamp, '>');
  $query2->addExpression('f.uid', 'uid');
  $query2->innerJoin('users', 'u', 'u.uid = f.uid');

  // Return the results of the UNIONed queries.
  return $query->union($query2)->execute()->fetchCol();
uwe
źródło
1

Na przyszłość, w ten sposób połączyłem dwa widoki oparte na tym samym stole razem. Te same zasady powinny mieć również zastosowanie do widoków opartych na różnych tabelach z taką samą liczbą pól.

W poniższym przypadku wybierany jest tylko identyfikator, ponieważ format jest ustawiony na renderowany byt. Ale jeśli korzystasz z pól, zawsze możesz dodać dodatkowe pola zastępcze do zapytania, które ma mniej pól, ponieważ dodałem znacznik czasu poniżej.

/**
 * 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()
    );
  };
}
duru
źródło
0

Wyobrażam sobie, że ma coś takiego:

/** 
* Implements hook_views_pre_execute().
*/     
function mymodule_views_pre_execute(&$view) {
  if ($view->name == 'myview') {
    $query = $view->query;
    $other_view = views_get_view('otherview');
    $other_query = $other_view->query;
    $query = $query->union($other_query);
    $view->query = $query;
  }
}

Chociaż tego nie testowałem.

Niektóre linki, które mogą pomóc:

http://api.drupal.org/api/drupal/include!database!select.inc/function/SelectQueryInterface%3A%3Aunion/7

http://drupal.org/node/557318#comment-1991910

cam8001
źródło
1
To nie wydaje się w pełni działać. $ view-> query jest obiektem pośrednim, którego używa Views do zbudowania zapytania. SelectQuery to $ view-> build_info ['zapytanie']. Gdy odpowiednio edytujesz, nie mogę wyjść poza błąd „Błąd krytyczny: wywołanie niezdefiniowanej metody SelectQuery :: render_pager ()”.
mpdonadio
1
Kod testowy bazy danych zawiera przykłady związków api.drupal.org/api/drupal/… i api.drupal.org/api/drupal/…
mikeytown2
Jedynym sposobem, w jaki może to działać, jest to, że oba widoki są prawie dokładnie takie same.
Dalin
0

Natknąłem się na moduł o nazwie Widoki Widok pola , który pozwala osadzić widok jako pole w innym widoku. Jeszcze tego nie wypróbowałem, ale może ci to pomóc.

Marijke Luttekes
źródło
2
Chociaż widoki Widok pola rzeczywiście może zawierać zarówno komentarze, jak i węzły, nie sądzę, aby istniał sposób sortowania według pól, tylko w obrębie nich.
Letharion
0

Funkcja zaplecza widoków EntityFieldQuery obsługuje zapytania dla wielu typów jednostek jednocześnie. Dlatego powinno być możliwe zapytanie o węzły i komentarze. Oba typy jednostek używają uidwłaściwości do łączenia się z ich autorami, dlatego na poziomie interfejsu API EntityFieldQuery :: propertyCondition () powinna umożliwiać wybieranie węzłów i komentarzy od jednego użytkownika. Wydaje mi się, że backend widoków oferuje tę samą funkcję.

Pierre Buyle
źródło
wygląda na to, że właśnie usunęli tę funkcję, aby wysłać
uwe
0

Innym podejściem może być utworzenie kanałów z węzłami i komentarzami (z filtrem kontekstowym identyfikatora użytkownika w adresie URL), a następnie połączenie tych dwóch kanałów w nowy kanał i wyświetlenie go według daty publikacji.

Sam Wilson
źródło
-2

Używane globalne: pola PHP ? Możesz ich użyć do sklejenia taśmy razem Widok, który łączy oba te elementy.

Utwórz widok zawartości z polami Treść: Tytuł i Treść: Komentarze (Wykluczone z wyświetlania).

Dodaj pole PHP, które oblicza, która jest nowsza, datę ostatniej aktualizacji lub datę ostatniego komentarza użytkownika i ustaw wartość pola na tę datę. Dodaj to pole jako warunek sortowania.

Dodaj podobne pole, które wyświetla łącze do komentarza lub do węzła.

To brzmi dla mnie dobrze!

Johnathan Elmore
źródło
ciekawy pomysł. Wymagałoby to dwóch filtrów kontekstowych (content.author = zalogowany użytkownik LUB comment.author = zalogowany użytkownik).
uwe
Mając nadzieję na epicką poprawę sytuacji na tym ...;)
Johnathan Elmore,
2
Skuteczność tego podejścia byłaby przerażająca. Potencjalna liczba wykonanych zapytań do bazy danych mogłaby zostać uwzględniona w astronomii.
Rider_X