Erweiterungen von Joomla! 3 zu Joomla! 4 migrieren
Im Laufe der Jahre hat sich die Anzahl der von mir betreuten Joomla!-Installationen deutlich reduziert. Von mehreren Websites ist noch eine Intranet-Seite übriggeblieben, welche bis vor Kurzem noch mit Joomla! 3 lief.
Hauptgrund hierfür war die aus meiner Sicht nur spärlich vorhandene Dokumentation für Entwickler, welche Anpassungen an Erweiterungen bei Versionsänderungen zu machen sind. Während zum Beispiel der Wechsel zu Hugo auf Grund der guten Dokumentation in Kombination mit einem ebenso guten Forum nur wenig Frustmomente bot, war schon die Erfahrung beim Umstieg von Joomla! 1.5 auf 2.5 derart nervig, daß im Laufe der Zeit alle Websites von Joomla! zu WordPress migriert wurden, statt den Versuch zu starten, die bestehende Funktionalität unter der neuen Joomla!-Version lauffähig zu bekommen.
Nachdem inzwischen aber Joomla! 5 veröffentlicht ist, sollte auch die Intranet-Site zumindest auf Joomla! 4 migriert und somit auch die selbstentwickelten Erweiterungen angepasst werden, was sich wieder als frustrierendes Erlebnis entpuppte. Wenn es schon Zusammenstellungen wie “Potential backward compatibility issues in Joomla 4” gibt, wäre es hilfreich, wenn dort nicht als erstes ein “Content is Incomplete” ins Auge springen würde und viele der hier aufgelisteten Dinge auch dort zu finden wären.
In diesem Beitrag habe ich die verschiedenen Quellen gesammelt, mit denen ich die Erweiterungen mit Joomla! 4 lauffähig gemacht habe - am Ende des jeweiligen Abschnitts ist als Quelle die Seite angegeben, auf welcher ich als erstes auf meiner Suche nach Lösungen fündig wurde. Vieles davon ist sog. Legacy-Funktionalität, d.h. ich habe nicht nach aktueller Philosophie neu entwickelt, sondern versucht, mit minimalem Aufwand die jeweilige Erweiterung zu reparieren und wieder funktionsfähig zu bekommen.
JArrayHelper
“JArrayHelper” wurde entfernt, stattdessen übernimmt “Joomla\Utilities\ArrayHelper” die Funktionalität:
JArrayHelper::toInteger($cid)
wird zu
Joomla\Utilities\ArrayHelper::toInteger($cid)
Quelle: Potential backward compatibility issues in Joomla 4
JRequest
“JRequest” wurde entfernt und wurde durch die “Input”-Klasse ersetzt:
$option = JRequest::getCmd('option');
wird zu
$jinput = JFactory::getApplication()->input;
$option = $jinput->get('option');
Quelle: error Class ‘JRequest’ not found in Joomla 4
An den Inhalt des “POST”-Arrays kommt man nun auf folgenden Weg:
$post = $jinput->post->getArray();
Quelle: JRequest::get(‘post’, JREQUEST_ALLOWRAW) has been deprecated, what is the working code now?
Für die anderen Variablen gestaltet sich das ähnlich:
$val = $input->get->get(param_name, default_value, filter);
$val = $input->post->get(param_name, default_value, filter);
$val = $input->server->get(param_name, default_value, filter);
Quelle: Retrieving request data using JInput
Will man auf Datei-Uploads zugreifen, so ist auch hier neuerdings die “Input”-Klasse zuständig:
$upload = JRequest::get('files')['document_upload']
wird zu
$upload = $jinput->files->get('document_upload')
Quelle: How to use the filesystem package
MysqliDriver
Beim MysqliDriver wurde die “query”-Methode entfernt und durch “execute” ersetzt:
if (!$db->query()) { JError::raiseWarning( 500, $db->getError() ); }
wird zu
if (!$db->execute()) { JError::raiseWarning( 500, $db->getError() ); }
Quelle: Call to undefined method Joomla\Database\Mysqli\MysqliDriver::stderr()
JSubmenuHelper
Im Administrationsbereich muß die Verwendung von “JSubmenuHelper” durch “JHtmlSidebar” ersetzt und ggf. muß auch noch das Template entsprechend angepasst werden:
JSubmenuHelper::addEntry(
...
);
wird zu
JHtmlSidebar::addEntry(
...
);
Quelle: Replacing JSubmenuHelper with JHtmlSidebar / Administrative menu in Joomla 4
parseXMLInstallFile
“parseXMLInstallFile” wird nun nicht mehr von “ApplicationHelper” sondern von “JInstaller” bereitgestellt:
$xmldata = JApplicationHelper::parseXMLInstallFile(JPATH_COMPONENT . DIRECTORY_SEPARATOR . 'tinydoc.xml'))
wird zu
$xmldata = JInstaller::parseXMLInstallFile(JPATH_COMPONENT . DIRECTORY_SEPARATOR . 'tinydoc.xml'))
Quelle: Joomla! API Deprecated Elements
JHtmlBehavior::calendar
“behavior::calendar” wurde entfernt, weshalb eine Zeile wie
JHTML::_('behavior.calendar');
aus dem Quellcode entfernt werden muß - sonst kommt es zu einem “behavior::calendar not found”-Fehler.
Quelle: Remove the deprecated code in the JHtmlBehavior class
grid.published
“grid.published” wurde um ein vorangestelltes “j” ergänzt und statt dem kompletten Element gibt es nur noch den “published”-Status als Parameter:
JHTML::_('grid.published', $row, $i)
wird zu
JHtml::_('jgrid.published', $row->published, $i)
Quelle: Html::_(‘grid.published’) does not pick up tick.png icon
JFile::read($file);
“JFile::read($file);” wurde ebenfalls entfernt, stattdessen soll nun die PHP-Funktion “file_get_contents()” verwendet werden.
$documentData = JFile::read($file);
wird zu
$documentData = file_get_contents($file);
Quelle Joomla! API Deprecated Elements
assignRef
Eine Änderung, die mit PHP5 Einzug gehalten hat, macht die Verwendung von “assignRef” überflüssig:
$this->assignRef('document', $document)
$this->document = $document
Quelle: Joomla 3 - What to use instead of assignRef?
JResponse::setHeader
Mit “JResponse::setHeader” können keine zusätzlichen Header-Daten mehr Richtung Browser geschickt werden, hierfür ist nun “JFactory::getApplication()->setHeader” zuständig.
JResponse::setHeader('Content-Transfer-Encoding', 'binary')
$app = JFactory::getApplication();
$app->setHeader('Content-Transfer-Encoding', 'binary');
Quelle: How to add custom Header Data in Joomla
Routing
Auch beim Routing einer Komponente hat sich einiges geändert und es gibt zwei Möglichkeiten, einen Router für Joomla! 4 zu implementieren:
Der vielleicht schönere Weg ist über einen eigenen RouterView. Eine gute Erklärung, was in welcher Reihenfolge zu tun ist, findet sich im Google Groups-Beitrag “How to use the new View Based Router Classes”.
Eher quick & dirty ist der Ansatz des “Traditional Routers”, bei dem große Teile des bestehenden Router-Codes übernommen werden können:
In der “router.php” eine Klasse mit dem Namen der Komponente (ohne “com_"-Präfix) anlegen, welche von “RouterInterface” abgeleitet wird:
use Joomla\CMS\Component\Router\RouterInterface;
class TinyDocRouter implements RouterInterface {
...
}
In dieser Klasse dann einen Konstruktor sowie die Funktionen “build”, “parse” und “preprocess” definieren. Sofern eine dieser Funktionen nicht definiert ist, beschwert sich Joomla! mit der Fehlermeldung “Error: Class TinyDocRouter contains … abstract method and must therefore be declared abstract or implement the remaining methods”.
public function __construct($application, $menu) {
...
}
public function build(&$query) {
$segments = [];
...
return $segments;
}
public function parse(&$segments) {
$vars = [];
...
// clear segments
$segments = [];
return $vars;
}
public function preprocess($query) {
...
return $query;
}
In die Funktionen “build” und “parse” kann der alte Router-Code übernommen werden, es ist aber darauf zu achten, in der Funktion “parse” das “segments”-Array zu leeren, da es sonst zu einem “HTTP 404 (page not found)"-Fehler kommt.
Quellen: Developing an MVC Component/Upgrading to Joomla4 sowie TraditionalRouter.php
JError::raiseWarning, JError::raiseError und $this->setError
Auch “$this->setError” ist - genau wie “JError::raiseWarning” oder “JError::raiseError” - mit Joomla! 4 Geschichte. Die Aufgabe kann stattdessen von “$this->setMessage” übernommen werden:
$this->setError(JText::_('Error uploading file'));
$this->setMessage(JText::_('Error uploading file'), 'error');
Im zweiten Parameter kann festgelegt werden, ob es sich um eine Information (= Default ‘message’), einen Fehler (’error’) oder eine Warnung (‘warning’) handelt.
Quelle: What is the best way for raising an error message in Joomla 4