Userabhängige Toolbar im CK-Editor in Pimcore

Pimcore verwendet als WYSIWYG-Editor den CK-Editor, ein in JavaScript implementierter Editor der sehr viele Möglichkeiten bietet, einen Text direkt im Browser zu bearbeiten.
Da es oft keine gute Idee ist, den User einen Text mit allen Möglichkeiten bearbeiten zu lassen, bietet der Editor die Möglichkeit, die Toolbar selbst zu definieren.

Mit ein wenig Geschick lässt sich dies sogar Userabhängig bewerkstelligen, so daß beispielsweise ein Admin-User die vollständige Toolbar sieht, ein normaler User aber nur eine eingeschränkte.
Die Information, welcher User gerade eingeloggt ist, lässt sich dem pimcore.globalmanager mit der Methode get(“user”) entlocken.

Ein kleines Script, dass die Konfiguration dann Userabhängig gestaltet, könnte dann so aussehen:

CKEDITOR.editorConfig = function( config ) {
  var user = pimcore.globalmanager.get("user");

  if (!user.admin) {
    config.toolbar = [
      [ 'Source', '-', 'NewPage', 'Preview', '-', 'Templates' ],
      [ 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo' ],
      '/',
      [ 'Bold', 'Italic' ]
    ];
  }
};

Dieses Stück Code kann man zum Beispiel in pimcore/static/js/lib/ckeditor/config.js ablegen.

PHPStorm Filewatcher für LessCss

Für CSS gibt es eine Anzahl von Präprozessoren, die einem den Umgang mit dieser deklarativen Sprache erleichtern. So werden geschachtelte Definitionen, Variablen, Mathematik und Makros ermöglicht.

Einer dieser kleinen Helfer, den wir gerne einsetzen ist Less, die Sprache für „Less CSS“

Der Vorgang ist, unabhängig vom verwendeten Dialekt, immer gleich:

  1. Erweitertes CSS schreiben
  2. Verarbeiten lassen
  3. dem Browser übermitteln

Gebräuchlich sind hierfür nun zwei Methoden;

  1. Dem Browser direkt die Rohdaten übermitteln und selbst übersetzen lassen, zum Beispiel mit less.js
  2. Die .less Datei vom Server übersetzen lassen und als fertiges CSS ausliefern, zum Beispiel mit lessphp

Letzteres wird zum Beispiel von Pimcore mit einem Outputfilter realisiert; hierbei wird der HTML-Sourcecode nach einem <link rel=”stylesheet/less” type=”text/css” href=”BLAHFASEL.less”> durchsucht, gefundene Links auf die .less-Quelldateien an lessphp übergeben, der Link auf das Resultat „umgebogen“ und das angepasste HTML schlussendlich an den Browser übergeben.

Seit PHPStorm Version 6 gibt es nun eine dritte Möglichkeit, die noch früher ansetzt: das .less wird direkt von der IDE zu CSS übersetzt.

Filewatcher

Es gibt für diese IDE nun sogenannte Filewatcher, also Hintergrundprozesse, die Aufgaben für definierte Files ausführen, sobald sich diese verändern. Dies eröffnet eine ganze Reihe von Möglichkeiten, eine davon ist es, ein .less File direkt nach dem Abspeichern in ein CSS übersetzen zu lassen. Dadurch wird dieser einmalige Task sofort und vom Rechner des Entwicklers erledigt, und weder Webserver noch Browser müssen sich damit jemals wieder mit LessCss beschäftigen.

Darüber hinaus zeigt der Prozess sofort auf, wenn Fehler beim Übersetzen aufgetreten sind, das erleichtert die Erkennung von Fehlern.

less.js installieren um lesscss zu verarbeiten

Der Präprozessor für .less–Files muss als Befehl für die Kommandozeile vorliegen. Hier könnte man zum Beispiel less.php im CLI-Modus von PHP ausführen lassen, ich habe mich der Einfachheit halber aber für die Node.js Variante entschieden.

Zuerst muss natürlich node.js installiert sein. Unter Gentoo erreicht man das mit einem einfachen Befehl:

emerge nodejs

Node.js bringt seinen eigenen Paketmanager mit, damit lässt sich dann leicht less.js nachladen und installieren:

npm install -g less

Das war’s, mehr ist nicht zu tun.

Konfiguration des Filewatchers

PHPStorm frägt, ob ein Watcher eingerichtet werden soll

PHPStorm frägt, ob ein Watcher eingerichtet werden soll

PHPStorm erkennt anhand der Filekennung automatisch, ob ein File bearbeitet wird, für den sinnvollerweise ein Watcher eingerichtet werden könnte und schlägt dies dann vor. Mit einem Klick auf “Add watcher” kann man dies nun tun, bei einem Klick auf “Dismiss” verschwindet der Vorschlag – und kehrt auch nie wieder.

Filewatcher Konfiguration

Filewatcher Konfiguration

Wenn man den Vorschlag einmal weggeklickt hat, oder den Filewatcher nachträglich bearbeiten muss, kann man dies in den Einstellungen von PHPStorm erledigen, die man über

File – Settings – Project Settings – File Watchers erreicht.

Man sollte darauf achten, das Immediate file synchronisation und Check file for syntax errors aktiviert ist, der Pfad zum Compiler findet man an der Konsole heraus mit den Kommando

which lessc

Ein Klick auf OK speichert die Einstellungen ab.

Automatisches Hochladen aktivieren

Automatisches Hochladen aktivieren

Wer auf Remote Servern arbeitet, sollte noch das automatische Hochladen der resultierenden CSS-Datei aktivieren, sonst ist es erforderlich, diese jedes Mal per Hand hochzuladen.

Dies kann man unter Tools->Deployment->Options erreichen, wichtig ist es bei „Upload changed files automatically to the default server“ die Einstellung always zu wählen und bei „Upload external changes&ldquot; einen Haken zu machen.

Fortan sieht man beim Abspeichern der .less-Datei im File-Transfer Infofenster von PHPStorm, dass zwei Dateien auf den Server übertragen wurden :)

