Das Views Modul für Drupal ist eines meiner absoluten Lieblingsmodule. Es ist relativ leicht zu erweitern, wenn man sich einmal mit der OOP-Struktur angefreundet hat. So kann man dann, einen eigenen Filter zu schreiben, um z.B. bestimmte Nodes auszuwählen.
In unserem Fall ging es darum, dass über CCK Node Reference Abhängigkeiten zwischen Nodes bis zu einer Entfernung von 5 Tabellen erstellt wurden. Mit Views ist dies sogar aufzulösen, indem man mehrere Beziehungen erstellt und dann diese Daten filtert. Im Hintergrund erstellt Views für uns SQL JOINS und zieht die Daten zusammen. Allerdings verliert man jede Übersicht und dass die Abfragen besonders toll sind, wage ich nicht zu behaupten.
Also haben wir die Abfragen, die ermitteln, welche Inhalte zum gerade aktiven User gehören, aus Views herausgenommen und mit PHP in eine API mit Cache gelegt. Auf dieser Basis haben wir dann einen einfachen Views Filter geschrieben. So ist alles einfacher, hat mehr Leistung und man verliert dennoch nicht die vielen Vorteile von Views.
hook_views_api
Um einen Filter zu schreiben, beginnt man mit dem Einbinden der Views API. Dies ist typisch für Module die von merlinofchaos entwickelt wurden. Der Pfad ist optional, aber es empfiehlt sich, einen eigenen Ordner zu benutzen, typischerweise "includes". Das ist einfach aufgeräumter. Views erwartet, das eine Klasse in einer eigenen Datei liegt.
<?php
/**
* Implementation of hook_views_api
*/
function myfilter_views_api() {
return array(
'api' => 2,
'path' => drupal_get_path('module', 'myfilter') . '/includes',
);
}
?>hook_views_data
Dann kann man mit hook_views_data() ganz einfach an "node" seinen Filter hängen. "node" bezeichnet hier die Basistabelle und wir wollen hier ja als Beispiel auf Node IDs filtern.
<?php
function myfilter_views_data() {
$data = array();
$data['node']['myfilter'] = array(
'title' => t('My TEST Filter'),
'help' => t('Filter stuff like I want!'),
'filter' => array(
'handler' => 'myfilter_handler',
),
);
return $data;
}
?>hook_views_handlers
Zusätzlich muss man nun noch den Handler definieren, den wir eben in hook_views_data() angegeben haben. "Handler" kann man mit "Steuerungsprogramm" übersetzen werden und ist der Programmteil, der den eigentlichen Vorgang steuert. Auch hier können und sollten wir einen eigenen Ordner angeben, wo sich der Handler befindet.
Der "parent" des Handlers ist hier eine interessante Sache. Views verwendet hier eine Art "auto_load" Funktion und wird bis zu einer Tiefe von 10 alle Eltern der Klasse einbinden. Ich denke, dass "views_handler_filter" schon von anderen Modulen geladen wurde und ich es wohl nicht angeben bräuchte, aber so ist leichter zu sehen, was wir hier machen. Allerdings sieht man, dass im Handler selbst auch durch "myfilter_api_handler extends views_handler_filter". In Drupal 7 wird das alles überflüssig sein, da dann Klassen über PHP autoload geladen werden.
<?php
function myfilter_views_handlers() {
return array(
'info' => array(
'path' => drupal_get_path('module', 'myfilter') . '/includes',
),
'handlers' => array(
'myfilter_handler' => array(
'parent' => 'views_handler_filter',
),
),
);
}
?>myfilter_handler extends views_handler_filter
Nun zum eigentlichen Handler. Dieser ist eine Vererbung von views_handler_filter. Ist es nicht toll, dass man mit so wenig Zeilen seinen ganzen Handler fertig hat? :)
<?php
class myfilter_handler extends views_handler_filter {
function query() {
$this->query->add_where($this->options['group'], 'node.nid = 123');
}
}
?>Mal im Ernst: Wenn man sich durch die ganzen Klassen durchgekämpft hat und vom OOP-Geschreibsel absieht, dann sind es wirklich wenige Zeilen, mit denen man einen View manipulieren kann. Oder ein Projekt so auf Views umstellen, dass man eine ganze Arbeitsaufteilung erreichen kann. Wir programmieren auf der Basis von Views und der eigentliche Contentmanager kann sich darauf konzentrieren seine Inhalte auf die Site zu bringen.
Gehen wir aber noch auf ein paar nette Eigenschaften der Klasse "views_handler_filter" ein:
admin_summary
<?php
/**
* Display the filter on the administrative summary
*/
function admin_summary() {
return check_plain((string) $this->operator) . ' ' . check_plain((string) $this->value);
}
?>Mit dieser Funktion kann man für die Übersicht ausgeben, wie der Filter angezeigt werden soll. Sehr einfach und sehr praktisch.
operator_form & option_definition
<?php
function operator_form(&$form, &$form_state) {
$form['myfilter'] = array(
'#type' => 'checkboxes',
'#title' => t('Some Checkboxes'),
'#default_value' => $this->options['myfilter'],
'#options' => array(
MYFILTER_A => 'myfilter setting A',
MYFILTER_B => 'myfilter setting B',
MYFILTER_C => 'myfilter setting C',
),
'#description' => t('Some decription'),
);
parent::operator_form(&$form, &$form_state);
}
function option_definition() {
$options = parent::option_definition();
$options['myfilter'] = array('default' => MYFILTER_A);
return $options;
}
?>Mit "operator_form" kann man wie mit der FAPI gewohnt ein Formular bauen und für unseren Filter Daten speichern. Schön hierbei ist, dass Views sich für uns darum kümmert, dass dies alles bezogen auf die aktive Ansicht / Ausgabeart des Views geschieht. Deshalb muss man auch "option_definition" benutzen. Damit braucht man sich eigentlich um nichts weiter zu kümmern als um den Ablauf, was mit den Daten passieren soll. Das ist wirklich toll!
query
<?php
/**
* Add this filter to the query.
*
* Due to the nature of fapi, the value and the operator have an unintended
* level of indirection. You will find them in $this->operator
* and $this->value respectively.
*/
function query() {
$this->ensure_my_table();
$this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field " . $this->operator . " '%s'", $this->value);
}
?>Query ist ein eigenes Views Objekt, das man im Views Modul unter inc/query.inc finden kann. Das Beispiel oben ist aus der Standard-Implementation aus dem "views_handler_filter" Objekt.
"$this->ensure_my_table();" bedeutet, dass man sichergeht, das auch ja die verwendeten Tabellen im Query vorhanden sind.
"$this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field " . $this->operator . " '%s'", $this->value);" Der erste Parameter ist die Gruppe ist eine wichtige und interessante Sache, da man hiermit entscheidet zu welcher Gruppe von WHERE-Klauseln diese nun gehört. Damit entscheidet sich auch die Verwendung von AND und OR. Der zweite Parameter ist dann die eigentlich WHERE-Klausel. Man muss beachten, dass der richtige Alias verwendet wird und kann dann anhand der Einstellungen die Einschränkung zusammensetzen. Hier geht einfach alles, was SQL bietet.
Das query Objekt kann noch eine Menge mehr. Ich beschränke mich hier einfach darauf, dass ihr euch die Datei selbst einmal anseht. Für mich ist erst mal wichtig zu zeigen, dass man mit Views leicht zusammenarbeiten kann und keine Angst davor zu haben braucht. Und dann ist es ein Quell reiner Freude!














