Shopware 5.3 Backend Plugin 101 | First Steps

Sobald man nicht nur einen Service erweitert, sich auf ein Event hooked, oder das Frontend anpasst, kommt man schnell an den Punkt, in dem man sein Plugin auch im Backend abbilden möchte. In diesem Artikel möchte ich auf genau das eingehen…

ExtJs das Backend Framework

Ich spreche vermutlich den meisten Entwicklern aus der Seele, wenn ich sage, dass ExtJS ein „pain in the arse“ ist. Ich möchte hier nicht auf alle Punkte eingehen und verweise daher auf diesen Artikel

Was kommt als nächstes?

Nach Rückfrage bei Shopware habe ich vor kurzem die Info bekommen das VUE.JS noch nicht final als Backend Framework auserwählt wurde, aber es bereit eine erste Version in Shopware Labs gibt die man sich auch anschauen und probieren kann (hier mehr dazu)

Vue.js macht einen guten Eindruck (Vergleich zwischen Vue, Angular und React) – schön wäre es zeitnah zu Wissen auf was man sich einstellen kann, so kann man eventuell in anderen Projekten bereits mit Vue.js spielen und wird nicht ins kalte Wasser geworfen.

Backend Entwicklung mit ExtJS

Controller

In meinem Beispiel nutze ich Bug als meinen Controller/Model. Als erstes legen wir einen Controller für das Backend in unserer Pluginstruktur an. Wie immer befinden wir uns inst custom/plugins/MihoMeinPlugin – wir erstellen den Ordner Controllers/Backend

mkdir Controllers/Backend && cd Controllers/Backend && touch Bug.php

und fügen dort die Datei Bug.php

<?php

/**
 * Backend bug controller
 */
class Shopware_Controllers_Backend_Bug extends Shopware_Controllers_Backend_Application
{
	protected $model = 'MihoMeinPlugin\Models\Bug';
	protected $alias = 'bug';
}

mit dem obigen Inhalt.

Ich gehe davon aus, dass Ihr bereits ein Model erstellt hat, auf dieses greift Ihr später nämlich zu. ExtJS nutzt später die Resource in Models/Bug.php

menu.xml

Diese Datei brauchen wir um den Menüeintrag zu definieren – sie muss in Resources liegen:

touch Resources/menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/shopware/shopware/5.2/engine/Shopware/Components/Plugin/schema/menu.xsd">
    <entries>
        <entry>
            <name>Bugs</name>
            <label lang="en">Bug overview</label>
            <label lang="de">Bug Übersicht</label>
            <controller>Bug</controller>
            <action>index</action>
            <class>sprite-bug</class>
            <parent identifiedBy="controller">Customer</parent>
        </entry>
    </entries>
</menu>

Name und Label erklären sich denke ich von selbst – bei Controller tragt Ihr den jeweiligen Controller ein (in unserem Fall Bug) in action sollte immer index stehen (das ist euer Einstiegspunkt) in class setzt ihr das jeweilige Logo/Icon/Sprint (Liste der Sprites) und der parent tag sagt wo das ganze erscheinen soll – in unserem Fall im „Kunden“ Top Menu Punkt des Backends.

Backend Views

Ich habe in meinem Plugin die Template Registration auf Resources/views gelegt – daher lege ich den backend Ordner auch dort an

mkdir Resources/views/backend

darin befindet sich folgende Struktur:

Zu sehen sind hier die wichtigsten Files um die Grundfunktionalitäten eines eigenen Controllers/Models abzubilden.

app.js

Ext.define('Shopware.apps.Bug', {
    extend: 'Enlight.app.SubApplication',

    name:'Shopware.apps.Bug',

    loadPath: '{url action=load}',
    bulkLoad: true,

    controllers: [ 'Main' ],

    views: [
        'list.Window',
        'list.List',

        'detail.Container',
        'detail.Window'

    ],

    models: [ 'Bug' ],
    stores: [ 'Bug' ],

    launch: function() {
        return this.getController('Main').mainWindow;
    }
});

