Jelenlegi hely

Nézetek sminkelése saját modulból

CSÉCSY László képe

Ha ritkán is, de előfordul, hogy nézeteket sminktől függetlenül kell sminkelni (és/vagy előfeldolgozóval ellátni), hogy a webhelyen használatos sminkek mindegyikében egyformán legyen használható az adott nézet anélkül, hogy minden sminkben külön-külön ugyanazt kéne megvalósítani. Két tipikusnak tűnő példa és megoldásuk olvasható alább.

CCK-s jelölőnégyzet megjelenített értékeinek átírása

Adott egy tartalomtípusban két szöveg típusú egyszerű be/ki jelölőnégyzet. Az egyiknél „Nem” és „Beérkezett”, a másiknál „Nem” és „Megerősítve” a megengedett értékek (az első a „ki”, a második a „be” állapotnak felel meg), minek következtében az adatbázisba is ezek az értékek kerülhetnek. A jelölőnégyzet címkéje a „be” állapothoz tartozó érték címkéje lesz. A feladat: egy listában a mezőnevek legyenek a fejlécek, de az értékek „Nem” és „Igen” legyenek.

Tulajdonképpen egyszerű sminkfüggvényt kell írnunk, ami figyeli a mező értékét: ha az „Nem”, ugyanazt adja vissza, ha bármi egyéb, akkor „Igen” szöveget jelenít meg helyette. Ily módon kihasználhatjuk a tényt, hogy mindkét esetben a „ki” állapot értéke „Nem”, és mindkét mezőhöz hozzárendelhetjük ugyanazon sminkfüggvényt.

A sminkfüggvény (nem túl meglepő módon) a smink-réteghez tartozik, s mint ilyen, a hook_theme() megvalósításával kezdődik a megoldás. Íme:

/**
 * Implementation of hook_theme().
 */
function mymodule_theme() {
  return array(
    'views_view_field__field_beerkezett_value' => array(
      'arguments' => array('view' => NULL, 'field' => NULL, 'row' => NULL),
      'function' => 'theme_mymodule_views_view_field__bool',
      'preprocess functions' => array(
        'template_preprocess',
        'template_preprocess_views_view_field',
      ),
    ),
    'views_view_field__field_megerositve_value' => array(
      'arguments' => array('view' => NULL, 'field' => NULL, 'row' => NULL),
      'function' => 'theme_mymodule_views_view_field__bool',
      'preprocess functions' => array(
        'template_preprocess',
        'template_preprocess_views_view_field',
      ),
    ),
  );
}

Itt a views_view_field__field_beerkezett_value és views_view_field__field_megerositve_value a két mező sminkbeli neve, melyeket a nézet összeállításánál a smink információknál lehet megtalálni. (Igaz, hogy ott csak sablonfájlok listáját találjuk, de ne essünk kétségbe: hagyjuk el a .tpl.php végződést, és a kötőjeleket cseréljük aláhúzásjelekre, s máris megkapjuk az adott sablonfájlhoz tartozó sminkfüggvény nevét.)

Az arguments mutatja meg a smink rétegnek, hogy milyen paraméterekkel kell meghívnia az adott sminkfüggvényt. Ezt a listát megjelenítés, stílus és sorstílus esetében megtaláljuk a Views dokumentációjában, mezők esetében pedig a fenti használatos.

A function jelentése kettős. Egyrészt már a neve is mutatja, hogy jelen bejegyzés nem sablonfájlt, hanem csak sminkfüggvényt fog definiálni; másrészt az értéke mondja meg a smink rétegnek azon függvény nevét, melyet meg kell hívnia. (Ugyan megadhatnánk bármit, a theme_mymodule_ előtag használata egy hasznos megszokás: egyrészt mutatja, hogy a függvényünk a smink réteghez tartozik valójában, másrészt mutatja, hogy a saját modulunkhoz - így elkerülhetőek a függvénynév-ütközések.)

A preprocess functions tömb azon függvények neveit tartalmazza, melyeket a smink rétegnek a mi függvényünk hívása előtt meg kell hívnia, a megfelelő sorrendben. Mivel jelen esetben nem megjelenítést, sort vagy sorstílust, hanem mezőt sminkelünk, ezért a fenti két függvény az, amely előkészíti a mi függvényünk számára átadandó paramétereket. (Egyéb esetekre lásd a már említett Views dokumentációt.)

