Joomla 4 baut auf Namespaces beim Finden seiner Klassen bzw. Dateien sowie auf Importe/Verfügbarmachung derselben mit use-Zeilen. Eigene Erweiterungen können Namensräume automatisiert registrieren lassen. An einem kurzen Beispiel für eine Erweiterung möchte ich zeigen wie ein Modul aufgebaut sein kann, um es sowohl in Version 3 als auch 4 "genamespacet" zu verwenden. Es soll für beide kompatibel sein.

"For a safe connection use..." © Re:Later 2006

Grundfunktion des Moduls

Das Modul mod_firlefanz verwendet eine Helper-Klasse, die eine Methode getList() enthält; ja nicht unüblich in Joomla. Diese lädt alle Firlefanz-Einträge aus der Datenbank, um sie dann im Layout als Liste anzuzeigen.

Die Helper-Methode wird in Datei mod_firlefanz.php abgefeuert, befüllt eine Variable $list, die anschließend im Layout tmpl/default.php als aufbereitete Ansicht ausgegeben wird. Zuvor muss mod_firlefanz.php die Helper-Klasse finden und kennen.

Altbekanntes Prozedere.

Laden/Registrieren der Helper-Klasse

Während in Joomla 3 die Helper-Klassen-Datei, oft schlicht helper.php benannt, häufig irgendwo oder spezifischer "herumlag" und gaaaaanz früher mit einem require geladen wurde, dann moderner und effizienter mit einem JLoader-Joomla-Kommando registriert wurde, verwendet man jetzt use, davon ausgehend, dass sich der Helper in einem zuvor definierten Namensraum befindet (Joomla 4 definiert da automatisch mehr als 3, wenn die eigene Extension entsprechend präpariert ist).

Man kann darüber streiten, was nun eingängiger und leichter zu durschauen ist, lohnt sich aber nicht, außer dass erste der drei Varianten vorab mehr lädt als gegebenenfalls überhaupt nötig ist und "ewig durch den Code mitschleppt" => No-Go.

Beachte: Folgende J!4-Links zeigen auf eine veraltete Joomla-4.0.0-Version. Für das Verständnis vollkommen ausreichend. Zusätzlich einen Blick in den jeweils aktuellsten Code zu werfen nenne ich mal ratsam.

Beispiel aus Joomla 3.6.2 (require)

  1. https://github.com/joomla/joomla-cms/blob/3.6.2/modules/mod_articles_archive/mod_articles_archive.php#L13
  2. https://github.com/joomla/joomla-cms/blob/3.6.2/modules/mod_articles_archive/mod_articles_archive.php#L17

Beispiel aus Joomla 3.9.28 (JLoader)

  1. https://github.com/joomla/joomla-cms/blob/3.9.28/modules/mod_articles_archive/mod_articles_archive.php#L13
  2. https://github.com/joomla/joomla-cms/blob/3.9.28/modules/mod_articles_archive/mod_articles_archive.php#L17

Beispiel aus Joomla 4.0.0-rc4 (use)

  1. https://github.com/joomla/joomla-cms/blob/4.0.0-rc4/modules/mod_articles_archive/mod_articles_archive.php#L13
  2. https://github.com/joomla/joomla-cms/blob/4.0.0-rc4/modules/mod_articles_archive/mod_articles_archive.php#L16

Ordner-Struktur

Ein Vergleich des Verzeichnisses von modules/mod_articles_archive zeigt deutliche Unterschiede.

Beispiel aus Joomla 3

Die Datei helper.php flackt in Kleinschrift im Stammordner herum und gibt keinerlei Hinweis wie die Klasse darin heißt (class ModArchiveHelper). Warum eigentlich nicht konsequenterweise class ModArticlesArchiveHelper? Egal...

Beispiel aus Joomla 4

Die Datei ArticlesArchiveHelper.php liegt im Unterordner src/Helper, ist in Camel-Case-Schreibweise benannt. Der Dateiname entspricht dem Klassen-Namen in dieser Datei (class ArticlesArchiveHelper).

An diese Ordner- und Benennungs-Konventionen sollte man sich zukünftig bei eigenen Erweiterungen nach Möglichkeit halten. Wer rumforscht wird src/-Ordner in diversen Erweiterungs-Stamm-Verzeichnissen finden, und nicht nur dort, mehr oder weniger bestückt mit Unterordnern, die mit einem Großbuchstaben beginnen, mit mehr oder weniger Dateien darin. Sie ermöglichen praktische Automatismen in Joomla 4.

Auch in Joomla 3 kann man sie schon mal etablieren, selbst, wenn man erst mal die Klassen dann weiterhin mit JLoader registriert/lädt. Statt einem

JLoader::register('ModFirlefanzHelper', __DIR__ . '/helper.php');

$list = ModFirlefanzHelper::getList();

für meine Klasse class ModFirlefanzHelper in Datei helper.php mach ich halt zukünftig

JLoader::register('FirlefanzHelper', __DIR__ . '/src/Helper/FirlefanzHelper.php');

$list = FirlefanzHelper::getList();

für meine Klasse class FirlefanzHelper in Datei src/Helper/FirlefanzHelper.php.

Jedenfalls habe ich so schon mal einen Teil der Arbeit für "die ultimativ echte" Joomla-4-Kompatibiltät vorweggenommen.

Die Manifestdatei mod_firlefanz.xml

Ab J4 gibt es den neuen Tag <namespace> in Erweiterungs-XML-Manifesten.

