Filterfunktion in eigenem Modul einbauen

Hallo zusammen,

wir betreiben einen OXID-Shop, in den ich mich gerade hereinarbeite. Da der Vorgänger unerwartet gegangen ist und ich mich seit erst seit wenigen Tagen mit OXID und dem gesamten MVC-Pattern beschäftige, bin ich zurzeit etwas hilflos.
Es wurden verschiedene, selbstentwickelte Module hinterlassen. Eins davon (zur Erstellung/Verwaltung von Coupons) funktioniert im BackEnd noch nicht ganz richtig.
Jetzt wurde ich gebeten zu versuchen, u.a. die fehlende Funktionalität des Moduls zu implementieren. Und zwar sind im BackEnd zwei Felder hinterlegt, mit denen man die darunterliegende Spalte filtern kann (siehe Screenshot). Diese haben noch keine Funktion. Konkret heißt das, bei Eingabe soll eine entsprechende SQL-Query abgeschickt werden und das Ergebnis in der Listenansicht wie gehabt angezeigt werden.

Jetzt bin ich leider wie gesagt weder mit PHP, geschweige denn mit MVC besonders vertraut, obwohl ich seit Tagen Tutorials durcharbeite.

Könnte mir jemand etwas Starthilfe geben, wie das ganze umzusetzen wäre? Muss ich quasi einen neuen Controller anlegen, registrieren und da kann ich dann die Filterlogik umsetzen? Und in einem Block wird dann das ResultSet abgelegt und über die TPL-Datei platziert?

Hier der Link zum Modul-Repo:
https://github.com/stuck1a/kcs/tree/main/kcs_coupon

Vorab herzlichen Dank für jede Hilfe! Ich komme hier gerade nicht wirklich voran.

Das heißt, bei Eingabe von “Ostern” willst nur das erste aus der Liste im Bild angezeigt bekommen? Da fehlt wohl der button zum Abschicken der Suche.

Schau dir die Artikeliste im Admin an. Dann gibst Titel oder Artikelnummer an und dann mal beides richtig und mal falsch. Der Query wird aus den gefüllten Suchfeldern und “AND” zusammengestellt. Das kannst am Namen der einzelnen Input-Felder sehen Bsp:

> where[oxarticles][oxartnum]

Danke für die Antwort!
Stimmt, die Artikelliste enthält bereits die exakt gewünschte Filterfunktion.
Ich versuche mal, mir die Funktion davon abzukupfern.
Sollte ich kein Erfolg haben, melde ich mich hier wieder zu Wort.

Habe versucht anhand des vorhandenen Codes die Filterfunktion umzusetzen.
Aber das klappt leider hinten und vorne noch nicht. Kein Wunder, habe nicht allzuviel von dem Code verstanden. Orientiert habe ich mich am hieran:

Immerhin ist besagter Button zum Abschicken der Suche nun vorhanden, wenngleich er nur zum Home-Bildschirm weiterleitet. Das man auch keine Autovervollständigung nutzen kann macht Try-and-Error so gut wie unmöglich… Die aktuelle Version ist im obigen Repo. Hoffe, mir kann noch weiter geholfen werden.

PS: Zum Testen muss bei im Modulroot lliegende install.sql manuell ausgeführt werden. Habe es noch nicht geschafft, diese über das Activate-Event zu starten.

Hier mein aktueller Code in der Template-Datei ‘kcscoupon_list.tpl’:

[{include file="headitem.tpl" title="GENERAL_ADMIN_TITLE"|oxmultilangassign box="list"}]
[{assign var="where" value=$oView->getListFilter()}]
[{$GefilterteListe = }]

[{if $readonly}]
    [{assign var="readonly" value="readonly disabled"}]
[{else}]
    [{assign var="readonly" value=""}]
[{/if}]

<script type="text/javascript">
<!--
window.onload = function ()
{
    top.reloadEditFrame();
    [{ if $updatelist == 1}]
        top.oxid.admin.updateList('[{$oxid}]');
    [{ /if}]
}
//-->
</script>

