Anpassung einer Datenbank-Abfrage innerhalb einer bestehenden Komponente

  • Guten Tag zusammen,


    ich habe eine Frage zu einer Komponente, die mir Profile aus einer Datenbank ausliest und ausgibt. Standard der Komponente ist, dass alle Profile in der Datenbank ausgegeben werden.


    Nun suche ich aber einen Weg, nur Profile auszugeben, die eine bestimmte Bedingung erfüllen. Ich müsste also im Grunde in die Datenbank-Abfrage der Komponente eingreifen, um eine WHERE-Bedingung einbauen zu können. Ist das möglich? Wenn ja, wie und wo?

  • Das kommt darauf an, ob die Komponente Joomla-Standards verwendet oder nicht, ob es egal ist, wenn du Core-Dateien veränderst und ggf. anderes.

    Wenn ja, wie und wo?

    Woher sollten wir das wissen, ohne die Komponente zu kennen ;-)


    Auf dieser Seite findest du Verlinkungen auf Joomla-Datenbank-Abfrage-Standards: https://docs.joomla.org/Access…_database_using_JDatabase

  • Das soll natürlich kein Geheimnis sein. Es geht um die Komponente TLP Team. Licence GPLv2 or Later


    Wie gesagt, Standard ist, dass alle Profile angezeigt werden. Ich würde das aber gerne mit einer Bedingung so verändern wollen, dass nur bestimmte Profile angezeigt werden.

  • Das beantwortet aber noch nicht, ob du die Änderungen updatesicher durchführen willst oder das ggf. hohe Risiko eingehen willst, die Komponente inklusive deiner Hacks nicht mehr zu updaten.


    Wenn ich die Free-Version der Erweiterung überfliege,

    - würde ich wahrscheinlich eher ein eigenes Modul programmieren. Das im Paket enthaltene Modul macht das im helper.php ja schon (recht plump).


    - oder komponentenseitig eher die Daten aus den schon fertig abgefragten php-Array entfernen, die ich nicht drinnen haben mag. Das geht in einem Joomla-Template-Override der Frontend-Ausgabe und ist updatefähig.


    - oder plump in so einem Override, die Datenbankabfrage noch mal machen, erweitert um die zusätzlichen WHEREs.


    - würde ich zuallerletzt, da eben nicht updatefähig, die Datei im Ordner /models/ verändern. Da findest Methode getListQuery(), wo man vermutlich ansetzen kann.


    Weiter habe ich mir nicht angeschaut, ob man ggf. die Frontend-Filterfunktion der Komponente verwenden kann. Aber wenn, auch nicht weniger aufwendig als obige Vorgehensweisen.

  • - oder komponentenseitig eher die Daten aus den schon fertig abgefragten php-Array entfernen, die ich nicht drinnen haben mag. Das geht in einem Joomla-Template-Override der Frontend-Ausgabe und ist updatefähig.

    Das klingt am sinnvollsten und wollte ich so auch eigentlich machen. Ein Template Override habe ich bereits gemacht. Aber ich weiß leider nicht, wie ich da dann genau vorgehen müsste. Ich kenne das halt nur mit den klassischen PHP Abfragen, wo man die Bedingungen entsprechend ändern kann.

  • Ich habe die erweiterung schon wieder gelöscht.


    Irgendwo wird es ein foreach($this->items....), oder foreach($list....) oder foreach($rows....) oder so was geben, was das Array mit allen Einzel-Einträgen ist. Innerhalb der foreach() gibt das Layout die einzelnen Einträge nacheinander aus.


    Wenn du dann weißt wie das Array heißt, sagen wir mal $rows, machst am Anfang der Datei vorab eine eigene Säuberung. Irgend so was


    Code
    foreach ($rows as $index => $einzelneReihe)
    {
        if ($einzelneReihe->diesdas !== 'sonstwas')
        {
            unset($rows[$index]);
        }
    }

    Unter der Annahme, dass $rows ein Array aus Objekten (= einzelne Einträge) ist, was zumindest in Joomla der Normalfall ist.

  • Du meinst voraussichtlich dieses hier, oder?


    Code
    foreach ($this->items as $i => $item) : $i++;


    Ich bin mir nicht sicher, ob ich das richtig verstanden habe. Ich denke also etwas anders und selektiere nicht, wie ich es gewohnt bin, die Datensätze mit Bedingungen aus, die ich brauche, sondern Ich unterdrücke also quasi die Datensätze, die ich mit meiner Bedingung nicht brauche? Hab ich das richtig verstanden? So?


    Code
    foreach ($this->items as $i => $item) : $i++;
    {
        if($item->MeineBedingung !== 'sonstwas')
        {
            unset($this->items[$i]);
        }
    }
  • Das

    Code
    : $i++;

    gehört alles weg. Da du dich ja am Anfang der Datei bereits in einem Block befindest, der mit <?php geöffnet ist und später mit einem ?> geschlossen wird. Die Doppelpunktschreibweise verwendet man üblicherweise nur innerhalb von HTML-Blöcken (und ich auch da sehr ungern. Ist aber nun mal Usus).

    Außerdem wird Index $i in dieser Schleife ja eh automatisch erhöht.


    Generell solltest du erst mal statt $i mein $index verwenden, um später ggf. Konflikte zu vermeiden. Ebenso das $item. Ich habe wie gesagt den Gesamtcode nicht vor mir. Ob nun unten $i und $item verwendet wird, ist für das Array vollkommen wurst. Muss also obe und unten nicht übereinstimmen.


    Ich unterdrücke also quasi die Datensätze, die ich mit meiner Bedingung nicht brauche?

    genau.


    Natürlich kannst du die Objekte, die zutreffen, auch in einem eigenen Array sammeln und gibst das dann halt später aus, statt $this->items.


    Code
    §meinObjectArray = array();
    foreach ($this->items as $index => => $einzelneReihe)
    {
    if ($einzelneReihe->MeineBedingung == 'sonstwas')
    {
    $meinObjectArray[$index] = $this->items[$index];
    }
    }


    Und unten durchläufst dann dein Array bei der Ausgabe statt $this->items

    Code
    foreach ($meinObjectArray as $i => $item) : $i++;

    So die Theorie ;-)

  • Also erst einmal danke für deine Unterstützung bis hierher! Muss auch mal gesagt werden!


    Ich fürchte, dass der Entwickler der Komponente dann anscheinend eher unüblich entwickelt hat, denn wenn ich das richtig überblicke, befindet sich dieses foreach nicht im ersten PHP Block, sondern tatsächlich im HTML Teil, in welchem er dann PHP eingefügt hat. aber siehe selbst. Ich blicke es ja auch nicht immer richtig:



    Daher wollte ich das mit dem :$i++; nochmal hinterfragen, bevor ich nachher was wichtiges weglasse.

  • Du verstehst noch nicht.


    Klar gibt es später in der Datei noch mal ein foreach. Das sollst du, wenn überhaupt, nur tangential veränden. Das $i++ bleibt da jedenfalls immer drinnen.


    Du musst dieses spätere foreach gar nicht verändern, wenn du das unset()-Verfahren aus Post#6 verwendest, s,u. angepasst.


    Du sollst aber noch ein foreach zuvor reinbauen, das vorab eine Säuberung macht, damit das 2. foreach bestimmte Daten nicht mehr drinnen hat!


    Hinter die Zeile

    Code
    defined('_JEXEC') or die;

    gehört also deine ZUSÄTZLICHE Putzschleife reingeschoben.

    Code
    foreach ($this->items as $index => $einzelneReihe)
    {
    if ($einzelneReihe->diesdas !== 'sonstwas')
    {
    unset($this->items[$index]);
    }
    }

    Natürlich habe ich keine Ahnung nach welchen Kriterien, du überhaupt filtern willst. Deshalb in meinem Code die Keine-Ahnung-Platzhalter

    Code
    diesdas

    und

    Code
    sonstwas

    Alles andere, auch $index und

    Code
    $einzelneReihe

    kann so bleiben.

  • So, am Wochenende habe ich mich nochmal damit beschäftigt. Danke Re:Later !!! Hat alles wunderbar geklappt, wie ich es brauche. Perfekt!


    Um das gelernte aber nun abrunden zu können, habe ich noch eine Frage:


    Wenn man jetzt statt


    Zitat

    $einzelneReihe->diesdas !== 'sonstwas'


    Zitat

    $einzelneReihe->diesdas like '%son_twas%'


    abfragen wollen würde, um Zeilen, die in der betreffenden Spalte etwas bestimmtes in einer Zeichenkette haben, abzurufen, funktioniert das ja oben in dem Beispiel logischerweise nicht, weil das if keine SQL-Anweisungen verarbeiten kann. Wie könnte ich so etwas im Rahmen einer Säuberung lösen?

  • Wenn genau dieser Override auch zur Ausgabe genutzt wird ist es doch sinnvoller, in der Schleife einfach mit continue die Ausgabe von Daten zu überspringen, da verständlicher, schneller, einfacher.

    PHP
    foreach ($this->items as $i => $item) : $i++;
    if ($item->category != 'meine_filter_kategorie') continue;
  • Du verwendest doch das Model von com_users für die Datenbankabfrage?

    Nein. Die Komponente com_tlpteam fragt eine eigene Tabelle ab und macht lediglich einen JOIN über die users-Tabelle. Und es ist keine eigene Komponente des TE.


    Deshalb ging es doch auch darum, eine updatesichere Variante zu finden. TE hat sich halt für Override ohne ganze, neue, redundante DB-Abfrage im Override entschieden, was theoretisch ja auch möglich wäre, aber weitaus komplexer in diesem Fall, da auch Fiter (getUserStateFromRequest) einzubauen sind.

    in der Schleife einfach mit continue die Ausgabe von Daten zu überspringen, da verständlicher, schneller, einfacher.

    1) Wissen wir nicht, was noch alles an Filterkram kommt.

    2) zeigt es sich im Laufe dieses Threads, dass es eben nicht für alle einfacher ist, im Dateien-Kuddelmuddel-Code reinzustricken

    3) Wenn die Erweiterung upgedatet wird und neue Features bekommt, die man gerne in seinem Override ebenfalls nutzen möchte, ist es weitaus einfacher, zeiteffizienter, einen sauber abgetrennten Block zu haben, den man im neuen Override 1:1 am Anfang reinpasten kann. Da sind mir die eventuellen Millisekunden auch egal.

  • Code
    if (strpos($einzelneReihe->diesdas, 'son_twas') !== false)

    https://www.php.net/manual/de/function.strpos.php

    Ja, das leuchtet mir ein. Meine Frage war wohl nicht konkret genug bzw. falsch gestellt. strpos ist mir grundsätzlich bekannt. Allerdings sucht strpos in einem String ja nach dem ersten treffer des needle, unabhängig von der Position. Ich kann lediglich bestimmen, ab welchem Integer er mit der Suche beginnen soll.


    Wenn ich aber z. B. eine Selektion nach Postleitzahlen machen möchte:


    Ich habe eine Spalte plz als varchar. Wenn ich nun nach allen PLZ mit der ersten Ziffer 7, oder mit den ersten beiden Ziffern 72 suchen will, ist das meiner Kenntnis nach mit strpos nicht umsetzbar (zumindest mir nicht bekannt). Wenn ich z. B. mit 7 suchen würde, spuckt er mir ja dann auch 12347 aus obwohl ich eigentlich alle Einträge mit der Ziffer 7 in der plz am Anfang brauche. Oder überblicke ich das falsch?

  • Schau halt einfach in den Link ins PHP-Manual, den ich drangehängt habe, wo ja auch einfache Besipeile dabei sind. Wenn strpos was findet liefert es ein Integer der Fund-Position, beginnend mit 0 für die erste Position im String.


    Wenn es nix findet liefert es ein bool false. ===false bedeutet also: Nix.

    Wenn es was findet, ergibt sich also das !== false in meinem Code. Das bedeutet ich habe was gefunden an irgendeiner Position.

    Das war deine Aufgabenstellung mit deinem LIKE.


    Ergo "Wenn 7 an erster Stelle gefunden":

    Code
    $plz = '73452';
    $findMich = '7';
    if (strpos($plz, $findMich) === 0)


    Ergo "Wenn 734 ab erster Stelle gefunden":

    Code
    $plz = '73452';
    $findMich = '734';
    if (strpos($plz, $findMich) === 0)


    Ich weiß nicht, ob das heutzutage noch erlaubt ist, glaub aber schon, jedenfalls ging auch mal (ohne PHP-Warnings), den String als Array zu handhaben:

    Code
    $plz = '73452';
    if ($plz[0] === '7')

    Betonung auf String.