Hinweis: Der <namespace>-Tag funktioniert nicht in Template-Manifesten (templateDetails.xml). Das ist jedoch zur Zeit des Schreibens für Joomla-Version 4.3 in Planung. Siehe github.com/joomla/joomla-cms/pull/39011

J3 ignoriert diesen Tag einfach weg. Es hat ein zugehöriges Core-Plugin namens "Erweiterungen - Namespace Updater" noch nicht dabei, das damit was anfangen könnte. Aber er macht auch nichts kaputt. Gut so!

In meinem Firlefanz-Modul mod_firlefanz kann ich getrost eintragen.

<namespace path="src">Joomla\Module\Firlefanz</namespace>

Das path="src" bestimmt, dass der angegebene Basis-Namensraum, so nenne ich das mal, in eben jenem Ordner des Moduls etabliert wird. Man könnte also variieren, das ist das Schöne an Namensräumen statt starrer Pfadangaben, tue ich aber bis auf Weiteres nicht. Vielleicht mal in einer Situation, wo das Sinn macht.

Ich will Ihnen nichts vormachen. Diese Namensraum-Einträge sind ohne Übung und/oder Recherche nicht immer einfach nachzuvollziehen, vor allem, wenn es dann an die use-Zeilen geht, die man in Dateien einsetzt, um diese oder jene "genamespacte" Klasse zu verwenden. Sie werden im Hintergrund in "echte" Pfadangaben übersetzt. PHP-Magie. Für Joomla-Module lautet er in der Manifest-XML immer analog der oben gezeigten Zeile, egal, ob für Back-End oder Front-End-Module.

namespace-Zeile in der Helper-Datei

Ich trage als allererste(!) Zeile in die src/Helper/FirlefanzHelper.php ein, sogar noch vor der defined()-Zeile (beachte den Rückwärtsstrich davor, der auf den globalen PHP-Namensraum verweist):

namespace Joomla\Module\Firlefanz\Site\Helper;

\defined('_JEXEC') or die;

Wäre mein Modul ein Back-End-Modul würde ich schreiben:

namespace Joomla\Module\Firlefanz\Administrator\Helper;

use-Zeile in mod_firlefanz.php

... bzw. in den Dateien, in denen ich den Helper nutzen möchte und zwar in jeder Datei, in der ich den Helper nutzen möchte.

Ich trage nach der defined()-Zeile (die diesmal keinen Rückwärtsstrich davor braucht, weil die mod_firlefanz.php für sich selbst keinen Namensraum mittels namespace definiert. Man kann ihn bei Unsicherheit trotzdem davor setzen.):

defined('_JEXEC') or die;

use Joomla\Module\Firlefanz\Site\Helper\FirlefanzHelper;

Wer nun die bis hier gezeigten namespace-Einträge von oben nach unten durchsieht, erkennt, dass sich da schrittweise so was ähnliches wie Dateipfade "zusammanbastelt". Im finalen Schritt wird durch Zauberei daraus ein echter Dateipfad JoomlaROOT/modules/mod_firlefanz/src/Helper/FirlefanzHelper.php.

Jetzt kann ich, (nahezu) egal wo, in der Datei mod_firlefanz.php mein

$list = FirlefanzHelper::getList();

abfeuern. Die Methode der Klasse wird ausgeführt. Ebenso im Layout tmpl/default.php, falls ich da die use-Zeile ebenfalls einsetze. Und sogar außerhalb des Moduls, vorausgesetzt Joomla- und PHP-Magie haben die betreffenden Namespaces bereits bekannt gemacht.

Mein Joomla 3 explodiert jetzt allerdings enttäuschenderweise. Nichts hat sich darum gekümmert, im Unterschied zu Joomla 4, dass die use-Zeile seinen Weg in die richtige Datei findet.

0 - Class "Joomla\Module\Firlefanz\Site\Helper\FirlefanzHelper" not found

"Eine Enttäuschung bezeichnet das Gefühl, einem sei eine Hoffnung zerstört oder auch unerwartet ein Kummer bereitet worden." (Wikipedia)

namespace händisch registrieren

In der mod_firlefanz.php, weil die sehr früh ausgeführt wird im Modulablauf:

<?php
defined('_JEXEC') or die;

if (version_compare(JVERSION, '4', 'lt'))
{
	JLoader::registerNamespace(
		'Joomla\Module\Firlefanz\Site',
		__DIR__ . '/src',
		false, false, 'psr4'
	);
}

use Joomla\Module\Firlefanz\Site\Helper\FirlefanzHelper;

$list = FirlefanzHelper::getList();

Wenn die Joomla-Version kleiner als 4 ist, dann wird der zu sehende Namensraum (beachte das \Site am Ende, was in einem Backend-Modul ein \Administrator wäre) erzwungen registriert. Ab diesem Zeitpunkt kann man die use-Zeile ohne diese if-Abrage verwenden, also auch in der tmpl/default.php.

So kann man überall im Joomla-Code Namespaces definieren, wenn auch manchmal mit etwas Tüftelei, zugegebenermaßen. Unter J!4 bisschen weniger zusätzlicher Code...

Hinweis für Faule, Verwirrte, Verärgerte: "Keine Panik!" (Douglas Adams)

Eigentlich braucht man den ganzen "Namespace-Quatsch" gar nicht. Ein stinknormales, kleines Joomla-3-Modul wird auch unter Joomla 4 unverändert meckerfrei laufen. Irgendwann wird vielleicht der Tag kommen, an dem es das nicht mehr tut ;-)