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.

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 :)

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));

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;

Captchas von Zend Forms in individuelle Formulargestaltung integrieren.

In Formulare in Pimcore einfach erstellt hatten wir ja schon erläutert, wie man ein Formular “zu Fuss” programmiert und sich nur bei den benötigten Elementen bedient, um so das Formular ganz individuell ohne den Aufwand eigener Decorator zu erstellen.

Problem bei der Herangehensweise ist aber, dass Captcha Elemente keine renderViewHelper() Methode kennen und nur über render() ausgegeben werden können. Hierbei werden dann die default-Decorators benutzt, die man dann mit eigenen ersetzen müsste.

Um nun alle Elemente des Captchas (Captcha-Bild, Eingabefeld und hidden-field mit “Lösung”) auszugeben muss man die Schritte ausführen, die Zend_Form_Decorator_Captcha_Word mittels render() erledigen würde:

    public function render($content)
    {
        $element = $this->getElement();
        $view    = $element->getView();
        if (null === $view) {
            return $content;
        }

        $name = $element->getFullyQualifiedName();

        $hiddenName = $name . '[id]';
        $textName   = $name . '[input]';

        $label = $element->getDecorator("Label");
        if($label) {
            $label->setOption("id", $element->getId()."-input");
        }

        $placement = $this->getPlacement();
        $separator = $this->getSeparator();

        $hidden = $view->formHidden($hiddenName, $element->getValue(), $element->getAttribs());
        $text   = $view->formText($textName, '', $element->getAttribs());
        switch ($placement) {
            case 'PREPEND':
                $content = $hidden . $separator . $text . $separator . $content;
                break;
            case 'APPEND':
            default:
                $content = $content . $separator . $hidden . $separator . $text;
        }
        return $content;
    }

Interessant sind hier für uns die Codeteile, die sich mit dem Text- und Hiddenfield befassen.
Diese bedienen sich anderen View Helpern, nämlich Zend_View_Helper_FormHidden und Zend_View_Helper_FormText, die nur mit geeigneten Parametern wie dem Feldnamen oder zu vererbenden Attributen versorgt werden müssen.

Hier ein Beispiel, wie man die Darstellung behandeln kann:

<?php
$formbuilder = new Formbuilder_Frontend();
$form = $formbuilder->getForm("kontakt");
$captcha = $form->getElement("captcha");
$name = $captcha->getFullyQualifiedName(); // Der Name des Eingabefelds
$hiddenName = $name . '[id]'; // Der Name des hidden-fields, erweitert als Array
$textName   = $name . '[input]'; // Der Name des text-fields, erweitert als Array
?>

        <tr>
            <td><?php print $form->captcha->renderLabel() ?></td>
            <td>
              <?php print $form->captcha->renderCaptcha() ?><br>
              <?php print $this->formHidden($hiddenName, $captcha->getValue(), $captcha->getAttribs()); ?>
              <?php print $this->formText($textName, '', $captcha->getAttribs());  ?>
              <?php print $form->captcha->renderErrors() ?></td>
        </tr>

Formulare in Pimcore einfach erstellt

Pimcore liefert mit dem unterliegenden Zend Framework und dem Formbuilder-Plugin von Alexandre Delattre eine komfortable Möglichkeit, eigene Formulare zu erstellen und zu behandeln.

Die Zend Forms sind die eierlegende Wollmilchsau, die alles bietet von der Definition der Felder selbst über die Verifizierung der Inhalte und ihrer Bereinigung bis zu Ihrer Verarbeitung – und, nicht zuletzt, ihrer Darstellung im Browser.
Diese Darstellung erfolgt mit dem Strukturmuster der Decorator, jedes Element “weiss”, wie es dargestellt werden sollte und das Formular kann “sich selbst” ausgeben. Das ist sehr angenehm und praktisch, da für einfache Anwendungen keine weitere Schritte unternommen werden müssen als ein <?php print $form; ?>. Hier liegt aber auch die Krux, denn wirklich aufwändige Designs umzusetzen erfordert einen unverhältnismäßig hohen Aufwand zur Definition der oftmals für jedes Element individuellen Decorator.

Man kann aber auch den umgekehrten Weg gehen und das Formular “zu Fuss” programmieren und sich nur bei den benötigten Elementen des Formulars bedienen.
Genau das soll in diesem Beispiel geschehen, zusammen mit ein paar anderen Tricks und Kniffen.

