Migration 20260912000800 ergänzt page.robots, page.og_media_id, website.settings und die Tabelle redirect. Alles Maschinenlesbare wird aus dem veröffentlichten Bestand abgeleitet, nichts separat gepflegt: die Sitemap listet nur veröffentlichte, indexierbare Seiten samt Beitragsübersicht und Begriffsarchiven, und dieselbe Einstellung setzt auch das noindex-Meta - beide Aussagen können nicht auseinanderlaufen. Strukturierte Daten entstehen nur aus gepflegten Werten: ohne Angaben wird kein leerer Organization-Block ausgegeben. JSON-LD ist ein Datenblock, kein Skript, daher bleibt script-src 'none' unberührt. Weiterleitungen greifen vor dem 404, aber nach der Seitensuche: eine vorhandene Seite gewinnt immer, sonst könnte ein alter Eintrag eine neue Seite unerreichbar machen. Ketten werden abgewiesen. robots.txt nimmt zusätzliche Zeilen nur nach festem Muster an, damit ein Eintrag die Datei nicht umdeuten kann. llms.txt ist standardmäßig aus. Geprüft: 128 PHP-Tests / 507 Assertions unter PHP 8.2.12 und 8.4.22, 14 JavaScript-Modelltests, Lint/Format/Container. Dazu eine reine Sichtprüfung im Browser auf einer lokalen Demoseite - weiterhin keine axe- oder Lighthouse-Messung. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
68 lines
3.3 KiB
PHP
68 lines
3.3 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 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);
|
|
foreach ($schema->toSql($db->getDatabasePlatform()) as $sql) {
|
|
$db->executeStatement($sql);
|
|
}
|
|
Version20260912000400::applyIndexes($db);
|
|
Version20260912000600::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]);
|