<div id="liste">

    <form name="search" id="search" action="[{ $oViewConf->getSelfLink() }]" method="post">

        <!-- Erzeugen der vollständigen Liste gemäß DB-Model -->
        [{foreach from=$oView->getListSorting() item=aField key=sTable}]
        [{foreach from=$aField item=sSorting key=sField}]

    <input type="hidden" name="sort[[{$sTable}]][[{$sField}]]" value="[{$sSorting}]">
        [{/foreach}]
        [{/foreach}]


        <table cellspacing="0" cellpadding="0" border="0" width="100%">
            <colgroup>
                <col width="5%">
                <col width="60%">
                <col width="25%">
                <col width="10%">
            </colgroup>
            <!-- Überschriftenzeile aufbauen -->
            <tr class="listitem">

                <!-- Kopfzeile Reihe 1 ("A") -->
                <td valign="top" class="listfilter first" height="35">&nbsp;</td>

                <!-- Kopfzeile Reihe 2 ("TITLE")-->
                <td valign="top" class="listfilter">
                    <input class="listedit" type="text" size="50" maxlength="128" name="where[kcscouponseries][oxtitle]" value="[{ $where.kcscouponseries.oxtitle }]">
                </td>

                <!-- Kopfzeile Reihe 3 ("IDENT") -->
                <td valign="top" class="listfilter">
                    <input class="listedit" type="text" size="50" maxlength="128" name="where[kcscouponseries][oxid]" value="[{ $where.kcscouponseries.oxid }]">
                </td>

                <!-- Kopfzeile Reihe 4 ("SUCHEN-BUTTON") -->
                <td valign="top" class="listfilter">
                    <div class="find">
                        <input class="listedit" type="submit" name="submitit" value="[{ oxmultilang ident="KCSCOUPON_SEARCH" }]">
                    </div>
                </td>
            </tr>
            <tr>
                <!--  Erzeugen der Listeneinträge inkl Sortierung durch setSorting()  -->
                <td class="listheader first" height="15" width="30" align="center">[{ oxmultilang ident="GENERAL_ACTIVTITLE" }]</td>
                <td class="listheader">&nbsp;<a href="Javascript:top.oxid.admin.setSorting( document.search, 'kcscouponseries', 'oxtitle', 'asc');document.search.submit('where[kcscouponseries][oxtitle]');" class="listheader">[{ oxmultilang ident="KCSCOUPON_OXTITLE" }]</a></td>
                <td class="listheader">&nbsp;<a href="Javascript:top.oxid.admin.setSorting( document.search, 'kcscouponseries', 'oxid', 'asc');document.search.submit('where[kcscouponseries][oxid]');" class="listheader">[{ oxmultilang ident="KCSCOUPON_OXID" }]</a></td>
                <td class="listheader">&nbsp;</td>
            </tr>

            [{assign var="blWhite" value=""}]
            [{assign var="_cnt" value=0}]
            [{foreach from=$mylist item=listitem}]
            [{assign var="_cnt" value=$_cnt+1}]
            <tr id="row.[{$_cnt}]">
                [{ if $listitem->blacklist == 1}]
                [{assign var="listclass" value=listitem3 }]
                [{ else}]
                [{assign var="listclass" value=listitem$blWhite }]
                [{ /if}]
                [{ if $listitem->getId() == $oxid }]
                [{assign var="listclass" value=listitem4 }]
                [{ /if}]

                <!--  Aussortieren der Einträge gemäß Filtermaske  -->
                <td valign="top" class="[{ $listclass}][{ if $listitem->kcscouponseries->value == 1}] active[{/if}]" height="15"><div class="listitemfloating">&nbsp;</div></td>
                <td valign="top" class="[{ $listclass}]"><div class="listitemfloating">&nbsp; <a href="Javascript:top.oxid.admin.editThis('[{ $listitem->kcscouponseries__oxid->value}]');" class="[{ $listclass}]">[{ $listitem->kcscouponseries__oxid->value }]</a></div></td>
                <td valign="top" class="[{ $listclass}]"><div class="listitemfloating">&nbsp; <a href="Javascript:top.oxid.admin.editThis('[{ $listitem->kcscouponseries__oxtitle->value}]');" class="[{ $listclass}]">[{ $listitem->kcscouponseries__oxtitle->value }]</a></div></td>
                <td class="[{ $listclass}]">[{ if !$listitem->isOx() && !$readonly }]<a href="Javascript:top.oxid.admin.deleteThis('[{ $listitem->kcscouponseries__oxid->value }]');" class="delete" id="del.[{$_cnt}]" [{include file="help.tpl" helpid=item_delete}]></a>[{/if}]</td>
            </tr>
            [{if $blWhite == "2"}]
            [{assign var="blWhite" value=""}]
            [{else}]

            [{assign var="blWhite" value="2"}]
            [{/if}]
            [{/foreach}]
            [{include file="pagenavisnippet.tpl" colspan="4"}]
        </table>

    </form>

</div>

[{include file="pagetabsnippet.tpl"}]