Zuerst muss natürlich das Formular im Formbuilder Plugin gestaltet werden. Hierzu fügt man einfach die benötigten Form Elemente zusammen und stattet diese mit sinnvollen Validatoren zur Prüfung erlaubter Eingaben und Filtern zur Entfernung unerwünschter Inhalte aus.

Ist das Formular erstellt und gespeichert, kann man es im Controller seiner View zuweisen:

public function uploadAction () {
  $formbuilder = new Formbuilder_Frontend();
  $form = $formbuilder->getForm("onlinebewerbung");
  $this->view->form = $form;
}

In der View könnte man es nun theoretisch einfach nur ausgeben und die Ausgabe wäre damit erschöpfend behandelt:

<?php print $this->form; ?>

Hier wollen wir aber eingreifen und jedes Feld per Hand in individuellem HTML/PHP-Code ausgeben. Im Wesentlichen besteht ein Element hierfür aus den Komponenten Label, also der Feldbeschriftung, ViewHelper für die Darstellung des eigentlichen Eingabelemenents und dem Error für den Fall, das ein Validator eingreift.

Die Ausgabe erfolgt nun über entsprechende Methoden:

<?php $form = $this->form; ?>
<?php print $form->anrede->renderLabel() ?>  <?php print $form->anrede->renderViewHelper() ?><?php print $form->anrede->renderErrors() ?>

Was am Label nicht per Default dranhängt ist die Anzeige ob die Eingabe eines Feldes erforderlich ist. Der Label-Decorator kennt aber ein “requiredSuffix” mit dem man bestimmen kann, was das Label in diesem Fall rendern soll.

Nun muss man nur noch das ausgefüllte Formular verarbeiten. Dabei bedienen wir uns eines Tricks um die Code-Workflow übersichtlich und gering zu halten.
Wird die Seite einfach nur so (also per GET) aufgerufen, liegt in der Regel keine Wertübermittlung vor und das Formular soll nur ausgegeben werden.
Als action gibt man im form nun die URL des forms an – es ruft sich also selbst auf, vorzugsweise mit einem POST! Diesen POST kann man nun als Signal für die Weiterverarbeitung auswerten; if ($this->getRequest()->isPost()). Das Formular muss nun auf korrekte Eingabgen geprüft werden: if ($form->isValid($_POST)) {.
Bei dieser Prüfung setzt Zend_Form, falls nötig, die entsprechenden Fehlermeldungen. Nur bei erfolgreicher Prüfung verarbeitet man also weiter, kommt die Prüfung mit dem Ergebnis false zurück soll der Code wieder die Darstellung übernehmen – nur mit dem Unterschied, dass das Form mit den notwendigen Fehlermeldungen ausgestattet wurde, die nun mittels renderErrors() im View dargestellt werden.
War die Prüfung dagegen erfolgreich wird die Eingabe geeignet verarbeitet und die Ausführung auf einer Folgeseite mittels _redirect($url) fortgesetzt.

public function uploadAction () {
  $formbuilder = new Formbuilder_Frontend();
  $form = $formbuilder->getForm("onlinebewerbung");

  // Das Formular verarbeiten wenn es per POST übermittelt wurde
  if ($this->getRequest()->isPost()) {

    // Ist die Eingabe valide?
    if ($form->isValid($_POST)) {
      $values = $form->getValues(); // Alles OK, die Werte abholen

      // Hier nun was damit anfangen

      $this->_redirect("/danke"); // Redirect an die Folgeseite
      // Hier kommen wir nun nicht mehr hin!
    }
  }
  // Das Formular wird zum ersten Mal aufgerufen oder die Eingabe war nicht valide

  // Die Elemente, die ausgefüllt werden müssen,
  // mit einem "*" nach dem Label rendern
  foreach ($form->getElements() as $formelement) {
    $decorator = $formelement->getDecorator('label');
    if (is_object($decorator)) {
      $decorator->setOption('requiredSuffix',' *');
    }
  }
  $this->view->form = $form;
}

Ein paar Klippen gilt es vielleicht noch zu umschiffen. Das Element für Fileuploads kennt keine renderLabel() Methode, man kann es nur vollständig (inklusive Label) mit render() ausgeben lassen. Muss man gewisse Designvorgaben umsetzen und z.B. nach dem Label einen “:” ausgeben, kann man den Label-Decorator entsprechend konfigurieren:

foreach ($form as $element) {
  $label = $element->getDecorator("Label");
  if (is_object($label)) $label->setOption("separator", ":"); // nach jedem Label einen : rendern.
}

Auch lassen sich leider Captchas nicht “zerlegen” sondern nur komplett rendern, eigene Umsetzungen sind hier nur schwer möglich – dem widme ich aber noch einen eigenen Blogeintrag :-)