Hast Du Kommentare, Fragen oder Anregungen zum LESS-Filewatcher? Wir freuen uns über Beiträge in unserem Kommentarbereich!

Objekte erzeugen in Pimcore beschleunigen

Wer in Pimcore schon in der Situation war, viele User-Objekte erzeugen zu müssen (zum Beispiel bei Datenabgleichen mit anderen System) wird festgestellt haben, dass dies eher gemächlich vonstatten geht.

Mit zwei einfachen Maßnahmen kann man dem Prozess gehörig auf die Sprünge helfen.

Den Cache aktivieren

Ist in Pimcore kein Cache konfiguriert, wird per Default der Zend_File_Cache verwendet.
Das ist zwar besser wie nichts, aber immer noch sehr langsam.

Der Cache wird nur dann deaktiviert, wenn man dies explizit mit

Pimcore_Model_Cache::disable();

so setzt.

Es empfiehlt sich daher, den Cache auf eine schnelle Variante wie Memcached oder die MongoDB zu konfigurieren.

Memcache

Memcache ist ultraschnell, da er ausschliesslich im Speicher läuft, hat aber einen Nachteil – alles, was da reingestopft wird, ist global für jeden mit Zugriff auf den Daemon verfügbar. Um hier abgrenzen zu können, setzt Pimcore eine Zwischenschicht zum Taggen ein, und jene Tags werden wiederum in der normalen SQL-Datenbank abgelegt – dieser Umstand macht also den Memcache für Pimcore nicht zu ersten Wahl.

MongoDB

Die MongoDB ist die schnellere Alternative zum Memcache – obwohl sie im Prinzip eigentlich die langsamere wäre, es fehlt aber das Tagging-Handicap.
Die Installation der Datenbank sollte einfach zu bewerkstelligen sein, die meisten Distributionen enthalten sie.

Die Konfiguration in Pimcore erfolgt über die Datei website/var/config/cache.xml. Eine Beispiel-Datei existiert schon in dem Verzeichnis.

Eine funktionierende Version der cache.xml für die MongoDB würde Beispielsweise so aussehen:


    
    
        Core
        
            pricelist_
            99999
            true
        
    
    
        Pimcore_Cache_Backend_Mongodb
        true
        
            pimcore_cache
        
    

Die Datei wird bei jedem Request an Pimcore gesucht, sobald sie vorhanden ist, ist der Cache aktiv.

