OXID Artikel mit zusätzlichem Textfeld erweitern

OXID eShop

Das OXID eShop Backend kann man nun schon einige Zeit erweitern, aber jedes Mal, wenn ich z.B. den Artikel um ein zusätzliches HTML-fähiges Feld erweitern möchte stolpere ich über die gleichen Probleme. Es war also mal an der Zeit hier eine Lösung zu finden, bei der man nicht jedes Mal alles von vorne baut und vor allem bei der man nicht schon wieder einen der Schritte vergisst. Bei meiner Suche bin ich auf eine smarte Idee gestoßen, die das Einbinden eines zusätzlichen Feldes wirklich einfach macht. Ich bin gespannt was ihr dazu sagt.

Vorbereitende Schritte

Damit das neue Feld in vollem Glanz erstrahlen kann, müssen wir zwei Dinge tun:

  • Die OXID Tabelle in der Datenbank erweitern die von dem Feld gefüllt werden soll
  • Das Backend über ein Modul erweitern, das sich um die Anzeige des Feldes kümmert

Das Feld könnt ihr über ein SQL-Statement anlegen, z.B.

ALTER TABLE oxarticles ADD someotherdescription text;

Sehr komfortabel für den Shop-Administrator ist, wenn das SQL-Statement beim aktivieren des Moduls automatisch ausgeführt wird. Achtet dabei aber auf die folgenden Punkte:

  • Nach dem Anlegen einer neuen Spalte in der OXID Datenbank müssen die Views neu generiert werden
  • Wenn ihr Übersetzungen braucht, dann müsst ihr die entsprechenden Multilangfelder mit anlegen, hier also z.B. someotherdescription_1, someotherderscription_2 usw. (Die korrekte Verwendung macht OXID später automatisch)

Neben den Änderungen an der Datenbank müsst Ihr noch ein Modul herrichten. Ich gehe an dieser Stelle davon aus, dass Ihr wisst wie das geht. Falls nicht empfehle ich einen Blick auf z.B. dieses Tutorial zum Einstieg in die OXID Modulentwicklung von Marco Steinhäuser.

OXID Extra-Feld – jetzt geht’s los!

Nehmen wir nun an, wir wollen ein zusätzliches HTML-Textfeld beim Artikel anlegen. Unterhalb des Feldes für die Langbeschreibung. Das Datenbank-Feld, das wir angelegt haben heißt ‘someotherdescription’ (zusätzlich die entsprechenden multilanguage Felder).

Also suchen wir uns erstmal die Stelle in den Templates, an der wir unseren Code gerne einfügen möchten. In unserem Fall ist das die Datei ‘article_main.tpl’. Glücklicherweise finden wir die Langbeschreibung innerhalb des Blocks ‘admin_article_main_editor’ wieder. Das heißt, wir können diesen Block verwenden um unseren Code anzuhängen. Damit dies passiert, müssen wir in der metadata.php folgenden Eintrag im Bereich ‘blocks’ machen:

array(
  'template' => 'article_main.tpl', 
  'block'=>'admin_article_main_editor', 
  'file'=>'application/views/admin/blocks/unser_zusatz_feld_fuer_admin_article_main.tpl'
)

Die Datei ‘unser_zusatz_feld_fuer_admin_article_main.tpl’ sucht OXID im von uns angegebenen Pfad, relativ zu unserem Modulverzeichnis.

Grundsätzlich nimmt uns OXID einiges an Arbeit ab, wenn wir uns im TPL-File darum bemühen die Konventionen einzuhalten. Nehmen wir uns z.B. mal das Feld, in dem man den Titel eines Artikels angeben kann:

<input 
  type="text" 
  class="editinput" 
  size="32" 
  maxlength="[{$edit->oxarticles__oxtitle->fldmax_length}]" 
  name="editval[oxarticles__oxtitle]" 
  value="[{$edit->oxarticles__oxtitle->value}]">

Was hier auffällt ist, dass maxlength, name und value Werte enthalten, die man auch von anderen Stellen im Shop her kennt und die auf das entsprechende Datenbankfeld referenzieren.

  • Schema DBTABELLE__DBSPALTE: oxarticles__oxtitle ist also die Spalte oxtitle in der Tabelle oxarticles
  • ‘editval’ wird vom Controller ausgewertet und entsprechend in die DB geschrieben
  • ‘$edit’ wird vom Controller automatisch aufgebaut anhand aller in der DB-Tabelle vorhandenen Spalten. Dort sind die üblichen Werte abfragbar, wie auch schon aus den Fronend-Templates bekannt.

Wenn wir uns an dieses Schema halten, dann müssen wir grundsätzlich nichts weiter tun. Unser Modul kommt dann mit einer einzigen TPL Datei aus, in der dieses Feld definiert ist. Den Rest macht OXID. Fast…

Gleich und doch ein bisschen anders

Das oben beschriebene Schema funktioniert mit den üblichen Feldern, auch mit Checkboxen etc. Dabei ergeben sich aus den HTML Eigenheiten der Felder leichte Differenzen in der Umsetzung. Die findet man recht schnell heraus, indem man sich die Standardfelder in den TPL-Dateien einfach mal anschaut.

