Repository navigation
Conversation
- Removed legacy ITX and IT_Error classes, replacing them with a new LMO_Template class that extends HTML_Template_IT. - Updated init.php to utilize Composer's autoloader for dependency management. - Modified lmo-showmain2.php to instantiate LMO_Template instead of HTML_Template_IT. - Adjusted PHPUnit configuration to point to the correct vendor directory. - Enhanced GoldenMaster tests to handle Composer dependencies more efficiently by creating symlinks for the vendor directory. - Updated Normalizer to ignore vendor paths in include_path comparisons during tests.
- Implemented a new setup process for creating the first admin account if it doesn't exist. - Added language translations for initial setup messages in Bosnian, Czech, German, English, Spanish, French, Croatian, Italian, Hungarian, Dutch, Norwegian, Portuguese, Romanian, and Slovene. - Updated admin authentication and main admin pages to handle the new setup process. - Removed the old installer and integrated the setup logic directly into the application flow.
… views and snapshots, enhancing user experience by eliminating unnecessary warnings. Additionally, add language options to the admin footer for improved accessibility and localization.
SP aus der Ligadatei kommt als String, setSpielEnde() nimmt aber nur int an. Das Spielende blieb dadurch immer 0: Sonderpunkte fuer Verlaengerung und Elfmeterschiessen wurden nicht beruecksichtigt, und ein anschliessendes writeFile() schrieb SP=0 zurueck (Datenverlust). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sortTable() (liga) und ligaHandball::sortTable() werteten eine Gruppe punktgleicher Teams erst aus, wenn danach ein Team mit anderer Punktzahl folgte. Die letzte Gruppe der Tabelle wurde nie nach dem direkten Vergleich sortiert. Beide nutzen jetzt die gemeinsame Methode sortTiedGroups(). Sie berechnet nur Gruppen neu, die kleiner als die ganze Tabelle sind; sonst wuerde calcTableforTeams() -> sortTable() bei einem Unentschieden im direkten Duell endlos rekursiv weiterrechnen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
calcTableforTeams() buchte bei gTore == -2 die Punkte fuer die Niederlage (PointsForLost) beim Gast statt beim Heimteam: Das Heimteam bekam sie als Minuspunkte, der Gast als Pluspunkte (Kopierfehler aus dem Zweig darueber). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
factory() war nicht static; der dokumentierte Aufruf liga::factory($datei) endet unter PHP 8 mit einem Error. Ausserdem wurde aus LigaType=Handball der Klassenname "HandballLiga" gebildet, die Klasse heisst aber ligaHandball; dadurch kam immer ein liga-Objekt zurueck. Ohne LigaType gab es zusaetzlich eine Warnung (undefinierter Index). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Actual zaehlt ab 1, das Array $this->spieltage ab 0. Zurueckgegeben wurde bisher der Spieltag nach dem aktuellen (bzw. null beim letzten Spieltag). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Die Schleife las beim letzten Tabellenplatz $sort_pPkt[$i + 1] (undefinierter Index), die Torsummen fuer den direkten Vergleich wurden ohne Initialisierung hochgezaehlt und allPartieForTeams() kann null liefern. Unter PHP 8 brach jede Tabellenberechnung einer Fussball-Liga mit Warnungen ab. Ausserdem summierte der direkte Vergleich die Auswaertstore nicht (= statt +=), und nach einem Tausch wurde die Position des Paares falsch gesetzt. Die Regeln bleiben: Punkte, Spiele, Tordifferenz, Tore, dann direkter Vergleich (Tore, Auswaertstore im direkten Vergleich, alle Auswaertstore). sortDirectTable() gab statt einer Tabelle Debug-Text aus und liefert jetzt die normale Sortierung. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
'spiele' zaehlte jede angesetzte Partie, auch noch nicht gespielte. Diese nahmen ausserdem an der Suche nach hoechstem Heim-/Auswaertssieg und den meisten Toren teil (mit -1:-1 als Ergebnis). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Spiele ohne Niederlage" wurde mit = statt .= angehaengt und ersetzte so die vorherige Ausgabe (z. B. "2 Sieg(e)"); uebrig blieb nur die letzte Zeile. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fehlte das Zeichen, wurde strrpos() false und substr($str, 1) schnitt nur
das erste Zeichen ab ("ohnepunkt" -> "hnepunkt"). Jetzt wie strBeforChar():
leerer String.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Die Endung wird ohne Gross-/Kleinschreibung erkannt, der Name aber mit strrpos($data, 'l98') abgeschnitten. Bei "POKAL.L98" fand das nichts und der Name wurde "POKAL.L9". Jetzt wird alles vor dem letzten Punkt genommen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
findImage() gibt ohne Treffer den Alternativtext zurueck. Ist er gesetzt, brach die Schleife ueber CLASSLIB_IMG_TYPES schon nach der ersten Endung (.gif) ab; Logos als .jpg oder .png wurden nie gefunden. Der Alternativtext wird jetzt erst verwendet, wenn keine Endung passt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Neue Testsuite "unit" (tests/Unit), laeuft vor den Golden-Master-Tests. ClasslibTestCase laedt die classlib ohne init.php und baut Ligen im Speicher oder als kleine .l98-Datei auf. Abgedeckt: Hilfsfunktionen, team, sektion, optionsSektion, partie, spieltag, liga (Nachschlagen, gamesSorted, loadFile inkl. Pokal mit Hin- und Rueckspiel, calcTable mit Heim/Gast/Hin/Rueck, Strafen, Kegel, n.V./i.E., gruener Tisch, direkter Vergleich), ligaFussball, ligaHandball, factory(), stats und html_output.php. Die Tests sichern die vorangehenden Bugfixes ab. Nicht abgedeckt: writeFile() (bindet init.php ein) und loadFromDb() (braucht eine Datenbank). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lmo-calctable.php verglich fuer die Gruppenbildung substr($tab0, 7, 9), also nur die letzte Ziffer der Punkte plus die Minuspunkte. Teams mit z.B. 59 und 49 Punkten galten als gleichauf, wenn sie in der Tabelle direkt untereinander standen; ihre Duelle flossen dann in den direkten Vergleich der tatsaechlich punktgleichen Teams ein. Nachgewiesen an der Primera Division 2013/14: Villarreal und Real Sociedad (je 59) gerieten in die Gruppe von Valencia und Celta (je 49), Celta stand dadurch faelschlich vor Valencia. Jetzt wird der komplette Punkte- und Minuspunkteblock verglichen.
Die classlib wich bei Punktgleichheit vom Kern ab: - Gleichstand wurde ueber Plus- und Minuspunkte erkannt, auch ohne Zwei-Punkte-Regel. Jetzt zaehlen die Minuspunkte nur bei MinusPoints=2. - Brachte der direkte Vergleich keine Entscheidung (Teams haben noch nicht gegeneinander gespielt oder das Duell war ausgeglichen), ging die Reihenfolge nach Tordifferenz verloren; entschieden hat dann der Objektvergleich der Teams. Jetzt bleibt die bisherige Reihenfolge. - Der direkte Vergleich wurde innerhalb des direkten Vergleichs erneut angewendet. Wie im Kern wird jetzt nur einmal ausgewertet. Die Sortierung der Gleichstandsgruppe steht in compareDirect() (Punkte, Minuspunkte, Tordifferenz, Tore; Kegel: Tore vor Tordifferenz), Handball hat eine eigene Variante (Punkte, Spiele, Tordifferenz). Gefunden mit echten Ligen (Serie A, Primera Division mit Wikipedia- Abschlusstabellen): die classlib lag dort in 6 Saisons falsch.
Der Rang aus dem direkten Vergleich ersetzt in $tab0 die erste Ziffer der
Tordifferenz. Ab Rang 10 wurde er zweistellig geschrieben und ueberschrieb
dabei die letzte Ziffer der Minuspunkte. Mit Minuspunkten (Zwei-Punkte-
Regel) stand das beste Team der Gruppe dann ganz unten, z.B. in einer
Handball-Liga nach einem Spieltag mit lauter Unentschieden.
Der Rang belegt jetzt immer genau eine Stelle; ab 10 folgen die Zeichen
hinter "9" (":", ";", ...), die als String richtig dahinter sortieren.
Fuer Gruppen mit weniger als zehn Teams aendert sich $tab0 nicht.
Wertung "beidseitiges Erg." (ET=3): laut Hilfetext zaehlt das Ergebnis fuer beide Mannschaften gleichermassen aus Sicht der Heimmannschaft. In der Praxis ist das die Spielwertung gegen beide Mannschaften (z.B. beide nicht angetreten), eingetragen als 0:2. Bisher bekamen beide Teams nur die Tore und das Spiel, aber weder Sieg, Remis oder Niederlage noch Punkte und Minuspunkte. In einer Liga mit Minuspunkten standen beide dadurch besser da als richtig. Jetzt wird das Ergebnis aus Heimsicht fuer beide gewertet, in der Tabelle und im direkten Vergleich (lmo-calctable1.php). Golden Master: geaendert sind die Ligen mit dieser Wertung (wertung, direct_wertung, direct_wertung_many) und die Ergebniseingabe im Admin-Test, die ein 1:1 beidseitig eintraegt. Spiele und Tore bleiben gleich, es aendern sich Bilanz, Punkte, Minuspunkte, Serien und die Reihenfolge.
Die Standardtabelle rechnet bis $endtab = $anzst, also bis zum letzten Spieltag der Saison, auch wenn erst wenige Spieltage gespielt sind. Eine Strafe "ab Spieltag 20" wurde dadurch schon nach Spieltag 5 abgezogen. Massgeblich ist jetzt der letzte Spieltag mit einem Ergebnis ($calc_lastst): die Strafe zaehlt, wenn er (bzw. der angezeigte Spieltag, falls frueher) mindestens X ist. Strafen ab Spieltag 0 zaehlen wie bisher sofort. Heim- und Auswaertstabelle bleiben ohne Strafen.
Straf-/Bonustore gibt man in lmo-adminteams.php als "x : y" ein, gespeichert werden sie negiert (TOR1 = -x, TOR2 = -y); "+2" bei den Gegentoren heisst also zwei Gegentore mehr. strafen() zog TOR2 mit abs() ab und machte aus zusaetzlichen Gegentoren weniger Gegentore. Jetzt wie lmo-calctable.php: mTor -= TOR2.
Die classlib buchte Strafen innerhalb der Partien eines Spieltags: - War das Team an Spieltag STDA spielfrei, entfiel die Strafe ganz. - Strafen zaehlten auch in Heim- und Auswaertstabelle. - Eine Strafe ab einem spaeteren Spieltag zaehlte schon, sobald die Tabelle bis dahin gerechnet wurde, auch ohne gespielte Partien. Jetzt entscheidet strafeFaellig(), ob eine Strafe in dieser Tabelle zaehlt (nicht in Heim-/Auswaertstabelle, Hin- und Rueckrunde wie lmo-calctable.php, erst wenn Spieltag STDA Ergebnisse hat). calcTable() bucht faellige Strafen nach jedem Spieltag genau einmal je Team, unabhaengig davon, ob es spielt; so stimmt auch die Platzierung je Spieltag (possp).
Die classlib kannte die Wertung "beidseitiges Erg." nicht und wertete das Spiel normal: bei einer Spielwertung 0:2 gegen beide Mannschaften bekam das Gastteam einen Sieg. Wie im Kern gilt das Ergebnis jetzt fuer beide Teams aus Sicht der Heimmannschaft (Tore, Sieg/Remis/Niederlage, Punkte, Minuspunkte), in calcTable() und im direkten Vergleich. Gebucht wird ueber die neue Hilfsmethode addResult().
Neue Testsuite "real-data" (tests/RealData). Jede Liga wird mit lmo-calctable.php und mit liga::calcTable() gerechnet; Spiele, Punkte, Minuspunkte, Tore und Reihenfolge muessen mit der Vergleichstabelle uebereinstimmen. - 97 Saisons von OpenLigaDB (1.-3. Liga, Frauen-Bundesliga, Premier League, Serie A, Primera Division), dazu fuer 55 Saisons die offizielle Abschlusstabelle aus der englischen Wikipedia. 75 davon sind als Pruefmassstab nutzbar (Spiele und Tabelle passen zueinander); Serie A und Primera Division nur mit offizieller Tabelle, weil OpenLigaDB den direkten Vergleich nicht wertet. - 10 konstruierte Ligen fuer Faelle, die echte Ligen nicht liefern: Kegelwertung, Zwei-Punkte-Regel mit ungleich vielen Spielen, Sonderpunkte n.V./i.E., gruener Tisch, Bonustore und negative Punkte, Strafe bei Spielfrei, Strafe ab spaeterem Spieltag, beidseitiges Ergebnis, zehn punktgleiche Teams mit direktem Vergleich und Schritt 4 der Bundesliga-Reihenfolge. Bekannte Regelvarianten, die LMO nicht abbildet (nur die Werte werden geprueft): La Liga 2010/11 (Dreiervergleich) und Bundesliga Schritt 4 (direkter Vergleich nach Punkten, Tordifferenz und Toren). Daten aktualisieren: php tests/RealData/bin/fetch_openligadb.php und php tests/RealData/bin/fetch_wikipedia.php (Rohdaten in .cache, ignoriert).
calcTableforTeams() wertete fuer den direkten Vergleich immer alle Partien der ganzen Saison, auch Pokalrunden. In der Tabelle nach Spieltag 1 flossen so Duelle aus spaeteren Spieltagen ein, in Heim- und Auswaertstabelle auch die Spiele am jeweils anderen Spielort. Betroffen waren Tabellen nach einem frueheren Spieltag, Heim-, Auswaerts-, Hin- und Rueckrundentabelle und die Platzierung je Spieltag (possp). calcTable() gibt jetzt ueber directContext mit, welche Spieltage und welche Tabellenart gerade gerechnet werden. Der direkte Vergleich zaehlt nur diese Partien und in Heim-/Auswaertstabelle nur die passende Seite (keepSide()), wie lmo-calctable1.php. Ausserhalb von calcTable() zaehlen wie bisher alle Partien.
ClasslibParityTest rechnet jede Liga der Testinstanz mit lmo-calctable.php und mit liga::calcTable(), in Gesamt-, Heim-, Auswaerts-, Hin- und Rueckrundentabelle und nach jedem einzelnen Spieltag. Spiele, Punkte, Minuspunkte, Tore, Gegentore und Platz muessen uebereinstimmen. Ausgenommen: vollstaendiger Gleichstand (gleiche Punkte, Minuspunkte und Tore; Kern und classlib entscheiden ihn verschieden, eine Regel gibt es nicht) und Handicap (nur im Kern, nur Gesamttabelle). calc.php rechnet mit dem neuen Parameter "alle" jeden Spieltag (Runner::calc($datei, true)); ohne ihn wie bisher die feste Auswahl fuer den Golden Master.
writeFile() band update_addons.php bei jedem Aufruf mit include ein. Die Datei deklariert die Funktion updateAddons(), ein zweites writeFile() im selben Request brach deshalb mit "Cannot redeclare updateAddons()" ab. Die heutigen Aufrufer (lmo-rueckrunde.php, lmo-adminrounds.php) speichern nur einmal je Request; jeder Code, der zwei Ligen nacheinander speichert, stuerzte ab. Jetzt require_once.
ClasslibWriteTest legt alle 85 Ligen aus tests/RealData/fixtures komplett ueber die classlib an (Teams, Spieltage, Partien, Optionen, Strafen, Sonderwertungen; RealLeague::buildLiga()) und speichert sie mit writeFile() - in der Testinstanz mit init.php und updateAddons(), alle in einem Prozess (bin/classlib_write.php, Runner::classlibWrite()). Danach: - der Kern liest jede gespeicherte Datei und muss die erwartete Tabelle rechnen - die classlib liest sie wieder ein und muss dieselbe Liga bekommen Die Tabellenpruefung von RealLeagueTest liegt dafuer jetzt im Trait ComparesTables und wird von beiden Tests genutzt.
loadFile() ordnete in den [RoundN]-Abschnitten alles ausser D1, D2 und MO einer Partie zu. Schluessel ohne Nummer wie HS (Handicap-Reihenfolge je Spieltag) passten nicht und wurden verworfen; writeFile() schrieb sie nicht. Nach "Rueckrunde erzeugen" oder "Spieltage verschieben" waren in einer Handicap-Liga alle Handicap-Angaben weg. spieltag hat jetzt setParameter()/getParameter() (wie partie). loadFile() legt dort alle Spieltagswerte ohne Partienummer ab, writeFile() schreibt sie zurueck.
writeFile() ersetzte den Titel der Liga immer durch "<acronym title='Liga Manager Online (classlib 2.8)'>LMO</acronym>" und setzte den aktuellen Spieltag (Actual) auf den letzten Spieltag mit einem Ergebnis. Beides sind Einstellungen aus der Oberflaeche und gingen bei jedem Speichern ueber die classlib verloren. Der Titel wird jetzt nur gesetzt, wenn er leer ist; Actual bleibt, wenn es ein gueltiger Spieltag ist, sonst wird es wie bisher berechnet.
updateAddons() oeffnete die gespeicherte Liga mit basename($fileName), also ohne Unterordner. Lag die Liga in einem Unterordner des Ligenverzeichnisses, wurde sie nicht gefunden; HTML-Export und Statistik liefen danach ohne Daten (Warnungen, je nach Einstellung Abbruch in lmo-savehtml1.php). Betroffen: "Rueckrunde erzeugen" und "Spieltage verschieben". $file ist jetzt wie im restlichen LMO der Pfad relativ zum Ligenverzeichnis; $liga bleibt der reine Name fuer das Tippspiel.
lmo-rueckrunde.php liess sich ohne Anmeldung direkt aufrufen (lmo-rueckrunde.php?file=...) und schrieb dann die angegebene Ligadatei neu. Jetzt wie die anderen Admin-Includes: lmo-admintest.php bricht ab, wenn die Datei nicht aus dem Admin-Bereich eingebunden wird, zusaetzlich wird die Admin-Anmeldung geprueft. Golden Master: der Sicherheitstest fuer direkte Aufrufe hielt bisher die veraenderte Ligadatei fest. Der Abschnitt zu lmo-rueckrunde.php ist jetzt leer, Dateiaenderungen: keine.
ClasslibRoundtripTest: jede Liga der Testinstanz und eine Pokal-Liga (Hin- und Rueckspiel, Verlaengerung, Finale) wird erst von LMO selbst gespeichert (lmo-openfile.php + lmo-savefile.php wie im Admin), dann mit liga::loadFile() geladen und mit liga::writeFile() gespeichert. Kein Schluessel darf verloren gehen oder sich aendern. Laeuft als Kindprozess in der Testinstanz (bin/classlib_roundtrip.php, Runner::classlibRoundtrip()) auf Kopien in ligen/roundtrip/ mit eigenem Dateinamen, weil LMO Ausgabedateien nur nach dem Dateinamen benennt.
- lmo/composer.json: Version 4.2.0 (2026-10-10), PHP-Mindestversion 8.0 statt 7.4 (classlib und Template-Bibliothek laufen nur noch ab PHP 8) - changelog.md: Abschnitt 4.2.0 in Deutsch und Englisch - Golden Master: Versionszeile der Info-Seiten
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.