Den Cache nutzen um Zend_Db_Table zu beschleunigen

Beim Anlegen von vielen Objekten zeigt sich eine kleine, ich will nicht sagen, Unzulänglichkeit, von Zend_Db_Table:

Standardmäßig fragt Zend_Db_Table_Abstract die darunterliegende Datenbank für die Metadaten der Tabelle ab immer wenn diese diese Daten benötigt werden um Tabellenoperationen durchzuführen. Das Tableobjekt holt die Metadaten der Tabelle von der Datenbank indem es die describeTable() Methode des Adapters verwendet.
[...]
In einigen Fällen, speziell wenn viele Table Objekte auf der gleichen Datenbanktabelle instanziert werden kann das Abfragen der Datenbank nach den Metadaten der Tabelle für jede Instanz unerwünscht sein wegen der Geschwindigkeit. In solchen Fällen, können Benutzer davon profitieren das die Metadaten der Tabelle, die von der Datenbank empfangen werden, gecached werden.

Die Kurzfassung: bei jedem Erzeugen eines Daten-Objekts wird die Datenbank gefragt, wie die Daten denn auszusehen haben.
Dieser Vorgang kostet enorm viel Zeit und kann gecached werden mit Zend_Db_Table_Abstract::setDefaultMetadataCache()

Dieser statischen Methode muss einfach nur ein Cache übergeben werden – und einen solchen stellt Pimcore, wie weiter oben beschrieben, zur Verfügung.

Folgende beiden Zeilen aktivieren daher den Metadaten-Cache für Zend_Db_Table:

$cache = Pimcore_Model_Cache::getInstance();
Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);

Die Praxis

Bei einem Kunden war es notwendig, ca 3500 Objekte (mit Assets, es finden also auch Kopiervorgänge auf der Platte statt) zu importieren.
Ohne Cache dauerte dies ca 2 Stunden, mit Cache 15 Minuten, und mit dem Metadaten-Cache nur noch fünf Minuten.

In der Praxis haben diese beiden Maßnahmen uns also enorme Geschwindigkeitssteigerungen gebracht!

EDIT:
Wir haben diese Verbesserung als Issue bei Elements eingereicht: Activate caching Zend table metadata by default.
Die zwei Zeilen sind angemommen worden, ab Version 1.4.10 ist der Cache daher nun im Core von vornherein mit drin :)

Mobile Chrome am Desktop über USB debuggen

Wir beschäftigen uns derzeit start mit Responsive Design in HTML mit Media Queries. Insbesondere interessant ist für uns dabei das Verhalten der mobilen Geräte wie Tablets oder Smartphones.

Leider gestaltet sich das Debuggen des HTML/CSS/Javascript sehr viel schwieriger bei mobilen Geräten als am Desktop, da die Konsole, wie sie zum Beispiel Firefox oder Chrome standardmäßig haben, nicht verwendbar ist. Die Nutzung würde sich mangels geeignetem Zeigegerät wie einer Maus und dem geringen Platz am Bildschirm sehr schwierig gestalten.

Debuggen mit Android

Google stellt allerdings für Android-Geräte mit dem USB-Debugging-Modus eine Möglichkeit bereit, den eigenen Browser Chrome anzuzapfen!

Um das nutzen zu können, braucht man nur am Desktop ebenfalls den Chrome-Browser sowie das das Android Software Development Kit (SDK), welches unter http://developer.android.com/sdk/index.html heruntergeladen werden kann. Für uns interessant sind hierbei aber nur die Platform Tools.

USB Debugging aktivieren am mobilen Gerät

Hier aktiviert man das USB-Debugging

Hier aktiviert man das USB-Debuggin


Um auf die Daten des Browsers zugreifen zu können, muss erst das Debugging aktiviert werden. Unter Android 4.x macht man dies in den Systemeinstellungen unter „Entwickleroptionen“ In diesem Menü macht man nun einen Haken bei “USB-Debugging”; fortan startet der Debugging-Modus, wenn das Gerät an USB angeschlossen wird.
Es empfiehlt sich, den Modus nach dem Debugging wieder zu deaktivieren, da sich hier Angriffsflächen für Hackingversuche bieten, wenn das Gerät in falsche Hände gerät.

