Funkcja przetwarzania wstępnego według typu zawartości

25

Mam kilka typów treści, które muszę wstępnie przetwarzać na różne sposoby. Więc template.phpw moim motywie fooobecnie wygląda następująco:

function foo_preprocess_node(&$variables) {
    if ('news' ==$variables['type']) _preprocess_news($variables);
    if ('event'==$variables['type']) _preprocess_event($variables);
    if ('alert'==$variables['type']) _preprocess_alert($variables);
    ...
}

function _preprocess_news(&$variables) {
    ...
}

function _preprocess_event(&$variables) {
    ...
}

function _preprocess_alert(&$variables) {
    ...
}

Chciałbym móc określić funkcję wstępnego przetwarzania specyficzną dla Drupala, która uzależniałaby nazwę komputera typu zawartości. Próbowałem użyć, foo_preprocess_newsale nigdy się nie nazywa.

Czy jest lepszy sposób?

Cherouvim
źródło

Odpowiedzi:

10

Nazwa funkcji wstępnego przetwarzania jest oparta na nazwie motywu, więc dla theme_table()funkcji wstępnego przetwarzania jest to MYTHEME_preprocess_table().

Ponieważ nie ma żadnej theme_node_node_typefunkcji, hak wstępnego przetwarzania, taki jak foo_preprocess_newslub foo_preprocess_node_news, nie działa po wyjęciu z pudełka.

Możesz zająć się nadpisywaniem rejestru motywów, aby zachowywał się inaczej dla węzłów, ale tak naprawdę nie polecałbym go; może być bardzo niechlujny.

Jestem wielkim fanem refaktoryzacji kodu, ale w twoim przypadku nie uważam tego za konieczne; jeśli masz złożoną logikę, która musi działać na haku przedprocesowym w zależności od typu węzła, to zastosowanie tej funkcji do różnych funkcji w sposób, w jaki obecnie robisz, wydaje mi się dobrą praktyką.

Inną metodą byłoby oczywiście zaimplementowanie niestandardowego modułu dla każdego z różnych typów treści i wdrożenie hook_preprocess_node()w każdym z nich. W ten sposób funkcja wstępnego przetwarzania każdego modułu może być odpowiedzialna za inny typ zawartości.

Jednak może to być przesada w twojej sytuacji; jeśli nie masz dodatkowej logiki (tj. logiki bezproblemowej obróbki wstępnej) do wykonania na każdym typie treści, wówczas ta metoda prawdopodobnie nie dodaje żadnej dodatkowej wartości.