Mindezek után a sminkfüggvényünk már meglehetősen egyszerű:

/**
 * Display a bool field as a Yes/No value.
 */
function theme_mymodule_views_view_field__bool($view, $field, $row) {
  $value = $row->{$field->field_alias};
  if (!empty($value) && ($value != 'Nem')) {
    return t('Yes');
  }
  return t('No');
}

A $value kinyerése módjának okát szinte minden Views sablonfájlban megtalálhatjuk: a mezőknek lehet (sőt egész pontosan: van) álnevük, és a $row objektumban ezen álnéven találhatóak meg (és nem $field néven, azaz a saját nevükön). Haladók megkérdezhetik, hogy az érték ellenőrzésénél a t() függvényt miért nem használjuk? Mert a CCK mezőnk értékét az ott megadottal akarjuk összehasonlítani, és nem egy lefordított valamivel. Igazán profik azt is megkérdezhetnék, miért van szükség az érték ürességének ellenőrzésére? Mert ha az adott tartalmat egy lusta modul a node_save() függvény használatával anélkül hozza létre, hogy explicite megadná az alapértelmezett (jelen esetben „Nem”) értéket, a mező tartalma üres lesz - márpedig ennek jelen esetben az a jelentése, hogy az adott tartalom nem érkezett be és nem erősítették meg.

Saját modul sablonfájljának használata nézet módosításához

A feladat egyszerűbb, mint a fenti esetben: három nézet tetején jelenítsük meg a címüket. (Igazából nem tudom, miért nem történik meg ez automatikusan, amikor a nézet/megjelenítés címe ki van töltve.) Pontosabban két nézet felett a saját címüket, s mivel a harmadik nézetben egy adott taxonómia-kifejezéssel rendelkező tartalmakat listázunk, ezért afölött a taxonómia-kifejezést.

A megoldás lépései hasonlóak: először egy hook_theme() implementáció, majd egy (két) előfeldolgozó, végül maga a sablonfájl.

/**
 * Implementation of hook_theme().
 */
function drogterapia_module_theme() {
  return array(
    'views_view__galeria__page_1' => array(
      'arguments' => array('view' => NULL),
      'template' => 'views-view--usetitle',
      'original hook' => 'views_view',
      'preprocess functions' => array(
        'template_preprocess',
        'template_preprocess_views_view',
        'mymodule_preprocess_views_view__viewtitle',
      ),
    ),
    'views_view__munkatarsak__page_1' => array(
      'arguments' => array('view' => NULL),
      'template' => 'views-view--usetitle',
      'original hook' => 'views_view',
      'preprocess functions' => array(
        'template_preprocess',
        'template_preprocess_views_view',
        'mymodule_preprocess_views_view__viewtitle',
      ),
    ),
    'views_view__dokumentumtar__page_1' => array(
      'arguments' => array('view' => NULL),
      'template' => 'views-view--usetitle',
      'original hook' => 'views_view',
      'preprocess functions' => array(
        'template_preprocess',
        'template_preprocess_views_view',
        'mymodule_preprocess_views_view__taxonomytitle',
      ),
    ),
  );
}

A views_view__galeria__page_1, views_view__munkatarsak__page_1 és a views_view__dokumentumtar__page_1 megintcsak az előfeldolgozók nevei, melyeket a smink információkból tudhatunk meg. Az arguments most egyszerűbb, lévén megjelenítést sminkelünk. A fenti példától eltérően itt template használatos: egyrészt megmondja, hogy sablonfájlt (is) fogunk definiálni, másrészt annak a nevét. (Fájlnévben a kötőjelet szokás használni elválasztónak, a .tpl.php utótagot pedig a smink réteg automatikusan odateszi.) Megfigyelhetjük, hogy mindhárom esetben ugyanazon sablonfájl használatos.

A trükkös rész az original hook: ez a Views smink rétegének mondja meg, hogy a mi előfeldolgozónk előtt a megadott előfeldolgozót is hajtsa végre.

A preprocess functions hasonló az előzőhöz, mivel azonban itt nem sminkfüggvényt, hanem előfeldolgozót írunk, ezért a saját függvényünk nevét is fel kell tüntetnünk a lista végén. Megfigyelhető, hogy az első két nézethez ugyanazon előfeldolgozót használjuk, a taxonómia-kifejezéssel szűrthez viszont egy másikat.

Lássuk előbb az egyszerűbbiket!

/**
 * Make available a $title pulled from the view.
 */
