Web Programming Weeks SS18

Aus THM-Wiki
Wechseln zu: Navigation, Suche
Kurs
Kursname Web Programming Weeks SS 18
Kurstyp Projektkurs
Dozent Priefer, Rost, Dalmulder
Semester SS 18
Studiengang Bachelor Informatik, Bachelor SMS, Master Informatik


Diese Seite dokumentiert die Ergebnisse der Gruppenprojekte.


Inhaltsverzeichnis

Gruppe 1

Das Team

Name GitHub-Account
Jonas Gonka jonasgonka
Nurcihan Demirbas nurcihandem

Aufgabe1 - JMail Exception Handling

Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Beispiel Fehlerseite

Die Aufgabe besteht darin, das Exception-Handling aus JMail zu entfernen, basierend auf PR#12179. Im Moment werden Fehler aus PHPMail direkt in JMail behandelt. Jegliche Fehler, die in der JMail antreffen, verursachen auf der Joomla-Oberfläche eine Weiterleitung zu einer Error-Seite, die dem Nutzer keine aufschlussreichen Informationen über den vorliegenden Fehler gibt. Durch das Exception-Handling an den Models, die diese Klasse verwenden, sollte die Weiterleitung auf eine Error-Seite verhindert und stattdessen die Einblendung eines Modalfensters bewirkt werden.

Nur unter der Bedingung, dass Exception-Throwing eingeschaltet ist (standardmäßig ein), sollen Fehler zurückgegeben werden. Wenn es ausgeschaltet ist, sollen nur bool'sche Werte zurückgegeben werden.

Außerdem müssen alle anderen Stellen in Joomla, an denen JMail verwendet wird, angepasst werden, um die Exceptions, die jetzt eventuell weitergegeben werden, abzufangen.

Projektdokumentation

1. Übernehmen der Änderungen aus PR #12179 in die Datei:

  libraries/src/Mail/Mail.php

2. Änderung aller anderen Dateien in denen die JMail Klasse verwendet wird:

Dateipfad Methode Link Beschreibung
/administrator/components/
com_messages/Model/MessageModel.php
save()
/administrator/index.php?option=com_messages&
view=message&layout=edit
Beim Senden einer Direktnachricht wird an den Empfänger eine Mail darüber gesandt, dass dieser eine neue Nachricht hat. Wenn diese Mail nicht gesendet werden kann und ein Fehler entsteht, würde der Sender der Nachricht auf eine Fehlerseite weitergeleitet werden.
/administrator/components/
com_users/Model/MailModel.php
send()
/administrator/index.php?option=com_users&view=mail
Wenn der Admin versucht eine Mass-Mail an Nutzer zu schicken und dies fehlschlägt soll ein Fehler angezeigt werden anstatt den Admin auf eine Fehler-Seite weiter zu leiten.
IM MOMENT NICHT TESTBAR DA DER BUTTON FÜR DAS VERSENDEN DER EMAIL EINEN JAVASCRIPT ERROR AUSLÖST!
plugins/system/updatenotification/
updatenotification.php
onAfterRender()
/administrator/index.php?
option=com_plugins&view=plugin&
layout=edit&extension_id=452
Wenn es ein Joomla Update gibt soll eine Mail an alle oder bestimmte Super-User gesendet werden wenndas updatenotification-plugin aktiviert ist. Wenn dies nicht klappt kann es sein das ein Admin direkt beim laden der Seite auf eine Fehlerseite weitergeleitet wird.

NOCH NICHT GETESTET!

/components/com_contact/
Controller/ContactControlller.php
_sendEmail()
/index.php/contact
Bei diesem Testfall, wurde der Menüpunkt 'contact' genannt.
Im Frontend kann den Nutzern ein Kontaktformular bereitstehen, durch das die Administratoren schriftlich kontaktiert werden können. Über den angegebenen Pfad gelangt man zum Menü. Um die Mail-Funktion in der Klasse ContactController.php zu triggern, muss im Menüpunkt "Contact Form" bei valider Eingabe der Send-Button geklickt werden. Abhängig der Permissions-Einstellungen, die der Administrator gesetzt hat, muss der Nutzer sich dafür noch zusätzlich anmelden.
/plugins/user/
joomla/joomla.php
onUserAfterSave()
/administrator/index.php?
option=com_users&
view=user$layout=edit
Sobald ein User im Backend erstellt wird, wird dieser neue Nutzer per Email benachrichtigt.
/components/com_mailto/
Controller/DisplayController.php
send()
/index.php?view=article&
id=1:dasisteinartikel&catid=2
In diesem Fall hat der Beispielartikel den Alias "dasisteinartikel". Die übergeordnete Kategorie hatte die Id 2.
Anforderungen dafür ist die Erstellung eines Artikels, der auf der Seite angezeigt wird. Dieser kann einer individellen oder der vordefinierten Kategorie zugeordnet werden. Im Frontend ist dann der Artikel mit einem Zahnrad versehen, das die Teilfunktion per Mail bereitstellt. Von dort aus gelangt man zu einem zusätzlichen Fenster, in dem man seine Mail anpassen kann. Bei Klick auf den "Send"-Button wird das vorliegende Skript angesprochen.
/components/com_users/
Model/RemindModel.php
processRemindRequest()
/index.php/component/
users/remind?Itemid=101
Hier wird nach Eintrag einer Nutzeremail eine Email versand, die den Nutzernamen des jeweiligen Nutzers enthält. Dafür muss in das jeweilige Field eine Email-Adresse eingefügt werden, die einem bereits existierenden User zuzuordnen ist.
/components/com_users/
Model/ResetModel.php
processResetRequest()
/index.php/component/
users/reset?Itemid=101
Hier erhält der Nutzer neben einem Verifikationscode einen Link, über diesen er sein Passwort zurücksetzen kann.

Implementationsdetails

Die oben aufgeführten Klassen enthalten Funktionen, die Instanzen der Klasse MailModel erstellen und dessen zugehörige Funktionen aufrufen. Bisher wurden die Fehler, die dabei entstehen können, in der MailModel-Klasse verarbeitet. Um dieser ungeeigneten Verarbeitung entgegenzuwirken, wurden die jeweiligen Codeblöcke, die MailModel-Funktionen verwendeten mit einem try{} umschlossen. Die Fehler, die potenziell dabei entstehen könnten, werden im dem darauffolgenden catch(){}-Block aufgefangen und in der Webseitenansicht angezeigt.

Grundlegender Arbeitsschritt dafür war, im Code alle Verwendungsbereiche aller Funktionen der MailModel-Klasse ausfindig zu machen. Davon ausgehend konnten die jeweiligen Komponenten auf der Webseitenoberfläche ausgemacht und im besten Fall getestet werden. Teilweise war ein Test jedoch nicht möglich, da die betroffenen Funktionen von keinem UI-Element getriggert wurden.

Das erfolgreiche Testen des ExceptionHandlings erfordert das Herbeiführen von Fehlern. Diese wurden bereits ohne zusätzliche Einstellungen erzeugt, da auf den Testrechnern keine Mailserver installiert waren und somit jegliche Mailaktivitäten nicht durchgeführt werden konnten.

Probleme

Das finden der meisten Anwendungsfällen der Methoden der JMail Klasse und das behandeln der neuen Exceptions war weitestgehend kein Problem. Allerdings stellte es sich teilweise als sehr schwierig heraus aus dem Code heraus nachzuvollziehen an welchen Stellen auf der Website dieser ausgeführt wird, und welche Schritte dafür notwendig sind.

Außerdem waren die benötigten Fehlermeldungen an einigen Stellen nicht verfügbar und mussten in den Übersetzung-Dateien hinzugefügt werden.

Aufgabe2 - Batching Articles

Anlehnend an das Issue #21285

Hier geht es um die Batch-Funktion in dem Menüpunkt Articles. Diese Funktion bewirkt, dass Artikel in andere Kategorien verschoben oder kopiert werden. Bisher wird der Nutzer nach Klick auf den "Process"-Button in dem zugehörigen Modalfenster zu einer Error-Meldung weitergeleitet. Diese wird durch die nicht definierten Funktionen und Klassen verursacht, die in der

/administrator/components/com_content/Model/ArticleModel.php

Datei aufgerufen wird.

Außerdem ist die Instanz 'dispatcher' der Klasse JEventDispatcher fehlerhaft. Der darauffolgende Funktionsaufruf, der auf diese Instanz getriggert wird, folglich auch.

Projektdokumentation

Die betroffenen Klassennamen sind "JLoader" und "FieldsHelper". Fehlerhaft ist zudem der Aufruf der Funktion createTagsHelper(). Von diesen fehlerhaften Aufrufen sind die Funktionen batchMove() und batchCopy() betroffen. Es existiert eine abstrakte JLoader Klasse und eine konkrete Klasse FieldsHelper. Im Gegensatz dazu kann keine Funktionsdeklaration für createTagsHelper() gefunden werden.

JLoader:

/libraries/loader.php

FieldsHelper:

/administrator/components/com_fields/helpers/fields.php

JEventDispatcher wurde im Joomla! 4.0 anders modelliert. Diese sind nun separiert in den Ordnern

/libraries/src/Event

und

/libraries/src/Dispatcher

zu finden. Diese werden jedoch nicht angesprochen; das Event wird durch direkte Ansprache der Application übergeben.

Implementationsdetails

Wie zuvor erwähnt, werden bei Nutzung der Klassen JLoader und FieldsHelper ein Fehler geworfen, obwohl die Klassen jedoch existieren. Die Begründung hierfür ist, dass die beiden Klassen nicht in dem namespace, das im ArticleModel herrscht, definiert sind. Somit kann die Verbindung zu den jeweiligen Klassendefinitionen nicht hergestellt werden. Lösen kann man diesen Fehler dadurch, dass man speziell für diese zwei Fälle den namespace globalisiert, indem man vor dem Klassennamen ein Backslash einfügt. Diese Änderungen mussten sowohl in der batchCopy() als auch in batchMove() vorgenommen werden.

