Dynamischer Altersvergeich mit Views: wie kann ich das filtern?
am 23.02.2010 - 23:44 Uhr in
Hallo zusammen,
ich hatte mein Problem schon in diesem Thread weiter unten angesprochen, aber ich denke, in diesem Unterforum ist es besser aufgehoben und es findet sich vielleicht auch jemand, der mir auf die Sprünge helfen kann. Vielen Dank soweit auch an Ronald, der sich bereits redlich bemüht hatte. Und keine Angst, ich will nicht alles vorgekaut haben, aber ich brauche einen kleinen Schubser von einem Views-Crack in die richtige Richtung, nachdem ich schon gefühlte 50 Sackgassen durch habe.
Eigentlich lässt sich die Aufgabenstellung sehr einfach umreißen und klingt gar nicht so wild: Der View soll alle User ausgeben, die älter (bzw. jünger) sind als der User, der den View gerade aufruft.
Klar ist, dass man hier mit Rollen nicht weit kommt - das Ganze muss beim Aufruf dynamisch berechnet werden. Ob das Geburtsdatum ein Feld vom Profile oder vom Content Profile ist, soll mir erstmal gleich sein, Hauptsache, ich bekomme überhaupt was hin. Das CCK-Feld des Content Profile wäre aber sicher für andere Berechnungen wie Alter besser geeignet.
Es ist eine Beziehung für das Content Profile angelegt, und ich komme im Filter auch an das Geburtsdatum (Inhalt: Geburtsdatum (field_geburtsdatum)) ran, kann es dort aber nur mit einem absoluten Wert vergleichen oder aber mit einem relativen Wert, der sich am aktuellen Datum orientiert. Ein Traum wäre es, wenn ich hier einfach das Geburtsdatum des aktuellen Users dynamisch einsetzen könnte, dann hätte ich es doch!
So, ein anderer Weg führte mich über die Argumente, aber mit denen bin ich noch nicht so ganz warm geworden. Ich könnte den aktuellen Benutzer als Standardargument übergeben, schön und gut. Ich könnte mit dem PHP Argument Handling Code sicher auch sowas wie sein Geburtsdatum als Timestamp rausziehen und als Argument zurückgeben.
Dann dachte ich, die weitere Berechnung und Filterung übernimmt vielleicht der Validator über "PHP validate code". Aber soweit ich das jetzt verstanden habe, wird da nur das eine Argument an sich auf seine Gültigkeit überprüft und dann einmalig TRUE oder FALSE zurückgegeben und entsprechend z.B. ein "Page not found" angezeigt.
Die Frage ist also: WO kann ich das Geburtsdatum des aktuellen Benutzers mit den Geburtsdaten aller anderen Benutzer vergleichen, und zwar nicht mal auf Gleichheit, sondern auf ausschließlich größer oder ausschließlich kleiner? So dass ich anschließend nur die ausgewählten Felder der passenden Nodes anzeigen kann?
Ich habe mir auch das Modul Views PHP Filter angeschaut, bin damit aber überhaupt nicht zurechtgekommen, nicht mal einfachste Testanfragen, das wird irgendwie in die übrigen MySQL-Abfragen reingewurschtelt, und ich bekam bloß Fehlermeldungen, was alles nicht gefunden wurde, wonach ich allerdings gar nicht gefragt hatte. Leider ist es nicht dokumentiert (keine Beispiele, keine Syntax-Hinweise), bei Issues verweist der Modulautor ans Forum auf drupal.org, dort wiederum bekamen andere Nutzer bislang keine brauchbaren Antworten. Scheint also kaum einer zu nutzen. Grundsätzlich schiene mir ein solches Modul aber geeignet, um meine eigene MySQL-Abfrage für den Filter zu schreiben und auf Argumente, so sie mir überhaupt nutzen würden, ganz zu verzichten. Vielleicht nutzt das ja zufällig jemand und kann mir ein Einstiegsbeispiel geben?
Ich bräuchte sowas wie: SELECT (Inhalt meiner Felder) FROM users (hier diverse JOINs rein, bis ich beim Geburtsdatum angekommen bin) WHERE (Geburtsdatum des Users) < (Geburtsdatum des aktuellen Users, das ich mir vorher noch rausziehen muss)
Also: kann mir jemand einen ganz heißen und vor allem funktionierenden Tipp geben, welche meiner Codeschnipsel ich nun wo unterbringe?
Oder geht das, was ich vorhabe, mit Views nicht (kann ich gar nicht glauben!) und ich muss am Ende mein erstes Modul schreiben?
LG
Sonja
- Anmelden oder Registrieren um Kommentare zu schreiben
Mmh, hat wohl echt noch
am 25.02.2010 - 22:45 Uhr
Mmh, hat wohl echt noch keiner so gemacht oder gebraucht hier?
Werd dann wohl echt mal schauen, ob ich das mit einem Modul mache, wo ich meine Abfrage reinpacke ... bloß erstmal das Modulschreiben üben!
Wenn jemand aber noch einen heißen Tipp hat zu meiner Fragestellung, immer her damit!
Drupal Freelancer im Rheinland gesucht?
Dynamischer Altersvergeich mit Views: wie kann ich das filtern?
am 26.02.2010 - 08:50 Uhr
Hi,
Du könntest es evtl. mit dem ComputedField probieren.
Hier könntest Du Dir die Daten holen und per Views dann danach filtern.
Hab es jetzt selber nicht getestet, könnte aber funktionieren.
Viele Grüße
Tom
Danke für den Vorschlag, das
am 26.02.2010 - 09:20 Uhr
Danke für den Vorschlag, das deckt aber, soweit ich das sehe, mein Problem an sich nicht ab, da es ja auch "nur" ein CCK-Feld ist wie in dem Fall mein Geburtsdatum.
Wobei, ich hab an anderer Stelle bei einer ganz anderen Sachen schon mit den Computed Fields gearbeitet, müsste mal schauen, dass ich irgendwie Timestamp ziehe, in ein solches Feld schreibe, und das dann nicht als Datum, sondern als Ganzzahl speichere ... so dass ich keine Daten, sondern Zahlen miteinander vergleiche ... mmh, muss mal schauen, ob Views das dann frisst oder ich mich dann wieder an der gleichen Stelle im Kreis drehe. Hab nur jetzt keine Zeit, da ich grad halb auf dem Abflug bin.
LG
Sonja
P.S.: Wenn noch jemand was hat, immer her damit!
Drupal Freelancer im Rheinland gesucht?
Gerade beim Drupalcamp Essen
am 27.02.2010 - 12:41 Uhr
Gerade beim Drupalcamp Essen total per Zufall in einer Session noch etwas mitgekriegt ... views_pre_execute, hat dazu jemand was zu sagen?
Muss gleich mal die Referentin dazu fragen, sie hatte auch bei ihrem Intranet-Projekt einen Punkt, wo Views normal nicht mehr ausreichte.
LG
Sonja
Drupal Freelancer im Rheinland gesucht?
So, ich habe in Essen vom
am 03.03.2010 - 00:11 Uhr
So, ich habe in Essen vom Views-Maintainer Daniel zwar dankenswerterweise ein wenig Hilfe und ein Stück Code bekommen, nur ans Laufen hat auch er es nicht bekommen, was aber auch dran liegen kann, dass er einfach sehr beschäftigt war und mittendrin ständig unterbrochen wurde und auf einmal einfach weg war.
Nachdem ich mich ans Modulschreiben bzw. in die Tiefen des Codes noch nicht gewagt hatte, habe ich aber doch recht gut verstanden, was sein Codeschnipsel macht und bis wohin er funktioniert. Vielleicht kann mir hier ja noch jemand den entscheidenden Tipp geben, damit die Variable endgültig in den Filter übernommen wird!
Auch er hat das schon von mir angedachte views_pre_execute hergenommen. Sinn des Ganzen ist, den an sich leeren Wert, der im Filter eingestellt würde (als absolutes Datum oder relativ zu now) mit dem Geburtsdatum des aktuellen Users vorzubelegen. Auch mir einleuchtend, dass es doch genauso funktionieren müsste.
Ich hab mal ein wenig weiter mit seinem Code rumgespielt, bin aber noch zu keinem besseren Ergebnis gekommen; der Filter greift einfach noch nicht.
<?php
// $Id$
/**
* dummy.module
*
* @author
* Daniel Wehner <daniel.wehner@erdfisch.de>
*/
/**
* Implements hook_views_api().
*/
function dummy_views_api() {
return array(
'api' => 2.0,
);
}
/**
* Implements hook_views_pre_execute().
*/
function dummy_views_pre_execute(&$view) {
if ($view->name == 'useransicht') {
// Load the node of the current user.
global $user;
$node = content_profile_load('testprofil1', $user->uid);
$value = $node->field_geburtsdatum[0]['value'];
$item = $view->filter['date_filter'];
$item->options['value']['value'] = $value;
$view->set_item($view->current_display, 'filter', 'date_filter', $item);
}
}
Der Wert wird auf jeden Fall richtig ausgelesen, das zeigt mir das Devel-Modul. Aber offensichtlich wird er einfach nicht an der richtigen Stelle eingesetzt. Ich habe auch die vier Möglichkeiten hier mal ausprobiert:
$item->options['value']['default_date'] = $value;
$item->options['default_date'] = $value;
$item->value['value'] = $value;
$item->value['default_date'] = $value;
Überall wird der Wert sauber reingeschrieben. Man muss dazu sagen, dass es sich in allen Fällen um Strings handelt. Möglicherweise spielt das eine Rolle für eine numerische Vergleichsoperation, aber das ist ja schon vorher jeweils so festgelegt, und ich denke, dass es vielleicht intern nochmal umgewandelt wird?
In der letzten Zeile wird dann u.a. das $item übergeben, bei dem es sich übrigens um einen date_api_filter_handler handelt.
Wenn ich mir per
dsm($view);
den View ausgeben lasse, stelle ich fest, dass mein Wert dort wohl irgendwie nicht angekommen ist.Die Abfrage lautet so:
SELECT users.uid AS uid, node_users__users.name AS node_users__users_name, node_users__users.uid AS node_users__users_uid FROM {users} users INNER JOIN {node} node_users ON users.uid = node_users.uid AND node_users.type = 'testprofil1' LEFT JOIN {content_type_testprofil1} node_users_node_data_field_geburtsdatum ON node_users.vid = node_users_node_data_field_geburtsdatum.vid INNER JOIN {users} node_users__users ON node_users.uid = node_users__users.uid WHERE (users.status <> 0) AND (node_users.type in ('%s'))
Ich habe noch zwei weitere Dinge, die ich im Filter abfrage (die hinter dem WHERE); außerdem habe ich den Filter normal angelegt mit "(Content Profile) Datum: Date (node) Inhalt: Geburtsdatum (field_geburtsdatum) = " und dann nur das Datum, das ja nun vorbelegt sein sollte, weggelassen. Ach ja, ich habe der Übersichtlichkeit wegen hier mal mit = statt > oder < operiert, ich dürfte dann nur das Profil des aktuellen Users rausbekommen.
Per Devel wird bei den Filtern auch der hier angezeigt: date_filter (Object) date_api_filter_handler; wenn man weiter aufklappt: ∞ (Recursion) - wie bei den anderen beiden funktionierenden Filtern auch. Wobei noch jemand zu mir meinte, dass da wohl irgendwas nicht stimmt.
So, wo gehört das Datum jetzt hin? Oder läuft etwas Anderes falsch? Grundsätzlich weiß ich, was da abläuft oder ablaufen soll, bin aber einfach noch nicht firm genug in den ganzen Funktionen und Schnittstellen.
LG
Sonja
Drupal Freelancer im Rheinland gesucht?
So, noch ein Ansatz! Ich
am 03.03.2010 - 13:39 Uhr
So, noch ein Ansatz!
Ich hatte Bedenken, dass vielleicht einfach der Wert aus der views_pre_execute wieder mit einem leeren Wert überschrieben wird, wenn im Filter keiner eingegeben wird. Aufgrund dieses Ansatzes habe ich mal versucht, die ganze Query von vornherein zu modifizieren.
EDIT: Ich habe jetzt die passende Abfrage gefunden und den geposteten Code dementsprechend noch mal geändert:
$view->build_info['query']="SELECT users.uid AS uid, node_users__users.name AS node_users__users_name, node_users__users.uid AS node_users__users_uid FROM {users} users INNER JOIN {node} node_users ON users.uid = node_users.uid AND node_users.type = 'testprofil1' LEFT JOIN {content_type_testprofil1} node_users_node_data_field_geburtsdatum ON node_users.vid = node_users_node_data_field_geburtsdatum.vid INNER JOIN {users} node_users__users ON node_users.uid = node_users__users.uid WHERE (users.status <> 0) AND (node_users.type in ('%s')) AND (field_geburtsdatum_value < '$value')";
Im Prinzip wäre das ja schon so anwendbar, einziges Contra: Ich möchte noch exposed filters anwenden, und da wäre es wohl eher abträglich, wenn die komplette Query schon hartgecodet ist! Daher mag ich den Beitrag noch nicht als gelöst markieren, und mir wäre lieber, wenn ich den $value eben doch woanders reinschreiben könnte, wo er auch genommen wird. Alternativ eine Möglichkeit, diese Query mit nachfolgenden exposed filters durch den User zu verknüpfen - geht das?
Vielleicht weiß auch noch jemand, wie das mit der Reihenfolge ist beim vorherigen Vorschlag: wird der Wert quasi vorher für den Filter so festgelegt, oder wird bei Existenz des date_filter nachträglich nach diesem Wert geschaut? Einfach wegen der Sache mit dem vielleicht doch wieder überschrieben werden oder nicht.
LG
Sonja
Drupal Freelancer im Rheinland gesucht?