Eigene Formularelemente im Produkt erstellen, gestalten und benutzen

30.01.2010   //   von Tobias Vogt   //   Entwicklung, Magento  //  11 Kommentare

In Magento lassen sich über die Attribute-Sets ohne weiteres Felder zum Produkt hinzufügen. Die Typen der Felder sind auf Text Field, Text Area, Date, Yes/No, Multiple Select, Dropdown, Price, Gallery, Media Image und Fixed Product Tax beschränkt. Im folgenden möchte ich zeigen wie ein eigenes Datenfeld gestaltet und und implementiert wird. Das Ziel soll es sein dem Shopbetreiber die Möglichkeit zu geben beliebig viele Datenblätter zu einem Produkt hochzuladen.

1. Attribute anlegen

Zuerst müssen wir ein einfaches Attribute anlegen. Dazu wählen wir Catalog/ Attributes/ Manage Attributes. Ich gehe bei dem neuen Attribute davon aus das als Code “datenblatt” gewählt wurde. Der Einfachhalt halber verzichte ich darauf die Datenblätter in einer separaten Kreuztabelle zu speichern – stattdessen werden die Zuordnungen direkt in das Datenbankfeld geschrieben. Aus diesem Grund sollte der Typ des Attributes auf “TextArea” stehen. Zusätzlich muss das neue Attribute, damit es sichtbar ist, noch dem Default-Set zugeordnet werden.

2. Datenbank anpassen

