Entwicklung eines Pimcore-Plugins

Pimcore ist schon von sich aus ein sehr flexibles System. Mit den vorhandenen Mitteln sind wir problemlos in der Lage, die meisten CMS- und PIM-Anforderungen zu erfüllen. In manchen Fällen ergibt es allerdings Sinn, ein Plugin für Pimcore zu schreiben.

In der Regel aus folgenden Gründen:

  • Wir brauchen eine komplett neue Funktionalität, z. B. eine Integration mit anderen Systemen oder APIs.
  • Wir brauchen weitere Funktionalitäten in der GUI, um z. B. die Benutzung zu vereinfachen oder Features hinzuzufügen.
  • Wir brauchen individuelle Object-Felder, Bricks oder Editables.

Entwicklungsprozess

Das Entwickeln eines Pimcore-Plugins ist ziemlich geradlinig – sobald man weiß, wo etwas hingehört und welche Möglichkeiten man hat. Es gibt eine offizielle Dokumentation dazu, wir wollen dieses Thema allerdings ein wenig strukturierter angehen. Wir möchten Dich durch den gesamten Prozess führen. Vom Anfang bis zum fertigen Plugin, das auf GitHub und Packagist veröffentlicht wird.

Das Grundgerüst erstellen

Der erste Schritt könnte kaum einfacher sein. Gehe auf Extras > Extensions und klicke den „Create new plugin skeleton”-Button. Gib den Namen Deines Plugins ein, und schon ist Dein Grundgerüst fertig. In unserem Fall heißt es einfach „TestPlugin”. Nun musst Du es nur noch mit dem grünen Plusbutton aktivieren und Du bist startklar. Dieses Skelett bietet Dir schon eine Menge an Möglichkeiten an, um mit der Entwicklung zu beginnen. Wir werden allerdings genauer darüber schreiben, was möglich ist und wie wir es erreichen.

Pimcore erweitern

Wir wollen über sieben Wege reden, auf denen du Pimcore mit Plugins erweitern kannst. Natürlich gibt es noch anderen Wege, aber mit diesen sieben ist das meiste abgedeckt. Code zu allen Beispiel findest Du auf dem dazugehörigen Repository auf GitHub: https://github.com/basilicom/pimcore-TestPlugin

Das GUI im Backend anpassen

Das ist der einfachste Weg, um schnell ein Resultat zu sehen. Nicht ganz „Hello World”, aber fast! Wir fügen einen neuen Eintrag in das Extras-Menü ein!

(siehe: /TestPlugin/static/js/startup.js)

// Add this to pimcoreReady method of startup.jsvar sideNavigation = Ext.get("pimcore_navigation");var action = new Ext.Action({    id: "your_plugin_button",    text: t('Test plugin 1'),    iconCls: "TestPluginIcon",    handler: function(){        alert("Button clicked");    }});layoutToolbar.extrasMenu.add(action);
Wie wäre es damit, einen Button für die Toolbar im Dokumentenpanel hinzuzufügen? (Ähnlich geht das auch bei den Object- und Assetpanels.) Du musst dafür einfach nur eine postOpendocument-Methode zur startup.js hinzufügen.

(siehe: /TestPlugin/static/js/startup.js)

