feat(export): use MacroResolutionService in ProExportService for flexible macro injection
This commit is contained in:
parent
81b2a9caf6
commit
cef247336e
|
|
@ -27,7 +27,7 @@ public function importPro(Request $request): JsonResponse
|
|||
}
|
||||
|
||||
try {
|
||||
$service = new ProImportService;
|
||||
$service = new ProImportService();
|
||||
$songs = $service->import($file);
|
||||
|
||||
return response()->json([
|
||||
|
|
@ -53,7 +53,7 @@ public function downloadPro(Song $song): BinaryFileResponse
|
|||
abort(422, 'Song hat keine Gruppen oder Slides zum Exportieren.');
|
||||
}
|
||||
|
||||
$exportService = new ProExportService;
|
||||
$exportService = app(ProExportService::class);
|
||||
$tempPath = $exportService->generateProFile($song);
|
||||
|
||||
$filename = preg_replace('/[^a-zA-Z0-9äöüÄÖÜß\-_ ]/', '', $song->title).'.pro';
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ private function generatePlaylistFromAgenda(Service $service, Collection $agenda
|
|||
$announcementPatterns = Setting::get('agenda_announcement_position');
|
||||
$announcementInserted = false;
|
||||
|
||||
$exportService = new ProExportService;
|
||||
$exportService = app(ProExportService::class);
|
||||
$tempDir = sys_get_temp_dir().'/playlist-export-'.uniqid();
|
||||
mkdir($tempDir, 0755, true);
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ private function generatePlaylistFromAgenda(Service $service, Collection $agenda
|
|||
continue;
|
||||
}
|
||||
|
||||
$proPath = $exportService->generateProFile($song);
|
||||
$proPath = $exportService->generateProFile($song, $service);
|
||||
$proFilename = preg_replace('/[^a-zA-Z0-9äöüÄÖÜß\-_ ]/', '', $song->title).'.pro';
|
||||
$destPath = $tempDir.'/'.$proFilename;
|
||||
rename($proPath, $destPath);
|
||||
|
|
@ -176,7 +176,7 @@ private function generatePlaylistLegacy(Service $service): array
|
|||
$skippedUnmatched = $service->serviceSongs()->whereNull('song_id')->count();
|
||||
$skippedEmpty = 0;
|
||||
|
||||
$exportService = new ProExportService;
|
||||
$exportService = app(ProExportService::class);
|
||||
$tempDir = sys_get_temp_dir().'/playlist-export-'.uniqid();
|
||||
mkdir($tempDir, 0755, true);
|
||||
|
||||
|
|
@ -201,7 +201,7 @@ private function generatePlaylistLegacy(Service $service): array
|
|||
continue;
|
||||
}
|
||||
|
||||
$proPath = $exportService->generateProFile($song);
|
||||
$proPath = $exportService->generateProFile($song, $service);
|
||||
$proFilename = preg_replace('/[^a-zA-Z0-9äöüÄÖÜß\-_ ]/', '', $song->title).'.pro';
|
||||
$destPath = $tempDir.'/'.$proFilename;
|
||||
rename($proPath, $destPath);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ public function generateBundle(Service $service, string $blockType): string
|
|||
public function generateAgendaItemBundle(ServiceAgendaItem $agendaItem): string
|
||||
{
|
||||
$agendaItem->loadMissing([
|
||||
'service',
|
||||
'slides',
|
||||
'serviceSong.song.arrangements.arrangementLabels.label.songSlides',
|
||||
]);
|
||||
|
|
@ -52,7 +53,7 @@ public function generateAgendaItemBundle(ServiceAgendaItem $agendaItem): string
|
|||
throw new RuntimeException('Song "'.$song->title.'" hat keine Gruppen.');
|
||||
}
|
||||
|
||||
$parserSong = (new ProExportService)->generateParserSong($song);
|
||||
$parserSong = app(ProExportService::class)->generateParserSong($song, $agendaItem->service);
|
||||
$proFilename = self::safeFilename($song->title).'.pro';
|
||||
|
||||
$bundle = new PresentationBundle($parserSong, $proFilename);
|
||||
|
|
|
|||
|
|
@ -2,20 +2,25 @@
|
|||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Setting;
|
||||
use App\Models\Service;
|
||||
use App\Models\Song;
|
||||
use ProPresenter\Parser\ProFileGenerator;
|
||||
|
||||
class ProExportService
|
||||
{
|
||||
public function generateProFile(Song $song): string
|
||||
public function __construct(
|
||||
private readonly MacroResolutionService $macroResolutionService,
|
||||
) {
|
||||
}
|
||||
|
||||
public function generateProFile(Song $song, ?Service $service = null): string
|
||||
{
|
||||
$tempPath = sys_get_temp_dir().'/'.uniqid('pro-export-').'.pro';
|
||||
|
||||
ProFileGenerator::generateAndWrite(
|
||||
$tempPath,
|
||||
$song->title,
|
||||
$this->buildGroups($song),
|
||||
$this->buildGroups($song, $service),
|
||||
$this->buildArrangements($song),
|
||||
$this->buildCcliMetadata($song),
|
||||
);
|
||||
|
|
@ -23,19 +28,19 @@ public function generateProFile(Song $song): string
|
|||
return $tempPath;
|
||||
}
|
||||
|
||||
public function generateParserSong(Song $song): \ProPresenter\Parser\Song
|
||||
public function generateParserSong(Song $song, ?Service $service = null): \ProPresenter\Parser\Song
|
||||
{
|
||||
$song->loadMissing(['arrangements.arrangementLabels.label.songSlides']);
|
||||
|
||||
return ProFileGenerator::generate(
|
||||
$song->title,
|
||||
$this->buildGroups($song),
|
||||
$this->buildGroups($song, $service),
|
||||
$this->buildArrangements($song),
|
||||
$this->buildCcliMetadata($song),
|
||||
);
|
||||
}
|
||||
|
||||
private function buildGroups(Song $song): array
|
||||
private function buildGroups(Song $song, ?Service $service = null): array
|
||||
{
|
||||
$defaultArr = $song->arrangements->firstWhere('is_default', true) ?? $song->arrangements->first();
|
||||
|
||||
|
|
@ -45,7 +50,6 @@ private function buildGroups(Song $song): array
|
|||
|
||||
$defaultArr->loadMissing('arrangementLabels.label.songSlides');
|
||||
|
||||
$macroData = $this->buildMacroData();
|
||||
$groups = [];
|
||||
$seenLabelIds = [];
|
||||
|
||||
|
|
@ -61,18 +65,28 @@ private function buildGroups(Song $song): array
|
|||
}
|
||||
$seenLabelIds[] = $label->id;
|
||||
|
||||
$isCopyrightGroup = strcasecmp($label->name, 'COPYRIGHT') === 0;
|
||||
$slides = [];
|
||||
$labelSlides = $label->songSlides->sortBy('order')->values();
|
||||
$totalSlides = $labelSlides->count();
|
||||
|
||||
foreach ($label->songSlides->sortBy('order') as $slide) {
|
||||
foreach ($labelSlides as $slideIndex => $slide) {
|
||||
$slideData = ['text' => $slide->text_content ?? ''];
|
||||
|
||||
if ($slide->text_content_translated) {
|
||||
$slideData['translation'] = $slide->text_content_translated;
|
||||
}
|
||||
|
||||
if ($isCopyrightGroup && $macroData) {
|
||||
$slideData['macro'] = $macroData;
|
||||
if ($service !== null) {
|
||||
$macros = $this->macroResolutionService->macrosForSlide(
|
||||
$service,
|
||||
'song',
|
||||
['index' => $slideIndex, 'total' => $totalSlides, 'label_id' => $label->id],
|
||||
);
|
||||
|
||||
if (! empty($macros)) {
|
||||
// ProPresenter parser currently supports one `macro` entry per slide; keep the first resolved macro until stacked macros are supported.
|
||||
$slideData['macro'] = $macros[0];
|
||||
}
|
||||
}
|
||||
|
||||
$slides[] = $slideData;
|
||||
|
|
@ -88,23 +102,6 @@ private function buildGroups(Song $song): array
|
|||
return $groups;
|
||||
}
|
||||
|
||||
private function buildMacroData(): ?array
|
||||
{
|
||||
$name = Setting::get('macro_name');
|
||||
$uuid = Setting::get('macro_uuid');
|
||||
|
||||
if (! $name || ! $uuid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'name' => $name,
|
||||
'uuid' => $uuid,
|
||||
'collectionName' => Setting::get('macro_collection_name', '--MAIN--'),
|
||||
'collectionUuid' => Setting::get('macro_collection_uuid', '8D02FC57-83F8-4042-9B90-81C229728426'),
|
||||
];
|
||||
}
|
||||
|
||||
private function buildArrangements(Song $song): array
|
||||
{
|
||||
$arrangements = [];
|
||||
|
|
|
|||
|
|
@ -3,8 +3,13 @@
|
|||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Label;
|
||||
use App\Models\Macro;
|
||||
use App\Models\MacroAssignment;
|
||||
use App\Models\MacroCollection;
|
||||
use App\Models\Service;
|
||||
use App\Models\Song;
|
||||
use App\Models\User;
|
||||
use App\Services\ProExportService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
|
|
@ -202,6 +207,96 @@ public function test_download_pro_roundtrip_preserves_content(): void
|
|||
}
|
||||
}
|
||||
|
||||
public function test_export_ohne_service_context_enthaelt_keine_macros(): void
|
||||
{
|
||||
$song = $this->createSongWithContent();
|
||||
$macro = $this->createMacroForExport('Service Macro');
|
||||
MacroAssignment::create([
|
||||
'part_type' => 'song',
|
||||
'macro_id' => $macro->id,
|
||||
'position' => 'all_slides',
|
||||
'order' => 0,
|
||||
]);
|
||||
|
||||
$parserSong = app(ProExportService::class)->generateParserSong($song);
|
||||
|
||||
foreach ($this->allParserSlides($parserSong) as $slide) {
|
||||
$this->assertFalse($slide->hasMacro());
|
||||
}
|
||||
}
|
||||
|
||||
public function test_export_mit_globaler_song_zuweisung_enthaelt_macro_auf_allen_slides(): void
|
||||
{
|
||||
$service = Service::factory()->create();
|
||||
$song = $this->createSongWithContent();
|
||||
$macro = $this->createMacroForExport('Alle Folien Macro');
|
||||
MacroAssignment::create([
|
||||
'part_type' => 'song',
|
||||
'macro_id' => $macro->id,
|
||||
'position' => 'all_slides',
|
||||
'order' => 0,
|
||||
]);
|
||||
|
||||
$parserSong = app(ProExportService::class)->generateParserSong($song, $service);
|
||||
$slides = $this->allParserSlides($parserSong);
|
||||
|
||||
$this->assertNotEmpty($slides);
|
||||
foreach ($slides as $slide) {
|
||||
$this->assertTrue($slide->hasMacro());
|
||||
$this->assertSame('Alle Folien Macro', $slide->getMacroName());
|
||||
$this->assertSame($macro->uuid, $slide->getMacroUuid());
|
||||
$this->assertSame('Export Collection', $slide->getMacroCollectionName());
|
||||
}
|
||||
}
|
||||
|
||||
public function test_export_mit_ausgeblendeter_macro_enthaelt_keine_macro(): void
|
||||
{
|
||||
$service = Service::factory()->create();
|
||||
$song = $this->createSongWithContent();
|
||||
$macro = $this->createMacroForExport('Ausgeblendete Macro', ['hidden_at' => now()]);
|
||||
MacroAssignment::create([
|
||||
'part_type' => 'song',
|
||||
'macro_id' => $macro->id,
|
||||
'position' => 'all_slides',
|
||||
'order' => 0,
|
||||
]);
|
||||
|
||||
$parserSong = app(ProExportService::class)->generateParserSong($song, $service);
|
||||
|
||||
foreach ($this->allParserSlides($parserSong) as $slide) {
|
||||
$this->assertFalse($slide->hasMacro());
|
||||
}
|
||||
}
|
||||
|
||||
private function createMacroForExport(string $name, array $attributes = []): Macro
|
||||
{
|
||||
$macro = Macro::factory()->create(array_merge([
|
||||
'uuid' => '11111111-2222-4333-8444-555555555555',
|
||||
'name' => $name,
|
||||
], $attributes));
|
||||
|
||||
$collection = MacroCollection::create([
|
||||
'uuid' => '99999999-8888-4777-8666-555555555555',
|
||||
'name' => 'Export Collection',
|
||||
]);
|
||||
$collection->macros()->attach($macro->id, ['order' => 0]);
|
||||
|
||||
return $macro;
|
||||
}
|
||||
|
||||
private function allParserSlides(\ProPresenter\Parser\Song $parserSong): array
|
||||
{
|
||||
$slides = [];
|
||||
|
||||
foreach ($parserSong->getGroups() as $group) {
|
||||
foreach ($parserSong->getSlidesForGroup($group) as $slide) {
|
||||
$slides[] = $slide;
|
||||
}
|
||||
}
|
||||
|
||||
return $slides;
|
||||
}
|
||||
|
||||
private function assertStringContains(string $needle, ?string $haystack): void
|
||||
{
|
||||
$this->assertNotNull($haystack);
|
||||
|
|
|
|||
Loading…
Reference in a new issue