Eure Files sollten stehts den gleichen Appnamen ‚Shopware.apps.Bug….‘ haben, das hat bei mir Anfangs etwas für Verwirrung gesorgt.

controller

main.js

Ext.define('Shopware.apps.Bug.controller.Main', {
    extend: 'Enlight.app.Controller',

    init: function() {
        var me = this;
        me.mainWindow = me.getView('list.Window').create({ }).show();
    }
});

Auch in der main.js sieht man das, nur das noch controller und Main anhängt. Extended wird das ganze von Enlight.app.Controller

Hier wird auch der View aus dem Ordnern list aufgerufen (window.js).

view Ordner

list.js

Ext.define('Shopware.apps.Bug.view.list.List', {
    extend: 'Shopware.grid.Panel',
    alias:  'widget.bug-reporting-listing-grid',
    region: 'center',

    configure: function() {
        return {
            detailWindow: 'Shopware.apps.Bug.view.detail.Window',
            columns: {
                short_description: {  }
            }
        };
    }

});

Der View extended hier vom Shopware.grid.Panel, der alias ist nicht zwingend erforderlich und die region gibt den Ort des erscheinen des Fensters an (bei uns also in der Mitte des Browserfensters).

Interessant für uns schon hier die Konfigurationen – mit detailWindow geben wir den jeweiligen View an, welchen wir beim pressen von bearbeiten oder erstellen bekommen.

columns gibt an welche Datensätze wir im Listing sehen.

window.js

Ext.define('Shopware.apps.Bug.view.list.Window', {
    extend: 'Shopware.window.Listing',
    alias: 'widget.bug-reporting-list-window',
    height: 450,
    title : 'Bugs',

    configure: function() {
        return {
            listingGrid: 'Shopware.apps.Bug.view.list.List',
            listingStore: 'Shopware.apps.Bug.store.Bug'
        }


    }
});

detail/container.js

Ext.define('Shopware.apps.Bug.view.detail.Container', {
    extend: 'Shopware.model.Container',
    padding: 20,

    configure: function() {
        return {
        };
    }
});

Hier gibt es nicht wirklich viel zu sagen – hier wird einfach der Model Container extended und dann ein padding mitgegeben – es bestimmt es den inneren Abstand im Fenster zu den Input Feldern.

detail/window.js

Ext.define('Shopware.apps.Bug.view.detail.Window', {
    extend: 'Shopware.window.Detail',
    alias: 'widget.bug-reporting-detail-window',

    title : 'Bug Detailansicht',
    height: 420,
    width: 900
});

Auch hier wird lediglich ein extend zum SW Standard Window gesetzt und danach der Titel des Fensters sowie Höhe und Breite.

Das ganze sieht dann ungefähr so aus:

Ihr könnt die Erscheinung dieser Views ohne eine Neuinstallation anpassen, müsst dafür aber das Backend neuladen (F5 oder STRG +UMSCH + R)

model

Hier definieren wir einfach unser Model welches vom ‚Shopware.data.Model‘ erbt, setzen unseren Controller und bestimmen den Detail Container.

In fields bestimmen wir die genutzten Felder.

bug.js

Ext.define('Shopware.apps.Bug.model.Bug', {
    extend: 'Shopware.data.Model',

    configure: function() {
        return {
            controller: 'Bug',
            detail: 'Shopware.apps.Bug.view.detail.Container'
        };
    },


    fields: [
        { name : 'id', type: 'int', useNull: true },
        { name : 'short_description', type: 'string', useNull: false },
    ]


});

store.js

Ext.define('Shopware.apps.Bug.store.Bug', {
    extend:'Shopware.store.Listing',

    configure: function() {
        return {
            controller: 'Bug'
        };
    },
    model: 'Shopware.apps.Bug.model.Bug'
});

Die store.js benötigen wir, damit damit die Backend App weiß wohin alles gespeichert werden muss. Sie wird zum Beispiel in der app.js

stores: [ 'Bug' ],

genutzt oder in der window.js des list Views.

listingStore: 'Shopware.apps.Bug.store.Bug'

Nun müssen wir das Plugin neuinstallieren oder falls Ihr das noch nicht gemacht habt inital installieren.

Mögliche Errors

Aller Anfang ist schwer – oft kommt dieser Fehler zu Anfang:

SyntaxError / Unexpected Token <

In den meisten Fällen hat das mit der Namenskonvention vom Backend Controller (Controllers/Backend/MeinController.php) und dem Appnamen zu tun (Ext.define(‚Shopware.apps.Bug…….) – diese müssen übereinstimmen – selbst

Ext.define('Shopware.apps.Bug

und

class Shopware_Controllers_Backend_Bugs extends Shopware_Controllers_Backend_Application

funktioniert nicht.

That’s it – schon habt Ihr euer eigenes Backend Modul.Debuggen der ganzen Geschichte ist noch einmal etwas anderes – Shopware empfiehlt hier die Chrome Extension von Sencha. Ich wünsche euch in jedem Fall viel Erfolg.

8 Antworten auf „Shopware 5.3 Backend Plugin 101 | First Steps“

  1. „In den meisten Fällen hat das mit der Namenskonvention vom Backend Controller (Controllers/Backend/MeinController.php) und dem Appnamen zu tun (Ext.define(‚Shopware.apps.Bug…….) – diese müssen übereinstimmen – selbst“

    Kannst du das bitte genauer erklären, was genau übereinstimmen muss? Ich bekomme nämlich so einen Unexpected Token < Fehler.

    Ich habe in meiner javascript app.js Ext.define('Shopware.apps.Bug', {
    stehen.

    Was stimmt da jetzt nicht überein? Ich denke "Eure Files sollten stehts den gleichen Appnamen ‚Shopware.apps.Bug….‘ haben"
    Oder meinst du, dass der filename statt app.js Shopware.apps.Bug.js, Shopware.model.Bug.js usw heißen muss?

    1. Hi Jenny,
      ich war am Anfang etwas verwirrt und hatte nicht in jeder define die Beschreibung ‚Shopware.apps.Bug…‘ stehen. Das kann unter anderem zu diesem Error führen.

      Heißt dein Model und Controller auch Bug? Würde da auf jeden Fall etwas beschreibendes nehmen. An die Namen der app.js usw. musst du dich stehts halten. Vielleicht hilft dir das noch weiter https://developers.shopware.com/developers-guide/debugging/#extjs – dort auch als Tipp das du alle Files in der app.js registieren musst.

  2. Hallo Micha,

    ich nutze bezüglich Ext JS Debugging Sencha.
    Zuerst hatte ich Bug, habe das dann in Ticket geändert.
    ich versteh halt nicht, was an stelle der Punkte stehen müsste.
    Shopware.apps.Bug…
    Weil, oben im Code steht auch nichts anderes als bei mir.
    Shopware.apps.Bug.model.Bug

    Bei mir sieht das so aus
    Ext.define(‚Shopware.apps.GwenBackendExtension.model.Ticket‘, {…
    GwenBackendExtension ist mein Verzeichnisname unter Resources/backend/model und Ticket ist mein Model unter Models

    Ext.define(‚Shopware.apps.GwenBackendExtension.store.Ticket‘, { …
    ist bei mir ticket.js unter ../store. Bei dir steht aber store.js (?)

  3. Ich habe mal deine Original Struktur genommen und bekomme noch folgenden Error
    Unable to load template snippet ‚backend/bug/app.js‘ in engine/Library/Smarty/sysplugins/smarty_internal_templatebase.php on line 127

    obwohl die app.js unter /backend/bug/ liegt

  4. Hi,
    In shopware backend for products list, search is done using whole set of words , not by splitting words in word to check each word matching with product name, categories, suppliers. Is there possibility to search things by splitting search key words.

    Your help appreciable!

  5. Jut, dann kannste die Kommentare auch wieder löschen 🙂 Hilft ja so sonst keinem. Grüße aus Kölle. Und Danke für den Beitrag.

Schreibe einen Kommentar zu micha Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert