pp-planer/app/Services/ProBundleExportService.php
Thorsten Bus eee35722fb fix(export): inject macros for information/moderation/sermon/agenda_item parts
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-04 06:48:17 +02:00

152 lines
4.9 KiB
PHP

<?php
namespace App\Services;
use App\Models\Service;
use App\Models\ServiceAgendaItem;
use Illuminate\Support\Facades\Storage;
use InvalidArgumentException;
use ProPresenter\Parser\PresentationBundle;
use ProPresenter\Parser\ProBundleWriter;
use ProPresenter\Parser\ProFileGenerator;
use RuntimeException;
class ProBundleExportService
{
private const ALLOWED_BLOCK_TYPES = ['information', 'moderation', 'sermon'];
public function __construct(
private readonly MacroResolutionService $macroResolutionService,
) {}
public function generateBundle(Service $service, string $blockType): string
{
if (! in_array($blockType, self::ALLOWED_BLOCK_TYPES, true)) {
throw new InvalidArgumentException('Ungültiger Blocktyp für .probundle Export.');
}
$slides = $service->slides()
->where('type', $blockType)
->orderBy('sort_order')
->get();
$groupName = ucfirst($blockType);
return $this->buildBundleFromSlides($slides, $groupName, $service, $blockType);
}
public function generateAgendaItemBundle(ServiceAgendaItem $agendaItem): string
{
$agendaItem->loadMissing([
'service',
'slides',
'serviceSong.song.arrangements.arrangementLabels.label.songSlides',
]);
$title = $agendaItem->title ?: 'Ablauf-Element';
if ($agendaItem->serviceSong?->song_id && $agendaItem->serviceSong->song) {
$song = $agendaItem->serviceSong->song;
$labelCount = $song->arrangements()
->withCount('arrangementLabels')
->get()
->sum('arrangement_labels_count');
if ($labelCount === 0) {
throw new RuntimeException('Song "'.$song->title.'" hat keine Gruppen.');
}
$parserSong = app(ProExportService::class)->generateParserSong($song, $agendaItem->service);
$proFilename = self::safeFilename($song->title).'.pro';
$bundle = new PresentationBundle($parserSong, $proFilename);
$bundlePath = sys_get_temp_dir().'/'.uniqid('agenda-song-').'.probundle';
ProBundleWriter::write($bundle, $bundlePath);
return $bundlePath;
}
$slides = $agendaItem->slides()
->whereNull('deleted_at')
->orderBy('sort_order')
->get();
return $this->buildBundleFromSlides($slides, $title, $agendaItem->service, 'agenda_item');
}
/** @param \Illuminate\Database\Eloquent\Collection<int, \App\Models\Slide> $slides */
private function buildBundleFromSlides($slides, string $groupName, ?Service $service = null, ?string $partType = null): string
{
$slideData = [];
$mediaFiles = [];
foreach ($slides as $slide) {
$sourcePath = Storage::disk('public')->path($slide->stored_filename);
if (! file_exists($sourcePath)) {
continue;
}
$imageFilename = basename($slide->stored_filename);
$imageContent = file_get_contents($sourcePath);
if ($imageContent === false) {
continue;
}
$mediaFiles[$imageFilename] = $imageContent;
$singleSlideData = [
'media' => $imageFilename,
'format' => 'JPG',
'label' => $slide->original_filename,
];
if ($service !== null && $partType !== null) {
$slideIndex = count($slideData);
$totalSlides = $slides->count();
$macros = $this->macroResolutionService->macrosForSlide(
$service,
$partType,
['index' => $slideIndex, 'total' => $totalSlides, 'label_id' => null],
);
if (! empty($macros)) {
// ProPresenter parser currently supports one `macro` entry per slide
$singleSlideData['macro'] = $macros[0];
}
}
$slideData[] = $singleSlideData;
}
$groups = [
[
'name' => $groupName,
'color' => [0, 0, 0, 1],
'slides' => $slideData,
],
];
$arrangements = [
[
'name' => 'normal',
'groupNames' => [$groupName],
],
];
$song = ProFileGenerator::generate($groupName, $groups, $arrangements);
$proFilename = self::safeFilename($groupName).'.pro';
$bundle = new PresentationBundle($song, $proFilename, $mediaFiles);
$bundlePath = sys_get_temp_dir().'/'.uniqid('bundle-').'.probundle';
ProBundleWriter::write($bundle, $bundlePath);
return $bundlePath;
}
private static function safeFilename(string $name): string
{
return preg_replace('/[^a-zA-Z0-9äöüÄÖÜß\-_ ]/', '', $name) ?: 'presentation';
}
}