Für die createTagsHelper()-Funktion wurde zu Vergleichszwecken zunächst nach anderen Verwendungsbereichen gesucht, die in der vierten Joomla!-Version nicht vorzufinden waren. Im Hinblick darauf, wurde nach Funktionen gesucht, die zwar einen anderen Funktionsnamen haben, inhaltlich jedoch das selbe erledigen. Als auch hier keine aufschlussreichen Ergebnisse vorlagen, wurde diese Methode in der alten Joomla!-Version gesucht. Alle Verwendungsbereiche, die in der früheren Version vorlagen, waren bis auf den Fall im ArticleModel nicht mehr vorhanden. So kann man davon ausgehen, dass die Funktion eigentlich komplett entfernt wurde, nur in der einen Klasse vergessen wurde, entfernt zu werden. Bei einer simplen Entfernung der CodeZeile und der if-Klausel, die diese umschließt, ist das Issue vollständig gelöst, sodass die Artikel nun erfolgreich verschoben oder kopiert werden.

Die JEventDispatcher-Deklaration und der darauffolgende Eventaufruf wurden entfernt und durch die Zeile

Factory::getApplication()->triggerEvent('onContentAfterSave', array('com_content.article', &$this->table, false, $fieldsData));

ersetzt. Diese Änderung musste in den beiden Funktionen batchMove() und batchCopy() vorgenommen werden.

Letztlich wurde folgender PR erstellt und gemerged: #21325

Probleme

Schwierigkeiten gab es dabei kaum. Nach einigen Absprachen mit Herrn Dalmulder konnten Lösungswege schnell erfasst und umgesetzt werden. Die Irrelevanz der createTagsHelper()-Funktion war lediglich schwierig zu beweisen, erfolgte dann jedoch schnell, sobald an der richtigen Stelle gesucht wurde.

Aufgabe3 - Artikel Batch-Operationen Anzeige

Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Modal-Fenster mit fehlerhafter Anzeige der Optionen

Bei der Anzeige des Modalfensters zur Ausführung von Batch-Operationen auf Artikel wurde die Option zur Auswahl ob die Artikel in neue Kategorien kopiert oder verschoben werden sollen angezeigt bevor der Nutzer ausgewählt hat ob eine solche Operation durchgeführt werden soll. Dies soll dahingehend geändert werden das diese Optionen erst angezeigt werden wenn eine Option ausgewählt wurde.

Projektdokumentation

In der Datei \build\media\system\js\fields\batch-language.js wurde eine Zeile hinzugefügt die während der Umstellung von jQuery auf reines javascript verloren gegangen ist.

Nach dem testen wurde der PR#21340 angelegt.

Implementationsdetails

Um die Optionen standardmäßig auszublenden bis eine Auswahl getroffen wurde, ist folgende Zeile Code verwendet worden:

batchCopyMove.style.display = 'none';

Probleme

Da das Modal die Einblendung der Optionen über eine change-Event realisiert wurde erst versucht dieses Event manuell beim öffnen oder laden des Modalfensters auszulösen. Dies wurde sowohl mit in dem Modalfenster eingebettetem javascript als auch mit php in den entsprechenden Klassen versucht, hat allerdings in beiden Fällen nicht funktioniert.

Gruppe 2

Das Team

Name GitHub-Account
Benedikt Weber bene-we
Bilal Reffas Bilal Reffas
Niklas Deworetzki niklas-deworetzki-thm

Niklas Deworetzki

Grundlagen zu PHP Sessions

Da HTTP ein zustandsloses Protokoll ist, entsteht die Notwendigkeit, Informationen zu Nutzern auch zwischen mehreren Aufrufen lokal zwischenzuspeichern. Für diese Aufgabe gibt es PHP Sessions. Jedem Benutzer wird dabei eine einzigartige Session-ID zugeordnet, die vom Browser bei jedem weiteren Aufruf gesendet wird.

Es gibt Einstellungen, die für diese Sessions angewandt werden können. Um eine Persistenz für die Einstellungen zu bieten, können diese nur geändert werden, bevor eine Session gestartet wird. Wenn bei einer gestarteten Session versucht wird, diese Einstellungen zu ändern (beispielsweise mit der Methode ini_set()), wirft PHP eine Exception.

Daher ist ein Zugriff auf diese Einstellungen ohne eine vorherige Überprüfung, ob eine Session gestartet wurde, auch in einer alleinstehenden PHP Anwendung wie Joomla! eine potentielle Fehlerquelle, da zum Beispiel eine Session von einem anderen Programm gestartet werden kann, welches dann Joomla! selbst ausführt.

Joomla! 3.8 - Es tritt ein Fehler auf, wenn zuvor eine PHP Session gestartet wurde

Issue#15742 - Check if there is a valid session before messing with session ini values

Beschreibung

Wenn eine PHP Session gestartet ist, bevor die Joomla!-Anwendung gestartet wird, kommt es zu folgender Fehlermeldung: Warning: ini_set(): A session is active. You cannot change the session module's ini settings at this time in xxx/libraries/joomla/session/handler/joomla.php on line 48

Dieser Fehler trat bereits im September 2016 das erste mal auf. In der aktuellen Joomla! Version 3.8 hat bereits @PhilETaylor begonnen, sich mit dem Fehler zu befassen. Bei der weiteren Analyse beziehe ich mich daher auf seine Arbeit.

Reproduktion

Der Fehler wie im Issue beschrieben tritt anscheinend im Zusammenhang mit einer aktiven PHP Session in der Startroutine von Joomla! auf. Der erste Ansatz war, mit einer eigenen Erweiterung eine Session zu starten, um den Fehler zu reproduzieren. Leider klappt dieser Ansatz nicht, da Joomla! zu dem Zeitpunkt, wenn Erweiterungen geladen werden, bereits von Joomla! selbst eine Session angelegt wurde.

Um schließlich den Fehler zu reproduzieren, ändere ich die index.php und füge nach der Überprüfung für die richtige PHP Version die Zeile session_start() ein, um manuell eine Session zu starten. Beim Aufruf der Website wird dann die PHP Datei geladen und die Session gestartet, bevor die Startroutine von Joomla! beginnt. Joomla! startet also in eine bereits aktive Session hinein, versucht Werte der Session zu ändern, was fehlschlägt und der beschriebene Fehler tritt auf.

Ursache

Wie bereits zu sehen ist, liegt der Fehler an einem Aufruf von ini_set(), welcher verboten ist, während bereits eine PHP Session aktiv ist. Die Methode ini_set() kann verwendet werden, um während der Laufzeit Einstellungen von PHP zu modifizieren, dabei hat die Methode jedoch eine Einschränkung: Sie schlägt fehl, wenn bereits eine PHP Session gestartet wurde und aktiv ist.

Der Ursprung des Fehlers ist der Konstruktor von JSessionHandlerJoomla, in welchem via ini_set('session.use_trans_sid', '0') der transparente SID-Support deaktiviert wird. Dieser Aufruf scheitert, wenn eine Session aktiv ist, weswegen dann die Fehlermeldung angezeigt wird.

Behebung

Um den Fehler zu beheben, muss lediglich eine Abfrage eingefügt werden, um zu überprüfen, ob bereits eine Session aktiv ist. Ist dies der Fall, wird die Methode abgebrochen und kein Fehler geworfen. In der vorhandenen Diskussion des Issues wurde jedoch beschlossen, bei der Behebung die betroffenen Codezeilen vom Konstruktor in die JSessionHandlerJoomla::start Methode verschoben werden sollen.

Es gibt zwei Möglichkeiten, in PHP zu überprüfen, ob keine aktive Session vorliegt. Die empfohlene Methode ist der Vergleich des Sessionstatus mit einer Konstante: session_status() == PHP_SESSION_NONE. Diese Methode wurde jedoch erst mit PHP 5.4.0 eingeführt. Da Joomla! 3.8 die PHP Version 5.3.10 oder höher voraussetzt, kann diese Methode zum Abfragen der Session nicht verwendet werden. Stattdessen muss auf einen alten Workaround zurückgegriffen werden, bei welchem die ID der aktiven Session mit einem leeren String verglichen wird: session_id() == ''. Das Problem bei dieser Art der Überprüfung ist, dass, wenn die aktive Session einen leeren String als ID hat, der Test ausgehebelt wird und beim anschließenden Versuch, Werte in der Session zu ändern, wieder ein Fehler geworfen wird. Es ist zwar selten, dass dieses Verhalten auftritt, aber es kann nicht ausgeschlossen werden. Da es aber keine andere Alternative gibt, um auf eine aktive Session zu überprüfen, muss dieser Code verwendet werden.

Nach dem Einfügen der Abfrage ist die alte Fehlermeldung verschwunden, jedoch auch eine Neue hinzugekommen.

Beschreibung des Folgefehlers

Nach der Behebung des ersten Fehlers, kommt eine neue Fehlermeldung zum Vorschein, die zuvor durch das Scheitern von ini_set unterdrückt wurde. Der Ausgangszustand ist gleich geblieben: Eine Session muss gestartet werden, bevor Joomla! selbst gestartet wird, jedoch sieht die neue Fehlermeldung folgendermaßen aus: Warning: session_set_cookie_params(): Cannot change session cookie parameters when session is active in xxx/libraries/joomla/session/handler/joomla.php on line 151

Ursache des Folgefehlers

Die Ursache für den zweiten Fehler ist ähnlich wie bei dem Ersten: Es wird versucht eine Änderung zu machen, die nicht erlaubt ist, da bereits eine PHP Session läuft. Dieses Mal kommt der Fehler jedoch aus der Methode JSessionHandlerJoomla::setCookieParams, in welcher session_set_cookie_params() fehlschlägt. Diese Methode ist nur ein Wrapper um mehrere ini_set() Aufrufe, welche das Verhalten von Session-Cookies ändern.

Bevor die scheiternde Methode ausgeführt wird, wird mit headers_sent() überprüft, ob bereits Daten von PHP versandt wurden. Dieser Test soll verhindern, dass ein verbotener Zugriff auf ini_set() geschieht, kann jedoch fehlschlagen, wenn die Session zwar initialisiert, aber noch keine Daten versandt wurden.