Wenn man nun das Gerät an USB anschliesst, muss unter Umständen unter Windows noch der ADK (Android Debugging Kit) Treiber installiert werden, Linux kommt ohne weiteres Zutun klar.

Die Verbindung zum Browser des Mobilgeräts herstellen

Als nächstes muss die Verbindung zwischen dem Desktop und dem Browser des Mobilgeräts hergestellt werden. Dies erledigt das adb Programm der Platform-Tools:

$ cd adt-bundle-linux-x86_64/sdk/platform-tools 
$ ./adb forward tcp:9222 localabstract:chrome_devtools_remote

Wenn kein Fehler auftritt, steht nun unter dem Port 9222 des localhost der mobile Browser zur Verfügung.

Den mobilen Browser ansprechen

Der mobile Chrome kann am Desktop debugged werden

Der mobile Chrome kann am Desktop debugged werden

Um den mobilen Browser anzusprechen, ruft man mit dem lokalen Chrome die URL http://localhost:9222 auf. Es erscheint eine Auswahl von aktuell vorhandenen Tabs am entfernten Browser, hier wählt man den Debug-Kandidaten aus.
Es erscheint nun das Entwickler-Fenster, wie man es von Chrome gewohnt ist – nur dass man jetzt die Interna des entfernten Browsers sieht. Die Werkzeuge verhalten sich exakt wie zum lokalen Pendant; wenn man z.B. ein Node im DOM mit dem Mauszeiger überfährt, wird dieses im Browserfenster des Mobilgeräts hervorgehoben.

Gibt es zum Thema „mobiles Debugging“ Fragen oder Anregungen? Wir freuen uns über Eure Kommentare!

Pimcore translations im Layout

Pimcore bietet mit seinem internen Übersetzer die Möglichkeit, “feststehende” Begriffe auf Webseiten zu komfortabel zu übersetzen.

Der Aufruf hierfür ist, zum Beispiel in einer View:

print $this->translate("Der zu übersetzende Begriff");

Wir die Webseite einmal aufgerufen nimmt Pimcore den Satz „Der zu übersetzende Begriff“ in die Liste mit auf. Dort kann man dann die Angaben in den gewünschten Sprachen machen, und abhängig von der im Frontend eingestellten Sprache wird dann die betreffende Übersetzung ausgegeben.

Die Sprache stellt man im Frontend ein über den Zend_Registry Eintrag “Locale”:

Zend_Registry::set("language", $language);
$locale = new Zend_Locale($language);
Zend_Registry::set("Zend_Locale", $locale);

Dies funktioniert wunderbar – mit einer Ausnahme: im Layout, bzw. Im Actioncontroller Website_Controller_Action

Alle Angaben, die hier gemacht werden, werden nicht übersetzt, weil der Translator noch nicht initialisiert ist.

Will man also beispielsweise Übersetzungen für ein Javascript bereits inline und global mitgeben:

$this->view->headScript()->captureStart(); ?>
var livesuche = "view->translate("Livesuche") ?>";
view->headScript()->captureEnd();

wird der String „Livesuche“ nicht übersetzt.

Um auch hier schon Übersetzungen zu erreichen, muss der Translator händisch initialisiert werden bevor das erste Mal die translate() Methode aufgerufen wird. Dies erreicht man mit:

      $this->initTranslation();

Pimcore: eine Page in mehreren Navigationen verwenden

Pimcore stellt eine komfortable Möglichkeit zur Verfügung, einer Webseite eine strukturierte Dokumentenhierarchie zu verleihen.
Diese Struktur kann automatisiert ausgelesen und sowohl in eine Navigation für die Webseite selbst als auch in sinnvolle und “sprechende” URLs verarbeitet werden.
So ist die URL zu einer Seite “Impressum” folgerichtig “/impressum”, und falls die Seite in einem Unterverzeichnis steckt dann “/unterverzeichnis/impressum”.

Häufiger hatten wir hier das Problem, dass auf der Webseite mehrere, voneinander getrennte Navigationen gewünscht sind. Diese kann man in Pimcore dann ganz leicht in Unterordnern zusammenfassen und jeden individuell auslesen und in eine Navigation verwandeln. Dies stellt aus Suchmaschinensicht aber nicht das Optimum dar, da mit jedem Unterpfad die Relevanz der Seite sinkt, von der “merkwüdigen” URL wie “/kopfnavigation/impressum” ganz zu schweigen.