<script type="text/javascript">
if (parent.parent)
{   parent.parent.sShopTitle   = "[{$actshopobj->oxshops__oxname->getRawValue()|oxaddslashes}]";
    parent.parent.sMenuItem    = "[{ oxmultilang ident="KCSCOUPON_CONTENT_LIST_MENUITEM" }]";
    parent.parent.sMenuSubItem = "[{ oxmultilang ident="KCSCOUPON_CONTENT_LIST_MENUSUBITEM" }]";
    parent.parent.sWorkArea    = "[{$_act}]";
    parent.parent.setTitle();
}
</script>
</body>
</html>

Dazu musst Dir die Shop-Datei article_list.tpl anschauen. Es fehlen die Formparameter, d.h. die Zeilen hinter [{$oViewConf->getHiddenSid()}] aus Deinem Beispiel.

Die Weiterleitung auf die Startseite dürfte dann auch von [{ $where.kcscouponseries.oxtitle LIKE 'Ostern' }] verursacht werden, wenn _prepareWhereQuery(…); in Verbindung mit _buildSelectString(…); im Controller nicht darauf ausgerichtet werden.

Die Fehler dürften im Log stehen. Daran kann man sich orientieren.

Hallo rubbercut,

danke, dass du dich meinem Problem angenommen hast. Mir ist klar, dass das nicht selbstverständlich ist, gerade bei so im Grunde hochgradig trivialen Basics.

Danke für den Hinweis, das hilft mir weiter! Werde morgen Rückmelden, ob ich es damit dann endlich geknackt bekommen habe.

Da ich das nicht wirklich verstehe, wird es wohl Zeit, nochmal zurück zu den Basic OXID Tutorials zu kehren. Allerdings ändert sich nichts, wenn das “LIKE ‘Ostern’” wieder rausgenommen wird (war nur zu Testzwecken drinnen), falls sich deine Aussage darauf bezog.

Verstehe, gut zu wissen. Werde morgen im Büro gleich mal die Logs checken.

Noch zwei andere Dinge:

  • Irgendwie kommt mir diese ganze Ordnerstruktur etwas ungewöhnlich für ein MVC-Pattern. Vermisse beispielsweise sowas wie einen Core-Ordner. In den Tutorials (i.d.R. nicht für OXID 6.3) sieht das meist etwas fülliger aus, genauso wie das entspr. Git-Repo. Aber sowohl FrontEnd als auch BackEnd scheinen normal zu funktionieren mit meiner Ordnerstruktur:

  • Andererseits bekomme (auch bei fresh install) ich bei jedem composer update ein Fehler vom Skript “oe:ide-helper:generate” (returned error code 1) - ist das normal?

Puh, sich in OXID einzuarbeiten, ist müheseliger, als angenommen :grin:

Habe das mal getestet. An dieser Stelle gibt es keinen “sichtbaren” Fehler, allerdings gehört es trotzdem nicht dorthin.

…den Core-Ordner findest im vendor.

Die Infos dazu findest hier, mit der Suche :wink:

Moin,

super, das Modul funktioniert nun, so wie es das soll.
Der Code war tatsächlich schon in Ordnung. Die Änderungen hat OXID allerdings erst übernommen, nachdem ich das Modul manuell gelöscht (aus ./vendors/… und ./source/modules/…, 1.yaml + ./source/tmp leeren) und neu eingetragen habe.

Der Vollständigkeit halber fürs Archiv hier noch das TPL-File:

[{include file="headitem.tpl" title="GENERAL_ADMIN_TITLE"|oxmultilangassign box="list"}]
[{assign var="where" value=$oView->getListFilter()}]

[{if $readonly}]
    [{assign var="readonly" value="readonly disabled"}]
[{else}]
    [{assign var="readonly" value=""}]
[{/if}]

<script type="text/javascript">
<!--
window.onload = function ()
{
    top.reloadEditFrame();
    [{ if $updatelist == 1 }]
        top.oxid.admin.updateList('[{$oxid}]');
    [{ /if }]
}
//-->
</script>

<div id="liste">

