Problembeschreibung

Mitunter passiert es, dass wenn Produkte in den Warenkorb gelegt werden in der Meldungsbox von VirtueMart für den Erfolg (oder auch Mißerfolg) die Box ohne einen Meldungstext ausgegeben wird. Erstmals war mir dieser Effekt bei VM 1.0.x aufgefallen bei einem Projekt welches ich per XAMPP local betrieb um dort zu entwickeln. Etwas genauer beschrieben: Die beim Klick auf den Warenkorb wird eine Meldungsbox (fancybox / facebox; mooprompt) eingeblendet. In diese Box wird der Success-Text der per Ajax empfangen wird eingespielt. Er meldet ob das Produkt zum Warenkorb hinzugefügt wurde oder nur die Menge erhöht wurde oder eben auch mal Fehlermeldungen. Diese Meldung blieb sporadisch aus.

 

Grundlagenwissen und Ursache für diese Erscheinung

Alle Meldungen die VirtueMart an den Browser zurückgeben will, werden zunächst in einem Array-Stack gesammelt ($vmLogger). Dafür gibt es entspr. Classenscripte zu finden unter administrator/components/com_virtuemart/classes/Log/ die das Handling dafür übernehmen und entspr. Objekte bereitstellten mit Ihren Methoden $vmLogger->tip, ~->notice, ~->debug, ~->error, ~->warning (die verschiedenen möglichen Errorlevel). Ebenfalls kann hierüber gesteuert werden wohin eine Ausgabe geloggt werden soll (Datei, E-Mail, Display, neu auch gesammelt über composite).

Wenn diese Meldungen erzeugt und in den Meldungs-Stack geschrieben werden, erhalten diese Array-Elemente eine Key der basiert auf einem md5-Hash. Diese Hash-ID wird erzeugt anhand der Milisekunde in der der Aufruf erfolgt. Für die Bildschirmausgabe wird also z.B. in der Log/LogInit.php über $vmLogger->addChild($vmDisplayLogger); ein Eintrag erzeugt und dem Stack hinzugefügt. Bei der Initialisierung des Display-Logger-Objektes wird in der Log/display.php in der Methode vmLog_display() die _id erzeugt die dann folgend immer als Key verwendet wird. Über die Class-Methode vmLog_null (s. Script Log/null.php) wird danach auch immer ein Null-Objekt dem Stack übergeben (Grund hierfür nicht untersucht). Hier genau entsteht folgender Konflikt:

Jede dieser addChild()-Aufrufe arbeitet bei der Erzeugung der _id's mit der der Anweisung $this->_id = md5(microtime()); Liegen aber die Aktionen zeitlich so eng zusammen, dass diese in der gleichen Millisekunde ausgeführt werden, dann bekommen Sie durch md5() den gleichen Hash als ID und überschreiben sich gegenseitig durch den gleichlautenden Array-Key. I.d.R. überschreibt die letzte Stack-Add-Aktion vmLog_null die vorherige womit die vorherige eben verloren ist.

 

Problembeseitigung

Im genannten Verzeichnis administrator/components/com_virtuemart/classes/Log/ gibt es die entsprechenden Class-Scripte mit ihren gleichlautenden Init-Methoden. In jeder dieser Methoden, aber zumindest in vmLog_display() müssen wir dafür sorgen, dass die erzeugte ID zuverlässig unique erzeugt wird. microtime() genügt dafür nicht, weshalb wir einfach noch .rand() hinzufügen. Die fertig modifizierte Scriptzeile sieht dann so aus:

$this->_id = md5(microtime().rand());

 

Oben ausgeführt Sachverhalt betreffen speziell die Version 1.0.x von VirtueMart.

Ab VirtueMart 2 gibt wird die Ausgabe der Meldungen anders gehandhabt. Hier gibt es ein helpers-Script administrator/components/com_virtuemart/helpers/config.php (class vmConfig) welches verschieden Funktionen zu Ausgabe von Meldungen deklariert (vmInfo, vmAdminInfo, vmWarn ...). Hier wird statt dessen mit JFactory::getApplication() gearbeitet, weshalb das Problem hier nicht auftritt.