Wir haben daher mit Hilfe der Eigenschaften, die in Pimcore jeder Seite vergeben werden können, eine Lösung entwickelt.

Folgende Ausgangssituation:

Es existieren drei Navigationen:

  1. Die Kopfnavigation
  2. Die Linke Navigation
  3. Die Hauptnavigation

Zudem gibt es im Fuß der Seite die Gesamtnavigation in der jeder mögliche Navigationspunkt nochmal aufgeführt ist:

In Pimcore sind diese Seiten in einer flachen Hierarchie untergebracht, um möglichst kurze URLs zu produzieren:

In der Umsetzung bedienen wir uns der Zend_Navigation, welche uns sehr viel Arbeit abnimmt.
Mit dem pimcoreNavigation() View Helper stellt uns Pimcore eine komfortable Möglichkeit zur Verfügung, eine fertige Zend_Navigation aus dem Dokumentenbaum zu erzeugen.
Dies erreicht man durch Aufrufen der Methode getNavigation($currentDocument, $navStartNode) des View Helpers. $currentDocument stellt dabei das Dokument dar, das in der Navigation als “aktiv” markiert werden soll. In unserem Zusammenhang ist das $this->document. Die Variable $navStartNode beschreibt das Dokument, dessen Kinder die einzelnen Links werden. In unserem Fall ist das “/home”.

      $navStartNode = Document::getById(1);
      $gesamte_nav = $this->view->pimcoreNavigation()->getNavigation($this->document, $navStartNode);

Aus dieser Navigation erzeugen wir nun die anderen, wir müssen jeder Seite nur noch die Information mitgeben, in welcher Navigation sie zusätzlich noch erscheinen soll.
Dies erreichen wir mit den Eigenschaften der Seite. Praktisch hierfür ist es, eine vorgefertige Eigenschaft zu definieren, aus der dann nur noch ausgewählt werden muß. Hier ist das eine “select” Eigenschaft mit den Werten “Kopf,Links,Haupt”:

Diese Eigenschaft kann man nun jeder Seite zuweisen:

Diese Information kann nun bequem ausgewertet werden, um die einzelnen Navigationen zu erzeugen.
Hierbei lesen wir jede Zend_Navigation_Page aus der Navigation aus und werten die Eigenschaft “navigation” des Documents der Page aus. Abhängig vom Inhalt wird eine Seite gegebenenfalls einer weiteren Navigation zugewiesen:

      $kopf_nav  = new Zend_Navigation();
      $linke_nav = new Zend_Navigation();
      $haupt_nav = new Zend_Navigation();

      foreach ($gesamte_nav as $page) {
        $newpage = clone $page;
        $nav_property = trim($page->getDocument()->getProperty("navigation"));
        if     ($nav_property == "Kopf")  $kopf_nav->addPage($newpage);
        elseif ($nav_property == "Haupt") $haupt_nav->addPage($newpage);
        elseif ($nav_property == "Links") $linke_nav->addPage($newpage);
      }

      $this->view->gesamte_nav = $gesamte_nav;
      $this->view->kopf_nav    = $kopf_nav;
      $this->view->linke_nav   = $linke_nav;
      $this->view->haupt_nav   = $haupt_nav;

Ganz wichtig hierbei ist es, $page vor der Zuweisung durch addPage() mit dem clone keywords zu kopieren (Zeile 6), da Zend_Navigation_Container der Seite beim addPage()-Vorgang ein neues Parent zuweist und damit der Gesamt-Navigation entziehen würde.

Die so erzeugten Navigationen können im Layout nun bequem ausgegeben werden:

echo $this->navigation()->menu()->renderMenu($this->kopf_nav, array("maxDepth" => 0));

Umgehung des Layouts bei Pimcore

Wer in Pimcore anstelle einer HTML-Ausgabe direkt eine Datei zum Runterladen produzieren möchte, stößt schnell auf das Problem dass einem die nützlichen Features von Pimcore – wie zum Beispiel die Erzeugung der richtigen HTTP-Header oder eines HTML-Grundgerüsts – in die Quere geraten.