<form name="search" id="search" action="[{$oViewConf->getSelfLink()}]" method="post">
[{include file="_formparams.tpl" cl="kcscoupon_list" lstrt=$lstrt actedit=$actedit oxid=$oxid fnc="" language=$actlang editlanguage=$actlang}]
<table cellspacing="0" cellpadding="0" border="0" width="100%">
    <colgroup>
        [{block name="admin_content_list_colgroup"}]
            <col width="3%">
            <col width="47%">
            <col width="20%">
            <col width="28%">
            <col width="2%">
        [{/block}]
    </colgroup>

    <!-- Zeile für die Suchfilter -->
    <tr class="listitem">
        [{block name="admin_content_list_filter"}]
        <td valign="top" class="listfilter first" align="right">
		    <div class="r1"><div class="b1">&nbsp;</div></div>
	    </td>

	        <!-- Textfeld für die Filtermaske für Spalte "Titel" -->
	    <td valign="top" class="listfilter" align="left">
            <div class="r1"><div class="b1">
            <input class="listedit" type="text" size="9" maxlength="128" name="where[kcscouponseries][oxtitle]" value="[{$where.kcscouponseries.oxtitle}]">
            </div></div>
        </td>

        <td valign="top" class="listfilter" height="20">
            <div class="r1"><div class="b1">
            </div></div>
        </td>

        <!-- ComboBox für die Auswahl der Sprache und das Suchfeld über dem Titel und den Suchen Submit-Button -->
        <td valign="top" class="listfilter" colspan="2" nowrap>
            <div class="r1"><div class="b1">
            <div class="find">
            <!-- ComboBox für die Sprachauswahl -->
            <select name="changelang" class="editinput" onChange="Javascript:top.oxid.admin.changeLanguage();">
            [{foreach from=$languages item=lang}]
            <option value="[{$lang->id}]" [{if $lang->selected}]SELECTED[{/if}]>[{$lang->name}]</option>
            [{/foreach}]
            </select>

            <!-- Suchen-Button -->
            <input class="listedit" type="submit" name="submitit" value="[{oxmultilang ident="GENERAL_SEARCH"}]" onClick="Javascript:document.search.lstrt.value=0;">
            </div>

             <!-- Suchfeld über der Beschreibung -->
            <input class="listedit" type="text" size="25" maxlength="128" name="where[kcscouponseries][oxid]" value="[{$where.kcscouponseries.oxid}]">
            </div></div>
        </td>
        [{/block}]

    </tr>

    <!-- Reihe mit den Spaltenüberschriften sowie deren Sortierfunktion -->
    <tr class="listitem">
        [{block name="admin_article_list_sorting"}]
            <!-- Überschrift für Spalte Active -->
            <td class="listheader first" height="15" width="30" align="center"><a href="Javascript:top.oxid.admin.setSorting( document.search, 'kcscouponseries', 'OXACTIVE', 'asc');document.search.submit();" class="listheader">[{oxmultilang ident="GENERAL_ACTIVTITLE"}]</a></td>

             <!-- Überschrift und Sortierfunktion für Spalte Titel -->
            <td class="listheader"><a href="Javascript:top.oxid.admin.setSorting( document.search, 'kcscouponseries', 'OXTITLE', 'asc');document.search.submit();" class="listheader">[{oxmultilang ident="GENERAL_TITLE"}]</a></td>

            <!-- Suchen-Button -->
            <td class="listheader" height="15">&nbsp;<a href="Javascript:top.oxid.admin.setSorting( document.search, 'kcscouponseries', 'OXID', 'asc');document.search.submit();" class="listheader">[{assign var="ident" value=GENERAL_ARTICLE_$pwrsearchfld}][{assign var="ident" value=$ident|oxupper}][{oxmultilang ident="KCSCOUPON_NUMBER"}]</a></td>

            <!-- Überschrift und Sortierfunktion für Spalte Ident -->
            <td class="listheader" colspan="2"><a href="Javascript:top.oxid.admin.setSorting( document.search, 'kcscouponseries', 'OXID', 'asc');document.search.submit();" class="listheader">[{oxmultilang ident="GENERAL_IDENT"}]</a></td>
        [{/block}]
    </tr>

[{assign var="blWhite" value=""}]
[{assign var="_cnt" value=0}]
[{foreach from=$mylist item=listitem}]
    [{assign var="_cnt" value=$_cnt+1}]
    <tr id="row.[{$_cnt}]">

        [{block name="admin_content_list_item"}]
            [{if $listitem->blacklist == 1}]
                [{assign var="listclass" value=listitem3 }]
            [{else}]
                [{assign var="listclass" value=listitem$blWhite }]
            [{/if}]
            [{if $listitem->getId() == $oxid}]
                [{assign var="listclass" value=listitem4 }]
            [{/if}]
            <td valign="top" class="[{$listclass}][{if $listitem->kcscouponseries__oxactive->value == 1}] active[{/if}]" height="15"><div class="listitemfloating">&nbsp</a></div></td>
            <td valign="top" class="[{$listclass}]" height="15"><div class="listitemfloating"><a href="Javascript:top.oxid.admin.editThis('[{ $listitem->kcscouponseries__oxid->value}]');" class="[{$listclass}]">[{if $listitem->kcscouponseries__oxtitle->value}][{$listitem->kcscouponseries__oxtitle->value}][{else}]---[{/if}]</a></div></td>
            <td valign="top" class="[{$listclass}]">
                <div class="listitemfloating">
                    <a href="Javascript:top.oxid.admin.editThis('[{$listitem->kcscouponseries__oxid->value}]');" class="[{$listclass}]">
                        <div style="height: 5px; position: relative; width: 70%; background: #6b6; margin: 5px 2px; overflow: hidden;">
                            <div style="position: absolute; top: 0; left: 0; height: 100%; width: [{$listitem->getStats(true)}]%; background: #b66; border-right: 1px solid #fff;"></div>
                        </div>
                    </a>
                </div>
            </td>
            <td valign="top" class="[{$listclass}]"><div class="listitemfloating"><a href="Javascript:top.oxid.admin.editThis('[{ $listitem->kcscouponseries__oxid->value}]');" class="[{$listclass}]">[{$listitem->kcscouponseries__oxid->value}]</a></div></td>
            <td class="[{$listclass}]">
            [{if !$readonly}]
            <a href="Javascript:top.oxid.admin.deleteThis('[{$listitem->kcscouponseries__oxid->value}]');" class="delete" id="del.[{$_cnt}]" alt="" [{include file="help.tpl" helpid=item_delete}]></a>
            [{/if}]
            </td>
        [{/block}]
    </tr>
[{if $blWhite == "2"}]
[{assign var="blWhite" value=""}]
[{else}]
[{assign var="blWhite" value="2"}]
[{/if}]
[{/foreach}]
[{include file="pagenavisnippet.tpl" colspan="4"}]
</table>
</form>
</div>

[{include file="pagetabsnippet.tpl"}]


<script type="text/javascript">
if (parent.parent)
{   parent.parent.sShopTitle   = "[{$actshopobj->oxshops__oxname->getRawValue()|oxaddslashes}]";
    parent.parent.sMenuItem    = "[{ oxmultilang ident="CONTENT_LIST_MENUITEM" }]";
    parent.parent.sMenuSubItem = "[{ oxmultilang ident="CONTENT_LIST_MENUSUBITEM" }]";
    parent.parent.sWorkArea    = "[{$_act}]";
    parent.parent.setTitle();
}
</script>
</body>
</html>

Vielen Dank für die Hilfe!

2 Likes

Gerne. Das kannst aber während der Entwicklung abkürzen. Wenn das Modul installiert ist, reichen Änderungen in

zzgl. Löschen des TMP. Änderungen an der metadata übernimmst mit ...install-configuration....
Nur bei Fertigstellung des Moduls kannst die anderen Ordner im vendor etc. aktualisieren.

Verstehe, alles klar.
Gut, habe mir inzwischen sowieso einen kleinen Batch geschrieben, der vom benannten Modul alles löscht, das lasse ich einfach durchlaufen, um Änderungen bei der Modulentwicklung zu übernehmen:

@echo off
chcp 1252

set VENDOR=gruntjs
set MODULE=grunt-cli
set OXROOT=C:\XAMPP\htdocs\oxid\

cls
echo.
echo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
echo Entferne Modul:        %VENDOR%/%MODULE%
echo Shop-Rootverzeichnis:  %OXROOT%
echo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

echo [#] Lösche Ordner .\vendor\%VENDOR%\%MODULE%\
rd /s /q %OXROOT%\vendor\%VENDOR%\%MODULE%\
echo.

echo [#] Lösche Ordner .\source\modules\%VENDOR%\%MODULE%\
rd /s /q %OXROOT%\source\modules\%VENDOR%\%MODULE%\
echo.

echo [#] Lösche alle *.php und *.txt in .\source\tmp
rd /s /q %OXROOT%\source\tmp\%VENDOR%\%MODULE%\
echo.

echo [#] Lösche *.php und *.txt in .\source\tmp\smarty
del %OXROOT%\source\tmp\*.txt /f /q
del %OXROOT%\source\tmp\*.php /f /q
del %OXROOT%\source\tmp\smarty\*.txt /f /q
del %OXROOT%\source\tmp\smarty\*.php /f /q
echo.

echo [#] Lösche die parent composer.lock
del %OXROOT%\composer.lock /f /q
echo.

echo [#] Entferne die Einträge in composer.json und 1.yaml per Composer
cd %OXROOT%
composer remove %VENDOR%/%MODULE% -n
echo.

echo INFO:
echo [!] Falls die Datenbank geändert wurde, müssen die Änderungen manuell rückgängig gemacht machen!
echo.
echo [#] Modul "%VENDOR%/%MODULE%" wurde deinstalliert!
pause

chcp 850
1 Like