b2in/database/seeders/AssetMediaImportSeeder.php
Kevin Adametz fcb10be120 Interior-Feinschliff: Hero-Slideshow, Lektorat, Rechtstexte, Aufräumen und Korrekturen 08.10.
Startseite und Heroes
- Hero-Slideshow (11 Motive inkl. Febrü) mit Infokarte, Laufzeit-Linie, größeren Klickflächen,
  Goldrahmen und mobiler Karte unter dem Bild; Zeile über der Überschrift, neue Vertrauenspunkte
- Hero-Stil auf Marken, Über uns und Kontakt übertragen, Breadcrumb entfernt
- Gründer-Leiste, Vision-Box auf Ocker, Showroom-Display in Box mit „Größer ansehen“/Vollbild
- Akzentfarbe #a8741f, größere Serif-Überschriften in der Interior-Welt
- Marken: Bildpause mit Zitat; Vereine aktualisiert und verlinkt

Inhalte
- Lektorat aller angezeigten Texte, /about-Korrekturen, Rechtstexte (DDG, TDDDG, Hosting Hetzner)
- Ablauf Maßanfertigung überall einheitlich, Magazin-Beitrag neu, alte Beiträge offline,
  deutsches Datum/Lesezeit, FAQ Projektausstattung, Otterpohl
- Referenzen-Seite per CMS-Schalter ausblendbar

CMS und Technik
- Tote Sektionen, Felder, Seiten und Komponenten entfernt und archiviert (dev/2026-08-28/archiv-*)
- Entwurf /entwurf, Farb-Schalter und /welcome entfernt; Test-Routen nur noch lokal
- Seitenbaum-Beschreibungen geprüft, fehlende CMS-Felder ergänzt, Markenliste aus „Kernmarken“
- Admin-Bildvorschauen repariert, verwendete Bilder in die Mediathek übernommen
- Seeder für das Deployment siehe dev/2026-08-28/entwicklungsplan.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:00:15 +00:00

125 lines
4.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Database\Seeders;
use App\Models\CmsArticle;
use App\Models\CmsBrand;
use FluxCms\Core\Models\CmsContent;
use FluxCms\Core\Models\CmsMedia;
use FluxCms\Core\Services\MediaConversionService;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
/**
* Übernimmt die Bilder, die Seeder unter public/img/assets/ abgelegt haben (Marken, Magazin,
* Slideshow …), in die Mediathek (07.10.2026) – damit sie im Bildauswahl-Dialog erscheinen.
*
* Name in der Mediathek ist der bisherige Pfad (z. B. `marken/cabinet/ankleide-solitaer-eiche-tano.webp`).
* Die Editoren speichern beim Auswählen genau diesen Namen, also bleiben alle Verweise gültig; der
* Admin (media_url()) zeigt das Bild aus der Mediathek. Die Datei wird kopiert, das Original unter
* public/img/assets/ bleibt liegen – die Website liefert weiter von dort (WebP-Fassungen).
*
* Übernommen wird nur, was Marken, Magazin oder CMS-Einträge (samt Standardtexten) tatsächlich
* verwenden. Bereits vorhandene Einträge werden übersprungen – mehrfaches Ausführen ist unbedenklich.
*
* php artisan db:seed --class=AssetMediaImportSeeder
*/
class AssetMediaImportSeeder extends Seeder
{
public function run(): void
{
$disk = config('flux-cms.media.disk', 'public');
$originals = config('flux-cms.media.originals_path', 'cms/media/originals');
$service = app(MediaConversionService::class);
$imported = 0;
foreach ($this->referencedAssets() as $value => $collection) {
if (CmsMedia::query()->where('filename', $value)->exists()) {
continue;
}
$source = public_path('img/assets/'.$value);
$extension = strtolower(pathinfo($source, PATHINFO_EXTENSION));
$path = $originals.'/'.Str::random(40).'.'.$extension;
Storage::disk($disk)->put($path, file_get_contents($source));
$isSvg = $extension === 'svg';
$dimensions = $isSvg ? false : @getimagesize($source);
$media = CmsMedia::create([
'filename' => $value,
'disk' => $disk,
'path' => $path,
'type' => 'image',
'mime_type' => $isSvg ? 'image/svg+xml' : (mime_content_type($source) ?: 'image/'.$extension),
'file_size' => filesize($source),
'original_width' => $dimensions ? $dimensions[0] : null,
'original_height' => $dimensions ? $dimensions[1] : null,
'collection' => $collection,
'conversions' => [],
]);
if (! $isSvg) {
$service->generateThumbnail($media);
}
$imported++;
}
$this->command?->info($imported === 0
? 'Mediathek: alle verwendeten Bilder sind bereits übernommen.'
: "Mediathek: {$imported} Bilder aus public/img/assets übernommen.");
}
/**
* Bildpfade, die Marken, Magazin oder CMS verwenden und die unter public/img/assets/ liegen,
* mit der Sammlung, in die sie kommen (die erste Quelle zählt: Marken, Magazin, Website).
*
* @return array<string, string>
*/
public function referencedAssets(): array
{
$values = [];
$collect = function (mixed $value, string $collection) use (&$collect, &$values): void {
if (is_array($value)) {
array_walk($value, fn ($item) => $collect($item, $collection));
return;
}
if (! is_string($value) || ! preg_match('/\.(jpe?g|png|webp|svg|gif)$/i', $value)) {
return;
}
$value = ltrim(trim($value), '/');
if (str_contains($value, '://') || str_starts_with($value, 'storage/') || str_starts_with($value, 'immobile/')) {
return;
}
if (is_file(public_path('img/assets/'.$value))) {
$values[$value] ??= $collection;
}
};
foreach (CmsBrand::query()->get() as $brand) {
$collect([$brand->logo, $brand->image, $brand->gallery, $brand->sections], 'Marken');
}
foreach (CmsArticle::query()->get() as $article) {
$collect($article->toArray(), 'Magazin');
}
foreach (CmsContent::query()->get() as $row) {
$collect($row->getTranslations('value'), 'Website');
}
$collect(trans('b2in.themes.'.config('app.theme', 'b2in'), [], 'de'), 'Website');
ksort($values);
return $values;
}
}