So kann man beispielsweise mit PHPExcel zwar on the fly Excel-Dokumente erzeugen und abspeichern, aber nicht ohne Weiteres an den User zurückgeben z.B. mit print file_get_contents(“export.xlsx”); da zum einen ein HTML-Mimetype gesendet wird, und zum anderen – so fern vorhanden – noch HTML mit ausgegeben wird. Ein direkter Download unter dem gewünschten Filenamen findet so auch nicht statt.

Hier muß man also die richtigen Maßnahmen ergreifen, um aus dem HTML-Framework auszubrechen und direkt die gewünschten Fileinhalte und Header produzieren.

Headerausgabe

Pimcore benutzt das Zend_Controller_Response Objekt des Zend Frameworks, welches Inhalte und/oder Header vereinigt um sie in einem Rutsch zu versenden.
Die Header und Inhalte werden von Pimcore automatisch erzeugt, man kann diese aber auch explizit setzen.

Besonders wichtig hier ist das Headerfeld des MIME-Types “Content-Type”, welches dem Browser sagt, von welchem Typ die empfangenen Daten sind. Meist ist das HTML (was direkt dargestellt wird), bei einem Download aber muss dies entsprechend gesetzt werden. Der MIME-Type für Excel ist application/vnd.ms-excel.

Es kann, per Headerfield “Content-Disposition”, bestimmt werden, unter welchem Filenamen die heruntergeladene Datei abgespeichert werden soll. Fehlt dieser Header erzeugen die Browser für gewöhnlich einen Namen aus Bestandteilen der aufgerufenen URL.

Zu guter Letzt können auch noch Headerinformationen gesetzt werden, die das Cacheingverhalten des Browsers (und unter Umständen auch das einiger Proxys) beinflussen um so von vornherein unerwartete Probleme zu vermeiden.

Zusammengefasst als Code sieht das, hier im Controller, so aus:

        $Response = $this->getResponse();
        $Response->setHeader("Content-Type", "application/vnd.ms-excel", true);
        $Response->setHeader("Content-Disposition", "attachment; filename=".$filename.".xlsx");
        $Response->setHeader("Expires", "0");
        $Response->setHeader("Cache-Control", "must-revalidate, post-check=0,pre-check=0");
        $Response->setHeader("Pragma", "public");

Deaktivierung der Layout-Ausgaben

Nun muß man Pimcore anweisen, die sonst übliche Ausgabe des Layouts und aller hier unnötigen Inhalte zu unterlassen:

$this->disableLayout(); // Nur nötig, wenn ein Layout verwendet wird
$this->removeViewRenderer();

Ausgabe des Inhalts

Zu guter Letzt kann nun der Inhalt ausgegeben werden. Ich nehme hier als Beispiel wieder die Ausgabe meines PHPExcel-Objekts:

        $objWriter = new PHPExcel_Writer_Excel2007($ExcelExport_Category);
        $tmp_filename = PIMCORE_TEMPORARY_DIRECTORY."/xls_export_".uniqid().".xlsx";
        $objWriter->save($tmp_filename);
        print file_get_contents($tmp_filename);
        unlink($tmp_filename);

Codevervollständigung in PhpStorm für unbekannte Typen

Wer im MVC Modell programmiert verteilt seinen Code über mehrere Stellen, der in seiner Logik eigentlich zusammengehört.

So ist es oft so, dass im Controller Variablen deklariert und mit Objekten belegt werden, um diese dann an die View zu übergeben:

public function detailAction() {
  $productid = intval($this->_getParam("productid"));
  $product = Object_Product::getById($productid);
  $this->view->product = $product;
}

Und in der View zB:

print $this->product->getName();

Wer mit professionellen IDEs arbeitet, wird die Codevervollständigung zu schätzen gelernt haben.
PhPStorm zum Beispiel kennt die Klassendefinition von Object_Product, welche im Controller $product zugewiesen wird, und kann bei Bedarf entsprechende Vorschläge für zur Verfügung stehende Methonden machen.