Behebung des Folgefehlers

Wieder reicht eine einfache Abfrage aus, um zu verhindern, dass in einer aktiven Session Werte geändert werden.

Reflexion

Obwohl das Issue in seiner Lösung vom Codeumfang her, eher klein erscheint, gibt es viele Probleme, die beachtet werden müssen:

Es ist einerseits sehr schwer, den Fehler überhaupt erst zu reproduzieren, da eine Session in PHP erstellt werden muss, bevor der Joomla! geladen und gestartet wird. Daher kann keine eigene Komponente verwendet werden, um das fehlerhafte Verhalten zu erzwingen. Auch über eine Konsolenanwendung ist es nicht leicht, Joomla! zu starten, sodass der Fehler auftritt. Zudem ist eine Orientierung an den ursprünglichen Issues #15680 und #12153 nur bedingt möglich, da sie sich auf andere Versionen von Joomla! beziehen. Dies wirft die Frage auf, unter welchen Umständen dieser Fehler überhaupt aufgetreten ist und ob nicht ein Fehler in der Art und Weise, wie Joomla! verwendet wird, vorliegt.

Ein weiteres Problem bei der Beseitigung des Fehlers ist, dass zwar die Fehlermeldung unterdrückt wird, aber das Setzen der Werte trotzdem fehlschlägt. Daher scheitert das Setzen von potentiell wichtigen Einstellungen unbemerkt, was zwar das Starten von Joomla! ohne Fehlermeldung ermöglicht, aber eventuell im weiteren Betrieb zu Einschränkungen in der Funktionsweise von Joomla! führen kann, welche dann nur noch sehr schwer nachzuvollziehen sind. Daher wird in der Dokumentation eine Warnung hinzugefügt, dass beim Setzen einer PHP Session vor dem Starten des Joomla!-Frameworks, unbedingt Einstellungen bezüglich der Cookies beachtet werden sollten.


Joomla! 4.0 - Es tritt ein Fehler auf, wenn zuvor eine PHP Session gestartet wurde

Issue #21337

Beschreibung und Ursache
Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Joomla! 4.0 wenn in eine aktive PHP Session hinein gestartet wurde

Wie bei Version 3.8 tritt auch in Joomla! 4.0 ein Fehler auf, wenn eine PHP Session gestartet wurde, bevor Joomla! selbst gestartet wird. Die ersten beiden Fehlermeldung ist ähnlich der aus Version 3.8, lediglich die Datei ist anders: /libraries/src/Session/Storage/JoomlaStorage.php

Es wird wie in Version 3.8 ohne Überprüfung versucht, Werte der PHP Session zu ändern. Da bereits eine Session gestartet wurde, ist dies nicht mehr erlaubt, woraufhin PHP eine Exception wirft, welche dem Nutzer auf der Website angezeigt wird.


Behebung

Um das Auftreten der Exception zu vermeiden, muss vor dem schreibenden Zugriff auf die Session abgefragt werden, ob die Session gestartet wurde. Da Joomla! 4.0 als Voraussetzung die PHP Version 7.0 erwartet, kann in diesem Fall mit session_status() gearbeitet werden.

Die Methode session_status() ist eine interne Methode von PHP, um abzufragen, welchen Zustand die aktuelle Session hat. Dabei können drei verschiedene Rückgabewerte vorkommen:

  • PHP_SESSION_DISABLED wenn die Sitzung deaktiviert ist.
  • PHP_SESSION_NONE wenn Sitzungen aktiviert sind, aber keine existiert.
  • PHP_SESSION_ACTIVE wenn Sitzungen aktiviert sind und eine existiert.

Da bei einer gestarteten Session (PHP_SESSION_ACTIVE) eine Exception geworfen wird, wenn versucht wird, Werte zu ändern, muss dieser Zustand abgefangen werden. Wenn keine gestartete Session vorliegt (PHP_SESSION_NONE) können problemlos Werte geändert werden, also muss dieser Zustand eine Änderung zulassen. Da aber noch ein dritten Status existiert (PHP_SESSION_DISABLED), gibt es zwei Möglichkeiten, die Überprüfung zu implementieren:

  1. Abfrage mit session_status() == PHP_SESSION_NONE überprüft, ob keine Session vorliegt
  2. Abfrage mit session_status() !== PHP_SESSION_ACTIVE überprüft, ob keine active Session vorliegt


session_status() session_status() == PHP_SESSION_NONE session_status() !== PHP_SESSION_ACTIVE
PHP_SESSION_DISABLED Änderungen verhindert Änderungen möglich
PHP_SESSION_NONE Änderungen möglich Änderungen möglich
PHP_SESSION_ACTIVE Änderungen verhindert Änderungen verhindert

Wie zu erkennen ist, liegt der Unterschied in den verschiedenen Implementierungen, wie mit dem Fall umgegangen wird, wenn die PHP Session deaktiviert wurde (PHP_SESSION_DISABLED). Es gibt in Joomla! 4.0 eine Klasse, die für die Verwaltung von PHP Sessions zuständig ist. Die in dieser Klasse vorgegebene Methode session/src/Storage/NativeStorage->isActive() ist nur eine Weiterleitung an session_status() == PHP_SESSION_ACTIVE.

Daher muss bei der Implementierung darüber nachgedacht werden, wie mit diesem Fall umgegangen werden soll. Die eigene Implementierung mit session_status() == PHP_SESSIO_NONE gibt Sicherheit im Fall, wenn Sessions deaktiviert sind, da dann keine Werte der Session geändert werden können. Die andere Methode ist dafür standardisiert und vom Joomla! Framework vorgegeben. Nach einer Diskussion mit @wilsonge, @mbabker und letztendlich auch @roland-d wurde beschlossen, die vom Framework vorgegebene Methode zu verwenden und die Tatsache zu ignorieren, dass diese bei deaktivierten PHP Sessions fehlschlägt. Die Begründung dafür ist, dass Joomla! mit deaktivierter Session keine Nutzerdaten speichern kann. Das bewirkt zum einen, dass man sich bei jedem Aufruf der Seite erneut anmelden muss, aber auch, dass potentiell andere wichtige Daten während der Laufzeit von Joomla! fehlen. Es ist daher nicht ratsam, Joomla! mit deaktivierten PHP Sessions zu verwenden und fragwürdig, ob Joomla! in dieser Situation überhaupt funktionstüchtig ist.

Das Testen mit deaktivierter Session gestaltet sich dabei auch als umständlich, da der einzige Weg, um Sessions in PHP zu deaktivieren ist, PHP ohne Sessionsupport zu installieren, welcher standardmäßig aktiviert ist. Daher muss, um PHP mit deaktivierten Sessions zu nutzen, das Paket selbst gebaut werden, was von typischen Nutzern des Joomla! CMS nicht erwartet wird.

Leere Fehlerseite nach Anwenden der Fixes

Nachdem die Abfragen in der Sessionverwaltung von Joomla! hinzugefügt wurde, erscheint beim Aufruf der Website immer noch eine Fehlerseite. Dabei wird jedoch keine Fehlernachricht, Exception oder Ähnliches angezeigt.

Da keine Informationen über die Fehlerursache vorhanden sind, wurde zunächst versucht, per Debugger nachzuvollziehen, wo in der Startroutine von Joomla! ein Fehler wegen der vorzeitig gestarteten Session auftritt. Wenn jedoch mit XDebug und PHPStorm gearbeitet wird, schafft es der Datenbanktreiber für MySQL nicht, eine Verbindung zur Datenbank aufzubauen, sodass ein komplett anderer Fehler entsteht. Daher kann in diesem Fall nicht mit dem Debugger gearbeitet werden. Die Alternative, manuell nach Codeteilen zu suchen, die mit der PHP Session interagieren, ist jedoch auch umständlich, da hunderte Klassen per Reflection geladen werden, sodass der Ablauf nur schwer nachzuvollziehen ist.

Daher habe ich Joomla!s Exceptionhandler gesucht, um ihn so umzuändern, dass eine Fehlermeldung angezeigt wird. Dabei gestaltete sich als zusätzliche Schwierigkeit die Tatsache, dass es in Version 4.0 mehrere Exceptionhandler gibt. Wie sich herausstellte, ist /libraries/vendor/symfony/debug/ExceptionHandler.php die gesuchte Klasse, welche sich so abändern lässt, dass eine genaue Fehlermeldung ausgegeben wird.

Im Stacktrace lässt sich die Ursache dann zurückverfolgen bis in die Klasse /libraries/vendor/joomla/session/src/Storage/NativeStorage.php, welche ein Wrapper für die PHP Session ist. Dort ist in Zeile 403 folgende Methode als Ursache des Fehlers zu erkennen:

 public function setName(string $name)
 {
 	if ($this->isActive())
 	{
 		throw new \LogicException('Cannot change the name of an active session');
 	}
 
 	session_name($name);
 
 	return $this;
 }

In der neuen Version von Joomla! ist man sich der Problematik bewusst, welche auftreten kann, wenn bereits eine PHP Session gestartet ist und behandelt ihn durch Beenden der gesamten Webanwendung.

Auswirkungen für Joomla! 3.8

Da es in Joomla! 4.0 gewollt ist, die Webanwendung zu beenden, wenn bereits eine Session gestartet wurde, muss in Betrachtung gezogen werden, dieses Verhalten auch für Joomla! 3.8 zu implementieren. Der vorzeitiger Start einer Session hat nicht so gravierende Auswirkungen, wie das Deaktivieren von Sessions, da zumindest noch Nutzerdaten in der Session gespeichert werden können, was ein nahezu normales Verhalten von Joomla! ermöglicht. Jedoch können bei einer aktiven Session die Einstellungen bezüglich der Cookies nicht mehr geändert werden, was ein potentielles Sicherheitsproblem darstellt oder bei fehlerhafter Konfiguration letztendlich auch dazu führen kann, dass Joomla! nicht wie gewollt funktioniert.

Zum aktuellen Zeitpunkt gab es jedoch kein Feedback von der Joomla! Community, sodass die Frage, ob das Verhalten von Joomla! 4.0 in Joomla! 3.8 imitiert werden sollte, noch offen steht.

