28.2 Modul erweitern
Blicken Sie auf die Ausgabeliste des Backend-Moduls Version 0.1.0, kommen wie von allein neue Ideen für Ergänzungen und Verbesserungen. Die Benutzer-ID ist wenig aussagekräftig, und was nützt die Liste, wenn man nicht direkt zur Beitragsbearbeitung springen kann? Und wie wäre es, wenn Backend-Contentpfleger die Möglichkeit hätten, nur ihre eigenen Beiträge anzuzeigen?
Zeit für ein Update.
Ziel: Sie erweitern das Modul um eine Konfigurationsseite, über die der Benutzer die anzuzeigenden Beiträge nach selbst erstellten Inhalten filtert. Ferner erscheint in der Liste im Kontrollzentrum nicht die ID des Autors, sondern der Benutzername, der Tooltip-Inhalt längerer Beitragstexte wird gekürzt, die Spaltenüberschriften beschreiben die Tabelleninhalte, und der Beitragstitel ist anklickbar und verlinkt zur Beitragsbearbeitung.
Vorgehen: Die Konfiguration erweitern Sie im XML-Manifest, die Beitragsfilterung und das Anziehen des Benutzernamens ist eine kleine Modifikation der SQL-Abfrage. Die Beitragstexte lassen sich ebenfalls im Model kürzen, dort, wo auch die introtext/fulltext-Unterscheidungen stattfinden. Danach folgt eine kleine Aktualisierung der HTML-Ausgabe, um die Spaltenüberschriften einzufügen.
All diese Änderungen nehmen Sie ab sofort direkt in den installierten Moduldateien unter /administrator/modules/mod_backendmodul/ vor. So lassen sich die Funktionalitätenerweiterungen schneller und direkter testen, da Sie im Browser lediglich das Kontrollzentrum mit (F5) (OS X: (cmd) + (R)) aktualisieren. Auch die Plugin-Konfiguration ist unmittelbar nach Aktualisierung des XML-Manifests im Entwicklungssystem aufrufbar.
Hinweis: Das komplette Paket zur Version 0.2.0 laden Sie gerne wieder unter https://joomla-handbuch.com/downloads/handbuch herunter.
28.2.1 XML-Manifest – »mod_backendmodul.xml«
Zur Ergänzung einer Modulkonfiguration bearbeiten Sie das XML-Manifest und fügen den im folgenden Listingausschnitt hervorgehobenen <config>-Block zwischen dem schließenden </files>- und </extension>-Tag hinzu.
[…]
</files>
<config>
<fields name="params">
<fieldset name="basic">
<field name="numberOfArticles"
type="text"
default="5"
label="Number of Articles"
description="How many articles are supposed to be listed?" />
<field name="onlyOwnArticles" type="radio"
default="0"
class="btn-group"
label="Show only own Content"
description="If No, content from all authors will be shown">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
</fieldset>
</fields>
</config>
</extension>
Der Inhalt des XML-<config>-Blocks wirkt vertraut, denn es handelt sich um JForm-Elemente wie auch bei der Template- und Plugin-Konfiguration. In diesem Fall ergänzen Sie ein einfaches Nummernfeld (type="number") für die Anzahlbegrenzung der anzuzeigenden Beiträge (siehe Abbildung 28.5), und einen Radiobutton-Umschalter, mit dem der Benutzer zwischen allen und eigenen Beiträgen wechselt. Wie beim Plugin erhält der Umschalter zur Verschönerung die Bootstrap-CSS-Klasse btn-group.
28.2.2 Model-Aktualisierung – »helper.php«
Die Aktualisierungen im Model sind etwas umfangreicher, da Sie die Datenbankabfrage erweitern, den Beitrags-Bearbeitungslink hinzufügen und den Beitragstext kürzen.
[…]
public static function getList(&$params)
{
$numberOfArticles = $params->get('numberOfArticles', 10);
$onlyOwnArticles = $params->get('onlyOwnArticles', 0);
$user = JFactory::getuser();
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->select($db-
>quoteName(array('content.id', 'title', 'introtext', 'fulltext', 'state',
'modified', 'modified_by', 'featured', 'username')));
$query->from($db->quoteName('#__content', 'content'));
$query->join('INNER', $db->quoteName('#__users', 'users') .
' ON (' . $db->quoteName('content.modified_by') . ' = ' .
$db->quoteName('users.id') . ')');
if ($onlyOwnArticles == 1)
{
$query->where($db->quoteName('modified_by') . ' = ' . $user->id);
}
$query->order('modified DESC');
$db->setQuery($query, 0, $numberOfArticles);
try
[…]
if ($user->authorise('core.edit', 'com_content.article.' . $fields->id))
{
$link = JRoute::_('index.php?option=com_content&task=
article.edit&id=' . $fields->id);
}
else
{
$link = '';
}
$results[$row]->title = ($link == '') ? $fields->title : '<a href=
"' . $link . '" target="_blank">' . $fields->title . '</a>';
$results[$row]->introtext = strip_tags($fields->introtext, '<br><br/>
<strong><em><b><i>');
$results[$row]->fulltext = strip_tags($fields->fulltext, '<br><br/>
<strong><em><b><i>');
if (!($results[$row]->introtext))
{
$results[$row]->summary = strlen($results[$row]->introtext) > 300 ?
substr($results[$row]->introtext, 0, 300) . " […]" : $results[$row]->
introtext;
}
else if (!($results[$row]->fulltext))
{
$results[$row]->summary = strlen($results[$row]->fulltext) > 300 ?
substr($results[$row]->fulltext, 0, 300) . " […]" : $results[$row]->
fulltext;
}
else
{
$results[$row]->summary = '[No Content]';
}
$results[$row]->modified_by = $fields->username;
$results[$row]->state = $fields->state;
[…]
Zu Beginn der getList()-Funktion liest $params->get() die Anzahl der darzustellenden Beiträge ($numberOfArticles) und die Markierung, ob nur eigene Beiträge angezeigt werden sollen ($onlyOwnArticles), aus der Modulkonfiguration. Beide Variablen finden kurz darauf in der Konstruktion der Datenbankabfrage Einsatz, die sich nun wie folgt aufbaut:
-
$query->select() listet alle zurückzugebenden Felder. Das erste Feld id erhält zur genaueren Bezeichnung den Tabellennamen (content.id), da die Daten aus der Abfrage gleich aus zwei verschiedenen Tabellen stammen: #__content für die Beiträge und #__users für den Benutzernamen. Dementsprechend enthält die select-Liste am Ende auch das neue Feld username.
-
Um an den Benutzernamen zu gelangen, erfolgt per INNER JOIN ($query->join('INNER',[…]) eine Verknüpfung der content- und users-Tabelle. Und zwar durch einen Abgleich zwischen der Benutzer-ID unter modified_by in der content-Tabelle und der Benutzer-ID (id) der users-Tabelle.
-
Falls der Modulkonfigurationsschalter $onlyOwnArticles wahr (1) ist, erhält die Abfrage eine zusätzliche WHERE-Klausel. Die Bedingung ist dann, dass nur Beiträge gelistet werden, deren modified_by-Benutzer-ID identisch mit der des aktuellen Benutzers ist. Die notwendige ID erhalten Sie aus dem Objekt $user, das einige Zeilen über der Datenbankabfrage aus der JFactory stammt.
-
Die Einstellung der Reihenfolge (order) bleibt identisch. Die letzte Anpassung erfolgt bei der Ausführung der Abfrage, wo die maximale Anzahl zurückzugebender Artikel von fixen 10 durch den Konfigurationswert in $numberOfArticles ersetzt wird.
Zum besseren Verständnis – interpretiert, ausgeschrieben und mit Beispiel-Tabellenpräfix und Benutzer-ID versehen, lautet die in phpMyAdmin testbare SQL-Anweisung:
SELECT `k6wz0_content`.`id`, `title`, `introtext`, `fulltext`, `state`,
`modified`, `modified_by`, `featured`, `username`
FROM `k6wz0_content`
INNER JOIN `k6wz0_users` ON `k6wz0_content`.`modified_by` = `k6wz0_users`.`id`
WHERE `modified_by`=842
ORDER BY `modified` DESC
LIMIT 0,15;
Nach Erhalt des Abfrageergebnisses folgt wieder die Schleife über alle einzelnen Beiträge (foreach). Der erste neue Block ergänzt den Beitragstitel um den Link zur Beitragsbearbeitung (JRoute), allerdings nur, wenn der aktuelle Benutzer zur Beitragsbearbeitung berechtigt ist ($user->authorise('core.edit', […]).
Um zu verhindern, dass die den Beitragsinhalt enthaltenen Tooltips später das gesamte Fenster verdecken, setzen die darauf folgenden Zeilen bei $results[$row]->summary die Schere an. Nach den ersten 300 Zeichen wird die Zeichenkette gnadenlos abgeschnitten (siehe Abbildung 28.6).
Die letzte Änderung betrifft noch mal den Namen des Benutzers, der den Beitrag zuletzt bearbeitete. Die Datenbankabfrage stellt den Namen in $fields->username bereit. Um später im HTML-Template keine große Änderungen machen zu müssen, setzen Sie den Benutzernamen kurzerhand in die existierende Variable $results[$row]->modified_by.
28.2.3 HTML-Ausgabe – »/tmpl/default.php«
Da alle Datenaktualisierungen bereits im Model erfolgten, fällt das Update des HTML-Templates erfreulich klein aus: Sie ergänzen lediglich die Tabellenüberschriften in vier Bootstrap-Spalten.
[…]
<div class="recentlyedited">
<div class="row-striped">
<div class="row-fluid">
<div class="span1 small">Online</div>
<div class="span6 small">Article Title</div>
<div class="span3 small">Last Modified</div>
<div class="span2 small">By</div>
</div>
<?php foreach ($list as $item) : ?>
<div class="row-fluid">
[…]
Testen Sie jetzt die neue Version des Backend-Moduls, indem Sie in seiner Konfiguration eine maximale Beitragszahl festlegen und nacheinander die beiden Schalterstellungen für die Beitragsfilterung ausprobieren.
28.2.4 Erweiterungspaket schnüren
Falls Sie nicht mit dem Download-Paket arbeiten, sondern die Listings selbst eingegeben haben, sammeln Sie nun alle erstellten Dateien (inklusive /tmpl/-Verzeichnis) in einem Erweiterungspaket ähnlich wie im vorherigen Plugin-Kapitel. Dazu kopieren Sie die Dateien aus dem Backend von Joomla! in ein separates, von Joomla! unabhängiges Verzeichnis und erzeugen daraus ein ZIP-Archiv, z. B. mod_backendmodul.zip. Dieses Paket lässt sich dann wie jede reguläre Erweiterung auf anderen Joomla!-Systemen installieren.
Dateipfade im Entwicklungssystem | Dateipfade im ZIP-Archiv |
---|---|
/administrator/modules/mod_backendmodul/index.html | /index.html |
/administrator/modules/mod_backendmodul/ mod_backendmodul.xml | /mod_backendmodul.xml |
/administrator/modules/mod_backendmodul/ mod_backendmodul.php | /mod_backendmodul.php |
/administrator/modules/mod_backendmodul/ helper.php | /helper.php |
/administrator/modules/mod_backendmodul/ tmpl/index.html | /tmpl/index.html |
/administrator/modules/mod_backendmodul/ tmpl/default.php | /tmpl/default.php |
Hintergrund: Unterschiede zwischen Frontend- und Backend-Modulen
Frontend-Module entwickeln Sie genau so wie das in diesem Kapitel vorgestellte Backend-Modul. Achten Sie dabei auf zwei Punkte:
-
Ändern Sie das client-Attribut im <extension>-Tag des XML-Manifests von administrator zu site.
-
Das Festlegen der Layout-Position erfolgt in der Modulliste des Frontends (Dropdown-Liste Filter: auf Site).