Eigene Formularelemente im Produkt erstellen, gestalten und benutzen

30.01.2010   //   von Tobias Vogt   //   Entwicklung, Magento  //  6 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.

6 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

Kommentar schreiben