Tech 26.09.2015 - 09:00 Uhr

Entwicklung eines Pimcore Plugins

Pimcore ist schon von sich aus ein sehr flexibles System. Mit den schon vorhandenen Mitteln sind wir problemlos in der Lage die meisten CMS und PIM Anforderungen zu erfüllen. In manchen Fällen macht 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.
  • Um in der GUI weite Funktionalitäten hinzuzufügen, um z. B. die Benutzung zu vereinfachen, oder Features hinzuzufügen.
  • Es werden individuelle Objectfelder, Bricks oder Editables gebraucht

 

Entwicklungsprozess

Das Entwickeln eines Pimcoreplugins ist ziemlich gradlinig - sobald man weiß, wo etwas hin gehö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.js
var 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 hinzurü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 Eventsystem benutzen

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

Das Eventziel, dass in der Callbackmethode übergeben wird, ist, je nach Eventtyp, 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 Fontendcontrollerplugin 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 Extensionpanel aktivieren, oder du benutzt die dontCheckEnabled Option, wenn du den Brick verwendest:

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

 

Ein neues Editable erstellen

Ein Editable zu erstellen bedarf einiger Schritte mehr, schau dir dazu das Beispiel Plugin an.

Schritt eins: 
Füge einen Inlcudepfad 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 Javascriptdatei, 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 Javascriptdatei in /YourPlugin/static/js/document/tags
(siehe /TestPlugin/static/js/document/tags/testeditable.js)

 

Ein neuen Objektdatenfeld 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 Objectfeldes.

Füge einen Includepfad der zum pluginIncludePaths Element in der plugin.xml hinzu 

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

Erstelle eine PHP Classe 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 das selbe 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 Javascriptdateien, mit jeweils dem selben 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 registrierten. 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 Pluginverzeichnis 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 dem selben Stand, den wir auf GitHub haben.

Dafür geht du bei GitHub auf die Settings des entsprechenden Repositorys. Wähle dort “Webhooks & Services” und füge dort “Packagist” hinzu. Gebe die verlangten Daten ein, klicke auf die “active” Checkbox. Danach ist auf der Übersichtseite 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!

Tim Jagodzinski
Software Engineer bei Basilicom
Igor Benko
Software Engineer bei Basilicom