chore: complete update

This commit is contained in:
2025-07-17 16:24:20 +02:00
parent 899227b0a4
commit 64a7051137
1300 changed files with 85570 additions and 2756 deletions

View File

@@ -0,0 +1,163 @@
<?php
declare(strict_types=1);
namespace App\Domain\Media;
/**
* Erzeugt HTML-Source-Sets für responsive Bilder
*/
final readonly class ImageSourceSetGenerator
{
/**
* Generiert ein vollständiges Picture-Element mit Source-Tags für verschiedene Formate und Größen
*
* @param Image $image Das Originalbild mit seinen Varianten
* @param string $variantType Der Variantentyp (thumbnail, gallery, hero)
* @param array $attributes Zusätzliche Attribute für das img-Tag (alt, class, etc.)
* @return string HTML Picture-Element
*/
public function generatePictureElement(Image $image, string $variantType = 'gallery', array $attributes = []): string
{
$sources = [];
// Varianten nach Format gruppieren
$variantsByFormat = $this->groupVariantsByFormat($image, $variantType);
// Source-Tags für jedes Format generieren
foreach (['avif', 'webp', 'jpeg'] as $format) {
if (isset($variantsByFormat[$format])) {
$sources[] = $this->generateSourceElement($variantsByFormat[$format], ImageFormat::from($format));
}
}
// Fallback img-Tag
$fallbackImage = $this->getFallbackImage($variantsByFormat, $image);
$attributes['src'] = $fallbackImage->getUrl();
$attributes['width'] = $fallbackImage->width;
$attributes['height'] = $fallbackImage->height;
if (!isset($attributes['alt'])) {
$attributes['alt'] = '';
}
$sources[] = $this->generateImgTag($attributes);
return '<picture>' . implode('', $sources) . '</picture>';
}
/**
* Generiert einen einfachen source-Tag mit srcset
*
* @param array $variants Bildvarianten für ein bestimmtes Format
* @param ImageFormat $format Das Bildformat
* @return string HTML source-Element
*/
private function generateSourceElement(array $variants, ImageFormat $format): string
{
$srcset = [];
$sizes = [];
// Nach Größe sortieren (klein nach groß)
usort($variants, function (ImageVariant $a, ImageVariant $b) {
return $a->width <=> $b->width;
});
foreach ($variants as $variant) {
// URL und Breite für srcset
$srcset[] = $variant->getUrl() . ' ' . $variant->width . 'w';
// Sizes basierend auf Breakpoints
$size = ImageSize::from($variant->size);
$breakpoint = $size->getBreakpoint();
if ($breakpoint !== null) {
$sizes[] = "(max-width: {$breakpoint}px) {$variant->width}px";
}
}
// Größte Variante als Standardgröße hinzufügen
$sizes[] = $variants[count($variants) - 1]->width . 'px';
return sprintf(
'<source type="%s" srcset="%s" sizes="%s">',
$format->getMimeType(),
implode(', ', $srcset),
implode(', ', $sizes)
);
}
/**
* Erzeugt einen img-Tag mit den angegebenen Attributen
*
* @param array $attributes HTML-Attribute für das img-Tag
* @return string HTML img-Element
*/
private function generateImgTag(array $attributes): string
{
$htmlAttributes = [];
foreach ($attributes as $name => $value) {
$htmlAttributes[] = sprintf('%s="%s"', $name, htmlspecialchars((string)$value));
}
return '<img ' . implode(' ', $htmlAttributes) . '>';
}
/**
* Gruppiert Bildvarianten nach Format
*
* @param Image $image Das Originalbild
* @param string $variantType Der Variantentyp
* @return array Varianten gruppiert nach Format
*/
private function groupVariantsByFormat(Image $image, string $variantType): array
{
$variantsByFormat = [];
foreach ($image->variants as $variant) {
if ($variant->variantType === $variantType) {
$variantsByFormat[$variant->format][] = $variant;
}
}
return $variantsByFormat;
}
/**
* Wählt das beste Fallback-Bild aus
*
* @param array $variantsByFormat Varianten gruppiert nach Format
* @param Image $image Das Originalbild
* @return ImageVariant Die beste Fallback-Variante
*/
private function getFallbackImage(array $variantsByFormat, Image $image): ImageVariant
{
// Bevorzugen JPEG als Fallback
if (isset($variantsByFormat['jpeg']) && !empty($variantsByFormat['jpeg'])) {
// Mittlere Größe als Fallback verwenden
$variants = $variantsByFormat['jpeg'];
return $variants[min(1, count($variants) - 1)];
}
// Alternativen, falls kein JPEG verfügbar
foreach (['webp', 'avif'] as $format) {
if (isset($variantsByFormat[$format]) && !empty($variantsByFormat[$format])) {
return $variantsByFormat[$format][0];
}
}
// Wenn keine Varianten gefunden wurden, das Originalbild verwenden
return new ImageVariant(
imageId: $image->ulid,
variantType: 'original',
size: 'original',
format: pathinfo($image->filename, PATHINFO_EXTENSION),
mimeType: $image->mimeType,
fileSize: $image->fileSize,
width: $image->width,
height: $image->height,
filename: $image->filename,
path: $image->path,
);
}
}