Template: foreach-Schleife vorzeitig beenden

  • Seid gegrüßt,

    meine Frage bezieht sich auf die Template-Anweisung von {foreach}. Ist es möglich, innerhalb eines Templates die Ausführung einer foreach-Schleife vorzeitig zu beenden? Zumindest bin ich nicht auf eine break-Anweisung gestoßen, womit ich die Schleife z.B. wie folgt beenden kann:

    Smarty
    {foreach from=$objects item=object name=objectsForeach}
        <li>
            {$object->getTitle()}
        </li>
        {if $object->someBreakCondition()}
            {* foreach break *}
        {/if}
    {/foreach}

    Wenn das nicht der Fall sein sollte, ließe sich die break-Anweisung vielleicht via der $tpl[foreach][objectsForeach]-Variable bewerkstelligen? Könnte man auf Templatebasis z.B. $tpl[foreach][objectsForeach][iteration] einfach auf $tpl[foreach][objectsForeach][last] setzen?

    Viele Grüße

    Joe

    • Offizieller Beitrag

    Hallo,

    Tim Düsterhus Das XY-Problem ist mir durchaus bewusst, ändert aber nichts an der Relevanz/Daseinsberechtigung meiner Frage :)

    na, schon. break; in einer foreach()-Schleife ist schon in PHP-Code selten, wenn man das in Templates benötigt, dann besteht aller Wahrscheinlichkeit nach irgendwo ein Designfehler. Entsprechend: Was möchtest du erreichen?

  • Ich denke, man müsste doch vorher schon irgendwie filtern können, was im Template angezeigt werden soll und was nicht. Und erst wenn man alles hat was ausgegeben werden soll, und auch nur das, würde ich zum Template senden und ausgeben.

    Wenn man erst im Template nach einer besonderen Variablen oder einen Wert sucht, wo man dann eine Liste unterbrechen möchte oder so, dann ist es ja schon viel zu spät.

    Man müsste vorher schon die Suche nach dem entsprechenden BREAK machen, bevor es zum Template geht.

    Ich denke das ist mit der Ausführung von Tim Düsterhus gemeint.

  • Wenn man erst im Template nach einer besonderen Variablen oder einen Wert sucht, wo man dann eine Liste unterbrechen möchte oder so, dann ist es ja schon viel zu spät.

    Danke für deine ausführliche Erläuterung!

    Ich verstehe, was du meinst und ich stimme dir auch zu, dass es keinen Sinn ergibt, erst auf Template-Ebene viele, einzelne Elemente rauszufiltern. Dann hätte man das gleich auf PHP-Ebene, bevor man die Template-Variable endgültig setzt, die ganzen Elemente filtern können. Das verstehe ich alles :thumbup: Dennoch hat es mich interessiert, ob es eine break-Funktion auf Template-Ebene gibt. Es ist nicht so, dass ich komplett darauf angewiesen bin, aber fragen schadet ja nicht ;) Wie du auch gleich an meinem Beispiel sehen kennst, nimmt das rausfiltern in meinem Fall keine große Dimensionen an.

    Entsprechend: Was möchtest du erreichen?

    Nichts Großes:

    Tatsächlich will ich (optional) in meinem Template einfach einen "Weiter"-Button platzieren, wenn es mehr Elemente gibt, als mein Template ausgibt. Wenn ich also z.B. 5 Elemente anzeigen lassen will und ich weiß, dass es mehr als 5 davon gibt, würde ich den Button platzieren.

    Aus diesem Grund hatte ich zuerst die Idee, dass ich auf PHP-Ebene 6 (Irgendwie muss ich ja die Information herkriegen, dass es mehr als 5 von diesen Elementen gibt) von diesen Elemente an das Template übergebe und das Template eben kurz vor Ende mit einem potentiellen break stoppt.

    Die Option hat sich aber offensichtlich erledigt, aber es führen mehrere Wege zum Ziel. Wenn du hier eine gute Idee hast, wie man das kleine Problem schön und mit möglichst wenig Datenbankabfragen lösen kann, dann bin ich ganz Ohr :thumbup: Derzeit tendiere ich dazu 1) auf PHP-Ebene die Anzahl der Elemente zu zählen und bei 6 Elemente eine Variable auf true zu setzen, die dann im Template die Platzierung des Buttons triggert und dann 2) dafür zu sorgen, dass die Liste (in diesem Fall eine DatebaseObjectList) eben um ein Element gekürzt wird, bevor sie zum Template weitergereicht wird.

  • Dein zuletzt genannter Ansatz ist eigentlich korrekt. Kürze die Anzahl der Elemente in PHP und lege eine boolsche Template-Variable an, um im Template abfragen zu können ob es weitere Elemente gibt.

    Die "View" ist eigentlich nur dafür zuständig, die angegebenen Daten optisch auszugeben. Diese sollte keine Logik beinhalten.

  • Vielen Dank! :)

    Eine Frage habe ich noch:

    Kürze die Anzahl der Elemente in PHP

    Wie entfernt man am besten Elemente aus einer DatabaseObjectList ? Klar, ich könnte einfach ein Array anlegen und dort alle Elemente bis auf das Letzte einfügen. Dann hätte ich aber keine DatabaseObjectList mehr, sondern eben "nur" ein Array. Derzeit bin ich mir unsicher, ob das nicht (künftig) zu Problemen kommen kann, weil ich dann z.B. keinen Zugriff auf die Methoden der ObjetList habe. Von daher wäre es ideal, wenn das Entfernen des Elements nicht zu einem "Verlust" des ursprünglichen Datentyps führen würde.

  • Du kannst zuvor die Anzahl der tatsächlichen Elemente über $list->countObjects(); herausfinden. ($list ist nur eine Beispielvariable).

    Wenn die Anzahl größer als 5 ist, dann kannst du per $list->sqlLimit = 5; auf 5 begrenzen.

  • Das würde dann aber dann im Endeffekt auf zwei, anstatt einer Datenbankabfrage hinauslaufen, oder? Genau das habe ich ursprünglich versucht zu verhindern. Das ist der Grund, warum mir zuerst die erste Idee eingefallen ist, weil ich damit zwei Fliegen mit einer Klappe schlagen könnte (benötigte Elemente rausfischen + schauen, ob der Button angezeigt werden muss). Oder beanspruchen die COUNT-Operationen in SQL (wenn ggf noch WHERE-Bedingungen und JOINS hinzukommen) so wenig Performance, dass man hier ein Auge zudrücken kann?

    Nicht falsch verstehen: Ich möchte nicht auf Biegen und Brechen die Anzahl der Abfragen auf das Minimum halten, aber das Ganze soll ja auch so effizient wie möglich laufen ;)

  • Das Count-Aggregat ist relativ schnell und im Normalfall günstiger, als alle Objekte auslesen zu müssen und nachträglich darüber zu entscheiden, ob es mehr Elemente waren als benötigt.

    • Offizieller Beitrag

    Hallo,

    Die Option hat sich aber offensichtlich erledigt, aber es führen mehrere Wege zum Ziel. Wenn du hier eine gute Idee hast, wie man das kleine Problem schön und mit möglichst wenig Datenbankabfragen lösen kann, dann bin ich ganz Ohr :thumbup: Derzeit tendiere ich dazu 1) auf PHP-Ebene die Anzahl der Elemente zu zählen und bei 6 Elemente eine Variable auf true zu setzen, die dann im Template die Platzierung des Buttons triggert und dann 2) dafür zu sorgen, dass die Liste (in diesem Fall eine DatebaseObjectList) eben um ein Element gekürzt wird, bevor sie zum Template weitergereicht wird.

    Du kannst das tatsächlich auch rein mit Template-Scripting lösen:

    Smarty
    {foreach from=$myItems item='myItem' name='myItemLoop'}
      {if $tpl.foreach.myItemLoop.iteration < 5}
        {$myItem|print_r:true}
      {/if}
    {/foreach}

    Grundsätzlich ist ein COUNT(*) in SQL aber das was du machen möchtest.

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!