Migration 20260912000900 ergänzt page.publish_at, page.deleted_at und revision.seq. Verschieben nimmt den ganzen Teilbaum mit und hinterlässt für jede alte Adresse ein 301. Kollisionen, Tiefengrenze und das Verschieben unter eigene Unterseiten werden vor der ersten Änderung abgewiesen; alles in einer Transaktion, weil ein halb verschobener Teilbaum Seiten unerreichbar machen würde. Der Papierkorb ersetzt das sofortige Löschen für die Editorrolle: alle Fassungen bleiben, öffentlich 404, verschwunden aus Navigation, Archiven, Feed, Sitemap, llms.txt und Editorliste. Unterseiten gehen mit, beim Wiederherstellen muss das Elternteil zuerst zurück. Eine Fassung wiederherzustellen überschreibt nichts, sondern legt eine neue an. revision.seq behebt dabei einen echten Fehler: die Reihenfolge des Verlaufs war nicht eindeutig, weil created_at nur Sekunden kennt und mehrere Speichervorgänge in dieselbe Sekunde fallen - "vorherige Fassung wiederherstellen" hätte die falsche treffen können. Geplante Veröffentlichung über cms:publish-due. Ohne Cron bleibt die Seite ein Entwurf, was die sichere Richtung ist. Eine frei wählbare Startseite fehlt bewusst: der Pfad home gilt an elf Stellen als Wurzel, das ist ein eigener Schritt (ADR 022). Geprüft: 160 PHP-Tests / 622 Assertions unter PHP 8.2.12 und 8.4.22, 15 JavaScript-Modelltests, vollständiger Editortest mit axe, Migration zuerst gegen eine Datenbankkopie samt Kontrolle des Backfills. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
71 lines
3.4 KiB
PHP
71 lines
3.4 KiB
PHP
<?php
|
|
|
|
// Isolated test data only. Never touches the configured application database.
|
|
require dirname(__DIR__).'/vendor/autoload.php';
|
|
|
|
use App\Content\DemoContent;
|
|
use App\Content\DocumentValidator;
|
|
use App\Content\PageRepository;
|
|
use App\Infrastructure\ConnectionFactory;
|
|
use Doctrine\DBAL\Schema\Schema;
|
|
use DoctrineMigrations\Version20260912000100;
|
|
use DoctrineMigrations\Version20260912000200;
|
|
use DoctrineMigrations\Version20260912000300;
|
|
use DoctrineMigrations\Version20260912000400;
|
|
use DoctrineMigrations\Version20260912000500;
|
|
use DoctrineMigrations\Version20260912000600;
|
|
use DoctrineMigrations\Version20260912000700;
|
|
use DoctrineMigrations\Version20260912000800;
|
|
use DoctrineMigrations\Version20260912000900;
|
|
use Psr\Log\NullLogger;
|
|
|
|
$directory = dirname(__DIR__).'/var/browser-tests';
|
|
if (!is_dir($directory)) {
|
|
mkdir($directory, 0775, true);
|
|
}
|
|
$path = $directory.'/'.bin2hex(random_bytes(12)).'.db';
|
|
$url = 'sqlite:///'.str_replace('\\', '/', $path);
|
|
$db = ConnectionFactory::create($url);
|
|
$schema = new Schema();
|
|
(new Version20260912000100($db, new NullLogger()))->up($schema);
|
|
(new Version20260912000200($db, new NullLogger()))->up($schema);
|
|
(new Version20260912000300($db, new NullLogger()))->up($schema);
|
|
(new Version20260912000400($db, new NullLogger()))->up($schema);
|
|
(new Version20260912000500($db, new NullLogger()))->up($schema);
|
|
(new Version20260912000600($db, new NullLogger()))->up($schema);
|
|
(new Version20260912000700($db, new NullLogger()))->up($schema);
|
|
(new Version20260912000800($db, new NullLogger()))->up($schema);
|
|
(new Version20260912000900($db, new NullLogger()))->up($schema);
|
|
foreach ($schema->toSql($db->getDatabasePlatform()) as $sql) {
|
|
$db->executeStatement($sql);
|
|
}
|
|
Version20260912000400::applyIndexes($db);
|
|
Version20260912000600::applyIndexes($db);
|
|
Version20260912000900::applyIndexes($db);
|
|
$db->insert('website', ['id' => 'default', 'name' => 'Browser test', 'default_locale' => 'de', 'theme' => '{}']);
|
|
$pages = new PageRepository($db, new DocumentValidator());
|
|
foreach (DemoContent::pages() as $slug => $document) {
|
|
$id = 'test-'.$slug;
|
|
$db->insert('page', ['id' => $id, 'slug' => $slug, 'path' => $slug, 'type' => 'page', 'locale' => 'de', 'website_id' => 'default', 'version' => 0, 'created_at' => gmdate('Y-m-d H:i:s')]);
|
|
$revision = $pages->saveDraft($id, $document, 0);
|
|
$pages->publish($id, $revision, 1);
|
|
}
|
|
$password = bin2hex(random_bytes(20));
|
|
$username = 'browser-'.bin2hex(random_bytes(6));
|
|
$db->insert('cms_user', ['id' => $username, 'username' => $username, 'password_hash' => password_hash($password, PASSWORD_BCRYPT, ['cost' => 4]), 'roles' => '["ROLE_ADMIN"]']);
|
|
$images = [];
|
|
foreach (['Berge', 'Küste'] as $index => $title) {
|
|
$image = imagecreatetruecolor(1800, 1200);
|
|
for ($y = 0; $y < 1200; ++$y) {
|
|
$color = imagecolorallocate($image, 110 + (int) ($y / 18), 150 + (int) ($y / 30), 155 + (int) ($y / 28));
|
|
imageline($image, 0, $y, 1799, $y, $color);
|
|
}
|
|
imagefilledellipse($image, 1300, 270, 210, 210, imagecolorallocate($image, 245, 223, 169));
|
|
imagefilledpolygon($image, [0, 1000, 420, 350 + $index * 150, 950, 980, 1400, 550, 1800, 1100, 1800, 1200, 0, 1200], imagecolorallocate($image, 42, 83 + $index * 20, 75));
|
|
$imagePath = $path.'-'.$title.'.png';
|
|
imagepng($image, $imagePath);
|
|
imagedestroy($image);
|
|
$images[] = $imagePath;
|
|
}
|
|
echo json_encode(['databaseUrl' => $url, 'mediaDirectory' => $path.'-media', 'images' => $images, 'username' => $username, 'password' => $password]);
|