function mymodule_preprocess_views_view__viewtitle(&$vars) {
  $vars['title'] = $vars['view']->display[$vars['view']->current_display]->display_options['title'];
  if (empty($vars['title'])) {
    $vars['title'] = $vars['view']->display['default']->display_options['title'];
  }
}

Az előfeldolgozók mindig cím szerint veszik át a paraméterüket, hogy ugyanazon tömbbe vissza is tudják tenni a módosításaikat. A címet először megpróbáljuk az adott nézet éppen aktuális megjelenítéséből kinyerni, majd ha ez nem hozott volna eredményt, az alapértelmezett megjelenítés címét használjuk.

A taxonómiás előfeldolgozó is csak egy kicsivel bonyolultabb.

/**
 * Make available a $title pulled from the taxonomy.
 */
function mymodule_preprocess_views_view__taxonomytitle(&$vars) {
  list($term) = taxonomy_get_term_by_name($vars['view']->build_info['query_args'][1]);
  $vars['title'] = check_plain($term->name);
  if (empty($vars['title'])) {
    $vars['title'] = $vars['view']->display['default']->display_options['title'];
  }
  else {
    drupal_set_title($vars['title']);
  }
}

A legelső sorban előszedjük a nézet első paramétereként megadott taxonómia-kifejezést. (A taxonomy_get_term_by_name() függvény több kifejezést is visszaadhat, melyek közül az elsőt használjuk.) Az esetleges biztonsági hibák elkerülése végett ezt az eredményt a check_plain() függvénnyel biztonságossá tesszük megjelenítése előtt. Ha netán nem találtuk volna meg a megfelelő kifejezést, a nézet címeként az alapértelmezett megjelenítés címét használjuk; ha megtaláltuk, akkor viszont a böngésző címsorába is kiíratjuk.

Végül jöhet a views-view--usetitle.tpl.php sablonfájl.

<div class="view view-<?php print $css_name; ?> view-id-<?php print $name; ?> view-display-id-<?php print $display_id; ?> view-dom-id-<?php print $dom_id; ?>">
  <?php if ($admin_links): ?>
    <div class="views-admin-links views-hide">
      <?php print $admin_links; ?>
    </div>
  <?php endif; ?>
  <?php if ($title): ?>
    <div class="view-title"><h1>
      <?php print $title; ?>
    </h1></div>
  <?php endif; ?>
  <?php if ($header): ?>
    <div class="view-header">
      <?php print $header; ?>
    </div>
  <?php endif; ?>
 
  <?php if ($exposed): ?>
    <div class="view-filters">
      <?php print $exposed; ?>
    </div>
  <?php endif; ?>
 
  <?php if ($attachment_before): ?>
    <div class="attachment attachment-before">
      <?php print $attachment_before; ?>
    </div>
  <?php endif; ?>
 
  <?php if ($rows): ?>
    <div class="view-content">
      <?php print $rows; ?>
    </div>
  <?php elseif ($empty): ?>
    <div class="view-empty">
      <?php print $empty; ?>
    </div>
  <?php endif; ?>
 
  <?php if ($pager): ?>
    <?php print $pager; ?>
  <?php endif; ?>
 
  <?php if ($attachment_after): ?>
    <div class="attachment attachment-after">
      <?php print $attachment_after; ?>
    </div>
  <?php endif; ?>
 
  <?php if ($more): ?>
    <?php print $more; ?>
  <?php endif; ?>
 
  <?php if ($footer): ?>
    <div class="view-footer">
      <?php print $footer; ?>
    </div>
  <?php endif; ?>
 
  <?php if ($feed_icon): ?>
    <div class="feed-icon">
      <?php print $feed_icon; ?>
    </div>
  <?php endif; ?>
 
</div>

Tulajdonképpen ez a Views views-view.tpl.php fájljához képest csak az alábbi plusz sorokat tartalmazza:

  <?php if ($title): ?>
    <div class="view-title"><h1>
      <?php print $title; ?>
    </h1></div>
  <?php endif; ?>

Magyarul: ha valamilyen előfeldolgozó adott értéket a $title változónknak, azt szépen megformázva írjuk is ki.

Mint láthatjuk, egyik megoldás sem ördöngősség, mindazáltal a trükktarisznya hasznos eszköze lehet, ha egy nézetet nem csak sminkből, hanem modulból is tudunk sminkelni.

Technológia: