Commit a8bb6e0a authored by oskar's avatar oskar Committed by Falk@JTL
Browse files

docs proofreading

parent 170f1b7b
......@@ -15,7 +15,7 @@ extensions = [
source_suffix = '.rst'
master_doc = 'index'
project = 'JTL-Shop'
copyright = u'2010-2019, JTL-Software GmbH'
copyright = u'2010-2020, JTL-Software GmbH'
version = ''
release = ''
exclude_patterns = []
......
......@@ -5,110 +5,114 @@ Allgemein
<br />
Das Pluginsystem im JTL-Shop ermöglicht es, verschiedene Arten von Zusatzfunktionalitäten hinzuzufügen,
ohne den Shop-Core-Code zu modifizieren. Dadurch bleibt der Shop jederzeit updatefähig.
Das Pluginsystem von JTL-Shop ermöglicht es, verschiedene Arten von Zusatzfunktionalitäten hinzuzufügen,
ohne den Core-Code von JTL-Shop zu modifizieren. Dadurch bleibt JTL-Shop jederzeit updatefähig.
Plugins werden vom Shopbetreiber/Admin installiert. |br|
Die Installation besteht aus dem Hochladen des Plugins in das für Plugins vorgesehene Verzeichnis
``<Shop-Root>/includes/plugins/`` (bei Shop Versionen 4+), bzw. das Verzeichnis ``<Shop-Root>/plugins/``
``<Shop-Root>/includes/plugins/`` (bei Shop-Versionen 4+), bzw. das Verzeichnis ``<Shop-Root>/plugins/``
(bei Shop Versionen 5+) und anschließender Installation über die Pluginverwaltung im Adminbereich des Shops.
In der Pluginverwaltung können installierte Plugins außerdem *temporär deaktiviert* bzw. *permanent deinstalliert* werden.
Die Funktionen der Pluginverwaltung können im laufenden Shopbetrieb genutzt werden. |br|
In der Pluginverwaltung können installierte Plugins außerdem *temporär deaktiviert* bzw. *permanent deinstalliert*
werden. Die Funktionen der Pluginverwaltung können im laufenden Shopbetrieb genutzt werden. |br|
Weiterhin können Plugins optional durch eine Lizenzprüfung geschützt werden.
Es gibt viele Arten von Plugins, die verschiedenste Aufgaben im JTL-Shop wahrnehmen können:
Es gibt viele Arten von Plugins, die verschiedenste Aufgaben in JTL-Shop wahrnehmen können:
* Plugins, die im Shopfrontend sichtbare oder unsichtbare Funktionen ausführen ("*Frontend-Links*")
* Plugins, die nur im Shop-Backend spezielle Funktionen zur Verfügung stellen, wie z.B. Auswertungen und
* Ausführen sichtbarer oder unsichtbarer Funktionen im Frontend von JTL-Shop ("*Frontend-Links*")
* Bereitstellung spezieller Funktionen im Backend on JTL-Shop, wie z. B. Auswertungen und
Statistiken ("*Custom-Links*")
* neue Zahlungsmethoden bereitstellen als "Zahlungsarten-Plugin"
* neue Boxen für das Frontend bereitstellen ("Boxenverwaltung")
* Plugins, die neue E-Mail-Vorlagen in den Shop integrieren
* Bereitstellung neuer Zahlungsmethoden als "Zahlungsarten-Plugin"
* Bereitstellung neuer Boxen für das Frontend von JTL-Shop ("Boxenverwaltung")
* Integration neuer E-Mail-Vorlagen in JTL-Shop
* und vieles mehr
Ein Plugin kann *eine* dieser Aufgaben oder *eine Kombination* davon erfüllen.
Das Pluginsystem arbeitet mit Hilfe von :doc:`Hooks </shop_plugins/hooks>`, die im Shop-Code an verschiedenen Stellen
hinterlegt sind. |br|
Das Pluginsystem arbeitet mit Hilfe von :doc:`Hooks </shop_plugins/hooks>`, die im Code von JTL-Shop an verschiedenen
Stellen hinterlegt sind. |br|
Ein Plugin kann einen oder mehrere Hooks nutzen, um eigenen Code an diesen Stellen auszuführen.
.. hint::
Sind mehrere Plugins installiert, die dieselben Hooks nutzen, so wird der Code *jedes* Plugins an dieser Stelle
ausgeführt, in der zeitlichen Reihenfolge, wie die Plugins installiert wurden.
Sind mehrere Plugins installiert, die dieselben Hooks nutzen, wird der Code *jedes* Plugins an dieser Stelle
ausgeführt, und zwar in der zeitlichen Reihenfolge, wie die Plugins installiert wurden.
Plugins sind *versioniert*, wodurch sie updatefähig bleiben. |br|
Plugin-updates können das Plugin um neue Funktionalität und/oder Fehlerbehebungen bereichern.
Pluginupdates können neue Funktionalitäten und/oder Fehlerbehebungen enthalten.
Die Pluginverwaltung erkennt automatisch, nach dem Upload der neuen Plugindaten, im Pluginverzeichnis des Shops,
dass eine neue Version des Plugins vorhanden ist und bietet einen Update-Button an. |br|
Ein Update eines Plugins wird vom Shopbetreiber selbst durchgeführt, die Prozedur ist analog zur Installation. |br|
Das Update eines Plugins wird vom Shopbetreiber selbst durchgeführt, die Prozedur ist analog zur Installation. |br|
Nach dem Upload einer neuen Pluginversion in das Pluginverzeichnis des Onlineshops, erkennt die Pluginverwaltung
automatisch, daß eine neue Version des Plugins vorhanden ist und bietet einen Update-Button an. |br|
Nach dem Klicken des Update-Buttons wird das Plugin automatisch auf die neue Version aktualisiert. Das aktualisierte
Plugin ist nach dem Update direkt aktiviert.
Plugins können eine Mindestversion des Shops voraussetzen. |br|
Da das Shopsystem bei einem Shop-Update um neue Funktionen bereichert werden kann, können Plugins z.B. diese neuen
Funktionen erweitern oder darauf zugreifen. Dies würde in einer älteren Shopversion nicht funktionieren und ggf. zu
Fehlern führen.
Plugins benötigen ggf. eine Mindestversion des Onlineshops. |br|
Da das Onlineshopsystem bei einem Update des Onlineshops um neue Funktionen bereichert werden kann, können Plugins
z. B. diese neuen Funktionen erweitern oder darauf zugreifen. Dies würde in einer älteren Version des Onlineshops
nicht funktionieren und ggf. zu Fehlern führen.
Das Herzstück jedes Plugins ist die XML Datei ``info.xml``, die das Plugin beschreibt. |br|
Diese XML-Datei muss auch eine Mindest-XML-Strukturversion angeben, damit die vom Plugin beschriebene Funktionalität
auch tatsächlich vom Shop interpretiert werden kann. Durch die Plugin-XML-Version bleibt somit das Pluginsystem selbst
erweiterbar. |br|
So wurde z.B. in JTL-Shop 3.04 diese XML-Struktur um selbst definierte Emailvorlagen erweitert, die ein Plugin über die
XML-Version automatisch erstellen und versenden kann.
auch tatsächlich von JTL-Shop interpretiert werden kann. Durch die Plugin-XML-Version bleibt somit das Pluginsystem
selbst erweiterbar. |br|
So wurde z. B. in JTL-Shop 3.04 diese XML-Struktur um selbst definierte E-Mail-Vorlagen erweitert, die ein Plugin über
die XML-Version automatisch erstellen und versenden kann.
Ein JTL-Shop kann mehrsprachig betrieben werden. |br|
Eine im Pluginsystem integrierte Sprachvariablenverwaltung ermöglicht es Plugins, Daten in beliebig vielen Sprachen
lokalisiert auszuliefern. |br|
Durch die im Pluginsystem integrierte Sprachvariablenverwaltung können Daten in beliebig vielen Sprachen
lokalisiert ausgeliefert werden. |br|
Die Pluginverwaltung ermöglicht dem Shopbetreiber zudem, alle Sprachvariablen für die eigenen Anforderungen anzupassen.
Sprachvariablen können weiterhin vom Shopbetreiber auch jederzeit in den Installationszustand zurückgesetzt werden. |br|
Sobald ein Plugin mehr Sprachen mitliefert als im Shopsystem vorhanden sind, werden auch nur diese vom Shopsystem
installiert. Liefert ein Plugin andererseits Sprachvariablen in weniger Sprachen aus, als der Shop aktuell aktiviert
hat, so werden die Sprachvariablen der sonstigen Sprachen mit der Standardsprache ausgefüllt.
Sprachvariablen können weiterhin vom Shopbetreiber jederzeit auf den Installationszustand zurückgesetzt werden. |br|
Wenn ein Plugin mehr Sprachen mitliefert als im Onlineshopsystem vorhanden sind, werden nur die im System vorhandenen
Sprachen installiert. Liefert ein Plugin andererseits Sprachvariablen in weniger Sprachen aus als aktuell im Onlineshop
aktiviert sind, werden die Sprachvariablen der sonstigen Sprachen mit der Standardsprache ausgefüllt.
Pluginverwaltung im Shop-Backend
--------------------------------
Pluginverwaltung im Backend von JTL-Shop
----------------------------------------
Die Pluginverwaltung ist der zentrale Punkt im Shop-Backend, wo Plugins installiert/deinstalliert,
Die Pluginverwaltung ist der zentrale Ort im Backend von JTL-Shop, an dem Plugins installiert/deinstalliert,
aktiviert/deaktiviert, aktualisiert oder konfiguriert werden können.
Ab JTL Shop 5 trägt sie den Namen "Plugin-Manager".
Bei einer Plugin-Deinstallation werden Plugin-Einstellungen und eventuell zusätzlich durch das Plugin geschriebene
Tabellen gelöscht. Anders bei der Plugin-Deaktivierung: Hier bleiben Plugin-Einstellungen und -Tabellen erhalten,
das Plugin wird jedoch nicht weiter ausgeführt.
Bei der *Deinstallation* eines Plugins werden Plugineinstellungen und eventuell zusätzlich durch das Plugin
geschriebene Tabellen gelöscht. Anders bei der *Deaktivierung* eines Plugins: Hier bleiben Plugineinstellungen
und -tabellen erhalten, das Plugin wird jedoch nicht weiter ausgeführt.
.. important::
Deinstallierte Plugins verlieren nicht nur alle eigenen Einstellungen und alle Sprachvariablen, es werden auch
alle Datenbanktabellen des Plugins gelöscht! |br|
Deaktivierte Plugins werden vom Shopsystem nicht geladen und verbrauchen keine Systemressourcen.
Deaktivierte Plugins werden vom Onlineshopsystem nicht geladen und verbrauchen keine Systemressourcen.
Plugin-Installation
"""""""""""""""""""
Die Installation von Plugins besteht aus zwei Schritten und kann im laufenden Betrieb des Shops vorgenommen werden:
Die Installation von Plugins besteht aus zwei Schritten. Sie können diese im laufenden Betrieb des Onlineshops
vornehmen.
1. Upload des Plugins |br|
1. Laden Sie das Plugin hoch: |br|
**ab Shop Version 4.x** in das Verzeichnis ``includes/plugins/``, |br|
**ab Shop Version 5.x** in das Verzeichnis ``plugins/`` |br|
(Der Upload erfolgt in "ausgepackter" Form. Dateiarchive, wie z.B. ``*.zip`` oder ``*.tgz``,
(Der Upload erfolgt in "ausgepackter" Form. Dateiarchive, wie z. B. ``*.zip`` oder ``*.tgz``,
werden *nicht unterstützt*.)
2. Auslösen der Installation im Backend, über den Menüpunkt "*Pluginverwaltung*", im Reiter "*Vorhanden*". |br|
2. Starten Sie die Installation im Backend über den Menüpunkt "*Pluginverwaltung*" im Reiter "*Vorhanden*". |br|
Die Installation läuft vollautomatisch ab.
Plugin-Konfiguration
""""""""""""""""""""
Jedes Plugin, in JTL-Shop, erhält nach der Installation einen eigenen Eintrag in der Pluginverwaltung. |br|
Den Inhalt hinter diesem Eintrag kann das Plugin selbst bestimmen.
Jedes Plugin kann beliebig viele *Custom Links* (Links, die eigenen Code ausführen und eigenen Inhalt produzieren) und
*Setting Links* (Links, die Einstellungen zum Plugin enthalten) definieren.
Eigene Einstellungen kann ein Plugin zwar auch selbst über einen *Custom Link* abfragen und abspeichern,
jedoch bieten *Setting Links* eine Methode die sehr viel schneller und sicherer ist, um Einstellungen zu hinterlegen und
abzufragen. |br|
Insbesondere wird der Zugriff auf diese Einstellungen im eigenen Plugin-Code stark vereinfacht, das Look&Feel
von Einstellungen im Shop bleibt erhalten und man spart viel Programmcode, da benötigte Einstellungen
über *Setting Links* einfach in der XML Datei des Plugins hinterlegt werden können - kein weiterer Code ist
hierbei notwendig!
Jedes Plugin in JTL-Shop erhält nach der Installation einen eigenen Eintrag in der Pluginverwaltung. |br|
Der hier angezeigte Name entspricht dem Inhalt des Tags ``<Description>`` in der ``info.xml`` des jeweiligen Plugins
und stellt somit den textuellen Namen dieses Plugins dar.
Jedes Plugin kann beliebig viele *Custom Links* und *Setting Links* definieren. |br|
*Custom Links* sind Links, die eigenen Code ausführen und eigenen Inhalt produzieren. |br|
*Setting Links* enthalten Einstellungen zum Plugin.
Plugins können eigene Einstellungen über einen *Custom Link* abfragen und abspeichern.
Schneller und sicherer können Einstellungen jedoch über *Setting Links* hinterlegt und
abgefragt werden. |br|
Insbesondere wird der Zugriff auf diese Einstellungen im eigenen Code des Plugins stark vereinfacht und das Look&Feel
von Einstellungen im Shop bleibt erhalten. Zudem wird viel Programmcode gespart, da benötigte Einstellungen
über *Setting Links* einfach in der XML-Datei des Plugins hinterlegt werden können.
Hierbei ist kein weiterer Code notwendig!
This diff is collapsed.
......@@ -5,14 +5,14 @@ Bootstrapping
<br />
Bootstrapping bezeichnet im Kontext des JTL-Shops die Initialisierung eines Plugins zur anschließenden Nutzung
Bootstrapping bezeichnet im Kontext von JTL-Shop die Initialisierung eines Plugins zur anschließenden Nutzung
des *EventDispatchers*.
Struktur
--------
Zentraler Einstiegspunkt des Bootstrappers ist die Datei ``Bootstrap.php`` im Hauptverzeichnis eines Plugins. |br|
In dieser Datei muss die Klasse ``Bootstrap``, im *namespaces* des Plugins, angelegt werden und diese muss
In dieser Datei muss die Klasse ``Bootstrap`` im *namespaces* des Plugins angelegt werden und diese muss
das Interface ``JTL\Plugin\BootstrapperInterface`` implementieren.
Das Interface sieht wie folgt aus:
......@@ -108,47 +108,46 @@ Das Interface sieht wie folgt aus:
.. danger::
Die Methode ``boot()``, der Klasse ``Bootstrap``, sollte ausschließlich dazu dienen, Hooks zu registrierten. |br|
Da dieser Methode eine zentrale Bedeutung zukommt - **sie wird bei jeden Frontend- UND Backend-Aufruf
aufgerufen** - kann ein Fehler in ``boot()`` dazu führen, dass das komplette Backend (und somit auch die
Die Methode ``boot()`` der Klasse ``Bootstrap`` sollte ausschließlich dazu dienen, Hooks zu registrierten. |br|
Dieser Methode kommt eine zentrale Bedeutung zu: **Sie wird bei jedem Frontend- UND Backend-Aufruf
aufgerufen.** Ein Fehler in ``boot()`` kann deshalb dazu führen, dass das komplette Backend (und somit auch die
Möglichkeit, das fehlerhafte Plugin zu deinstallieren) versperrt ist.
Beispiele hierfür wären Programmierfehler (z.B.: Endlosschleifen), nicht antwortende Server von Drittanbietern
Beispiele hierfür wären Programmierfehler wie Endlosschleifen, nicht antwortende Server von Drittanbietern
und dergleichen. |br|
**Ein "Stop" der Applikation an dieser Stelle stoppt auch die Administrationsobfläche!**
**Ein "Stopp" der Applikation an dieser Stelle stoppt auch die Administrationsobfläche!**
Implementierbare Methoden
"""""""""""""""""""""""""
+-------------------------------------------------------------------------+----------------------------------------------------------------------------------+
| Methode | Hinweis zur Implementierung |
+=========================================================================+==================================================================================+
| ``installed()`` | wird unmittelbar nach der Installation eines Plugins aufgerufen |br| |
| | und bietet sich daher für Logik an, die einmalig ausgeführt werden muss |br| |
| | aber für Migrationen ungeeignet ist. |
+-------------------------------------------------------------------------+----------------------------------------------------------------------------------+
| ``updated($oldVersion, $newVersion)`` | wird nach der Aktualisierung eines Plugins über das Shopbackend ausgeführt |
+-------------------------------------------------------------------------+----------------------------------------------------------------------------------+
| ``enabled()`` | wird ausgeführt, nachdem ein Plugin aktiviert wurde |
+-------------------------------------------------------------------------+----------------------------------------------------------------------------------+
| ``disabled()`` | wird ausgeführt, nachdem es deaktiviert wurde |
+-------------------------------------------------------------------------+----------------------------------------------------------------------------------+
| ``uninstalled(bool $deleteData = true)`` | wird ausgeführt, nachdem ein Plguin im Backend komplett deinstalliert wurde |
+-------------------------------------------------------------------------+----------------------------------------------------------------------------------+
| ``boot(Dispatcher $dispatcher)`` | wird möglichst früh im Verlauf eines jeden Requests im Shop aufgerufen. |br| |
| | (sowohl im Kontext des Front- und Backends als auch während eines |br| |
| | Wawi-Abgleichs) |
+-------------------------------------------------------------------------+----------------------------------------------------------------------------------+
| ``uninstalled(bool $deleteData = true)`` | wird ausgeführt, nachdem ein Plguin im Backend komplett deinstalliert wurde |br| |
| | Falls der Parameter TRUE ist, wünscht der Nutzer, dass Plugindaten |br| |
| | nicht permanent gelöscht werden sollen (bspw. Datenbanktabellen). |
+-------------------------------------------------------------------------+----------------------------------------------------------------------------------+
| ``renderAdminMenuTab(string $tabName, int $menuID, JTLSmarty $smarty)`` | Kann genutzt werden, um HTML-Code für eigene Plugin-Tabs auszugeben, |br| |
| | beispielsweise via ``$smarty->fetch()`` |
+-------------------------------------------------------------------------+----------------------------------------------------------------------------------+
| ``prepareFrontend(LinkInterface $link, JTLSmarty $smarty)`` | Kann gentutz werden, um in Smarty eigene Variablen vor der Anzeige von |br| |
| | Sollte in diesem Fall TRUE zurückgeben. |
+-------------------------------------------------------------------------+----------------------------------------------------------------------------------+
+-------------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| Methode | Hinweis zur Implementierung |
+=========================================================================+===================================================================================+
| ``installed()`` | Wird unmittelbar nach der Installation eines Plugins aufgerufen. |br| |
| | Bietet sich daher für Logik an, die einmalig ausgeführt werden muss, |br| |
| | aber für Migrationen ungeeignet ist. |
+-------------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| ``updated($oldVersion, $newVersion)`` | Wird nach der Plugin-Aktualisierung über das Backend von JTL-Shop ausgeführt. |
+-------------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| ``enabled()`` | Wird ausgeführt, nachdem ein Plugin aktiviert wurde. |
+-------------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| ``disabled()`` | Wird ausgeführt, nachdem ein Plugin deaktiviert wurde. |
+-------------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| ``boot(Dispatcher $dispatcher)`` | Wird möglichst früh im Verlauf eines jeden Requests in JTL-Shop aufgerufen |br| |
| | (sowohl im Kontext des Front- und Backends als auch während eines |br| |
| | Abgleich mit JTL-Wawi). |
+-------------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| ``uninstalled(bool $deleteData = true)`` | Wird ausgeführt, nachdem ein Plugin im Backend komplett deinstalliert wurde. |br| |
| | Falls der Parameter TRUE ist, wünscht der Nutzer, dass Plugin-Daten |br| |
| | permanent gelöscht werden sollen (bspw. Datenbanktabellen). |
+-------------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| ``renderAdminMenuTab(string $tabName, int $menuID, JTLSmarty $smarty)`` | Kann genutzt werden, um HTML-Code für eigene Plugin-Tabs auszugeben, |br| |
| | beispielsweise via ``$smarty->fetch()``. |
+-------------------------------------------------------------------------+-----------------------------------------------------------------------------------+
| ``prepareFrontend(LinkInterface $link, JTLSmarty $smarty)`` | Kann genutzt werden, um in Smarty eigene Variablen vor der Anzeige von |br| |
| | *Fontend Links* zu definieren. |br| |
| | Sie sollte in diesem Fall TRUE zurückgeben. |
+-------------------------------------------------------------------------+-----------------------------------------------------------------------------------+
.. _label_bootstrapping_eventdispatcher:
......@@ -160,7 +159,7 @@ zu Hooks anbieten. |br|
Im Vergleich zu den via ``info.xml`` registrierten Hooks können *EventListener* dynamisch generiert werden.
Jeder Hook erzeugt automatisch ein Event mit dem Namen ``shop.hook.<HOOK-ID>``. |br|
Um also beispielsweise den Hook ``HOOK_ARTIKEL_CLASS_FUELLEARTIKEL`` zu nutzen, lässt sich folgendes
Um also beispielsweise den Hook ``HOOK_ARTIKEL_CLASS_FUELLEARTIKEL`` zu nutzen, lässt sich Folgendes
innerhalb der ``boot()``-Methode schreiben:
.. code-block:: php
......@@ -169,13 +168,12 @@ innerhalb der ``boot()``-Methode schreiben:
$args['oArtikel']->cName = 'Neuer Name';
});
Dies hat den Vorteil, dass der Listener nur in Abhängigkeit einer Plugin-Option registriert werden kann und somit,
anders als bei statischen Hooks, die in der ``info.xml`` registriert wurden, der Hook nicht immer ausgeführt
wird. |br|
Dies hat den Vorteil, dass der Listener nur in Abhängigkeit einer Plugin-Option registriert werden kann. Somit wird
der Hook, anders als bei statischen Hooks, die in der ``info.xml`` registriert wurden, nicht immer ausgeführt.|br|
Auch muss so der objektorientierte Kontext des Bootstrappers nicht verlassen werden, während Hooks jeweils nur
PHP-Dateien mit funktionalem Code aufrufen können.
Ab Shop Version 5.0 kann zudem auch die Priorität, ähnlich dem Hook-Knoten ``<priority>`` der ``info.xml``, als
Ab JTL-Shop 5.0 kann zudem auch die Priorität, ähnlich dem Hook-Knoten ``<priority>`` der ``info.xml``, als
dritter Parameter angegeben werden:
.. code-block:: php
......@@ -194,7 +192,7 @@ dritter Parameter angegeben werden:
);
}
(siehe auch Abschnitt "Die info.xml", :ref:`label_infoxml_hooks`)
Siehe auch Abschnitt "Die info.xml", :ref:`label_infoxml_hooks`.
Innerhalb des Bootstrappers hat man via ``$this->getPlugin()`` immer Zugriff auf die Instanz des Plugins,
Innerhalb des Bootstrappers haben Sie via ``$this->getPlugin()`` immer Zugriff auf die Instanz des Plugins,
via ``$this->getDB()`` auf die Datenbank, sowie via ``$this->getCache()`` auf den Objektcache.
......@@ -6,13 +6,13 @@ Cache
<br />
Über die Klasse ``JTLCache`` bzw. ``JTL\Cache\JTLCache`` sowie die zugehörigen Backend-Klassen
in ``<Shop-Root>/classes/CachingMethods/`` bzw. ``<Shop-Root>/includes/src/Cache/Methods/`` wird seit Shop 4 ein Objektcache bereitgestellt,
welcher auch in Plugins genutzt werden kann.
in ``<Shop-Root>/classes/CachingMethods/`` bzw. ``<Shop-Root>/includes/src/Cache/Methods/`` wird seit JTL-Shop 4 ein
Objektcache bereitgestellt, welcher auch in Plugins genutzt werden kann.
Die Konfiguration erfolgt im Backend über den Menüpunkt "*System -> Cache*" (Shop bis Version 4.x) und
"*Einstellungen -> Cache*" (ab Shop Version 5.x).
Die Konfiguration erfolgt im Backend über den Menüpunkt "*System -> Wartung -> Cache*" (bis JTL-Shop 4.x) und
"*System -> Cache*" (ab JTL-Shop 5.x).
Standardmäßig unterstützt der Shop die folgenden Caching-Mechanismen:
Standardmäßig unterstützt JTL-Shop die folgenden Caching-Methoden:
* Redis
* Memcache(d)
......@@ -37,13 +37,13 @@ Die zur Verfügung stehenden Standard-Gruppen lauten:
+--------------------------------+--------------------------------+
| ``CACHING_GROUP_TEMPLATE`` | Templates und Templateoptionen |
+--------------------------------+--------------------------------+
| ``CACHING_GROUP_OPTION`` | allgemeine Optionen |
| ``CACHING_GROUP_OPTION`` | Allgemeine Optionen |
+--------------------------------+--------------------------------+
| ``CACHING_GROUP_PLUGIN`` | Plugins und Optionen |
+--------------------------------+--------------------------------+
| ``CACHING_GROUP_CORE`` | wichtige Core-Daten |
| ``CACHING_GROUP_CORE`` | Wichtige Core-Daten |
+--------------------------------+--------------------------------+
| ``CACHING_GROUP_OBJECT`` | allgemeine Objekte |
| ``CACHING_GROUP_OBJECT`` | Allgemeine Objekte |
+--------------------------------+--------------------------------+
| ``CACHING_GROUP_BOX`` | Boxen |
+--------------------------------+--------------------------------+
......@@ -61,13 +61,13 @@ Wenn ein beliebiges Datum unter einer eindeutigen ID gespeichert wird, ist es sc
invalidieren.
Entweder müsste dazu die genaue ID bekannt sein oder es müssten sämtliche Einträge auf einmal gelöscht werden.
Letzteres würde zu einem sehr häufigen Neuaufbau des Caches führen. Andererseit müssen Cache-IDs aber so genau wie
Letzteres würde zu einem sehr häufigen Neuaufbau des Caches führen. Andererseits müssen Cache-IDs aber so genau wie
möglich sein. Falls beispielsweise eine Produktobjekt im Cache gespeichert werden soll, hängen dessen Daten von
verschiedenen Faktoren wie aktueller Sprache, Kundengruppe etc. ab.
Haben sich, z.B. durch Synchronisation mit der Wawi, Produktdaten geändert, muss dieser Eintrag nun aber invalidiert
werden. Entweder, indem alle Cache-IDs gelöscht werden, oder indem alle zulässigen Werte einzeln gelöscht werden.
So müsste man also für alle Sprachen und alle Kundengruppen Cache-IDs generieren und anschließend alle löschen.
Haben sich z. B. durch die Synchronisation mit JTL-Wawi Produktdaten geändert, muss dieser Eintrag nun aber invalidiert
werden. Entweder indem alle Cache-IDs gelöscht werden, oder indem alle zulässigen Werte einzeln gelöscht werden.
So müssten also für alle Sprachen und alle Kundengruppen Cache-IDs generiert und anschließend alle gelöscht werden.
Einfacher ist dies mit Tags:
......@@ -81,22 +81,22 @@ Das Verfahren mit Kategorien ist analog.
Ähnlich ist es beim Speichern von Optionen im Backend: |br|
Sobald der Nutzer dort auf "*Speichern*" klickt, werden alle mit dem Cache-Tag ``CACHING_GROUP_OPTION`` versehenen
Einträge gelöscht. Und das Speichern von Plugin-Optionen invalidiert automatisch die
Einträge gelöscht. Das Speichern von Plugin-Optionen invalidiert automatisch die
Gruppe ``CACHING_GROUP_PLUGIN_$kPlugin``.
Ein weiterer Vorteil der Tags ist die Möglichkeit, dass der Nutzer einzelne Bereiche des Shopsystems gezielt vom
Ein weiterer Vorteil der Tags ist die Möglichkeit, dass der Nutzer einzelne Bereiche von JTL-Shop gezielt vom
Caching ausnehmen kann. |br|
Über das Backend sind daher alle Standard-Tags jeweils einzeln deaktivierbar, sodass Schreibversuche in diesen Gruppen
nicht mehr möglich sind und Leseoperationen stets *FALSE* zurückgeben.
Generelles Vorgehen beim Lesen/Speichern
1. Klasseninstanz holen, via ``Shop::Cache()``
1. Klasseninstanz holen via ``Shop::Cache()``
2. CacheID generieren
3. mit ``mixed|bool JTLCache::get(string $cacheID [,callable $callback = null, mixed $customData = null])``
im Cache nach entsprechendem Eintrag suchen
4. bei *Hit* direkt zurückgeben
5. bei *Miss* Daten berechnen und
5. bei *Miss* Daten berechnen
6. Daten im Cache über
``bool JTLCache::set(string $cacheID, mixed $content [, array $tags = null, int $expiration = null])`` speichern
und dabei mit Tags versehen
......@@ -149,8 +149,8 @@ Generelles Invalidieren
.. important::
Falls sich betroffene Daten ändern -- bei Wawi-Abgleich oder durch Nutzerinteraktion -- müssen die Caches
(repräsentiert durch die *CacheID*) gelöscht werden.
Falls sich betroffene Daten ändern, z. B. beim Abgleich mit JTL-Wawi oder durch Nutzerinteraktion, müssen
die Caches (repräsentiert durch die *CacheID*) gelöscht werden.
Hierzu kann via ``$cache->flush($cacheID)``, bzw. der Kurzform ``Shop::Cache()->delete(string $cacheID)``,
die ID gelöscht werden oder via ``$cache->flushTags(array $tags)`` bzw. ``Shop::Cache()->flushTags(array $tags)``
......@@ -176,12 +176,12 @@ ganze Tags gelöscht werden.
Generierung von IDs
-------------------
*Cache-IDs* sollten natürlich möglichst einzigartig sein, gleichzeitig aber auch in Ihrer Berechnung nicht zu komplex,
*Cache-IDs* sollten möglichst einzigartig sein, gleichzeitig aber auch in ihrer Berechnung nicht zu komplex,
um den Geschwindigkeitsvorteil des Caches nicht wieder zu verspielen.
Generell sollten alle Faktoren, die die Berechnung eines Wertes beeinflussen, in die ID mit einbezogen werden. |br|
Dies betrifft im Shop häufig die aktuelle Sprache (``$_SESSION['kSprache']`` bzw. ``Shop::$kSprache``), die
Kundengruppe (``$_SESSION['Kunde']->kKundengruppe`` oder die Währung (``$_SESSION['Waehrung']->kWaehrung``).
Dies betrifft bei JTL-Shop häufig die aktuelle Sprache (``$_SESSION['kSprache']`` bzw. ``Shop::$kSprache``), die
Kundengruppe (``$_SESSION['Kunde']->kKundengruppe``) oder die Währung (``$_SESSION['Waehrung']->kWaehrung``).
Die Funktion ``JTLCache::getBaseID()`` versucht, die gängigsten Einflussfaktoren zu bedenken und so eine Basis-ID
zu generieren, die als Teil der CacheID verwendet werden kann. |br|
......@@ -191,12 +191,12 @@ Ihre Signatur sieht wie folgt aus:
string JTLCache::getBaseID([bool $hash = false, bool $customerID = false, bool $customerGroup = true, bool $currencyID = true, bool $sslStatus = true])
Der erste Parameter gibt dabei an, ob ein *md5-Hash* generiert werden soll und die weiteren,
Der erste Parameter gibt dabei an, ob ein *md5-Hash* generiert werden soll. Die weiteren Parameter geben an,
welche Faktoren bedachte werden sollen.
Zweckmäßig wäre es beispielsweise, diese *Basis-ID* mit einer Abkürzung des Funktionsnamens zu kombinieren,
in der die ID erstellt wird - wie ``$cacheID = 'mft_' . Shop::Cache()->getBaseID()``, wenn die entsprechende Zeile
beispielsweise in einer Funktion namens "*myFunctionTest*" steht.
wie beispielsweise ``$cacheID = 'mft_' . Shop::Cache()->getBaseID()``, wenn die entsprechende Zeile
in einer Funktion namens "*myFunctionTest*" steht.
CacheIDs und Tags in Plugins
----------------------------
......@@ -224,11 +224,11 @@ fehlgeschlagenen Lesevorgang zu unterscheiden.
//Cache miss - JTLCache::RES_FAIL
}
Mehrere Werte Setzen/Lesen
---------------------------
Mehrere Werte setzen/lesen
--------------------------
Über ``JTLCache::getMulti(array $cacheIDs)`` können mehrere Werte gleichzeitig ausgelesen,
sowie über ``JTLCache::setMulti(array $keyValue, array|null $tags[, int|null $expiration])`` gesetzt werden.
Über ``JTLCache::getMulti(array $cacheIDs)`` können mehrere Werte gleichzeitig ausgelesen
und über ``JTLCache::setMulti(array $keyValue, array|null $tags[, int|null $expiration])`` gesetzt werden.
**Beispiel:**
......@@ -257,7 +257,7 @@ sowie über ``JTLCache::setMulti(array $keyValue, array|null $tags[, int|null $e
Hooking
-------
Caching hat auch den Vorteil, dass gewisse Hooks nicht häufiger ausgeführt werden müssen als nötig - wie z.B.
Caching hat auch den Vorteil, dass gewisse Hooks nicht häufiger ausgeführt werden müssen als nötig - wie z. B.
Hook ``HOOK_ARTIKEL_CLASS_FUELLEARTIKEL`` (110). |br|
Um Plugins die Möglichkeit zu geben, auch eigene Cache-Tags
hinzufügen zu lassen, ist es angebracht, die vorgesehenen Tags ebenfalls an den Hook zu übergeben.
......@@ -279,26 +279,26 @@ Aufgrund vielfacher Wünsche von Entwicklern wird der *Hook 110* nun bei einem C
Der übergebene Parameter ``cached`` ist in diesem Fall auf *TRUE* gesetzt. Falls Sie ein Plugin programmieren, welches
einmalig Eigenschaften eines Artikels modifiziert, achten Sie bitte darauf, komplexe Logik nur auszuführen,
wenn der Parameter *FALSE* ist. |br|
Anschließend werden Ihre Änderungen automatisch im Cache gespeichert und brauchen **nicht** erneut
durchgeführt zu werden.
Anschließend werden Ihre Änderungen automatisch im Cache gespeichert und müssen **nicht** erneut
durchgeführt werden.
Auf diese Weise kann ein Plugin einen eigenen Tag hinzufügen und beispielsweise bei Änderungen
an den Plugin-Optionen reagieren und die betroffenen Caches leeren
(vgl. `jtl_example_plugin <https://gitlab.com/jtl-software/jtl-shop/plugins/jtl_test>`_).
Dabei ist die Reihenfolge wichtig:
Beachten Sie dabei die Reigenfolge:
1. Erst Standard-Cache-Tags definieren,
2. Dann Hook mit Daten und Tags ausführen,
3. Anschließend Daten speichern.
1. Standard-Cache-Tags definieren
2. Hook mit Daten und Tags ausführen
3. Daten speichern.
Nur so können die durch ein Plugin evtl. modifizierten Daten auch im Cache gespeichert und von diesem
invalidiert werden.
Welcher Mechanismus?
--------------------
Welche Caching-Methode?
-----------------------
Generell sind alle implementierten Mechanismen funktional, aufgrund ihrer Eigenheiten aber nur bedingt für alle
Generell sind alle implementierten Caching-Methoden funktional, aufgrund ihrer Eigenheiten aber nur bedingt für alle
Szenarien zu empfehlen.
Dateien-Cache
......@@ -312,32 +312,32 @@ deutlich beschleunigt werden.
Dateien(erweitert)-Cache
""""""""""""""""""""""""
Die, seit Version 4.05 enthaltene, Methode *Dateien (erweitert)* versucht, diese Nachteile durch
Die seit JTL-Shop 4.05 enthaltene Methode *Dateien (erweitert)* versucht, diese Nachteile durch
`Symlinks <https://de.wikipedia.org/wiki/Symbolische_Verkn%C3%BCpfung>`_ zu umgehen. |br|
Hierbei werden im Ordner ``templates_c/filecache/``, für jeden Tag, Unterordner angelegt, die Symlinks zu den
Hierbei werden im Ordner ``templates_c/filecache/`` für jeden Tag Unterordner angelegt, die Symlinks zu den
einzelnen Cache-Einträgen enthalten. Hierdurch kann eine bessere Parallelität beim Schreiben von neuen Einträgen
erreicht werden. |br|
Unter bislang ungeklärten Umständen kann es jedoch vorkommen, dass fehlerhafte Links erstellt werden, sodass der
Cache-Ordner nicht mehr geleert werden kann. Dies wird aktuell (Stand: Februar 2017) noch untersucht.
Cache-Ordner nicht mehr geleert werden kann. Dies wird aktuell (Stand: Februar 2020) noch untersucht.
APC-Cache
"""""""""
*APC* ist die schnellste Variante, hat im Praxistest bei hoher Belastung und vielen Einträgen aber
Skalierungsprobleme. Zumindest im Bereich von ca. 3-4GB Daten wird er außerdem stark fragmentiert und die Leistung
Skalierungsprobleme. Zumindest im Bereich von ca. 3-4 GB Daten wird er außerdem stark fragmentiert und die Leistung
kann einbrechen.
Redis-Cache
"""""""""""
Die für große Datenmengen am besten geeignet Variante ist *Redis*. |br|
Die für große Datenmengen am besten geeignete Variante ist *Redis*. |br|
Auch im Bereich von mehreren Gigabyte arbeitet sie schnell und kann außerdem
auch `als Session-Handler genutzt werden <https://github.com/phpredis/phpredis#php-session-handler>`_.
Memcache(d)-Cache
"""""""""""""""""
Für *memcache(d)* gilt prinzipiell dasselbe, wie für *Redis*, allerdings ist es weniger getestet.
Für *memcache(d)* gilt prinzipiell dasselbe wie für *Redis*, allerdings ist es weniger getestet.
XCache-Cache
""""""""""""
......
......@@ -5,16 +5,16 @@ Container
<br />
Seit Shop 5.0.0 steht im JTL-Shop ein sogenannter "*Dependency Injection Container*" zur Verfügung. |br|
In Zukunft wird ein Großteil aller JTL-Shop-Komponenten über diesen Container bereit gestellt. Zudem kann das
Verhalten des Shops über die im Container registrierten Komponenten von Plugins modifiziert oder erweitert werden.
Seit JTL-Shop 5.0.0 steht im JTL-Shop ein sogenannter "*Dependency Injection Container*" zur Verfügung. |br|
In Zukunft wird ein Großteil aller JTL-Shop-Komponenten über diesen Container bereitgestellt. Zudem kann das
Verhalten des Onlineshops über die im Container registrierten Komponenten von Plugins modifiziert oder erweitert werden.
SOLID & Dependency Inversion
----------------------------
Der Container dient der Umsetzung des "*Dependency Inversion Principles*". |br|
Der Container dient der Umsetzung des "*Dependency Inversion Principle*". |br|
Zu diesem Themenkomplex gibt es viele Erklärungen im Internet. Wir empfehlen Entwicklern daher zunächst, sich mit
*SOLID* und im Besonderen mit *Dependeny Inversion* vertraut zu machen.
*SOLID* und im Besonderen mit *Dependency Inversion* vertraut zu machen.
Container / Komponente holen
----------------------------
......@@ -30,9 +30,9 @@ Container / Komponente holen
$passwordService = $container->get(PasswordServiceInterface::class);
$randomPassword = $passwordService->generate(12);
Wie hier zu sehen ist, können über den Container Dienste und andere Komponenten vom JTL-Shop bezogen werden. |br|
Der Container ist hierbei gemäß PSR-11 von der PHP-FIG entworfen. (https://www.php-fig.org/psr/psr-11/)
Für den Fall, dass Sie eine IDE mit *IntelliSense* verwenden, haben wir zudem für alle, vom JTL-Shop bereit gestellten,
Wie hier zu sehen ist, können über den Container Dienste und andere Komponenten von JTL-Shop bezogen werden. |br|
Der Container ist hierbei gemäß PSR-11 von der PHP-FIG entworfen (https://www.php-fig.org/psr/psr-11/).
Für den Fall, dass Sie eine IDE mit *IntelliSense* verwenden, haben wir zudem für alle von JTL-Shop bereitgestellten
Komponenten eine Methode zum Container hinzugefügt.
.. code-block:: php
......@@ -52,8 +52,8 @@ Welche Komponenten vom JTL-Shop bereitgestellt werden, können Sie anhand der ve
Existenz prüfen
"""""""""""""""
Sollten Sie prüfen wollen, ob eine Komponente bereit steht, können Sie dies wie folgt tun. |br|
(Hinweis: Alle in ``DefaultServicesInterface`` definierten Komponenten sind immer verfügbar).
Wenn Sie prüfen wollen, ob eine Komponente bereitsteht, können Sie dies wie folgt tun. |br|
(Hinweis: Alle in ``DefaultServicesInterface`` definierten Komponenten sind immer verfügbar.)
.. code-block:: php
......@@ -69,9 +69,9 @@ Sollten Sie prüfen wollen, ob eine Komponente bereit steht, können Sie dies wi
Eigenen Komponente registrieren
-------------------------------
Sie haben die Möglichkeit eigene Komponenten im Container zu registrieren. |br|
Sie haben die Möglichkeit, eigene Komponenten im Container zu registrieren. |br|
Hierzu benötigen Sie zunächst eine Klasse, die Sie bereitstellen wollen. Wir empfehlen, für jede Komponente ein
Interface oder eine Abstrakte Klasse zu erstellen. Nur so kann das *Decorator-Pattern* eingesetzt werden (Siehe unten).
Interface oder eine abstrakte Klasse zu erstellen. Nur so kann das *Decorator Pattern* eingesetzt werden (siehe unten).
.. code-block:: php
......@@ -101,7 +101,7 @@ Nun können Sie die entsprechende Komponente im Container registrieren:
return new HelloWorldGenerator();
});
Nun steht ihre Komponente über den Container bereit und kann wie folgt abgerufen werden:
Nun steht die Komponente über den Container bereit und kann wie folgt abgerufen werden:
.. code-block:: php
......@@ -115,11 +115,11 @@ Komponenten überschreiben
-------------------------
Sie können alle im Container registrierten Komponenten ersetzen. |br|
Voraussetzung hierfür ist, dass Sie das genutzte Interface implementieren oder, im Falle einer Abstrakten Klasse, von
Voraussetzung hierfür ist, dass Sie das genutzte Interface implementieren oder, im Falle einer abstrakten Klasse, von
dieser erben. |br|
.. attention::
Wenn Sie Komponenten überschreiben, gilt dies für den gesamten Shop! |br|
Wenn Sie Komponenten überschreiben, gilt dies für den gesamten Onlineshop! |br|
Seien Sie also bitte vorsichtig und überschreiben Sie nur dann Komponenten, wenn Ihre Implementation zuverlässig
funktioniert.
......@@ -143,10 +143,10 @@ dieser erben. |br|
Komponenten erweitern (*Decorator Pattern*)
-------------------------------------------
Sie können sämtliche über den Container bereitstehenden Komponenten (falls eine Abstrakte Klasse oder ein Interface
bereit steht) mit Hilfe des *Decorator Patterns* erweitern.
Sie können sämtliche über den Container bereitstehenden Komponenten (falls eine abstrakte Klasse oder ein Interface
bereitsteht) mit Hilfe des *Decorator Pattern* erweitern.
Hierzu ein Beispiel, dass den "*HelloWorldContainer*" erweitert:
Hierzu ein Beispiel, das den "*HelloWorldContainer*" erweitert:
.. code-block:: php
......@@ -186,7 +186,7 @@ Hierzu ein Beispiel, dass den "*HelloWorldContainer*" erweitert:
Factory oder Singleton
----------------------