Bei unserem Textfeld gibt es nun aber eine signifikante Abweichung. In der Professional Edition gibt es einen WYSIWYG-Editor. Der wird im Controller gerendert und wenn wir ein zweites Feld mit den gleichen Eigenschaften haben wollen, müssen wir uns darum kümmern, dass ein zweiter Editor zur Verfügung steht. Ausserdem gibt es eine JavaScript Funktion, die den Inhalt in ein Verstecktes Feld nach dem o.g. Schema schreibt, damit der Wert auch beim Abschicken an den Controller übergeben wird. Wir erweitern also den Controller in unserem Modul, das heisst wir fügen eine zusätzliche Zeile in unsere metadata.php ein, diesmal in dem Bereich ‘extend’:

'article_main' => 'my_ext/application/controllers/admin/my_ext_article_main',

Achtung!! Hier ist das Verzeichnis relativ zum OXID Verzeichnis ‘modules’ anzugeben, nicht relativ zu unserem eigenen Modulverzeichnis.

Hinweis: Im Fall dass wir den Artikel um ein solches Feld erweitern wollen, müssen wir noch eine weitere Thematik im Controller berücksichtigen. Hier hat OXID leider das normale Verhalten aller anderen Controller abgewandelt, so dass wir dies in unserem Fall zurück bauen müssen

Lasst uns coden

unser_zusatz_feld_fuer_admin_article_main.tpl

[{* Den ursprünglichen Block übernehmen *}]
[{$smarty.block.parent}]

[{* Wir hängen unsere Änderungen an *}]
<br /><br />
<b>[{oxmultilang ident="ARTICLE_MAIN_INTERNATDELIVERY"}]</b><br/>

[{* Der neue Editor *}]
[{$editor2}]

[{* Das versteckte Feld, das die Daten an den Controller übergibt *}]
<input type="hidden" name="editval[oxarticles__someotherdescription]" value="">

[{* JavaScript, dass die ursprüngliche Kopierfunktion erweitert *}]
<script type="text/javascript">
    [{* Wie laden die Funktionen, die bei 'onsubmit' ausgeführt werden sollen *}]
    var originalOnSubmitFunction = document.getElementById('myedit').onsubmit;
    [{* Wenn das Formular abgesendet wird, führen wie die ursprüngliche Funktion aus
        und zusätzlich unsere eigene. *}]
    document.getElementById('myedit').onsubmit = function(event) {
        originalOnSubmitFunction();
        copyLongDesc('oxarticles__someotherdescription');
    }
</script>

my_ext_article_main

<?php

class my_ext_article_main extends my_ext_article_main_parent {

    /**
     * Loads article parameters and passes them to Smarty engine, returns
     * name of template file "article_main.tpl".
     *
     * @return string
     */
    public function render() {
        /* Funktionalität der Basisklasse aufrufen */
        $ret = parent::render();

        /* Generierung eines zweiten Editors und übergabe an die View als 'editor2' */
        $oArticle = $this->_aViewData['edit'];
        $this->_aViewData["editor2"] = $this->_generateTextEditor( "100%", 300, $oArticle, "oxarticles__someotherdescription", "details.tpl.css");

        return $ret;
    }


    /**
     * Returns string which must be edited by editor
     * ACHTUNG!!! DIES IST NUR BEI ERWEITERUNG VON ARTIKELN NOTWENDIG!
     *
     * @param oxbase $oObject object whifh field will be used for editing
     * @param string $sField  name of editable field
     *
     * @return string
     */
    protected function _getEditValue( $oObject, $sField )
    {
        $sEditObjectValue = '';
        
        /* Wenn das zu bearbeitende Feld die ursprüngliche Langbeschreibung ist,
           dann behalten wir die Funktion bei, ansonsten nehmen wir den Standard,
           der bei allen anderen Controllern genutzt wird */
        if ($sField === "oxarticles__oxlongdesc") {
            if ($oObject) {
                $oDescField = $oObject->getLongDescription();
                $sEditObjectValue = $this->_processEditValue($oDescField->getRawValue());
                $oDescField = new oxField($sEditObjectValue, oxField::T_RAW);
            }
        } else {
            if ($oObject && $sField && isset($oObject->$sField)) {
                if ($oObject->$sField instanceof oxField) {
                    $sEditObjectValue = $oObject->$sField->getRawValue();
                } else {
                    $sEditObjectValue = $oObject->$sField->value;
                }

                $sEditObjectValue = $this->_processEditValue($sEditObjectValue);
                $oObject->$sField = new oxField($sEditObjectValue, oxField::T_RAW);
            }
        }
        return $sEditObjectValue;
    }
}

Das OXID Backend hat ein neues Feld. Fertig!

Die ersten Male in denen ich solche Felder hinzugefügt habe, waren von etlichen Frustrationen geprägt. Vor allem weil ich immer irgendeinen Punkt übersehen hatte. Das Template habe ich anfangs wegen der JavaScript Thematik immer komplett überschrieben. Durch den kleinen JS Schnipsel, den wir jetzt im Modul drin haben, ist das nicht mehr nötig. Der von uns zu pflegende Code ist kurz und ausgelagert. Das schöne ist, wir können uns dieses Beispiel auf die Seite legen und immer wenn ein Feld benötigt wird einfach die entsprechenden Stellen erweitern/anpassen. Dank der OXID Konventionen ist das dann wirklich überschaubar und wenig fehleranfällig.

3 Comments

  1. Hallo,
    prima Artikel – wäre es möglich, die Dateien als Zip zur Verfügung zu stellen… oder gibt es die irgendwo auf Github?
    Dank vorab

    Reply

Leave a Comment.