Verwendung von veraltetem Code

    • Official Post

    Liebe Entwickler,


    im Laufe der vergangenen Versionen haben sich einige Komponenten angesammelt, die wir als veraltetet/deprecated markiert haben. Teilweise werden im Plugin-Store auch noch solche Komponenten verwendet, die seit Version 2.1 veraltet sind. Um diesen alten Code entfernen zu können, möchten wir hiermit auf relevanten Code aufmerksam machen und die Migration erläutern.

    In diesem Zuge möchten wir auch nochmals explizit darauf hinweisen, dass wir mittlerweile auch während der Entwicklung an neuen Versionen schon einen Migration Guide erstellen. So existiert mittlerweile auch schon eine Übersicht über Änderungen für Version 5.5, insbesondere eine Liste von Komponenten, die mit Version 5.5 veraltet sind bzw. entfernt werden.


    Im Folgenden haben wir eine Übersicht über einige veraltete Komponten erstellt, die wir bald entfernen möchten, aber teilweise noch in Paketen im Plugin-Store verwendet werden.

    PHP

    AttachmentBBCode::setAttachmentList()/AttachmentBBCode::setObjectID()

    Seit der Einführung der Embedded Objects-API mit Version 2.1, die neben Dateianhängen auch andere eingebundene Inhalte unterstützt, werden AttachmentBBCode::setAttachmentList() und AttachmentBBCode::setObjectID() nicht mehr benötigt, da die über diese Methoden gesetzten Werte nur dann verwendet werden, wenn AttachmentBBCode auf einen Dateianhang nicht über die Embedded Objects-API zugreifen kann.


    Wenn also die Embedded Objects-API verwendet wird, können diese beiden Methodenaufrufe entfernt werden. Ansonsten sollte dringend auf die Embedded Objects-API umgestelt werden.

    FileUtil::downloadFileFromHttp()

    FileUtil::downloadFileFromHttp() ist seit Version 2.0 veraltet und sollte, je nach unterstützten WoltLab Suite-Versionen durch HTTPRequest oder direkt durch Guzzle ersetzt werden.

    BlogDatabaseObject/CALENDARDatabaseObject/GalleryDatabaseObject/FilebaseDatabaseObject/WBBDatabaseObject

    App-spezifische DatabaseObject-Klassen werden seit Version 2.1 nicht mehr benötigt, da dass App-Präfix für die Datenbank-Tabellen von DatabaseObject selbst bestimmt wird. Es kann also direkt von DatabaseObject anstelle der App-spezifische DatabaseObject-Klasse geerbt werden.

    IEventListener

    IEventListener ist seit Version 2.1 veraltet und sollte durch IParameterizedEventListener bzw. AbstractEventListener ersetzt werden. Mit Version 5.5 werden wir neue Event-Klassen einführen, was wir bereits im Migration-Guide für Version 5.5 erklärt haben.

    ClassUtil::isInstanceOf()

    ClassUtil::isInstanceOf() ist seit Version 3.0 veraltet und sollte durch is_subclass_of() ersetzt werden.

    appendSession- und forceWCF-Parameter für LinkHandler::getLink()

    Der Session-Parameter appendSession und forceWCF werden seit Version 3.0 nur noch aus dem Parameter-Array von LinkHandler::getLink() gelöscht und ansonsten ignoriert. Sie können also aus dem Parameter-Array beim Methodenaufruf gelöscht werden.

    Mail

    Die Mail-Klasse ist seit Version 3.0 veraltet und sollte durch wcf\system\email\Email oder wcf\system\email\SimpleEmail ersetzt werden.

    UserProfile::getUserProfile() und UserProfile::getUserProfiles()

    UserProfile::getUserProfile() und UserProfile::getUserProfiles() sind seit Version 3.0 veraltet und sollten jeweils durch UserProfileRuntimeCache::getObject() und UserProfileRuntimeCache::getObjects() ersetzt werden, wobei UserProfileRuntimeCache::getObjects() für nicht-vorhandene Benutzer einen null-Eintrag zurückliefert.

    Event-Listeners und Cronjobs ohne Namen

    Seit Version 3.0 unterstützen Event-Listeners und Cronjobs ein name-Attribut, über das sie identifiziert werden können. Event-Listeners und Cronjobs ohne expliziten Namen sollten durch Event-Listeners und Cronjobs mit Namen ersetzt werden.

    IStackableUserNotificationObject

    IStackableUserNotificationObject ist seit Version 3.1 veraltet und wird nicht mehr verwendet. Das Interface sollte daher nicht mehr implementiert werden.

    EntryDataHandler/EventDataHandler/ImageDataHandler/PostDataHandler/CommentDataHandler

    Die DataHandler-Klassen wurde durch entsprechende RuntimeCache-Klassen ersetzt und sollten deshalb nicht mehr verwendet werden.

    Hinweis: filebase\system\file\FileDataHandler wird erst mit Version 5.5 veraltet sein und durch filebase\system\cache\runtime\FileRuntimeCache ersetzt.

    UserNotificationHandler::deleteNotifications()

    UserNotificationHandler::deleteNotifications() ist seit Version 2.1 veraltet und sollte durch Aufrufe von UserNotificationHandler::markAsConfirmed() (mit gleicher Methodensignatur) ersetzt werden.

    CryptoUtil-Methoden

    CryptoUtil::secureCompare() ist seit Version 5.2 veraltet und sollte durch \hash_equals() ersetzt werden. CryptoUtil::randomBytes() ist seit Version 5.2 veraltet und sollte durch \random_bytes() ersetzt werden. CryptoUtil::randomInt() ist seit Version 5.2 veraltet und sollte durch \random_int() ersetzt werden.

    Für die Kodierung von sicherheitsrelevanten Daten, die beispielsweise mit \random_bytes() genereriert werden, sollte ab Version 5.4 außerdem ein Constant Time Encoder genutzt werden.

    Callback

    Die Callback-Klasse ist seit Version 3.0 veraltet und sollte nicht mehr verwendet werden.

    Veraltete Seiten-Komponenten

    Seit der Überarbeitung der Seiten und Einführung von CMS-Seiten mit Version 3.0 sind IBreadcrumbProvider, IHistorySavingObjectTypeProvider::getActivePageMenuItem(), ISearchableObjectType::getActiveMenuItem(), ITrackablePage, IUserOnlineLocation und UserOnlineLocationHandler veraltet und sollten nicht mehr verwendet werden.

    AbstractHtmlInputNodeProcessorListener-Methoden

    AbstractHtmlInputNodeProcessorListener::replaceLinksWithBBCode() und AbstractHtmlInputNodeProcessorListener::setObjectTitles() sind seit Version 5.2 veraltet und sollten durch AbstractHtmlInputNodeProcessorListener::replaceLinks() ersetzt werden.

    SearchIndexManager::add() und SearchIndexManager::update()

    SearchIndexManager::add() und SearchIndexManager::update() sind seit Version 3.0 veraltet und sollten jeweils durch SearchIndexManager::set() ersetzt werden.

    SystemException

    SystemException ist zwar nicht offiziell veraltet, wird in neuem Code von uns nicht mehr verwendet. Wir verwenden stattdessen Exceptions aus der SPL oder eigene Exception-Klassen. In Plugins sollten deshalb soweit wie möglich auch keine SystemException mehr geworfen werden. Da SystemException von vorhandenem Code noch geworfen wird, müssen diese ggf. auch noch gefangen werden. Unter Umständen ist es aber möglich, stattdessen alle \Exception zu fangen.

    JavaScript

    WCF_CLICK_EVENT

    WCF_CLICK_EVENT sollte in JavaScript- und TypeScript-Code durch "click" ersetzt werden.

    WCF.ACP.Worker

    WCF.ACP.Worker ist seit Version 3.1 veraltet und kann einfach auf WoltLabSuite/Core/Acp/Ui/Worker umgeschrieben werden.

    Templates

    $__wcfVersion

    Die Template-Variable $__wcfVersion zum Brechen von Browser-Caches ist seit Version 2.1 veraltet und sollte durch LAST_UPDATE_TIME ersetzt werden.

    DateDiffModifierTemplatePlugin

    DateDiffModifierTemplatePlugin ist seit Version 3.1 veraltet und sollte durch DateIntervalFunctionTemplatePlugin ersetzt werden werden.

  • Seit wann entspricht WCF_CLICK_EVENT eigentlich bereits click? Im WSC 3.1 scheint das bereits der Fall zu sein (clickEvent wird nicht genutzt):


    JavaScript
        /* assigns a global constant defining the proper 'click' event depending on the browser,
           enforcing 'touchstart' on mobile devices for a better UX. We're using defineProperty()
           here because at the time of writing Safari does not support 'const'. Thanks Safari.
         */
        var clickEvent = ('touchstart' in document.documentElement || 'ontouchstart' in window || navigator.MaxTouchPoints > 0 || navigator.msMaxTouchPoints > 0) ? 'touchstart' : 'click';
        Object.defineProperty(window, 'WCF_CLICK_EVENT', {
            value: 'click' //clickEvent
        });
    • Official Post

    Hallo,

    Seit wann entspricht WCF_CLICK_EVENT eigentlich bereits click? Im WSC 3.1 scheint das bereits der Fall zu sein (clickEvent wird nicht genutzt):

    Use click event globally for now · WoltLab/WCF@7932131
    We need to evaluate if we can use a 3rd party library to consistently use pointer events. Using 'touchstart' has its issues, but gets rid of the lame tap delay.
    github.com

  • IEventListener ist seit Version 2.1 veraltet und sollte durch IParameterizedEventListener bzw. AbstractEventListener ersetzt werden. Mit Version 5.5 werden wir neue Event-Klassen einführen, was wir bereits im Migration-Guide für Version 5.5 erklärt haben.

    Heißt das IParameterizedEventListener wird auf absehbare Zeit deprecated? Für mich wirkt die neue Implementation mit IEvent deutlich unflexibler. Standardmäßig komme ich nicht an die aufrufende Klasse und deren Properties und kann generell nur das modifizieren, was der Entwickler des Ausgangspakets vorsieht, wenn ich das richtig sehe.

    Abgesehen davon, warum sollte ich eine Klasse für einen Listener erstellen und sie explizit aufrufen statt den Part in einer Funktion/Trait/direkt im Code zu handeln? Der explizite Listener muss ja im Ausgangspaket bekannt sein und die entsprechede Klasse vorhanden. Wo ist da der Sinn - oder deute ich die Doku falsch?

    • Official Post

    Hallo,

    Heißt das IParameterizedEventListener wird auf absehbare Zeit deprecated?

    Neue Events werden auf Basis von IEvent implementiert. Bei bestehenden Events kommen wir auf absehbare Zeit wohl nicht um IParameterizedEventListener drum herum.

    Standardmäßig komme ich nicht an die aufrufende Klasse und deren Properties und kann generell nur das modifizieren, was der Entwickler des Ausgangspakets vorsieht, wenn ich das richtig sehe.

    Das ist korrekt und genau so gewollt.

    Abgesehen davon, warum sollte ich eine Klasse für einen Listener erstellen und sie explizit aufrufen statt den Part in einer Funktion/Trait/direkt im Code zu handeln?

    Das musst du falsch verstanden haben. Konzeptionell funktionieren die Listener und Events wie die bereits bekannten Listener und Events. Mir ist auch nicht klar, wie ich das besser als die Beispiele in den Docs erklären können sollte.

  • Das musst du falsch verstanden haben.

    Manchmal hilft ein Beispiel… Beim Tippen gerade festgestellt, dass ich den Zwischenschritt über eine eigene Klasse fehlinterpretiert habe. Man hört jetzt im Prinzip auf die Klasse, die dazwischen hängt. :)


    Das ist korrekt und genau so gewollt.

    Joa, relativ uncool. Also für Drittentwickler, die über die Vorstellungskraft des Entwicklers des Ausgangspakets hinaus gehen wollen.

  • Joa, relativ uncool. Also für Drittentwickler, die über die Vorstellungskraft des Entwicklers des Ausgangspakets hinaus gehen wollen.

    Ob da in Zukunft ein Class-Proxy-System kommt? Find da die Umsetzung im XF interessant und echt flexibel.

    Hey, Designer: Ich will ein neues Design, aber nicht das was Ihr schon habt! Macht doch mit beim Design-Contest!

    • Official Post

    Hallo,

    Joa, relativ uncool. Also für Drittentwickler, die über die Vorstellungskraft des Entwicklers des Ausgangspakets hinaus gehen wollen.

    ich hätte in meiner ersten Antwort vermutlich noch ein wenig mehr ausführen sollen, weil sich in der Praxis eigentlich gar nichts ändert (bzw. die Flexibilität sogar steigt).

    1. Die Klassen sind ein sauberer Ersatz für das $parameters-Array, weil du komplette IDE-Unterstützung hast. Auch bei den $parameters bekommst du nur das, was der Entwickler dir bereitstellt.
    2. Die „alten“ Events waren nie als Freifahrtschein dafür gedacht an beliebigen Properties vom „feuernden“ Objekt rumzufummeln – hier muss ich erneut auf OO-Best-Practices verweisen. Dass das bislang möglich war ist also kein Feature, sondern eher der seit 2007 kaum überarbeiteten Architektur geschuldet, die zum Teil auch durch den schäbigen OO-Support in PHP um 2007 bedingt war. Diese feste Bindung an die Klasse die das Event feuert sorgt dafür, dass die bestehende Implementierung in der Praxis in Beton gegossen wird.
    3. Du kannst jetzt dasselbe logische Event an mehreren Stellen feuern. Bei dem Entwurf explizit als PoC-Beispiel genutzt wurde das in der Doku beispielhaft genannte UserLoggedIn-Event. Aktuell gibt es keine sinnvolle Möglichkeit zu erkennen, wann sich ein Benutzer konzeptionell einloggt, insbesondere wenn alternative Login-Möglichkeiten durch Plugins hinzukommen. Die Events in changeUser sind kein sinnvoller Indikator.
    4. Funktionieren die Events in der JavaScript-DOM-API, Javas Swing, den großen PHP-Frameworks (Laravel, Symfony) und PSR-14 ganz genau so. Dort scheint es offensichtlich auch zu funktionieren ;)
    5. Freuen wir uns natürlich über sinnvolle Vorschläge für Events. Insbesondere, da neue Events jetzt deutlich weniger invasiv in bestehenden Code integriert werden können. Es sind keine neuen Objekt-Properties von Nöten, die Events sind von der bestehenden Implementierung entkoppelt, was notwendiges Refactoring erleichtert, und auch dieser Pfusch mit $parameters entfällt.
  • Die Klassen sind ein sauberer Ersatz für das $parameters-Array, weil du komplette IDE-Unterstützung hast. Auch bei den $parameters bekommst du nur das, was der Entwickler dir bereitstellt.

    Die IDE Unterstützung ist prinzipiell super, ich hatte bisher halt immer instanceof verwendet oder phpDoc; je nach Anwendungsfall.

    Mir geht's weniger um die $parameter als um die Klassen-Properties, die man bisher relativ einfach überschreiben kann (teilweise), was Möglichkeiten schafft, die eventuell nicht ganz so vorgesehen waren oder es einfach nicht anders geht.

    Beispielsweise konnte ich einzelne Objekte aus der Liste herausnehmen oder auf einfache Art Bedingungen zu DatabaseObjectList-Objekten auf Seiten hinzufügen. Gut, effektiv hängt es schlussendlich von der genauen Implementierung der Events ab…


    Die „alten“ Events waren nie als Freifahrtschein dafür gedacht an beliebigen Properties vom „feuernden“ Objekt rumzufummeln – hier muss ich erneut auf OO-Best-Practices verweisen. Dass das bislang möglich war ist also kein Feature, sondern eher der seit 2007 kaum überarbeiteten Architektur geschuldet, die zum Teil auch durch den schäbigen OO-Support in PHP um 2007 bedingt war. Diese feste Bindung an die Klasse die das Event feuert sorgt dafür, dass die bestehende Implementierung in der Praxis in Beton gegossen wird.

    Dass das nicht dafür gedacht war, ist mir bewusst. Die komplette Klasse über den Autoloader auszutauschen ist aber noch mehr Blödsinn; musste ich aber tun, weil ihr eben keine Events eingebaut habt, die den Reaktionen z.B. doch wieder Wertungen zuführen könnten. Und für manche Anwendungen ist es eben notwendig, wenn nicht explizit für den Anwendungsfall Events implementiert werden - ich verweise hier einfach mal auf unsere qualitativen Diskussionen über Events hier und da, bei denen immer die Frage kommt "warum?" statt einfach mal "warum eigentlich nicht?".

    Ja, mir ist bewusst, dass man prinzipiell auch ein Objekt der Klasse Foo gegen ein Array hätte tauschen können und das dann vermutlich in der nächsten Funktion knallt, aber so viel Hirn traue ich den meisten doch zu. ;)


    Du kannst jetzt dasselbe logische Event an mehreren Stellen feuern. Bei dem Entwurf explizit als PoC-Beispiel genutzt wurde das in der Doku beispielhaft genannte UserLoggedIn-Event. Aktuell gibt es keine sinnvolle Möglichkeit zu erkennen, wann sich ein Benutzer konzeptionell einloggt, insbesondere wenn alternative Login-Möglichkeiten durch Plugins hinzukommen. Die Events in changeUser sind kein sinnvoller Indikator.

    Ja, die Glühbirne hat dann aufgeleuchtet, als ich's vorhin im Detail am Beispiel ausführen wollte. Das ist prinzipiell auch ganz cool bzw. sinnvoll.


    Freuen wir uns natürlich über sinnvolle Vorschläge für Events. Insbesondere, da neue Events jetzt deutlich weniger invasiv in bestehenden Code integriert werden können.

    Ich nehme dich beim Wort. ;)

    Ich werde mich damit vermutlich näher beschäftigen, wenn ihr anfangt umzubauen und mir die Möglichkeiten ausgehen.

    • Official Post

    Hallo,

    Die IDE Unterstützung ist prinzipiell super, ich hatte bisher halt immer instanceof verwendet oder phpDoc; je nach Anwendungsfall.

    Die IDE-Unterstützung funktioniert aber nicht mehr mit $parameters (ist beispielsweise in der Email-Klasse im Einsatz). Versuch mir mal ohne in den Code zu schauen zu sagen wie du den Versand einer E-Mail mit einem EventListener verhinderst. Mit den neuen Event-Klassen wäre das ein $event->preventDefault() (in Anlehnung an JavaScript).

    Beispielsweise konnte ich einzelne Objekte aus der Liste herausnehmen oder auf einfache Art Bedingungen zu DatabaseObjectList-Objekten auf Seiten hinzufügen. Gut, effektiv hängt es schlussendlich von der genauen Implementierung der Events ab…

    Das nutzen wir auch in unseren Plugins. Die Events hast du bei den Page|Form|Actions ja zwangsläufig weiterhin. In einer neuen Implementierung könnte die Page|Form|Action hypothetisch direkt IEvent implementieren, wenn es nur ein einziges sinnvolles Event für die Klasse gibt. Alternativ benutzt man irgendwie so etwas:

    PHP
    <?php
    final class BeforeSelect implements IEvent {
      public function __construct(MultipleLinkPage $page) { /* … */ }
      public function getObjectList(): DatabaseObjectList { return $page->objectList; }
    }
    
    // Benutzung in der UserListPage.
    EventHandler::getInstance()->fire(new BeforeSelect($this));

    Ich möchte nicht ausschließen, dass es da noch weitere Anpassungen gibt, wenn sich herausstellt, dass gewisse Dinge in der Praxis zu unschön werden. Das BeforeSelect-Event würde ich so wie beispielhaft dargestellt vermutlich nicht implementieren.

    ich verweise hier einfach mal auf unsere qualitativen Diskussionen über Events hier und da, bei denen immer die Frage kommt "warum?" statt einfach mal "warum eigentlich nicht?"

    Mit jeder neuen öffentlichen Schnittstelle und damit auch mit jedem Event geht man ein Commitment ein. Insbesondere mit dem bisherigen Konzept kommt dann wieder der Punkt mit dem Beton zum Einsatz: Wir müssen genau die Klasse mit genau den Properties beibehalten. Mit den unabhängigen Event-Klassen kann man das Event potentiell verschieben.


    Ein ganz konkretes Beispiel: https://github.com/WoltLab/WCF/issues/3608. Wenn es jetzt ein UserLoggedOut-Event gäbe, dann könnte man das Event in ein neues LogoutForm mitnehmen und ist nicht daran gebunden, dass der Logout über eine Action erfolgt. Das ist ein Implementierungsdetail was den Entwickler eigentlich gar nicht interessiert. Den Entwickler interessiert, dass ein Benutzer sich ausgeloggt hat – nicht, dass der Benutzer die LogoutAction erfolgreich benutzt hat.


    Grundsätzlich gilt aber natürlich weiterhin, dass man für etwaige Wünsche auch einen entsprechenden Use-Case mitbringen muss. Nicht immer ist die vorgeschlagene Lösung auch die konzeptionell sinnvollste Lösung. Stichwort: XY-Problem.

    Ja, mir ist bewusst, dass man prinzipiell auch ein Objekt der Klasse Foo gegen ein Array hätte tauschen können und das dann vermutlich in der nächsten Funktion knallt, aber so viel Hirn traue ich den meisten doch zu. ;)

    Ich würde es nicht auf fehlende „Hirnkapazität“ schieben, aber ich habe im Plugin-Store beispielsweise schon Plugins abgelehnt, die mittels Reflection dafür sorgen, dass Properties von private auf public gestellt wurden. Wenn das dann in einem Refactoring kaputt gehen würde, dann wäre natürlich wieder „WoltLab Schuld“, auch wenn die Intention dahinter durch das private mehr als deutlich sein sollte. Entsprechend sehe ich es auch als Aufgabe vom Framework an da entsprechende Guard-Rails bereitzustellen, damit man es gar nicht erst verkehrt machen kann.

    • Official Post

    Hallo,


    Add UserLoggedIn event and cancel lost password requests upon login by TimWolla · Pull Request #4356 · WoltLab/WCF
    Add a UserLoggedIn event Implement the UserLoggedIn event Cancel lost password requests when the user logs in
    github.com


    Es gibt jetzt einen ersten PR für ein UserLoggedIn-Event auf Basis der neuen Event-Klassen. Da ist dann auch ein beispielhafter EventListener mit drin.


    /cc MysteryCode (der schon Interesse gezeigt hat), Hanashi (der diverse externe Logins im Store hat).