Eine Joomla-Datenbank-Tabelle für deine Erweiterung
Deine Ansicht im Administrationsbereich enthält in der Regel nicht nur statischen Text. Du zeigst hier Daten an, die dynamisch sind. So arbeiten zumindest die meisten Erweiterungen. Deshalb legen wir in diesem Teil eine Datenbank für deine Komponente an. In der Datenbank speichern wir bei der Einrichtung drei Datensätze und zeigen diese im Administrationsbereich an. Am Ende wird eine statische Liste ausgegeben. Änderbar sind die einzelnen Einträge über das Backend bisher nicht. Daran arbeiten wir im nächsten Teil.
Für Ungeduldige: Sieh dir den geänderten Programmcode in der Diff-Ansicht[^codeberg.org/astrid/j4examplecode/compare/t5…t6] an und übernimm diese Änderungen in deine Entwicklungsversion.
Schritt für Schritt
Neue Dateien
administrator/components/com_foos/sql/install.mysql.utf8.sql
Wir legen eine Datei an, die SQL-Befehle für das Erstellen der Datenbanktabelle enthält. Damit diese Statements aufgerufen werden, fügen wir den Namen der Datei später im Manifest ein.
Neben der id
, über welche wir das Element eindeutig auffindbar machen und dem Namen name
, der optional ist und den Datensatz in unserer Erweiterung benennt, gibt es den Alias alias
. Letzterer bereitet die Daten unter anderem für das Routing vor. Stell dir eine System-URL wie http://www.example.com/index.php?option=com_foos&view=foo&id=1
vor. Diese ist für Menschen schlecht lesbar. Auch Maschinen wie Suchmaschinen verarbeiten eine solche URL schlecht. Eine textuelle Beschreibung ist zwingend. In Joomla geschieht dies mithilfe des Alias. Dieser kann vom Benutzer selbst festgelegt werden. Damit der Alias-Text für die URL ausschließlich gültige Zeichen enthält, gibt es automatische Abläufe in der Hintergrundverarbeitung von Joomla.
Via CREATE TABLE IF NOT EXISTS ...
legen wir die Datenbanktabelle an, falls diese nicht schon exisiert. Mit INSERT INTO ...
speichern wir Beispielinhalte in der Datenbanktabelle. In einer realen Erweiterung würde ich Beispieldaten nicht über die SQL-Datei bei der Installation hinzufügen. In Joomla 4 bietet sich ein Plugin des Typs sampledata
an. Zur Inspiration findest du Plugins in Joomla im Verzeichnis plugins/sampledata
.
administrator/components/com_foos/sql/install.mysql.utf8.sql
<!-- https://codeberg.org/astrid/j4examplecode/raw/branch/t6/src/administrator/components/com_foos/sql/install.mysql.utf8.sql -->
CREATE TABLE IF NOT EXISTS `#__foos_details` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`alias` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '',
`name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci;
INSERT INTO `#__foos_details` (`name`) VALUES
('Nina'),
('Astrid'),
('Elmar');
Lies im Vorwort dieses Tutorials, was genau das Präfix
#__
bedeutet, falls dir dieses unbekannt ist.
administrator/components/com_foos/sql/uninstall.mysql.utf8.sql
Damit Joomla im Falle einer Deinstallation keine unnötigen Daten enthält, erstellen wir eine Datei, die den SQL-Befehl zum Löschen der Datenbanktabelle beinhaltet. Diese wird beim Deinstallieren automatisch ausgeführt.
administrator/components/com_foos/sql/uninstall.mysql.utf8.sql
<!-- https://codeberg.org/astrid/j4examplecode/raw/branch/t6/src/administrator/components/com_foos/sql/uninstall.mysql.utf8.sql -->
DROP TABLE IF EXISTS `#__foos_details`;
Vielleicht denkst du weiter und fragst dich schon jetzt, wie du potentielle zukünftige Datenbankänderungen handhabst. Was ist notwendig, um in einer späteren Version neben dem Namen auch den Vornamen zu speichern. SQL-Updates sind in Joomla namensbasiert. Genau bedeutet das: Für jede Version der Komponente ist eine Datei anzulegen, deren Name aus der Versionsnummer und der Dateiendung
.sql
besteht, falls sich Datenbankinhalte ändern. Praktisch wirst du dies im weiteren Verlauf dieses Tutorials erleben.
administrator/components/com_foos/src/Model/FoosModel.php
Als nächstes erstellen wir ein Model für den Administrationsbereich. Da wir die Klasse ListModel
erweitern, ist es nicht erforderlich, dass wir uns selbst um die Verbindung zur Datenbank kümmern. Wir legen die Methode getListQuery()
an und geben hier unsere spezifischen Anforderungen an. Spezifisch sind beispielsweise die Namen der Datenbanktabelle und der Spalten.
Falls bisher nicht geschehen, wird dir hier klar, warum die Trennung von Model und View sinnvoll ist. Sieh dir einmal die Methode
getListQuery()
in Joomla-Komponenten an, zum Beispiel incom_content
. Das SQL-Statement ist meist umfangreich. Deshalb ist es übersichtlicher, dieses von anderen Teilen abzukapseln.
Der nachfolgende Code zeigt dir das in unserem Falle noch recht übersichtliche Model.
administrator/components/com_foos/src/Model/FoosModel.php
// https://codeberg.org/astrid/j4examplecode/raw/branch/t6/src/administrator/components/com_foos/src/Model/FoosModel.php
<?php
/**
* @package Joomla.Administrator
* @subpackage com_foos
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace FooNamespace\Component\Foos\Administrator\Model;
\defined('_JEXEC') or die;
use Joomla\CMS\MVC\Model\ListModel;
/**
* Methods supporting a list of foo records.
*
* @since __BUMP_VERSION__
*/
class FoosModel extends ListModel
{
/**
* Constructor.
*
* @param array $config An optional associative array of configuration settings.
*
* @see \JControllerLegacy
*
* @since __BUMP_VERSION__
*/
public function __construct($config = [])
{
parent::__construct($config);
}
/**
* Build an SQL query to load the list data.
*
* @return \JDatabaseQuery
*
* @since __BUMP_VERSION__
*/
protected function getListQuery()
{
// Create a new query object.
$db= $this->getDatabase();
$query = $db->getQuery(true);
// Select the required fields from the table.
$query->select(
$db->quoteName(['id', 'name', 'alias'])
);
$query->from($db->quoteName('#__foos_details'));
return $query;
}
}
Geänderte Dateien
administrator/components/com_foos/foos.xml
Der mit Pluszeichen markierte Eintrag im Installationsmanifest bewirkt, dass die SQL-Statements in den genannten Dateien zum passenden Zeitpunkt aufgerufen werden, nämlich während einer Installation oder während einer Deinstallation.
administrator/components/com_foos/foos.xml
<description>COM_FOOS_XML_DESCRIPTION</description>
<namespace path="src">FooNamespace\Component\Foos</namespace>
<scriptfile>script.php</scriptfile>
+ <install> <!-- Runs on install -->
+ <sql>
+ <file driver="mysql" charset="utf8">sql/install.mysql.utf8.sql</file>
+ </sql>
+ </install>
+ <uninstall> <!-- Runs on uninstall -->
+ <sql>
+ <file driver="mysql" charset="utf8">sql/uninstall.mysql.utf8.sql</file>
+ </sql>
+ </uninstall>
<!-- Frond-end files -->
<files folder="components/com_foos">
<folder>src</folder>
<files folder="administrator/components/com_foos">
<filename>foos.xml</filename>
<folder>services</folder>
+ <folder>sql</folder>
<folder>src</folder>
<folder>tmpl</folder>
</files>
Ich unterstütze in diesem Beispiel ausschließlich eine MySQL-Datenbank. Joomla unterstützt[^downloads.joomla.org/de/technical-requirements-de] neben MySQL (ab Version 5.6) genauso PostgreSQL (ab Version 11). Wenn du ebenfalls beide Datenbanken unterstützt, findest du eine Implementierung zum Abgucken in der Weblinks Komponente[^github.com/joomla-extensions/weblinks]. Wie du die Treiber benennst ist flexibel.
postgresql
undmysql
sind korrekt.mysqli
,pdomysql
undpgsql
werden von Joomla in der Datei/libraries/src/ Installer/Installer.php
angepasst, falls du diese Bezeichnungen verwendest.
Aktualisierungen
Der Vollständigkeit halber nehme ich hier Änderungen eines nachfolgenden Kapitels bezüglich Aktualisierung vorweg. Wenn sich in der Struktur der Datenban etwas ändert, reicht es aus, nur die Änderungen vorzunehmen. Dabei sollte darauf geachtet werden, dass bestehende Daten nicht tangiert werden. Die Neuerungen speicherst du für jede Version deiner Erweiterung in einer separaten Datei ab. Das Verzeichnis, in dem die Dateien für die Aktualisierungen abzulegen sind, schreibst du in das <update>
-Tag.
...
<update> <!-- Runs on update -->
<schemas>
<schemapath type="mysql">sql/updates/mysql</schemapath>
</schemas>
</update>
...
Nachfolgend siehst du den Inhalt der Datei src/administrator/components/ com_foos/sql/updates/mysql/10.0.0.sql
als Beispiel. Diese Datei kommt in einem späteren Kapitel zu den Beispieldateien hinzu.
ALTER TABLE `#__foos_details` ADD COLUMN `access` int(10) unsigned NOT NULL DEFAULT 0 AFTER `alias`;
ALTER TABLE `#__foos_details` ADD KEY `idx_access` (`access`);
administrator/components/com_foos/services/provider.php
Bisher war es nicht notwendig die MVCFactory
in der Datei provider.php
zu setzten, jetzt ist es erforderlich. Andernfalls siehst du die folgende Fehlermeldung oder bist gezwungen, die Verbindung zur Datenbank selbst zu programmieren: MVC factory not set in Joomla\CMS\Extension\MVCComponent
.
administrator/components/com_foos/services/provider.php
use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory;
use Joomla\CMS\Extension\Service\Provider\MVCFactory;
use Joomla\CMS\HTML\Registry;
+use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use FooNamespace\Component\Foos\Administrator\Extension\FoosComponent;
$component = new FoosComponent($container->get(ComponentDispatcherFactoryInterface::class));
$component->setRegistry($container->get(Registry::class));
+ $component->setMVCFactory($container->get(MVCFactoryInterface::class));
return $component;
}
administrator/components/com_foos/src/View/Foos/HtmlView.php
In der View sammeln wir am Ende alle Elemente. Hierzu rufen wir die Methode $this->get('Items')
des Models auf:
administrator/components/com_foos/src/View/Foos/HtmlView.php
*/
class HtmlView extends BaseHtmlView
{
+ protected $items;
+
/**
* Method to display the view.
*
*/
public function display($tpl = null): void
{
+ $this->items = $this->get('Items');
parent::display($tpl);
}
}
administrator/components/com_foos/tmpl/foos/default.php
Last but not least zeigen wir alles mithilfe der Template-Datei an. Anstelle des statischen Textes Hello Foos
steht jetzt eine Schleife, die alle Elemente durchläuft.
administrator/components/com_foos/tmpl/foos/default.php
*/
\defined('_JEXEC') or die;
?>
-Hello Foos
+<?php foreach ($this->items as $i => $item) : ?>
+<?php echo $item->name; ?>
+</br>
+<?php endforeach; ?>
Wunderst du dich über die Syntax? Im Vorwort hatte ich erklärt, warum ich in einer Template-Datei die alternative Syntax für PHP wähle und die einzelnen Zeilen in PHP-Tags einschließe.
Teste deine Joomla-Komponente
-
Installiere deine Komponente in Joomla Version 4, um sie zu testen: Kopiere die Dateien im
administrator
Ordner in denadministrator
Ordner deiner Joomla 4 Installation. Installiere deine Komponente wie in Teil eins beschrieben, nachdem du alle Dateien kopiert hast. Joomla legt bei der Installation die Datenbank an. -
Teste als nächstes, ob die Ansicht deiner Komponente im Administrationsbereich fehlerfrei ist. Siehst du drei Einträge? Diese hatten wir beim Einrichten der Datenbank als Beispieldaten in der SQL-Datei eingetragen.
- Vergewissere dich, dass die Elemente in der Datenbank gespeichert sind.
Ich nutze lokal phpmyadmin.net für die Administration der Datenbank.