Benedikt Weber

Improving menu item workflow #11766

Link zum originalen Pull-Request: #11766
Link zu meinem Pull-Request: #21357

Aufgabe / Ziel

Die Aufgabe besteht darin, den Workflow für das Anlegen von Artikeln und dem späteren Anlegen von Menüeinträgen zu verbessern. Dies geschieht durch einen Button auf der Seite, auf dem ein neuer Artikel angelegt wird. Beim Betätigen öffnet sich ein Modal-Fenster, in dem alle Einstellungen für den entsprechenden Menüeintrag getätigt werden können.

Aktuelle Situation

Wenn man einen neuen Artikel erstellt, benötigt man einen Menüeintrag, der auf diesen Artikel verweist (außer es existiert bereits ein Eintrag für mehrere Artikel, beispielsweise für eine Kategorie). Nach dem Speichern des Artikels muss man über die Sidebar über Menus - [Entsprechendes Menü] - New Menu Item auswählen, um einen referenzierenden Eintrag für den neu erstellten Artikel anzulegen.

Vorbereitung

Die erste Schwierigkeit bestand darin, sich mit dem System auseinanderzusetzen. Da das Feature Einzug in Joomla 4.0 halten soll, gestaltete sich die Recherche als sehr mühselig, da nahezu keine Dokumentation vorhanden ist. Aufgrund dessen musste ich mich langsam an das Problem herantasten und mich durch verschiedenste Dateien, Klassen und Methoden wühlen. Ziel waren Code-Fragmente, an denen ich mir die Funktionsweise der benötigten Komponenten herleiten konnte. Das Modal-Popup wurde in Version 4 von Joomla ebenfalls überarbeitet, weshalb ich dazu im Internet nicht fündig wurde. Als ersten Anhaltspunkt fand ich eine .php-Datei, die ein Modalfenster abbildet, um einen neuen Menüeintrag anzulegen (Speicherort: /administrator/components/com_menus/Field/Modal/MenuField.php). Diese Datei beinhaltet nicht nur den Inhalt für das Modalfenster, das auf der NewArticle-Seite eingebunden werden muss, sondern zusätzlich auch noch einen Button für ein anderes Modal-Popup, an dessen Code ich mich orientieren konnte. Mit dieser Basis konnte ich starten, den benötigten Button und das dazugehörige Modal zu implementieren.

Funktionsweise des Modal-Fensters

Das Modal-Fenster wird mittels Bootstrap dargestellt, dafür werden zwei .js-Dateien benötigt. Mit folgendem Code werden die Skripte in der /administrator/components/com_content/View/Article/HtmlView.php eingebunden:

// Add the modal field script to the document head.
HTMLHelper::_('jquery.framework');
HTMLHelper::_('script', 'system/fields/modal-fields.min.js', array('version' => 'auto', 'relative' => true));

Um das Modal auf der entsprechenden Seite anzuzeigen, muss der entsprechende HTML-Code generiert werden. Dazu müssen einige Parameter gesetzt werden:

// Add the modal html to the document
echo HTMLHelper::_(
	'bootstrap.renderModal',
	'ModalNewItem_' . $modalId,
	array(
		'title' => Text::_('COM_MENUS_NEW_MENUITEM'),
		'backdrop' => 'static',
		'keyboard' => false,
		'closeButton' => false,
		'url' => $urlNew,
		'height' => '400px',
		'width' => '800px',
		'bodyHeight' => 70,
		'modalWidth' => 80,
		'footer' => '<a role="button" class="btn btn-secondary" aria-hidden="true"'
			. ' onclick="window.processModalEdit(this, \'' . $modalId . '\', \'add\', \'item\', \'cancel\', \'item-form\'); return false;">'
			. Text::_('JLIB_HTML_BEHAVIOR_CLOSE') . '</a>'
			. '<a role="button" class="btn btn-primary" aria-hidden="true"'
			. ' onclick="window.processModalEdit(this, \'' . $modalId . '\', \'add\', \'item\', \'save\', \'item-form\'); return false;">'
			. Text::_('JSAVE') . '</a>'
			. '<a role="button" class="btn btn-success" aria-hidden="true"'
			. ' onclick="window.processModalEdit(this, \'' . $modalId . '\', \'add\', \'item\', \'apply\', \'item-form\'); return false;">'
			. Text::_('JAPPLY') . '</a>'
	)
);

Einige Parameter sind selbsterklärend, für diesen Anwendungsfall konnten die meisten aus der MenuField.php übernommen werden. Wichtige Attribute sind in Zeile 3 die ID des Modalfensters, damit man dieses per Button aufrufen kann, und die URL in Zeile 9.

Inhalt des Modal-Fensters durch URL festlegen

Durch die URL wird der Inhalt des Fensters spezifiziert, in diesem Fall die Seite für das Erstellen eines neuen Menü-Items. Die URL setzt sich aus den folgenden Teilen zusammen:

$linkSuffix = '&amp;layout=modal&amp;client_id=0&amp;tmpl=component&amp;' . Session::getFormToken() . '=1';
$linkItem   = 'index.php?option=com_menus&amp;view=item' . $linkSuffix;

if (isset($this->element['language']))
{
	$linkItem   .= '&amp;forcedLanguage=' . $this->element['language'];
}

$urlNew    = $linkItem . '&amp;task=item.add';

Eine Beispiel-URL könnte dabei folgendermaßen aussehen:

index.php?option=com_menus&view=item&layout=modal&client_id=0 &tmpl=component&a73ea85bae62f78d517fd337f2d5a6bc=1&task=item.add
  • Die benötigte Komponente ist com_menus
  • Der View der Komponente ist item (nicht items)
  • Die client_id ist 0, was für das Frontend steht; Im Backend werden keine Menüeinträge für Artikel benötigt
  • tmpl=component teilt der Seite mit, dass sie ohne Header, Footer oder sonstige Elemente angezeigt wird, die in einem Modal überflüssig sind
  • Die Session-ID ist natürlich Unique, die obenstehende ist nur ein Beispiel
  • Als letztes spezifieziert der task, was der Zweck des Modals ist, in diesem Fall möchte man ein neues Item anlegen; Je nach Task werden verschiedene Form-Elemente und Buttons angezeigt

Nun fehlt nur noch eine Schaltfläche, die der Nutzer betätigen kann:

Der Button zum Öffnen des Popups

Der letzte benötigte Schritt für ein funktionierendes Modal-Fenster ist nun ein Button, auf dessen Klick sich das Popup öffnet. In der MenuField.php wurde dies durch einen <a>-Tag realisiert:

$html .= '<a'
	. ' class="btn btn-secondary hasTooltip' . ($value ? ' sr-only' : '') . '"'
	. ' id="' . $this->id . '_new"'
	. ' data-toggle="modal"'
	. ' role="button"'
	. ' href="#ModalNew' . $modalId . '"'
	. ' title="' . HTMLHelper::tooltipText('COM_MENUS_NEW_MENUITEM') . '">'
	. '<span class="icon-new" aria-hidden="true"></span> ' . Text::_('JACTION_CREATE')
	. '</a>';

Dies ist auf der Article-Seite nicht ohne weiteres möglich, da der Button in der Toolbar angezeigt werden soll. Gibt man HTML auf der Seite aus, wird der Button lediglich unterhalb der Toolbar angezeigt, was nicht dem Ziellayout entspricht. Um der Toolbar einen vollwertigen Button hinzuzufügen, verwendete ich die ToolbarHelper-Klasse:

ToolbarHelper::modal('ModalNewItem_' . $this->id, 'icon-new', 'New Menu Item');

Dieser Einzeiler generiert den benötigten HTML-Code für einen Button, der ein Modal mit der entsprechenden ID öffnet.

Damit sind alle Komponenten fertig, ich musste lediglich noch einige Bugs fixen.

Bugfixes

Wie überall traten natürlich Bugs auf, die ich zuerst finden und dann fixen musste. Zum Glück konnte mir Roland bei vielen Dingen helfen, vor allem bei Joomla-spezifischen Entscheidungsfragen. Alle Bugs wurden erfolgreich beseitigt, wodurch dem Merge nichts mehr im Wege stand.

Edit: Roland fiel während der Präsentation auf, dass die Beschriftung nicht als Language String, sondern "hardcoded" als englischen Ausdruck ausgegeben wird.

Showcase


Fazit

Die Einarbeitungszeit benötigte wie oben erwähnt sehr lange, letztendlich wurde das Feature jedoch umgesetzt. Der Pull-Request wurde erfolgreich getestet und nach ungewöhnlich kurzer Zeit gemerged. Dies liegt daran, dass Joomla! 4.0 noch nicht Stable ist und bestimmte Bereiche noch überarbeitet werden müssen.
Link zur Präsentation

Bilal Karim Reffas

Aufgabe

Was muss an Joomla verändert werden, damit eine erfolgreiche Anbindung an eine MYSQL 8 Datenbank möglich ist? Zu dieser Aufgabe gibt es weder ein Issue noch ein Pull Request. Die Aufgabe beschäftigt sich damit, dass jegliche Konfiguration Dateien im Server überprüft werden müssen, wie auch der Code im Client, um den Fehler zu eliminieren. Dabei muss man von der untersten Ebene angefangen werden, weil noch keine Vorarbeit geleistet worden ist. Es kann am Ende durchaus sein, dass an Joomla Codebase nichts verändert werden muss, weil es sich eventuell um PHP-Fehler oder gar Server-Fehler handelt. Wenn es sich um ein Fehler handelt, welches von der Programmiersprache ausgeht, dann soll eine Meldung den Nutzern informieren, dass die aktuelle MYSQL Version noch nicht von Joomla unterstützt.

Aktuelles Situation