Clive
źródło
1
DOBRZE. Mógłbym również „zautomatyzować” foo_preprocess_node, wdrażając go tak call_user_func('_preprocess_' . $vars['type'], $vars);, aby uniknąć powtarzania ifs, ale prawdopodobnie najlepiej pozostać prosty.
Cherouvim
Zaimplementowałem hook_preprocess_node()na niestandardowym module i miałem nadzieję, że to ograniczy, gdy hak zostanie wywołany, ale tak nie jest. Jakikolwiek sposób ograniczenia, gdy hak zostanie wywołany według typu zawartości?
Keven
@Keven Nie można zatrzymać wywołania, jeśli funkcja istnieje, ale if ($vars['node']->type == 'foo') { ...osiągnie oczekiwany efekt
Clive
Naprawdę szukam tylko drobnych optymalizacji, podobnych do tego, co możesz zrobić hook_block_view_MODULE_DELTA_alter(). Obecnie robię to, co mówisz, ale chciałbym, aby istniał sposób ograniczenia, gdy hak zostanie trafiony.
Keven
To nie byłaby optymalizacja, choć @Keven - po prostu przeniosłeś proces decyzyjny na inną część kodu. W rzeczywistości, gdyby Drupal zaoferował takie zastąpienie, musiałoby być ogólne i prawie na pewno zajęłoby więcej czasu procesora. Już wygrywasz, podejmując decyzję tylko w ostatniej chwili
Clive
28

Podtemat zen osiąga to poprzez dodanie tego do swojej funkcji theme_preprocess_node:

function foo_preprocess_node(&$variables, $hook) {
  ...
    // Optionally, run node-type-specific preprocess functions, like
  // foo_preprocess_node_page() or foo_preprocess_node_story().
  $function = __FUNCTION__ . '_' . $variables['node']->type;
  if (function_exists($function)) {
    $function($variables, $hook);
  } 
  ...
}

Jeśli masz typ zawartości o nazwie „aktualności”, możesz utworzyć funkcję o nazwie foo_preprocess_node_news w pliku template.php.

Zło E
źródło
Używamy tego również na fundamencie ZURB z własnym impelementacją, bardzo przydatnym fragmentem kodu.
Marko Blazekovic
2

Właśnie miałem podobny problem, dlatego Google przeniósł mnie na tę stronę: moja funkcja wstępnego przetwarzania węzła rosła tak ogromnie, że wolałbym podzielić funkcję na wiele plików.

Podjąłem już podobne podejście w moim pliku template.php, który zawiera wszystkie funkcje alter, a ponieważ ta sama metoda działa tutaj doskonale, pomyślałem, że podzielę się tym podejściem:

konfiguracja pliku w folderze MYTHEME/preprocess:

- node.preprocess.inc
- node--blog-post.preprocess.inc
- node--device-variation.preprocess.inc
- (...)

powinieneś już mieć node.preprocess.inc, inne, które możesz sam stworzyć. to, jak je nazywasz, jest raczej arbitralne, ale lepiej nadaj im nazwy, które dobrze je identyfikują i pasują do całego systemu nazewnictwa Drupal.
dalej do treści tych plików!

node.preprocess.inctutaj robię coś takiego:

<?php

function MYTHEME_preprocess_node(&$variables) {

    switch($variables['type']) {

      case 'blog_post':
        // if the type of the node is a Blog Post, include this:
        include 'node--blog-post.preprocess.inc';
        break;

      case 'device_variation':
        // if Device Variation, include this:
        include 'node--device-variation.preprocess.inc';
        break;

      case 'foo':
        // ...
        break;
    }

    // additional stuff for all nodes

}

w zasadzie przełączamy rodzaj bieżącego węzła. to, co przełączysz, zależy od ciebie; #id, #view_modewszystko zależy od konkretnych potrzeb.
po znalezieniu dopasowania ładuje określony plik i działa na jego zawartość, tak jakby był zapisany bezpośrednio w tej funkcji.

zawartość tych includedplików wygląda dokładnie tak, jakbyś umieścił je w node.preprocess.incpliku, z tym wyjątkiem, że nie wywołujemy ponownie funkcji wstępnego przetwarzania:

node--device-variation.preprocess.inc

<?php

    // Device Name
    $device = drupal_clean_css_identifier(strtolower($variables['title']));

    // Determine whether only Device Version is of type 'N/A' and set ppvHasVariations accordingly
    $deviceHasVariations = true;
    if( $variables['content']['product:field_model_variation'][0]['#options']['entity']->weight == 0 ) {
        $deviceHasVariations = false;
    }
    //...

w zasadzie możesz to zrobić z dowolną liczbą plików, a nawet kaskadować wiele przełączników, na przykład dalej dzieląc określone pliki przetwarzania wstępnego węzła w zależności od #view_mode, mając jeden plik dla fulltrybu widoku, a drugi dlateaser

mam nadzieję, że to pomoże, jeśli ktoś kiedykolwiek natknie się na to pytanie (:

Bird-Kid
źródło
1

call_user_func()nie przekazuje parametrów przez odniesienie. Tak więc w przypadku $variablestwoich preprocess_foo()funkcji będzie działać tylko na kopiach oryginalnej tablicy; zmiany w obiektach innych niż obiekty nie zostaną zastosowane podczas pozostałego procesu renderowania.

kiszkasz
źródło
1

W głównym węźle hook_preprocess_node zaimplementuj następujący kod na końcu

$preprocess_function = 'themename_node__' . $node->type . '__preprocess';
if (function_exists($preprocess_function)) {
 $preprocess_function($variables);
}

Więc miałbyś teraz proces wstępny według typu węzła

Ziftman
źródło