postOpenDocument: function(document, documentType) {    // Add button to a document panel    var tab = pimcore.globalmanager.get("document_" + document.id);    var toolbar = tab.toolbar;    var toolbarButton = new Ext.Button({        text: t("Test button"),        scale: "medium",        handler: function() {            alert("It works");        }    });    // Add the button to the end of the toolbar    toolbar.insert(tab.toolbar.items.length, toolbarButton);    toolbar.doLayout();}

Das Event-System benutzen

Es gibt mehr als 40 Events in Pimcore, an die Du Dich binden kannst. Dazu gibt es eine Übersicht in der Dokumentation.

Das Event-Ziel, das in der Callback-Methode übergeben wird, ist, je nach Event-Typ, unterschiedlich. Schau Dir dazu die init-Methode an.
In /TestPlugin/lib/TestPlugin/Plugin.php findest Du ein Beispiel, wie das system.startup-Event genutzt wird, um ein Frontend-Controller-Plugin hinzuzufügen.

Area Bricks hinzufügen

Area Bricks mit einem Plugin hinzuzufügen, ist in Pimcore Version 3.0 ziemlich einfach geworden. Füge dem Ordner /views/area einfach Deine gewünschten Bricks hinzu und sie werden automatisch geladen. Ein Beispiel findest Du in /TestPlugin/views/areas/testArea. Du musst diesen Brick dann zusätzlich im Extension-Panel aktivieren, oder Du benutzt die dontCheckEnabled-Option, wenn Du den Brick verwendest:

<?= $this->areablock("areablock", [    "allowed" => ["testArea"],    "dontCheckEnabled" => true]); ?>

Ein neues Editable erstellen

Um ein Editable zu erstellen, bedarf es einiger Schritte mehr, schau Dir dazu das Beispiel-Plugin an.

Schritt eins:
Füge einen Inlcude-Pfad zu den pluginIncludePaths in der plugin.xml hinzu.

<pluginIncludePaths>    <path>/TestPlugin/lib</path>    <path>/TestPlugin/lib/Pimcore/Model</path></pluginIncludePaths>

Schritt zwei:
Erstelle eine Tag Class in: /YourPlugin/lib/Pimcore/Model/Document/Tag/
(siehe /TestPlugin/lib/Pimcore/Model/Document/Tag/Testeditable.php)

Schritt drei:
Füge die Javascript-Datei, die wir gleich erstellen werden, in der plugin.xml hinzu. (Wichtig: Wenn das pluginDocumentEditmodeJsPaths-Element nicht vorhanden ist, füge es einfach selbst hinzu.)

<pluginDocumentEditmodeJsPaths>    <!-- Document Editable -->    <path>/TestPlugin/static/js/document/tags/testeditable.js</path></pluginDocumentEditmodeJsPaths>

Nun erstelle eine Javascript-Datei in /YourPlugin/static/js/document/tags
(siehe /TestPlugin/static/js/document/tags/testeditable.js)

Ein neues Objekt-Datenfeld erstellen

Um ein neues Datenfeld für ein Objekt zu erstellen, brauchst Du drei Dateien. Die Object Class Definition (PHP), eine Object Data Class (JS) – sie übernimmt die Kommunikation zwischen dem Backend und dem Frontend –und eine Object Tag Class (JS) – diese kümmert sich um die GUI des Object-Feldes.

Füge einen Include-Pfad zum pluginIncludePaths-Element in der plugin.xml hinzu.

<pluginIncludePaths>    <path>/TestPlugin/lib</path>    <path>/TestPlugin/lib/Pimcore/Model</path></pluginIncludePaths>

Erstelle eine PHP-Class für das Object-Feld in: /YourPlugin/lib/Pimcore/Model/Object/ClassDefinition/Data
(siehe /TestPlugin/lib/Pimcore/Model/Object/ClassDefinition/Data/Testobjectfield.js).

Füge beide Javascripts der plugins.xml hinzu (Wichtig: Das ist nicht dasselbe Element, das ein Dokument-Editable benutzen würde.):

<pluginJsPaths>    <path>/plugins/TestPlugin/static/js/startup.js</path>    <!-- Object field →    <path>/TestPlugin/static/js/object/classes/data/testobjectfield.js</path>    <path>/TestPlugin/static/js/object/classes/tags/testobjectfield.js</path></pluginJsPaths>

Erstelle zwei Javascript-Dateien mit jeweils demselben Namen unter den Pfaden, die Du im vorherigen Schritt eingefügt hast (siehe /TestPlugin/static/js/object/classes/data/testobjectfield.js & /TestPlugin/static/js/object/classes/tags/testobjectfield.js).

Ein Front-Controller-Plugin erstellen

Front Controller können sehr nützlich sein, wenn es um Authentifizierungen geht, oder wenn man eine HTML-Antwort verändern oder etwas in sie injecten will. Zuerst müssen wir das Front-Controller-Plugin registrieren. Das geschieht beim system.startup-Event in der Plugin.php init()-Methode.

// Register front controller plugin\Pimcore::getEventManager()->attach("system.startup", function ($event) {    $front = \Zend_Controller_Front::getInstance();    $frontControllerPlugin = new FrontControllerPlugin();    $front->registerPlugin($frontControllerPlugin);});

Danach erstellen wir eine neue Klasse, diese muss \Zend_Controller_Plugin_Abstract erweitern (siehe /TestPlugin/lib/TestPlugin/FrontControllerPlugin.php).

namespace TestPlugin;use Pimcore\Tool;class FrontControllerPlugin extends \Zend_Controller_Plugin_Abstract{    public function routeStartup() { // Do something here }    public function routeShutdown() { // Do something here }    public function dispatchLoopStartup() { // Do something here }    public function preDispatch() { // Do something here }    public function postDispatch() { // Do something here }     public function dispatchLoopShutdown() { // Do something here }}

Eine Antwort modifizieren

Wir können nun eine Antwort durch unser Plugin modifizieren. Wir erweitern das vorherige Beispiel und injecten Inhalt am Anfang des HTML-Bodys (siehe /TestPlugin/lib/TestPlugin/FrontControllerPlugin.php).

public function dispatchLoopShutdown() {    if (Tool::isFrontend()) {            $contentToInject = "<h1>This is content injected by TestPlugin</h1>";            $response = $this->getResponse();            $body = $response->getBody();            $bodyTagPosition = stripos($body, "<body>");            if($bodyTagPosition !== false) {                $body = substr_replace($body, "<body>\n" . $contentToInject, $bodyTagPosition, 7);            }            $response->setBody($body);        }  }

Das Plugin auf Packagist veröffentlichen

Unser Plugin ist fertig. Wir müssen unsere Änderungen nur auf GitHub pushen, um es auf Packagist veröffentlichen zu können. Es ist vermutlich eine gute Idee, Deinen Commit mit einer Versionsnummer zu taggen.

Erstelle eine composer.json-Datei. Gehe in dein Plugin-Verzeichnis und erstelle ein Git-Repository, falls Du das noch nicht getan hast. In unserem Fall tun wir Folgendes:

cd plugins/TestPlugin/git init# Create a repository on github# Create a tag 1.0.0 (semantic versioning - http://semver.org/)# git add remote ....# git push ......

Damit sind wir fertig! Wir pushen unsere Änderungen auf GitHub und fügen das Repo auf Packagist hinzu. Danach solltest Du in Deinem GitHub-Account noch den Packagist-Servicehook einrichten. Dieser hält die Dateien auf Packagist auf demselben Stand, den wir auf GitHub haben.

Dafür gehst Du bei GitHub auf die Settings des entsprechenden Repositories. Wähle dort „Webhooks & Services” und füge dort „Packagist” hinzu. Gib die verlangten Daten ein, klicke auf die „active”-Checkbox. Danach ist auf der Übersichtsseite des Services ein Button „Test Service” sichtbar. Den klickst du einmal und Packagist registriert den Hook (oder etwas geht schief ;)).

Hier findest Du unser TestPlugin: https://packagist.org/packages/basilicom-pimcore-plugin/test-plugin

Dein Plugin ist jetzt bereit, die Welt zu erobern!