'', 'eyesVariant' => '', 'headVariant' => '', 'mouthVariant' => '', 'mustacheVariant' => '', 'noseVariant' => '', 'topVariant' => '', 'baseColor' => '', 'eyepatchColor' => '', 'glassesColor' => '', 'topColor' => '', 'backgroundColor' => '', ], self::colorCompanionDefaults()); } public static function options(): array { return [ 'beardVariant' => ['' => 'Keine'] + self::variantOptions(5), 'eyesVariant' => ['' => 'Keine'] + self::variantOptions(16), 'headVariant' => ['' => 'Keine'] + self::variantOptions(8), 'mouthVariant' => ['' => 'Keine'] + self::variantOptions(18), 'mustacheVariant' => ['' => 'Keine'] + self::variantOptions(4), 'noseVariant' => ['' => 'Keine'] + self::variantOptions(9), 'topVariant' => ['' => 'Keine'] + self::variantOptions(29), ]; } public static function componentDefinitions(): array { return [ 'headVariant' => ['label' => 'Kopf'], 'eyesVariant' => ['label' => 'Augen'], 'noseVariant' => ['label' => 'Nase'], 'mouthVariant' => ['label' => 'Mund'], 'topVariant' => ['label' => 'Top'], 'beardVariant' => ['label' => 'Bart'], 'mustacheVariant' => ['label' => 'Schnurrbart'], ]; } public static function colorDefinitions(): array { return [ 'baseColor' => ['label' => 'Basisfarbe', 'default' => '#e7ba9a'], 'eyepatchColor' => ['label' => 'Augenklappe', 'default' => '#283341'], 'glassesColor' => ['label' => 'Brille', 'default' => '#283341'], 'topColor' => ['label' => 'Top-Farbe', 'default' => '#4f6ea8'], 'backgroundColor' => ['label' => 'Hintergrund', 'default' => '#f2eadf'], ]; } public static function normalizeSeed(string $seed): string { $seed = strtolower(trim($seed)); $seed = preg_replace('/[^a-z0-9]+/', '-', $seed) ?: ''; $seed = trim($seed, '-'); if ($seed === '') { $seed = self::defaultSeed(); } return substr($seed, 0, 100); } public static function normalizeConfig(array $input): array { $defaults = self::defaultConfig(); $normalized = []; foreach ($defaults as $key => $defaultValue) { if (array_key_exists($key, self::colorDefinitions())) { $normalized[$key] = self::normalizeColor((string)($input[$key] ?? $defaultValue)); continue; } if (str_ends_with($key, 'Fill')) { $normalized[$key] = self::normalizeFill((string)($input[$key] ?? $defaultValue)); continue; } if (str_ends_with($key, 'FillStops')) { $normalized[$key] = self::normalizeFillStops($input[$key] ?? $defaultValue); continue; } if (str_ends_with($key, 'Angle')) { $normalized[$key] = self::normalizeAngle($input[$key] ?? $defaultValue); continue; } $normalized[$key] = self::normalizeVariant((string)($input[$key] ?? $defaultValue)); } return $normalized; } public static function buildQuery(string $seed, array $config): array { $config = self::normalizeConfig($config); $query = ['seed' => self::normalizeSeed($seed)]; $componentFields = array_keys(self::componentDefinitions()); foreach ($componentFields as $field) { $probability = preg_replace('/Variant$/', 'Probability', $field); if ($config[$field] === '') { $query[$probability] = '0'; continue; } $query[$field] = $config[$field]; $query[$probability] = '100'; } foreach (array_keys(self::colorDefinitions()) as $field) { if ($config[$field] !== '') { $query[$field] = $config[$field]; foreach (self::colorCompanionFields($field) as $companionField) { if ($config[$companionField] !== '') { $query[$companionField] = $config[$companionField]; } } } } return $query; } public static function queryToConfig(array $query): array { $config = self::defaultConfig(); foreach (array_keys(self::componentDefinitions()) as $field) { $config[$field] = self::normalizeVariant((string)($query[$field] ?? '')); $probability = (int)($query[preg_replace('/Variant$/', 'Probability', $field)] ?? 100); if ($probability <= 0) { $config[$field] = ''; } } foreach (array_keys(self::colorDefinitions()) as $field) { $config[$field] = self::normalizeColor((string)($query[$field] ?? '')); foreach (self::colorCompanionFields($field) as $companionField) { $config[$companionField] = (string)($query[$companionField] ?? ''); } } return self::normalizeConfig($config); } public static function fallbackSvg(string $seed, string $label = 'Avatar'): string { return Lorelei::fallbackSvg($seed, $label); } private static function normalizeVariant(string $value): string { $value = strtolower(trim($value)); if ($value === '') { return ''; } return preg_match('/^variant\d{2}$/', $value) === 1 ? $value : ''; } private static function normalizeColor(string $value): string { $value = strtolower(trim($value)); if ($value === '') { return ''; } return preg_match('/^#[0-9a-f]{6}$/', $value) === 1 ? $value : ''; } private static function normalizeFill(string $value): string { $value = strtolower(trim($value)); if ($value === '') { return ''; } return in_array($value, ['solid', 'linear', 'radial'], true) ? $value : ''; } private static function normalizeFillStops(mixed $value): string { if ($value === '' || $value === null) { return ''; } $number = max(2, min(8, (int)$value)); return (string)$number; } private static function normalizeAngle(mixed $value): string { if ($value === '' || $value === null) { return ''; } $number = max(-360, min(360, (int)$value)); return (string)$number; } private static function colorCompanionDefaults(): array { $defaults = []; foreach (array_keys(self::colorDefinitions()) as $field) { foreach (self::colorCompanionFields($field) as $companionField) { $defaults[$companionField] = ''; } } return $defaults; } private static function colorCompanionFields(string $field): array { return [ $field . 'Fill', $field . 'FillStops', $field . 'Angle', ]; } private static function variantOptions(int $count): array { $options = []; for ($index = 1; $index <= $count; $index++) { $key = sprintf('variant%02d', $index); $options[$key] = 'Variante ' . $index; } return $options; } }