Eigene Viewhelper durch Plugins zur Verfügung stellen

Pimcore bietet Entwicklern die Möglichkeit, eigene View Helfer zu definieren und in Controllern und Views zu verwenden. Auch in Plugins ist dies mit ein paar einfachen Schritten möglich.

Das Plugin selbst kann keine Viewhelper registrieren, das muss in einem Controller geschehen.
Zu Demonstrationszwecken verwenden wir das fiktive “Bounce-Plugin”

Entweder man macht dies in dem Controller, der den Viewhelper braucht (auch ein Controller des Plugins ist möglich), oder global in Website_Controller_Action unter /website/lib/Website/Controller/Action.php in der init()-Methode:

  public function init() {
    parent::init();
    $this->view->addHelperPath(PIMCORE_PLUGINS_PATH . "/Bounceplugin/lib/Bounceplugin/View/Helper", "Bounceplugin_View_Helper_");
  }

Hier werden nun gleich zwei “magische” Prozesse vom Zend Framework vorbereitet, zum einen wird im Autoloader der Namespace Bounceplugin_View_Helper_ mit dem zugehörigen Pfad registriert, damit PHP beim Casten eines Objekts des betreffenden Viewhelpers die benötigte Klassendefinition laden kann.

Als Beispiel verwenden wir hier einen “Bounce”-Helper, der nichts anderes macht als den übergebenen Parameter zurückzugeben.

Der Viewhelper muss nun in /Bounceplugin/lib/Bounceplugin/View/Helper untergebracht werden, das File muss dabei “Bounce.php” heissen – der große Anfangsbuchstabe ist wichtig da der Autoloader das so erwartet. Der Klassenname setzt sich nun zusammen aus dem zuvor registrierten Namespace und dem Namen der gewünschten Methode, hier “bounce”. Der Methodenname muss, im Gegensatz zum Klassennamen, klein geschrieben werden.

class Bounceplugin_View_Helper_Bounce extends Zend_View_Helper_Abstract {

  public function bounce($input) {
    return $input;
  }
}

Das Casten selbst geschieht nun automatisch, sobald der Viewhelper in einer View benutzt wird.
Dies geschieht nun durch einfaches Aufrufen der Methode im $this-Kontext:

	$this->bounce("Das kommt wieder");

Zend Forms mit dem eingebauten Übersetzer in Pimcore verwenden

Die mit dem Zend Forms gebauten Formulare lassen sich bekanntlich mit Validatoren ausstatten, die bei einer Regelverletzung eine entsprechende Fehlermeldung ausgeben.
Diese lässt sich, mit einigem Aufwand, internationalisieren.

Pimcore liefert einen komfortablen Übersetzungs-Manager mit, den man für seine eigenen Zwecke verwenden kann – dieser lässt sich auch mit Zend Forms verbinden!

Dies geschieht mit ein paar einfachen Schritten, hier exemplarisch in Verbindung mit einem durch Alexandre Delattres Form Builder Plugin erzeugten Form:

$formbuilder = new Formbuilder_Frontend();
$form = $formbuilder->getForm("kontakt");
		
$locale = Zend_Registry::get("Zend_Locale");
$translate = new Pimcore_Translate($locale);
$form->setTranslator($translate);
$form->setDefaultTranslator($translate);

Mit diesem Code-Konstrukt landen nun alle Strings, die das Form ausgibt, im Übersetzer und können bearbeitet werden. Praktischerweise wird die noch nicht Variablen-bereinigte Version in die Liste eingestellt, so dass eine kontextbezogene Anpassung der Übersetzungen möglich ist.

Gegebenenfalls muss in der Zend-Registry noch die benötigte Locale hinterlegt werden.

Dies kann zum Beispiel in website/lib/Website/Controller/Action.php erfolgen:

try {
  $locale = Zend_Registry::get("Zend_Locale");
} catch (Exception $e) {
  $locale = new Zend_Locale("de");
  Zend_Registry::set("Zend_Locale", $locale);
}

Dies nur beispielhaft für Deutsch, bei einer Verwendung mit mehreren Sprachen muss hier natürlich flexibler Code verwendet werden.