Fassung 1.4.2: die Systempruefung nennt die SQLite-Fassung
Auf dem Hosting brach die Installation im dritten Schritt ab: near
"(": syntax error. Dort laeuft SQLite in einer Fassung vor 3.16, und
Doctrine liest das Schema mit Tabellenfunktionen wie
pragma_table_info(...), die es erst seit 3.16 gibt.
Die Pruefung nennt die gefundene Fassung jetzt vor der Wahl der
Datenbank, und der Datenbankschritt bietet SQLite gar nicht erst an,
wenn sie zu alt ist - mit dem Hinweis auf MySQL. Eine Voraussetzung,
die erst mitten in der Installation auffaellt, ist keine Pruefung wert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c517173579
commit
ab88ad799f
7 files changed
+73
-3
No files matched your search
@@ -88,6 +88,8 @@ npm.cmd run audit
|
||||
|
||||
Unter Linux/macOS `npm` und `npx` ohne `.cmd`; in CI `npx playwright install --with-deps chromium`. `test:browser` und `audit` benötigen den laufenden lokalen Produktionsmodus auf Port 8080. Ein anderes Ziel lässt sich über `CMS_URL` konfigurieren. `test:editor` startet einen eigenen PHP-Prozess auf einem freien Port mit isolierter Datenbank und zufälligem Testkonto; es ändert keine echten Seiten oder Benutzer. `PHP_BINARY` kann dafür einen alternativen PHP-Pfad angeben. Testdaten bleiben unter `var/browser-tests`, Berichte/Screenshots unter `reports/`. Das Skript erneuert zuvor den Produktionscache.
|
||||
|
||||
**Datenbank:** SQLite ab Fassung 3.16 (Doctrine liest das Schema mit Tabellenfunktionen, die es erst seit dieser Fassung gibt) oder MySQL/MariaDB. Auf älteren Systemen – manche Shared Hoster liefern noch SQLite 3.7 – bleibt MySQL; die Systemprüfung des Installers nennt die gefundene Fassung und bietet SQLite gar nicht erst an, wenn sie zu alt ist.
|
||||
|
||||
Die Verwaltung liegt unter `/admin`. `php bin/console cms:admin:path meine-verwaltung` legt sie auf eine andere Adresse: der Wert landet in `.env.local`, gilt für Routen, Firewall und Schutzkopfzeilen, und wird in der `robots.txt` bewusst nicht genannt. Ohne Argument zeigt der Befehl die aktuelle Adresse.
|
||||
|
||||
`composer format` formatiert PHP. `composer build` wärmt den Symfony-Produktionscache; öffentliche CSS-Dateien sind direkt auslieferbar, es ist kein Frontend-Bundler nötig. Bei Änderungen an `public/assets/design-tokens.json` einmal `npm.cmd run build:design` ausführen und die erzeugte CSS-Datei mitliefern; Node ist auf dem Hosting nicht erforderlich. Nach Änderungen an Produktionskonfiguration/Templates `php bin/console cache:clear --env=prod --no-debug` ausführen. Falls lokale Tests alte Templates verwenden, vor PHPUnit auch `php bin/console cache:clear --env=test --no-debug` ausführen.
|
||||
|
||||
@@ -37,6 +37,7 @@ Erster Commit angelegt (`82b0782`); das Projekt hat damit einen Rückfallpunkt.
|
||||
- **Das erste Bild einer Seite lädt sofort**, alles darunter weiterhin verzögert. Es ist meistens das größte Ding über der Falz.
|
||||
- **Slider mit Punkten ohne Skript** (ADR 044): `::scroll-marker` zeichnet je Folie einen Punkt, der aktive ist erkennbar, die Rollleiste entfällt; ältere Browser behalten das wischbare Schiebefeld. Beitragskarten sind echte Karten (Bild 16:10, 18 px Ecken). Überschriften dürfen ein Wort hervorheben (`<mark>`, in Akzentfarbe). Behoben: die Theme-Schriftskala überschrieb die Größen in Karten und Aufruf-Bändern.
|
||||
- **„Weiterlesen" ist jetzt ein Link.** In der wechselseitigen Beitragsliste stand dort eine reine Beschriftung: sie sah aus wie ein Knopf und war keiner. Der Titel steckt für Vorlesesoftware im Linktext, damit nicht zwölf Links gleich heißen.
|
||||
- **Behoben in 1.4.2: die Systemprüfung nennt jetzt die SQLite-Fassung.** Auf dem Hosting scheiterte die Installation im dritten Schritt mit „near \"(\": syntax error" – dort läuft SQLite in einer Fassung vor 3.16, und Doctrine liest das Schema mit Tabellenfunktionen (`pragma_table_info(...)`), die es erst seit 3.16 gibt. Die Prüfung nennt die gefundene Fassung vor der Wahl der Datenbank, und der Datenbankschritt bietet SQLite gar nicht erst an, wenn sie zu alt ist – mit dem Hinweis auf MySQL. Eine Voraussetzung, die erst mitten in der Installation auffällt, ist keine Prüfung wert.
|
||||
- **Behoben in 1.4.1: dem Releasearchiv fehlten `migrations.php` und `cli-config.php`.** Auf dem Hosting brach die Installation deshalb im dritten Schritt ab – „The configuration file does not exist", genau dort, wo die Tabellen entstehen sollten. Die beiden Dateien standen weder in der Mitnahme- noch in der Ausschlussliste des Releaseskripts, also fiel niemandem auf, dass sie fehlen. Ein Test ordnet jetzt **jeden** Eintrag im Projektstamm einer der beiden Listen zu; was neu dazukommt und unbedacht bleibt, lässt ihn fehlschlagen. Der Installationsweg wurde anschließend vollständig durchgespielt: 3504 Dateien entpackt, 14 Migrationen ausgeführt, 15 Tabellen angelegt.
|
||||
- **Fassung 1.4.0 ist veröffentlicht** und der Installationsweg einmal vollständig durchgespielt: `install.php` aus dem Release geladen (anonym, ohne Anmeldung), in ein leeres Verzeichnis gelegt, aufgerufen – es lädt `kantsites-1.4.0.zip` (4,7 MB, 3502 Dateien mit `vendor/`), prüft die SHA-256-Summe, entpackt und löscht sich selbst. Die frische Installation antwortet mit der Systemprüfung unter `/install`. **Das Repository ist dafür öffentlich** – ein privates liefert die Downloadadresse ohne Anmeldung nicht aus.
|
||||
- **Die Verwaltung kann umziehen** (ADR 065): `php bin/console cms:admin:path meine-verwaltung` legt sie auf eine andere Adresse – geprüft wird, dass der Name frei ist und keine Seite verdeckt. Der Wert steht in `.env.local` und gilt für Routen, Firewall, Schutzkopfzeilen und Statistik. **In der `robots.txt` wird ein geänderter Name nicht genannt**; beim Standardnamen `admin` bleibt die Zeile, weil diese Adresse ohnehin bekannt ist. Die Systemseite zeigt die aktuelle Adresse an.
|
||||
|
||||
@@ -76,7 +76,12 @@ final class InstallController extends AbstractController
|
||||
'error' => $error,
|
||||
'values' => $request->request->all(),
|
||||
'mysql' => \extension_loaded('pdo_mysql'),
|
||||
'sqlite' => \extension_loaded('pdo_sqlite'),
|
||||
// SQLite nur, wenn die Fassung die Tabellenfunktionen kennt, mit denen Doctrine das
|
||||
// Schema liest - sonst scheitert erst der naechste Schritt, und zwar unverstaendlich.
|
||||
'sqlite' => \extension_loaded('pdo_sqlite') && null !== $this->installation->sqliteVersion()
|
||||
&& version_compare((string) $this->installation->sqliteVersion(), Installation::MIN_SQLITE, '>='),
|
||||
'sqliteVersion' => $this->installation->sqliteVersion(),
|
||||
'minSqlite' => Installation::MIN_SQLITE,
|
||||
...$this->token('datenbank'),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -71,6 +71,25 @@ final class Installation
|
||||
* Every failing check names the file or path that has to change. A check that is merely
|
||||
* advisable is marked as such, so a missing `proc_open` does not look like a reason to stop.
|
||||
*/
|
||||
/** Ab dieser Fassung kennt SQLite die Tabellenfunktionen, mit denen Doctrine das Schema liest. */
|
||||
public const MIN_SQLITE = '3.16.0';
|
||||
|
||||
/** Die Fassung der eingebauten SQLite-Bibliothek, oder null wenn es keine gibt. */
|
||||
public function sqliteVersion(): ?string
|
||||
{
|
||||
if (!extension_loaded('pdo_sqlite')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$version = (new \PDO('sqlite::memory:'))->query('SELECT sqlite_version()')?->fetchColumn();
|
||||
} catch (\PDOException) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return is_string($version) ? $version : null;
|
||||
}
|
||||
|
||||
public function checks(): array
|
||||
{
|
||||
$checks = [];
|
||||
@@ -83,6 +102,22 @@ final class Installation
|
||||
$drivers = array_values(array_intersect(['pdo_sqlite', 'pdo_mysql'], get_loaded_extensions()));
|
||||
$checks[] = $this->check('Datenbanktreiber', [] !== $drivers, 'Weder pdo_sqlite noch pdo_mysql ist vorhanden. Ohne einen von beiden gibt es keine Datenbank.', true, implode(', ', $drivers));
|
||||
|
||||
// Die Fassung von SQLite, und zwar vor der Wahl der Datenbank. Doctrine liest das Schema
|
||||
// mit Tabellenfunktionen wie `pragma_table_info(...)`; die gibt es erst seit SQLite 3.16
|
||||
// (Januar 2017). Auf einem Hosting mit aelterem SQLite bricht sonst mitten in der
|
||||
// Installation eine Abfrage mit `near "(": syntax error` ab - eine Meldung, die niemandem
|
||||
// sagt, was zu tun ist. Gefunden auf einem echten Hosting, nicht hier.
|
||||
$sqlite = $this->sqliteVersion();
|
||||
if (null !== $sqlite) {
|
||||
$checks[] = $this->check(
|
||||
'SQLite-Fassung',
|
||||
version_compare($sqlite, self::MIN_SQLITE, '>='),
|
||||
sprintf('Gefunden: %s. Für eine SQLite-Datenbank wird mindestens %s gebraucht. Diese Installation läuft trotzdem – aber mit MySQL statt SQLite; eine Datenbank legt man beim Hoster im Kundenmenü an.', $sqlite, self::MIN_SQLITE),
|
||||
false,
|
||||
$sqlite,
|
||||
);
|
||||
}
|
||||
|
||||
$webp = extension_loaded('gd') && (gd_info()['WebP Support'] ?? false);
|
||||
$checks[] = $this->check('GD mit WebP', $webp, 'Bilder werden beim Hochladen in WebP umgewandelt. Ohne GD mit WebP-Unterstützung schlägt jeder Upload fehl. Der Rest der Website funktioniert.', false);
|
||||
$checks[] = $this->check('ZIP-Erweiterung', class_exists(\ZipArchive::class), 'Wird für Sicherungen als Archiv gebraucht. Ohne sie bleibt die Sicherung ein Verzeichnis.', false);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<legend>Art der Datenbank</legend>
|
||||
<label class="check-label">
|
||||
<input type="radio" name="driver" value="sqlite" {{ driver != 'mysql' ? 'checked' : '' }} {{ sqlite ? '' : 'disabled' }}>
|
||||
<span><strong>SQLite</strong> – eine Datei unter <code>var/</code>. Empfohlen, wenn nichts dagegen spricht.{% if not sqlite %} <em>Auf diesem Server nicht verfügbar.</em>{% endif %}</span>
|
||||
<span><strong>SQLite</strong> – eine Datei unter <code>var/</code>. Empfohlen, wenn nichts dagegen spricht.{% if not sqlite %} <em>{% if sqliteVersion %}Dieser Server hat SQLite {{ sqliteVersion }}; gebraucht wird mindestens {{ minSqlite }}. Nimm MySQL – eine Datenbank legst du beim Hoster im Kundenmenü an.{% else %}Auf diesem Server nicht verfügbar.{% endif %}</em>{% endif %}</span>
|
||||
</label>
|
||||
<label class="check-label">
|
||||
<input type="radio" name="driver" value="mysql" {{ driver == 'mysql' ? 'checked' : '' }} {{ mysql ? '' : 'disabled' }}>
|
||||
|
||||
@@ -235,6 +235,33 @@ final class InstallationTest extends TestCase
|
||||
self::fail('Prüfung fehlt: '.$label);
|
||||
}
|
||||
|
||||
public function testTheSystemCheckNamesTheSqliteVersionBeforeItMatters(): void
|
||||
{
|
||||
// Auf einem echten Hosting gefunden: SQLite war zu alt für die Tabellenfunktionen, mit
|
||||
// denen Doctrine das Schema liest. Die Installation brach erst im dritten Schritt ab, mit
|
||||
// „near "(": syntax error" - eine Meldung, die niemandem sagt, was zu tun ist. Die Fassung
|
||||
// gehört deshalb in die Systemprüfung, vor die Wahl der Datenbank.
|
||||
$version = $this->installation->sqliteVersion();
|
||||
self::assertNotNull($version, 'Auf diesem Rechner gibt es pdo_sqlite - dann muss auch die Fassung lesbar sein.');
|
||||
self::assertMatchesRegularExpression('/^\d+\.\d+/', $version);
|
||||
|
||||
$namen = array_column($this->installation->checks(), 'label');
|
||||
self::assertContains('SQLite-Fassung', $namen);
|
||||
|
||||
$eintrag = null;
|
||||
foreach ($this->installation->checks() as $check) {
|
||||
if ('SQLite-Fassung' === $check['label']) {
|
||||
$eintrag = $check;
|
||||
}
|
||||
}
|
||||
self::assertNotNull($eintrag);
|
||||
self::assertSame($version, $eintrag['found']);
|
||||
// Sie ist eine Empfehlung, kein Hindernis: mit MySQL läuft die Installation auch auf einem
|
||||
// Server mit altem SQLite.
|
||||
self::assertFalse($eintrag['required']);
|
||||
self::assertSame(version_compare($version, Installation::MIN_SQLITE, '>='), $eintrag['ok']);
|
||||
}
|
||||
|
||||
private function removeDirectory(string $path): void
|
||||
{
|
||||
if (!is_dir($path)) {
|
||||
|
||||
Reference in new issue
Block a user