In der View ist das anders – hier wird die Variable während der Laufzeit durch $this->view->product an $this->product “durchgeschleust” und steht daher im Code der View deklarationslos da – die IDE hat hierbei keinerlei Informationen, um welchen Typ es sich handelt und kann keine Vorschläge machen.

Hier kommt nun PhpDoc in’s Spiel, mit dem man bekanntlich Klassen- und Methodendefinitionen dokumentieren kann, um automatisch eine Dokumentation der API erzeugen zu können.
Was offenbar viele nicht wissen: es lassen sich auch die Deklaration von Einzelvariablen direkt im Code mit PhpDoc dokumentieren – hiermit kann man den meisten IDEs Informationen über die Variable zukommen lassen:

/**
 * @var Object_Product $product
 */
$product = $this->product;

Wer die Syntax nicht kennt: PhpDoc wird eingeleitet durch einen Kommentar mit zwei Sternen: /**.
Ein Schlüsselwort, eingeleitet mit “@”, beschreibt dann einen eigenen Typ der Dokumentation, hier @var den Typ der Variable. Das Tag var erwartet als nächstes Wort den Typ der Variable, hier Object_Product, gefolgt vom Namen der Variable.

Mit diesen Angaben kennt dann auch die IDE den Typ der Variable und versorgt den Programmierer mit (mehr oder weniger ;-) ) sinnvollen Vorschlägen:

Dies funktioniert natürlich auch für die meisten anderen IDEs wie zum Beispiel Netbeans.

Liste von verfügbaren Sprachen in Pimcore auslesen und verarbeiten

Für ein Webformular brauchten wir wir eine Zend Framework Selectbox mit den validen Sprachen des Frontends.

Pimcore bietet auch hier wieder komfortable Möglichkeiten, die aktuell im Backend eingestellten Sprachen zu verarbeiten.

Das ganze Problem wird hierdurch wieder mal zum komfortablen Fünfzeiler wenn man weiß wo man hinfassen muss.

Pimcore liefert mit der statischen Methode Pimcore_Tool::getValidLanguages() einen Array an Kürzeln der validen Sprachen, also zB array(“de”, “en”).

Dies kann man sich nun noch vom Zend Framework übersetzen lassen, ebenfalls mit einer statischen Methode: Zend_Locale::getTranslation($kuerzel, “language”, $zielsprache).
Sinnvollerweise lässt man sich das Kürzel in die Sprache übersetzen, die es repräsentiert – ein auswählender User kann seine Sprache damit sicher identifizieren.

Der Select-Viewhelper erwartet nun noch die Werte im Format array($value => $label).

Zusammengefasst sieht das daher dann so aus:

$pimcore_languages = Pimcore_Tool::getValidLanguages();
$languages = array();
foreach ($pimcore_languages as $lang) {
  $languages[$lang] = Zend_Locale::getTranslation($lang, 'language', $lang);
}
$language = $this->createElement("select", "language");
$language->setLabel("Sprache")
         ->setMultioptions($languages);

Pimcore: Dropdown-Länderliste leicht befüllt

Wieder mal ein Griff in die Trickkiste, aus der Kategorie “nützliche Dreizeiler”.

Problemstellung war ein Kontaktformular mit einem Dropdown als Liste aller Länder.

Man kann diese Liste nun natürlich “zu Fuss” definieren, oder sich gleich komfortabel von Pimcore bzw dem Zend Framework befüllen lassen – dort liegen die Daten ohnehin schon vor:

    $countries = new Object_Class_Data_Country();
    $options = array();
    foreach ($countries->getOptions() as $country) $options[$country["value"]] = $country["key"];

Im Array $options liegen die Länder dann in der Form vor, wie man sie direkt in ein Zend Form Element vom Typ Select stecken kann:

    $land = $this->createElement("select", "land");
    $land->setLabel("Land")->setMultioptions($options);

Wer ein spezielleres Ergebnis braucht, kann die Erstellung auch selbst vornehmen und das abändern bzw kopieren, was in Object_Class_Data_Country gemacht wird:

        $countries = Zend_Locale::getTranslationList('territory');
        asort($countries);
        $options = array();

        foreach ($countries as $short => $translation) {
            if (strlen($short) == 2) {
                $options[] = array(
                    "key" => $translation,
                    "value" => $short
                );
            }
        }

        return $options;