Magento baut die Formulare teilweise anhand der Felder in der Datenbank zusammen. Es nutzt dafür ein sogenanntes EAV-Model. Dieses Model sorgt salopp gesagt dafür das wir fast beliebig viele neue Felder schaffen können ohne unser Datenbank-Layout zu verändern. Zudem haben wir die Möglichkeit anzugeben wie die Formularfelder erstellt und gespeichert werden. Hierzu gibt es den Frontend-Input-Renderer (Feldname: . Dieser kümmert sich vollständig um die Darstellung der Formularelemente. Das Gegenstück hierzu ist das Backend-Model (Feldname: ) welches sich um die Speicherung und Validierung der Eingaben kümmert.

Um nun unser Feld “datenblatt” optisch und funktional anzupassen gehen wir wie folgt vor:

Zuerst Datenbank z.B. im phpMyAdmin öffnen. Dann zur Tabelle eav_attribute wechseln und dort den Datensatz mit attribute_code = “datenblatt” heraussuchen und bearbeiten:

backend_model: test/product_backend_datenblatt
frontend_input_renderer: Test_Test_Renderer_Datenblatt

In diesem Fall weisen wir Magento an das Model Product/Backend/Datenblatt aus dem Modul Test zum Speichern unserer Daten zu verwenden. Im zweiten geben wir an das die Darstellung über die Class Test_Test_Renderer_Datenblatt erfolgt. Wichtig ist das, warum auch immer, das Backend-Model auf ein Model verweist – es muss also vor dem Slash das Modul stehen. Der Frontend-Input-Renderer dagegen erwartet direkt eine Class!

3. Frontend-Input-Renderer erstellen

Hierzu erstellen wir in app/code/local/Test/Test/Renderer die Datei Datenblatt.php mit folgendem Inhalt:

Datei: app/code/local/Test/Test/Renderer/Datenblatt.php

class Test_Test_Renderer_Datenblatt extends Varien_Data_Form_Element_File
{
	 /**
	 * Retrieve Element HTML fragment
	 *
	 * @return string
	 */
	 public function getElementHtml()
	 {
		 $html = '';

		 // Value lesen und Zeilenweise trennen
		 $data = $this->getData('value');
		 $lines = explode("\n", $data);

		 $html .= '<table>';

		 $html .= '<col width="110" /> ';
		 $html .= '<col width="150" /> ';
		 $html .= '<col /> ';

		 $html .= '    <thead>    <tr> <th>Datenblatt-Nr.</th> <th>Aktuelle Datei</th>  <th>Neue Datei</th> </tr> </thead> ';

		 $html .= '    <tbody>';

		 $i = 0;
		 foreach( $lines AS $cur ) {
		 $i++;

		 // pro Zeile wird genau ein Datensatz getrennt mit einem Gleich-Zeichen erwartet
		 $tmp = explode('=', $cur);
		 if ( count($tmp) != 2 ) {
		 	continue;
		 }
		 list($nr, $file)  = $tmp;

		 $nr = trim($nr);
		 $file = trim($file);

		 // Eine leere Datenblatt-Nummer akzeptieren wir nicht
		 if ( $nr == '' ) {
			 continue;
		 }

		 // HTML-Table aufbauen
		 $html .= '    <tr>';

		 $html .= '        <td> <input type="text" name="'.$this->getName().'[nr]['.$i.']" style="width: 100px" value="'.$this->_escape( $nr ).'" /> </td> ';

		 $html .= '        <td> '.$file;
		 $html .= '            <input type="hidden" name="'.$this->getName().'[filename]['.$i.']" value="'.$this->_escape($file).'" />';
		 $html .= '         </td> ';

		 $html .= '        <td> <input type="file" name="datenblatt_file_'.$i.'" style="width: 100px" /> </td> ';

		 $html .= '    </tr>';
		 }
		 $html .= '    </tbody>';

		 $html .= '    <tr>';
		 $html .= '        <td> <input type="text" name="'.$this->getName().'[nr][new]" style="width: 100px" /> </td> ';
		 $html .= '        <td> Neues Datenblatt </td>';
		 $html .= '        <td> <input type="file" name="datenblatt_file_new" style="width: 100px" /> </td> ';
		 $html .= '    </tr>';

		 $html .= '</table>';

		 // und ein kleiner Hinweis wie man Datenblätter löschen kann
		 $html .= '<small>Entfernen Sie die Datenblatt-Nr. um das Datenblatt zu löschen.</small>';

		 return $html;
	 }
}

4. Backend-Model zum Speichern der Daten

Wie sich unschwer erkenne lässt können wir unsere Daten nun hübsch darstellen. Was fehlt ist der Teil unserer Anwendung der sich darum kümmert das die Daten in Datenbank bzw. Dateisystem abgelegt werden. Hier kommt das Backend-Model ins Spiel: Datei: app/code/local/Test/Test/Renderer/Datenblatt.php

<?php

class Test_Test_Model_Product_Backend_Datenblatt extends Mage_Eav_Model_Entity_Attribute_Backend_Abstract
{

	public function beforeSave($object)
	{
		$path = Mage::getBaseDir('media') . DS . 'catalog' . DS . 'datenblatt';
		$name = $this->getAttribute()->getName();

		$inputs = $object->getData( $name );

		if ( !is_array($inputs['nr']) ) {
			return;
		}

		$res = array();

		foreach( $inputs['nr'] AS $i => $nr ) {

			if ( $nr == '' ) {
				continue;
			}

			try {
				$uploader = new Varien_File_Uploader( 'datenblatt_file_'.$i );
				//$uploader->setAllowedExtensions(array('pdf'));
				$uploader->setAllowRenameFiles(true);
				$uploader->save($path);

				$res[] = $nr.'='.$uploader->getUploadedFileName();

			} catch (Exception $e) {
				if( isset($inputs['filename'][$i]) ) {
					$res[] = $nr.'='.$inputs['filename'][$i];
				}
			}

		}

		$object->setData($this->getAttribute()->getName(),  join("\n", $res) );
		return;
	}

}

Fazit

In Magento ist es sehr einfach Produkte um weitere Standard-Eingabefelder zu erweitern. Sollen diese Eingaben jedoch besondere Eigenschaften bzw. Features aufweisen wird die Aufgabe ein wenig komplexer ist jedoch durchaus zu bewältigen. Der Aufwand lohnt sich in der Regel jedoch: das Pflegen von Produkten wird durch spezialisierte Eingaben deutlich einfacher und ist weniger fehleranfällig.

Der Autor

Tobias Vogt arbeitet seit 2008 mit Magento und ist seit 2011 durch Magento zertifizierter Entwickler. Beschäftigt ist er bei der code-x GmbH, einer Agentur für Internet und Marketing aus Paderborn. Er gehört zum Gründer-Team der Webguys und ist seit November 2011 Bachelor of Science (Wirtschaftsinformatik). Sie erreichen Ihn per E-Mail unter tobi@webguys.de.

11 Kommentare

  • Hallo,

    erstmal danke für das tolle Tutorial! Ich habe aber ledier Probleme beim Einbau!

    2 Fragen:

    1.app/local/Test/Test/Renderer

    Bei mir gibt es unter apps nur einen Ordner der locale heißt aber nicht local ! Meisnt du diesen Ordner?

    2. Den zweiten Code für das Backend Model, wo muss ich den einfügen bzw. wo muss ich Dateien und Ordner anlegen? Würde mic hsehr über Antwort von Dir freuen.

    LG

    cominaction

  • Hallo Philipp,

    ich werde schauen das ich mir deine Frage morgen im Laufe des Tages ein wenig näher anschaue – heute ist es schon zu spät :)

    Lg,
    Tobi

  • alles klar kein Problem! Ach übrigens, du hattest mir auch einen Link zu dem Tut mit den Attributsets geschickt im Magento Forum! Danke, hatte ich schon selber gelöst siehe hier :

    http://shop.isetsolar.eu/index.php/inverters/sma/sunny-boy-1200.html

    Aber danke für deinen Link, mach weiter so, zwar bis jetzt nicht viele Beiträge aber dafür sehr gute! Wenn du magst, würde mich vllt auch an dem Füllen von Beiträgen hier beteiligen! Sag mal bescheid

  • Hallo Phillip,

    zu Frage 1: Nein “local” ist richtig. In locale liegen Übersetzungen, in local dagegen eigene Erweiterungen von Magento. Der Pfad im Artikel ist jedoch falsch: Richtig ist app/code/local. Das habe ich soeben korrigiert.

    Zusätzlich musst du noch eine config.xml für das Modul erstellen. Sonst ist das Modul nicht aktiviert bzw. der Namespace nicht aktiv. Wie das mit dem Modulen geht findest du z.B. dort: http://rackspeed.de/forum/magento-faq-extensions/modulerstellung-erstelle-modul-funktion-ueberschreiben-19

    Zur Frage 2: Ich habe den Artikel um einen Pfad ergänzt. Du kannst in der Regel am Class-Namen den Pfad ableiten. Ein Unterstrich (_) stellt hier immer einen Ordnerwechsel dar. Ein Slash öffnet immer den Namespace eines Moduls.

    schönen Gruß und vielen Dank fürs Lob :)

    Tobi

    P.S. Zur Artikel schreiben muss ich erst mit meinem Mitschreiber sprechen. Da haben wir uns noch keine echten Gedanken zu gemacht :)

  • Hallo,
    ich bekomme es trotzdem nicht zum Laufen! Hast du eine Magento Installation wo ich mir das mal LIVE anschauen kann. Oder kannst du mir eine richtige step by step Anleitung geben! Ist für mich sehr Wichtig das ich das zum Laufen bekomme!

    Grüße aus HH

    Phil

  • Hallo Philipp,

    leider gibt es im Moment keine Magento-Installation wo du dir das näher anschauen könntest. Das Beispiel läuft ähnlich wie hier auf einer Kundenseite ;) Eine Step-By-Step Anleitung ist eigentlich nicht im Rahmen des Blocks der mehr unter dem Motto “Hilfe-Zur-Selbsthilfe” steht. Ich studiere neben meinen Job noch, muss noch eine Facharbeit schreiben und ähnliches – da ist es mir im Moment leider nicht möglich mich hinzusetzen und eine deutliche Anleitung zu schreiben, sorry!

    Ich hoffe du verstehst das!

    Tobi

  • hi Tobias,

    könntest du evtl. noch deine config.xml mal posten. Ich hab leider das Problem, dass ich die anscheinend nicht korrekt hinbekommen. Bei mir erscheint, wenn ich die Produkt-Detailseite im Backend aufrufe immer folgender Fehler.

    Invalid backend model specified: test/product_backend_datenblatt

    Mein XML sieht folgend aus:

    1.0.0

    Test_Test_Model_Product_Backend_Datenblatt

  • Vielen Dank für dieses Tutorial!
    Damit es bei mir funktioniert (Magento 1.4.1.1)müsste ich folgendes machen:

    1. Mein Modul heisst “Datenblatt” und liegt im Ordner “Meinfirma”
    2. So sieht meine config.xml Datei (im Ordner Meinfirma/Datenblatt/etc):

    0.1.0

    Model_Product_Backend_Datenblatt

    3. Mein Backend-Model Datei “Datenblatt.php” liegt im Ordner Meinefirma/Datenblatt/Model/Product/Backend

    4. MySQL: in der Tabelle “eav_attribute” habe ich lediglich das Feld “backend_model” ausgefüllt:
    meinefirma_datenblatt_model_product_backend_datenblatt
    Als “frontend_input” habe ich folgendes eingetragen:
    pdf

    5. Mein Renderer liegt in einer Datei mit dem Namen “Pdf.php” im Ordner lib/Varien/Data/Form/Element und beinhaltet folgende Klasse:
    class Varien_Data_Form_Element_Pdf extends Varien_Data_Form_Element_Abstract
    Diese Klasse hat 2 Methoden:
    public function __construct($data)
    {
    parent::__construct($data);
    $this->setType(‘file’);
    }
    public function getHtml()
    {
    // Hier den Inhalt der Funktion getElementHtml() von weiter oben übernehmen
    }

    Ich hoffe es hilft jemanden.
    Über eine Alternative wie ich die Renderer Datei in einem anderen Ordner als /lib/Varien hinkriege wäre ich dankbar.

  • Ich habe gerade gesehen dass die Seite mir die Codezeilen von der config.xml gefressen hat…
    Hier nochmal den Inhalt der Datei mit eckigen Klammern:
    [?xml version="1.0"?]
    [config]
    [modules]
    [Meinefirma_Datenblatt]
    [version]0.1.0[/version]
    [/Meinefirma_Datenblatt]
    [/modules]
    [global]
    [models]
    [datenblatt]
    [class]Model_Product_Backend_Datenblatt[/class]
    [/datenblatt]
    [/models]
    [/global]
    [/config]

  • Anscheinend kann man die Renderer Datei “Pdf.php” lokal im Ordner “app\code\local\Varien\Data\Form\Element” ablegen…
    Man braucht sie nicht im Systemordner “lib/Varien/Data/Form/Element” abzulegen..

  • Genau akleur. In den System-Ordner gehören auch keine eigenen Dateien. Im Beispiel oben sollte dies eigentlich auch im Modul-Ordner liegen. Mittels Namensräumen (der String vor dem Slash) kannst du Magento sagen in welcher Extension dein Modul zu finden ist. Leider ist das ganze nicht mal so salopp nebenbei in einem Kommentar erklärt sondern erfordert schon einiges an Arbeit. Eventuell helfen wir aber das Buch Magento, das Handbuch für Entwickler oder auch der Artikel von Matthias Zeis: http://www.matthias-zeis.com/archiv/tipps-entwicklung-mit-magento-teil-1

Kommentar schreiben

Am 14.02 ist Valentinstag!

FloraPrima Ihr Blumenversand Nebenbei eben ein Blumen für die Freundin bestellen?
Ich empfehle FloraPrima!

Magento-Support

Sie benötigen kurzfristig Unterstützung in einem Magento-Projekt oder möchten eine individuelle Extension einsetzen? Sprechen Sie uns an.