Nach dem Forken der aktuellen Joomla 4.0 Branch erscheint folgende Fehlermeldung, wenn man die Installation Schritte durchführt: [[Datei:Errormessage.png|mini| Fehlermeldung bei Verbindung von Joomla 4.0 & MYSQL 8] Dies geschieht währen des Setups der Webseite und bei der Auswahl von MYSQLi, allerdings tritt der selbe Fehler auf bei der Auswahl von PDO auf.

Gewünschte Situation

Das Gewünschte Ereignis ist, dass die Anwendung eine erfolgreiche Meldung ausgibt und eine Installation mit MYSQL 8 einwandfrei möglich ist.

MYSQL 8

In MYQL gibt es einige neue Features und dennoch besitzt MYSQL 8 auch breaking changes für viele Frameworks. Viele Programmiersprache wie Go, Perl und auch PHP haben das Problem, dass die internen SQL Treiber sich nicht mit einer MYSQL 8 anbinden lassen können. In MYSQL 8 wurde das Standard-Authentifizierungs-Plugin verändert, sodass das interne Handling von Passwörter anders funktioniert. Die neue Methode soll robuster, schneller und sicherer sein. Seit MYSQL 5.6 ist das sha256_password Standard-Authentifizierungs-Plugin schon verfügbar und wird jetzt als Standard Authentifizierung verwendet.

Arbeitsweise von MYSQL 8

Der Vorteil von mysql_native_password ist, dass es Challenge-Response-Mechanismen unterstützt, die sehr schnell sind und keine verschlüsselte Verbindung erfordern. Mysql_native_password stützt sich jedoch auf den SHA1-Algorithmus und NIST (National Institute of Standards and Technology) hat vorgeschlagen, es nicht mehr zu verwenden. Wenn zwei Benutzerkonten dasselbe Kennwort verwenden, ist die mysql_native_password-Umwandlung in der Tabelle mysql.user identisch. Obwohl die Hash-Informationen über das tatsächliche Kennwort nicht verfügbar macht, teilt es dennoch mit, welche zwei Benutzer dasselbe Kennwort verwenden. Um dies zu vermeiden, sollte Salt verwendet werden. Salt ist im Grunde eine Zufallszahl, die als eine der Eingaben für kryptografische Hash-Funktionen verwendet wird, die zum Transformieren von Benutzerpasswörtern verwendet werden. Da salt für jede Ausführung zufällig und unterschiedlich ist, würde das Endergebnis der Transformation sehr unterschiedlich aussehen, selbst wenn zwei Benutzer dieselben Passwörter verwenden. Seit MySQL 5.6 wird das sha256_password Authentifizierungs-Plugin unterstützt. Es verwendet mehrere Runden von SHA256-Hash für ein gesalzenes Passwort, um sicherzustellen, dass die Hash-Transformation sicherer ist. Es erfordert jedoch entweder verschlüsselte Verbindungen oder Unterstützung für ein RSA-Schlüsselpaar. Während also die Passwortsicherheit stärker ist, benötigen sichere Verbindungen und mehrere Runden von Hash-Transformationen mehr Zeit für den Authentifizierungsprozess.

Installation

Ubuntu

Installation von 16.04 und 18.04.

Module

Installation von MYSQL 8, xdev_api und deren Abhängigkeiten.

Konfiguration

Änderung der Konfigurationsdatei unter dem Pfad /etc/my.cnf.

Ausführung

Folgendes Skript soll eine Verbindung mit der MYSQL 8 Datenbank herstellen.

<?php
$con = @mysqli_connect('127.0.0.1', 'bilalreffas', 'Chiller123#', 'joomla_db');
if (!$con) {
    echo "Error: " . mysqli_connect_error();
	exit();
} else {
	echo 'Successfully Connected to MYSQL';
}
?>

Schwierigkeiten

Das PHP-Skript unter Ausführung gibt folgende Fehlermeldung aus:
The server requested authentication method unknown to the client. Auch andere große Open source Projekte haben Probleme mit der Anbindung wie zum Beispiel Phpmyadmin oder die Programmiersprache-GO. Da auf der lokalen Rechenmaschine nur MYSQL 5.7 installiert war, musste die aktuelle Version von MYSQL heruntergeladen werden. Dies war ohne weiteres nicht so einfach möglich, denn eine Installation von MYSQL 8 auf die lokale Umgebung, würde die Informationen von MYSQL 5.7 einfach überschreiben und das würde zu großen Fehlern führen. Letztendlich konnte ich erfolgreich per brew (Package Manger unter macOS) die Einstellungen so ändern, dass meine lokale Konfigurationen von MYSQL 5.7 nicht überschreibet werden. Nach der Installation von MYSQL 8, war wie erwartet, eine Installation von Joomla nicht möglich. Es ist nur eine Fehlermeldung sichtbar, die vor der Installation erscheint, wenn die Verbindung zur Datenbank hergestellt werden soll. Das Framework xdev_api ermöglicht die erfolgreiche Anbindung von MYSQL 8 per PHP. Es werden folgende Anforderungen benötigt, damit das Modul verwendet werden kann. Das Modul hat sehr viele Abhängigkeiten, dadurch kam es vermehrt zu Fehlermeldungen unter des Betriebssystems macOS. Da die Anforderungen unter Ubuntu beschrieben wurden, habe ich eine Virtuelle Maschine aufgesetzt, damit bei der Installation von den Abhängigkeiten keine Problemen enstehen. Obwohl ich Ubuntu 18 installiert hatte kam es dennoch zu Problemen, deshalb wurde die Installation der Abhängigkeiten unter Ubuntu 16 angewendet. Nach der Installation von Ubuntu 16 konnten die Abhängigkeiten erfolgreich installiert werden und es war eine Anbindung von PHP an eine MYSQL 8 Datenbank möglich. Das Modul ist für Joomla aber nicht zu empfehlen weil es das Feature von MYSQL 8 ermöglicht, das Daten als Dokumente gespeichert werden können. Joomla setzt allerdings auf Relation und deshalb kann das Modul nicht verwendet werden. Um herauszufiltern ob das Problem an PHP liegt wurde ein PHP-Skript entwickelt, um sich mit der MYSQL 8 Datenbank zu verbinden. Ein Workaround ermöglicht, dass das alte Passwordhandling zu bevorzugen ist, dadurch lässt sich Joomla wie gewohnt ohne Probleme aufsetzen. Unter dem Pfad /etc/my.cnf muss man in der Konfiguration-Datei folgende Einstellung vornehmen:

[mysqld]
default-authentication-plugin=mysql_native_password

Das ermöglicht das Joomla verwendet werden kann ohne weitere Probleme, außer bei Jooomla 4.0 da ist der Content der Webseite nicht sichtbar, unter Joomla 3.8 oder 3.9 ist dies aber nicht der Fall.
Das liegt an folgenden Queries unter des Projektes /Applications/MAMP/htdocs/joomla-cms/installation/sql/mysql/joomla.sql:

INSERT INTO `#__modules` (`id`, `asset_id`, `title`, `note`, `content`, `ordering`, `position`, `checked_out`, `checked_out_time`, `publish_up`, `publish_down`, `published`, `module`, `access`, `showtitle`, `params`, `client_id`, `language`) VALUES
(1, 39, 'Main Menu', '', '', 1, 'sidebar-right', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_menu', 1, 1, '{"menutype":"mainmenu","startLevel":"0","endLevel":"0","showAllChildren":"1","tag_id":"","class_sfx":"","window_open":"","layout":"","moduleclass_sfx":"_menu","cache":"1","cache_time":"900","cachemode":"itemid"}', 0, '*'),
(2, 40, 'Login', '', '', 1, 'login', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_login', 1, 1, '', 1, '*'),
(3, 41, 'Popular Articles', '', '', 3, 'cpanel', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_popular', 3, 1, '{"count":"5","catid":"","user_id":"0","layout":"_:default","moduleclass_sfx":"","cache":"0"}', 1, '*'),
(4, 42, 'Recently Added Articles', '', '', 4, 'cpanel', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_latest', 3, 1, '{"count":"5","ordering":"c_dsc","catid":"","user_id":"0","layout":"_:default","moduleclass_sfx":"","cache":"0"}', 1, '*'),
(8, 43, 'Toolbar', '', '', 1, 'toolbar', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_toolbar', 3, 1, '', 1, '*'),
(9, 44, 'Quick Icons', '', '', 1, 'icon', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_quickicon', 3, 1, '', 1, '*'),
(10, 45, 'Logged-in Users', '', '', 2, 'cpanel', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_logged', 3, 1, '{"count":"5","name":"1","layout":"_:default","moduleclass_sfx":"","cache":"0"}', 1, '*'),
(12, 46, 'Admin Menu', '', '', 1, 'menu', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_menu', 3, 1, '{"layout":"","moduleclass_sfx":"","shownew":"1","showhelp":"1","cache":"0"}', 1, '*'),
(13, 47, 'Admin Submenu', '', '', 1, 'submenu', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_submenu', 3, 1, '', 1, '*'),
(14, 48, 'User Status', '', '', 2, 'status', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_status', 3, 1, '', 1, '*'),
(15, 49, 'Title', '', '', 1, 'title', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_title', 3, 1, '', 1, '*'),
(16, 50, 'Login Form', '', '', 7, 'sidebar-right', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_login', 1, 1, '{"greeting":"1","name":"0"}', 0, '*'),
(17, 51, 'Breadcrumbs', '', '', 1, 'breadcrumbs', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_breadcrumbs', 1, 1, '{"moduleclass_sfx":"","showHome":"1","homeText":"","showComponent":"1","separator":"","cache":"0","cache_time":"0","cachemode":"itemid"}', 0, '*'),
(79, 52, 'Multilanguage status', '', '', 1, '', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 0, 'mod_multilangstatus', 3, 1, '{"layout":"_:default","moduleclass_sfx":"","cache":"0"}', 1, '*'),
(86, 53, 'Joomla Version', '', '', 1, 'status', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_version', 3, 1, '{"layout":"_:default","moduleclass_sfx":"","cache":"0"}', 1, '*'),
(87, 55, 'Sample Data', '', '', 0, 'cpanel', 0, '0000-00-00 00:00:00', '0000-00-00 00:00:00', '0000-00-00 00:00:00', 1, 'mod_sampledata', 6, 1, '{}', 1, '*');
Fehler beim Erstellen des Vorschaubildes: Datei fehlt
Nicht sichtbarer Inhalt unter Joomla 4.0 & MYSQL 8 mittels Workaround

MYSQL 8 gibt nämlich als Fehlermeldung zurück, dass das Datum einen inkorrekten Typen aufweist. Incorrect date value: '0000-00-00', welches daran liegt, dass seit MYSQL 5.7 keine zero values in Datetime unterstützt werden. Dieser Fehler lässt sich beheben indem das Datum auf '1970-01-01', NULL, oder CURRENT_TIMESTAMP umändert.

Fazit

Meine Fehleruntersuchung ergab, dass es ein Problem der Skriptsprache PHP handelt, welches nicht mit der aktuellsten Version von MYSQL umgehen kann, allerdings gibt es in der Version von PHP 7.3.0 schon einen gemerged pull request. Mehrere Programmiersprache haben das selbe Problem und arbeiten schon an einen Fehlerbehebung. Meine recherchen ergaben, dass an der Codebase von Joomla nichts verändert werden muss, außer eine Benachrichtigung an des Benutzern, wenn dieser MYSQL 8 verwenden möchte. Einen Wiki Eintrag habe ich verfasst auf der offiziellen Joomla Webseite, damit die oben beschriebene Punkte auch dort ihren Platz finden. Mein Pull Request ist leider noch nicht gemerged, aber es steht auf RTC.

Gruppe 3

Das Team

Name GitHub-Account
Paulina Niederhöfer priiish

Language File Review

* Pull Request

Task

The task was to review the existing language files for the Publishing Workflow feature of the upcoming version 4 of Joomla!.

Project documentation

First of all I installed the 4.0.0-dev version of Joomla! 4. Then I forked the corresponding repository from Github and worked in a cloned version (those steps are consistent for all upcoming tasks). After working in my own branch I created a pull request. I worked on two en-GB.com_workflow.ini files which can be found in administrator/language/en-GB/en-GB.com_workflow.ini.

Details of implementation

The implementation consisted of a complete file review. Due to the fact that the feature is completely new, a lot of translated messages were inconsistent with the declarations / translations in the global language files. I concentrated on translating the messages and expressions into correctly written English and also tried to stick to the structure used globally.

Difficulties

Due to the feature being very new and the translated English being sometimes really hard to understand, it was partly difficult to find out the real meaning of a certain message.


Software & UX Test

Pull Request for bug fixes

Pull Request for work on states & categories

Task

The task consisted of testing the new Publishing Workflow feature in regard to the application itself and the UX aswell. Due to my studies being a mix of media and IT, I know about the qualities of a good application in regard to technology and user friendly design.

Project documentation

The Publishing Workflow consists of a Workflow that can be set up individually. This means creating different states and categories which contain articles. The user can manage the workflow in the administrator view. I started testing the technical / functional side of the application. This included creating new workflows, states, categories and articles. I also tested the "default" option for states or "featured" option for articles. My aim was testing every possible action a user can execute. During those tests I noticed some errors being thrown that displayed false messages. Furthermore I noticed that the default option for a state could not be set using the star icon in the toolbar. From a UX point of view the application looked fine to me. The buttons contain helpful icons and nearly every action, a user can take, is explained as well (either marked with a keyword or a text pops up while hovering over an item). The connection between workflow, state, category and article can be confusing at first. A visualization of the user's individual workflow is already in planning though and I have written a Joomla! DOC for further explanation.

Details of implementation

There were several issues that I fixed.
1. Bug fixes
Issue: When trying to delete the default state an error message was thrown, displaying that "item must be published first". This was clearly the wrong message. The user needs to be informed that he / she is trying to delete the default item. A message that the "item must be published first" is useless. After the failed deletion a confirmation message was displayed; "0 items trashed" - which was quite confusing. This message should only be displayed if at least 1 item was moved to trash.

Fixes: Replaced JText::_('COM_WORKFLOW_ITEM_MUST_PUBLISHED') with JText::_('COM_WORKFLOW_MSG_DELETE_DEFAULT').

if ($table->load(array('id' => $pk)) && $table->default)
{
   $app->enqueueMessage(\JText::_('COM_WORKFLOW_MSG_DELETE_DEFAULT'), 'error');


I fixed the code so now only if the number of items deleted (moved to trash) is greater than 0 a message will be displayed.

if (count($cid))
{
   $this->setMessage(\JText::plural($ntext, count($cid)));
}


2. States & Categories in the Publishing Workflow
Issue: It was possible to move states and categories, that were in use by items, to trash. When trying to delete the trashed states or categories completely though, an error message came up displaying that the items could not be deleted, since they were in use by items. After consultation with Benjamin, we agreed that this does not make a lot of sense. Therefore it should not be possible to move states and categories, which were not empty, into the trash. Furthermore there was another problem with the deletion of states. Deleting empty states was possible but there was an error that the "table was not found".

Fixes: In the function publish() in AdminModel.php I inserted a trigger for the event_before_delete. As soon as the task "trash" is being executed, a function in joomla.php, which checks the categories and states before they can be deleted / moved to trash, is being called.

// Access checks.
foreach ($pks as $i => $pk)
{
   $table->reset();

if ($table->load($pk))
{ 
// Get the task - if it is "trash" then trigger event_before_delete
   $task = \JFactory::getApplication()->input->getCmd('task');

if ($task === 'trash')
 {
   $context = $this->option . '.' . $this->name;

// Trigger the before delete event so it checks if category is empty.
   $resultItem = \JFactory::getApplication()->triggerEvent($this->event_before_delete, array($context, $table));

// If the previously checked category has items associated with it, it cannot be moved to trash.
if (in_array(false, $resultItem, true))
{
// Prune items that you can't change.
    unset($pks[$i]);
    return false;

   }
  }
 }
}


Also I fixed a parameter in two functions regarding the state in joomla.php. In a function the variable tableinfo is set as

$tableInfo = [
			'com_content' => array('table_name' => '#__content')
		];


This array was then passed as a parameter in the next function call, that was setting up a db query. Because of the array the table could not be found.

// Now check to see if this is a known core extension
if (isset($tableInfo[$extension]))
{
// See if this category has any content items
   $count = $this->_countItemsFromState($extension, $pk, $tableInfo);


I fixed this into:

// Now check to see if this is a known core extension
if (isset($tableInfo[$extension]))
{
// Get table name for known core extensions
   $table = $tableInfo[$extension]['table_name'];

// See if this category has any content items
   $count = $this->_countItemsFromState($extension, $pk, $table);

Now the table in the db is correctly found and in use.

Difficulties

Since I have no experience with Joomla!, the new workflow or even PHP, it was a little challenging to get familiar with the code (structure).

Documentation Publishing Workflow in Joomla!4

Publishing Workflow

Tasks

My task was to create a documentation about the Publishing Workflow. The only existing DOCs at this point were documentations of the Google Summer of Code project and possible scenarios on how to use the new workflow.

Project documentation

I tried to analyze the different (technical) aspects of the application and document it as structured as possible.

Difficulties

Since there is no documentation available I had no references. In some cases I needed consulting first because I wasn't so sure about the functionality of certain items.

Gruppe 4

Das Team

Name GitHub-Account
Maurice Junior Tchangue Imele maurice
Raoul Yemetio Ngoula raoul
Yves Stephane Membou Talla stephane

Einleitung

Es ist das erste Mal für uns ( Maurice, Raoul und Stephane ) mit Joomla zu arbeiten. In der Tat haben kleine Erfahrung mit Php aber als wir in dieses Projekt eingestiegen sind haben wir uns die Herausforderung gegeben, dass wir was für den Open-Source von Joomla implementieren beziehungsweise weiter implementieren werden. An einem Open-Source zu arbeiten ist was sehr wichtig, wenn man ein perfekter Entwickler sein wird. Denn man bekommt sehr viele Denkweisne durch die Quelltexte je nachdem wie zahlreich die Beitragenden sind. Außerdem schreibt man Zeilencode nicht mehr nach seinen eigenen Wünschen oder seinem eigenen Geschmack sondern sollte man bestimmte Richtlinien einhalten. Es gibt ebenso so viele Sachen, die man beachten muss denn es handelt sich um einen "internationalen" Code, die Leuten verschiedener Länder und Horizonte zur Verfügung stehen werden.

Die Webentwicklung ist ein sehr verbreitetes Thema heutzutage und einer der wichtigen Punkte dabei ist sicherlich die Verwaltung der Inhalte von Webseiten (Content Management auf Englisch), die die Pflegung von Webanwendungen oder Webseiten erleichtert. Es gibt heutzutage so viele Systeme zur Verwaltung von einfachen Webseiten bis hin zu großen Webseiten oder Anwendungen.Diese Systemen sind unter dem Namen "Content Management System" (auf Englsich) bekannt. Joomla gliedert sich unter den Systemen, die sehr häufig benutzt sind und ist sogar das zweite System, dam am häufigsten benutzt sind zur Erstellung von Webseiten. Es enthält so viele interessante Modulen, die Webseiten sehr dynamisch macht. Ein solches Projekt gilt als eine Vorbereitung für größere Projekte später und ist auch eine Gelegenheit Erfahrung mit Open-Source beziehungsweise mit Entwicklern oder Entwicklerteams zu arbeiten, die man gar nicht kennt aber mit denen man ein gemeinsames Ziel hat.

Aufgaben

Aufgabe 1

Features for improving filter menu item

Es gibt keine Pull Request für dies Features. Die Aufgabe besteht darin folgende Filters darzustellen:

  • Ein Filter für Menueinträgen bei Komponenten.
  • Ein Filter bei Top Level Einträgen.
  • Breadcrumb(Pfad) für Menueinträgen im Kontext.

Project Documentation

Das offizielle Repository von Joomla (Joomla_Github) wird erstmal geforkt. Nach dem Fork soll der Repository lokal auf dem Rechner geklont werden. Die Arbeit muss natürlich im Zweig der 4. Version ("Release") von Joomla Open-Source erfolgen. Deshalb muss man sich vergewissern, dass man vom Zweig "staging" zum Zweig "4.0 dev" umstellt. Für jedes Feature muss einen lokalen Zweig ("Branch" auf Englisch) entprechend erstellt werden. Um eine sinnvolle Bearbeitung der Dateien zu ermöglichen, sollte es mit zwei Instanzen von Joomla gearbeitet werden : Eine Instanz, in der man den Code implementiert (die "Client"- Instanz) und eine andere, die synchron mit der ersten funktionniert ("Server"-Instanz) und die am Laufen auf dem Apache-Server betrieben wird. Damit diese Verbindung zwischen den beiden Instanzen realisiert wird sollte ein Paar Schritte eingehalten werden.

  1. Auf das Menü "Tools" im Menüleiste klicken
  2. Das Submenü "Deployment" auswählen
  3. Auf die Option "Configuration" klicken
  4. Die Option "Mappings" im Deployment-Fenster anklicken
  5. Die Dateien eintragen, die in der Server-Instanz geändert werden sollen.


Nach der Verbindung der Joomla-Instanzen sollte das Werkzeug (Tool) "CodeSniffer" (Joomla_CodeSniffer) eingerichtet werden, damit die Joomla-Programmierstandards eingehalten werden. Natürlich sollte ein Debugger (am besten Xdebug) installiert werden. NB: Bei der Verwendung des Debuggers läuft das App nicht mehr auf den Server (es stürtzt ab). Deshalb sollte man, bevor man das App wieder starten will, sich vergewissern, dass der Debugger ausgeschaltet ist. Das verhindert, dass die Prozessen, die für den Betrieb von Joomla-Instanz auf dem lokalen Server zuständig sind vom Debugger verdrängt werden und auf einen anderen Port umgestellt werden.

Implementationsdetails

Feature ' filter menu item by component '

Pull Request für dieses Feature hier Für dieses Feature haben wir mit den folgenden Dateien gearbeitet :

  • ItemsModel.php Die Klasse stellt das Model für die Einträge in Menüs dar. In dieser Klasse wurde für die Filter die Id der Komponenten und die Anfrage in der Datenbank entsprechend gestellt. Die Datei, die dafür zuständig ist, die Komponentennamen zu übersetzen war auch berücksichtigt, um jedesmal nach dem Auswählen eines Eintrages die anderen Einträgen mit ihren vollständigen Namen zu behalten.


  • filter_items.xml Es ging darum in dieser Datei, das "Kätschen" für das Filter nach den Komponenten zu erstellen.

filter


  • en-GB.com_menus.ini Das ist die Datei für die Sprachschlüssel, in der die Sprachschlüssel für das neue Filter hinzugefügt wurde.

language


  • MenuItemByComponentField.php Das ist die neue Datei, die erstellt wurde für das Suchfeld nach den Komponenten.
 <?php
/**
 * @package     Joomla.Administrator
 * @subpackage  com_menus
 *
 * @copyright   Copyright (C) 2005 - 2018 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

namespace Joomla\Component\Menus\Administrator\Field;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Form\Field\GroupedlistField;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\Component\Menus\Administrator\Helper\MenusHelper;
use Joomla\CMS\Language\Text;


/**
 * Supports an HTML grouped select list of menu item grouped by menu
 *
 * @since  3.8.0
 */
class MenuItemByComponentField extends GroupedlistField
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.8.0
	 */
	public $type = 'MenuItemByComponent';

	/**
	 * The menu type.
	 *
	 * @var    string
	 * @since  3.8.0
	 */
	protected $menuType;

	/**
	 * The client id.
	 *
	 * @var    string
	 * @since  3.8.0
	 */
	protected $clientId;

	/**
	 * The component id.
	 *
	 * @var    string
	 * @since  4.0
	 */
	protected $componentId;

	/**
	 * The language.
	 *
	 * @var    array
	 * @since  3.8.0
	 */
	protected $language;

	/**
	 * The published status.
	 *
	 * @var    array
	 * @since  3.8.0
	 */
	protected $published;

	/**
	 * The disabled status.
	 *
	 * @var    array
	 * @since  3.8.0
	 */
	protected $disable;

	/**
	 * Method to get certain otherwise inaccessible properties from the form field object.
	 *
	 * @param   string $name The property name for which to get the value.
	 *
	 * @return  mixed  The property value or null.
	 *
	 * @since   3.8.0
	 */
	public function __get($name)
	{
		switch ($name)
		{
			case 'menuType':
			case 'clientId':
			case 'componentId':
			case 'language':
			case 'published':
			case 'disable':
				return $this->$name;
		}

		return parent::__get($name);
	}

	/**
	 * Method to set certain otherwise inaccessible properties of the form field object.
	 *
	 * @param   string $name  The property name for which to set the value.
	 * @param   mixed  $value The value of the property.
	 *
	 * @return  void
	 *
	 * @since   3.8.0
	 */
	public function __set($name, $value)
	{
		switch ($name)
		{
			case 'menuType':
				$this->menuType = (string) $value;
				break;

			case 'clientId':
				$this->clientId = (int) $value;
				break;

			case 'componentId':
				$this->componentId = (int) $value;
				break;

			case 'language':
			case 'published':
			case 'disable':
				$value       = (string) $value;
				$this->$name = $value ? explode(',', $value) : array();
				break;

			default:
				parent::__set($name, $value);
		}

	}

	/**
	 * Method to attach a JForm object to the field.
	 *
	 * @param   \SimpleXMLElement $element   The SimpleXMLElement object representing the `<field>` tag for the form field object.
	 * @param   mixed             $value     The form field value to validate.
	 * @param   string            $group     The field name group control value. This acts as an array container for the field.
	 *                                       For example if the field has name="foo" and the group value is set to "bar" then the
	 *                                       full field name would end up being "bar[foo]".
	 *
	 * @return  boolean  True on success.
	 *
	 * @see     JFormField::setup()
	 * @since   3.8.0
	 */
	public function setup(\SimpleXMLElement $element, $value, $group = null)
	{
		$result = parent::setup($element, $value, $group);

		if ($result == true)
		{
			$menuType = (string) $this->element['menu_type'];

			if (!$menuType)
			{
				$app             = Factory::getApplication();
				$currentMenuType = $app->getUserState('com_menus.items.menutype', '');
				$menuType        = $app->input->getString('menutype', $currentMenuType);
			}

			$this->menuType    = $menuType;
			$this->clientId    = (int) $this->element['client_id'];
			$this->componentId = (int) $this->element['component_id'];
			$this->published   = $this->element['published'] ? explode(',', (string) $this->element['published']) : array();
			$this->disable     = $this->element['disable'] ? explode(',', (string) $this->element['disable']) : array();
			$this->language    = $this->element['language'] ? explode(',', (string) $this->element['language']) : array();
		}

		return $result;
	}

	/**
	 * Method to get the field option groups.
	 *
	 * @return  array  The field option objects as a nested array in groups.
	 *
	 * @since   3.8.0
	 */
	protected function getGroups()
	{
		$lang         = Factory::getLanguage();
		$extension    = 'com_menu';
		$base_dir     = JPATH_SITE;
		$language_tag = 'en-GB';
		$reload       = true;
		$lang->load($extension, $base_dir, $language_tag, $reload);


		$groups = array();

		$menuType = $this->menuType;

		// Get the menu items.
		$items = MenusHelper::getMenuLinks($menuType, 0, 0, $this->published, $this->language, $this->clientId);

		// Build group for a specific menu type.
		if ($menuType)
		{

			// If the menutype is empty, group the items by menutype.
			$db    = Factory::getDbo();
			$query = $db->getQuery(true)
				->select($db->quoteName('title'))
				->from($db->quoteName('#__menu_types'))
				->where($db->quoteName('menutype') . ' = ' . $db->quote($menuType));
			$db->setQuery($query);


			try
			{
				$menuTitle = $db->loadResult();
			}
			catch (\RuntimeException $e)
			{
				$menuTitle = $menuType;
			}

			// Initialize the group.
			$groups[$menuTitle] = array();

			// Build the options array.
			foreach ($items as $key => $link)
			{
				$lang->load($link->componentname . '.sys', JPATH_ADMINISTRATOR, null, false, true)
				|| $lang->load($link->componentname . '.sys', JPATH_ADMINISTRATOR . '/components/' . $link->componentname, null, false, true);


				// Unset if item is menu_item_root
				if ($link->text === 'Menu_Item_Root')
				{
					unset($items[$key]);
					continue;
				}

				$levelPrefix = str_repeat('- ', max(0, $link->level - 1));


				$link->componentname = Text::_($link->componentname);
				$link->component_id  = $link->component_id . ":" . $link->menutype;

				$groups[$menuTitle][] = HTMLHelper::_('select.option',
					$link->component_id, $levelPrefix . $link->componentname,
					'value',
					'text',
					in_array($link->type, $this->disable)
				);
			}
		}
		// Build groups for all menu types.
		else
		{
			// Build the groups arrays.
			foreach ($items as $menu)
			{

				// Initialize the group.
				$groups[$menu->title] = array();

				// Build the options array.
				foreach ($menu->links as $link)
				{
					$lang->load($link->componentname . '.sys', JPATH_ADMINISTRATOR, null, false, true)
					|| $lang->load($link->componentname . '.sys', JPATH_ADMINISTRATOR . '/components/' . $link->componentname, null, false, true);

					$levelPrefix = str_repeat('- ', $link->level - 1);

					$link->componentname = Text::_($link->componentname);
					$link->component_id  = $link->component_id . ":" . $link->menutype;

					$groups[$menu->title][] = HTMLHelper::_('select.option',
						$link->component_id,
						Text::_($link->componentname),
						'value',
						'text',
						in_array($link->type, $this->disable)
					);
				}
			}
		}

		$tmp_groups = array();

		foreach ($groups as $key => $currentGroup)
		{
			// Build temporary array for array_unique
			$tmp = array();
			foreach ($currentGroup as $k => $v)
				$tmp[$k] = $v->value;

			// Find duplicates in temporary array
			$tmp = array_unique($tmp);

			// Remove the duplicates from original array
			foreach ($currentGroup as $k => $v)
			{
				if (!array_key_exists($k, $tmp))
					unset($currentGroup[$k]);
			}
			$tmp_groups[$key] = $currentGroup;
		}


		// Merge any additional groups in the XML definition.
		$groups = array_merge(parent::getGroups(), $tmp_groups);

		return $groups;
	}
}

Feature für ' filter by top level menu item '

Feature für ' Breadcrumb for menu item context '

Pull request für dieses Feature hier

Für dieses Feature haben wir mit der Datei administrator/components/com_menus/tmpl/items/default.php gearbeitet. Es ist in dieser Datei, dass wir die Anzeige der Menüeinträge aktualisiert haben.



Da in der Tabelle __menus der Datenbank die Id der Vater der Menüeinträge in einer Spalte dargestellt wurden ging es nur in einer Schleife diese Ids mit der Funktion searchParentItem($Parent_id) rauszunehmen und bis die Einträge keine Vater mehr haben oder bis die Id der Vatereintäge größer als 1 sind. Außerdem sind die Vatereinträge nicht klickbar, da sie schon in einer Ebene darüber stehen. Im Bild unten hat man einen Überblick, wie das aussieht.

   <?php
      /*Breadcrumd relocated here */
      $parent_item_id = $item->parent_id;
      $allparent = "";
      while (!empty($parent_item_id) && $parent_item_id>1){
         $parent_item = $this->getModel()->searchParentItem($parent_item_id);
         $allparent = $parent_item->title . "/".$allparent;
         $parent_item_id =  $parent_item->parent_id;
      }
      echo $allparent;
   ?>

Die Funktion searchParentItem($Parent_id) ist wie der Name schon sagt dafür verantwortlich nach Vatereinträgen der Menüeinträge zu suchen anhand deren Ids und sie entsprechend im Pfad (Breadcrumb) darzustellen. Mit dem folgenden Codeabschnitt kann man die Implementierung dieser Funktion sehen.

 
  /*Search the parent item id to select the parent item nameBreadcrumb */
    public function searchParentItem($value) {
        $db    = Factory::getDbo();
        $query = $db->getQuery(true);
        $query->select("*")->from("#__menu")->where("id = " . $value );
        $result = $db->setQuery($query)->loadObject();
        if(empty($result)){
            return null;
        }else{

            return $result;
        }
    }

Wir haben anchließend gestestet, indem wir ein Paar Menueinträge erstellt haben die anderer Menüeinträge untergeordnet waren und das Ergebnis liefert uns die folgende Abbildung.

Breadcrumb

Probleme / Schwierigkeiten

Das erste Problem, das sich stellte war, dass der Apache Server auf einen anderen Port umstellte bei der Verwendung des Debuggers. Wir haben uns erstmal gedacht, dass dieses Problem mit der Ausführung anderer Prozesse im Hintergrund lag und das hat ein bisschen gedauert, bis wir wahrgenommen haben, dass das Problem die Verwendung des Debbugers war.

Für das erste Feature sind wir an das Problem gestoßen, dass sich die Namen der Komponenten, die nicht ausgewählt wurden ständig änderten, nachdem einen bestimmten Komponenten ausgewählt wurden.

  1. Komponentname vor der Auswahl
  2. Komponentname nach der Auswahl

Für das dritte Feature war es uns nicht ganz leicht die Stelle in der HtmlView zu finden wo, die Menüeinträge dargestellt waren, obwohl wir uns in der richtigen Datei fanden. Außerdem haben wir uns erstmal falsch überlegt, wie wir die Methode implementieren werden, um die Ids der Menüeinträge von der Datenbank rausnehmen zu können. Wir nehmen auch Vatereinträgen, die bereits vordefiniert wurden aber das war nicht in der Aufgabenstellung gemeint.


Aufgabe 2

In dieser Aufgabe sollten wir :

  1. Ein Feature implementieren zur Überprüfung der Zugriffsrechte vor der Installation der Erweiterungen (Plug-ins)
  2. Ein Feature implementieren zur Prüfung möglicher Ausnahmen/Fehler vor der Installation "externer" Plug-ins mit anhand deren Ordnern und die Datenbank über eventuelle Änderungen benachrichtigen und dabei Fehler beseitigen zu können.

Implementationsdetails

Es war für uns etwa schwer das erste Feature implementieren zu können, da das sich am besten mit einer virtuellen Maschine testen kann und es Dateisystem implizierte.

Ein Feature implementieren zur Prüfung möglicher Ausnahmen/Fehler vor der Installation "externer" Plug-ins (Plug-ins, die aus dem eigenen Rechner kommen)

Pull request for this feature check before external installation

Der englische Begriff für dieses Feature lautet 'Check for external installation and prevent database changes'. Für dieses Feature haben wir uns erstmal überlegt, welche Dateien beziehungsweise Komponenten für die Installation externer Komponenten zuständig waren. Nach einer kleinen Untersuchung haben wir die entsprechenden Dateien gefunden. Wir haben auch in die folgenden Dateien in com_installer einen Blick geworfen.

  • InstallModel.php
  • DatabaseModel.php
  • ComponentAdapter.php
  • InstallerAdapter.php
  • Installer.php
  • BaseDatabaseModel.php
  • filter_manage.xml

In der Datei Installer.php haben wir nach einer tiefen Suche die Stelle gefunden, wo die Anfragen für die Installation der Datenbank der Erweiterungen bearbeitet werden. Die Funktion "ParseQueries" war betroffen. In dieser Funktion, ging es einfach, darum eine Transaktion zu starten anschließend, die zu committen sobald alle Anfragen durchlaufen worden waren und wenn irgendeinen Fehler auftritt (z.B der Benutzer hat den Namen einer Tabelle geändert), einen "Rollback" der Transaktion auszuführen. In der Funktion "ParseQueries" wurde daher die Struktur geändert. Die neue Struktur dieser Funktion sieht so aus:

 public function parseQueries(\SimpleXMLElement $element)
	{
		// Get the database connector object
		$db = &$this->_db;

                // Begin the transaction
	       $db->transactionStart();

		if (!$element || !count($element->children()))
		{
			// Either the tag does not exist or has no children therefore we return zero files processed.
			return 0;
		}

		// Get the array of query nodes to process
		$queries = $element->children();

		if (count($queries) === 0)
		{
			// No queries to process
			return 0;
		}

		$update_count = 0;

		$isUtf8mb4Db = $db instanceof UTF8MB4SupportInterface;

		// Process each query in the $queries array (children of $tagName).
		try
		{
			foreach ($queries as $query)
			{
				if ($isUtf8mb4Db)
				{
					$query = $db->convertUtf8mb4QueryToUtf8($query);
				}

				$db->setQuery($query)->execute();
				$update_count++;
			}
			//Commit the transaction
			$db->transactionCommit();
		}
		catch (\JDatabaseExceptionExecuting $e)
		{
			// Rollback the transaction when any error occurs
			$db->transactionRollback();
			\JLog::add(\JText::sprintf('JLIB_INSTALLER_ERROR_SQL_ERROR', $e->getMessage()), \JLog::WARNING, 'jerror');

			return false;
		}

		return $update_count;
	}


Showcase


Wie wir gestestet haben Wir haben uns einen Komponenten erstellt, in dessen sql-Datei der Name der Tabelle, auf die sich andere Tabellen bezogen, umgeschrieben wurde. Wir erwarteten, dass nach der Installation des Komponenten eine Fehlermeldung erscheint (was der Fall war) und wir haben uns in der Datenbank geschaut, dass keine Tabelle oder zumindest keine Tabelle, die sich auf eine andere beziehen, in der Datenbank steht. In den folgenden Screenshots kann man den oben erklärten Test genau sehen.

Ein live test wird noch während der Abschlusspräsentation gemacht.

Probleme / Schwierigkeiten

Wenn es Fehler in der SQL-Datei der Komponenten gaben waren sie immer in die Datenbank hinzugefügt, obwohl die Fehler bei der Installation auftraten. Im Backend von Joomla bekam man immer eine Pop-Up Nachricht, die den Fehler bestätigtet aber beim Aktualisieren der Datenbank stellte man fest, dass die Tabellen trotzdem installiert wurde. Auch wenn, wir auf dem richtigen Weg waren wurde das Feature teilweise richtig implementiert, denn wir haben den Fehler spezifiziert.


Zusammenfassung des Projektes

Dieses zweiwöchige Projekt war voller Emotionen. Während den ersten zwei Tagen haben wir sehr viel Spaß gehabt erstmal wegen dem Konzept ' Pizza Bugs and Fun ' und wir lernten uns noch zusammen mit netten Leuten, die auch aus Ausland gekommen sind. Es gab außerdem am zweiten die Episode, wo wir ' Pull request ' testen sollten, die von anderen erstellt wurden. Ab diesem Moment fühlten wir allmählich, dass wir richtig in das Projekt einstiegen. Besonders interessant war auch, dass die Stimmung sehr locker war, was die Arbeit nicht schwer machte.

Es ist wichtig zu erwähnen, dass eines der Hauptprobleme während des Projektes die extreme Hitze war, die die Müdigkeit im Arbeitsraum beschleunigte, so dass wir manchmal gezwungen waren, ein bisschen früher Feierabend zu machen. Daneben gab es auch die Tatsache, dass wir ganz neu in Joomla waren und deshalb standen wir manchmal unter Druck, denn wir wussten, dass die Arbeit nicht klein war. Was die Programmierung angeht, verbrachten in einem Feature so viel Zeit je nachdem das Feature komplex war und wegen der Tatsache, dass wir ein Paar Regeln beim "Codetippen" einhalten sollten. Das war am Anfang sehr schwer, denn das war die erste Erfahrung und wie ein Vortest, bevor irgendetwas zu commiten. Aber man könnte sagen, dass wir einen neuen Programmierstil erlernt haben, die nicht nur offiziell ist sondern auch von vielen anderen bekannt sind.

Das Projekt ist insgesamt sehr gut verlaufen, da alle Interesse daran hatten und mitmachten, am Ende was Neues und Praktisches gelernt und an einem internationalen Projekt gearbeitet hat.